Author Topic: Screen Not Refreshing upon Menu Close  (Read 13286 times)

KM

  • Newcomer
  • Posts: 13
  • Karma: +0/-0
    • View Profile
Screen Not Refreshing upon Menu Close
« on: January 28, 2017, 10:39:39 PM »
I've been struggling lately with having my screen refresh upon the inventory or level-up menu being closed.  I'm going to put relevant parts of script here, any help is appreciated.  Other minor bugs;
1.  The screen, upon resizing, doesn't resize any of the menu bars to make them fit the new window size that bearlibterminal imparts.
2.  I'd like to be able to display names with just a mouse hover, rather than a mouse click, mouse-click I'd like to work into having a more full description come up.  Not sure where or if there are commands for these things.

Quote
def inventory_menu(header):
    global fov_recompute
    #show a menu with each item of the inventory as an option
    if len(inventory) == 0:
        options = ['Inventory is empty.']
    else:
        options = []
        for item in inventory:
            text = item.name
            #show additional info, in case it's equipped
            if item.equipment and item.equipment.is_equipped:
                text = text + ' (on ' + item.equipment.slot + ')'
            options.append(text)
        #options = [item.name for item in inventory]
    index = menu(header, options, INVENTORY_WIDTH)
    #if an item was chosen, return it
    if index is None or len(inventory) == 0: return None
    return inventory[index].item

    terminal.layer(6)
    terminal.clear_area(0, 0, MAP_WIDTH, MAP_HEIGHT)
    fov_recompute = True

Quote
def handle_keys():
    terminal.set('window.resizeable=true')
    global fov_recompute
    # Read keyboard input
    global key

    key = terminal.read()
    if key == terminal.TK_ESCAPE:
        # Close terminal
        return 'exit'
    if game_state == 'playing':
        #??? it was 'exit()'
        a = 'player moved'
        if key == terminal.TK_KP_2 or key == terminal.TK_DOWN:
            player_move_or_attack(0, 1)
            return a
        elif key == terminal.TK_KP_8 or key == terminal.TK_UP:
            player_move_or_attack(0, -1)
            return a
        elif key == terminal.TK_KP_6 or key == terminal.TK_RIGHT:
            player_move_or_attack(1, 0)
            return a
        elif key == terminal.TK_KP_4 or key == terminal.TK_LEFT:
            player_move_or_attack(-1, 0)
            return a
        elif key == terminal.TK_KP_7:
            player_move_or_attack(-1, -1)
            return a
        elif key == terminal.TK_KP_9:
            player_move_or_attack(1, -1)
            return a
        elif key == terminal.TK_KP_1:
            player_move_or_attack(-1, 1)
            return a
        elif key == terminal.TK_KP_3:
            player_move_or_attack(1, 1)
            return a
        elif key == terminal.TK_KP_5:
            return a
        else: #test for other keys
            if key == terminal.TK_G:
                #pick up an item
                for object in objects:  #look for an item in the player's tile
                    if object.x == player.x and object.y == player.y and object.item:
                        object.item.pick_up()
                        break

            if key == terminal.TK_I:
                #show the inventory; if an item is selected, use it
                chosen_item = inventory_menu('Press the key next to an item to use it, or any other to cancel.\n')
                if chosen_item is not None:
                    chosen_item.use()

            if key == terminal.TK_D:
                #show the inventory; if an item is selected, drop it
                chosen_item = inventory_menu('Press the key next to an item to drop it, or any other to cancel.\n')
                if chosen_item is not None:
                    chosen_item.drop()

            if key == terminal.TK_C:
                #show character info
                level_up_xp = LEVEL_UP_BASE + player.level * LEVEL_UP_FACTOR
                msgbox('Character Information\n\nLevel: ' + str(player.level) +
                       '\nExperience: ' + str(player.fighter.xp) + ' / ' + str(level_up_xp) +
                       '\n\nMaximum HP: ' + str(player.fighter.max_hp) +
                    '\nAttack: ' + str(player.fighter.power) + '\nDefense: ' + str(player.fighter.defense), CHARACTER_SCREEN_WIDTH)

            if key == terminal.TK_SHIFT:
                key = terminal.read()
                if key == terminal.TK_PERIOD and stairs.x == player.x and stairs.y == player.y:
                    #go down stairs, if the player is on them
                        next_level()
         
         key = terminal.read()
         if key == terminal.TK_RESIZED:
            new_columns = terminal.state(terminal.TK_WIDTH)
            new_rows = terminal.state(terminal.TK_HEIGHT)
         

    return 'didnt-take-turn'

tapeworm711

  • Newcomer
  • Posts: 12
  • Karma: +0/-0
    • View Profile
    • Email
Re: Screen Not Refreshing upon Menu Close
« Reply #1 on: January 29, 2017, 01:52:49 AM »
It could be a copy-paste error.

But the last three lines of your inventory code appear to be unreachable. Which is where your clear and FOV update code is.

Cfyz

  • Rogueliker
  • ***
  • Posts: 194
  • Karma: +0/-0
    • View Profile
    • Email
Re: Screen Not Refreshing upon Menu Close
« Reply #2 on: January 29, 2017, 03:22:55 AM »
It would be much, much easier (to look at and point things out) if you could publish the code in some repository, even if a temporary one. The forum is not really suited for big chunks of code and this problem will probably require the whole source.

Unfortunately, the code posted is not enough to see the source of the problem: when and how new_columns/new_rows are used is not shown, neither is menu() implementation. Also, it was probably mangled while copying, there is a suspicious unreachable part in the inventory_menu() function.

tapeworm711

  • Newcomer
  • Posts: 12
  • Karma: +0/-0
    • View Profile
    • Email
Re: Screen Not Refreshing upon Menu Close
« Reply #3 on: January 29, 2017, 05:25:36 AM »
You could start a github just got that. If the code is one file you could also use http://pastebin.com
« Last Edit: January 29, 2017, 07:24:54 AM by tapeworm711 »

KM

  • Newcomer
  • Posts: 13
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #4 on: January 29, 2017, 06:18:47 AM »
Passlain seems to be down; and I've never used github before.  I'll have to look into it.

tapeworm711

  • Newcomer
  • Posts: 12
  • Karma: +0/-0
    • View Profile
    • Email
Re: Screen Not Refreshing upon Menu Close
« Reply #5 on: January 29, 2017, 07:19:58 AM »
Sorry. That was pastebin.com.

Stupid phone keyboard.

KM

  • Newcomer
  • Posts: 13
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #6 on: February 04, 2017, 08:09:48 AM »
Ah, that makes more sense, lol.

Entire code on pastebin:
http://pastebin.com/E0u6JZe3

Avagart

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 567
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #7 on: February 04, 2017, 02:32:19 PM »
Seems your problem is in line 854. Return statement ends function execution, so lines 856-858 are unaccessible. You could pack these lines as indenpendent function

Code: [Select]
def layer_recompute():
    terminal.layer(6)
    terminal.clear_area(0, 0, MAP_WIDTH, MAP_HEIGHT)
    fov_recompute = True

then call it in handle_keys after inventory execution

Code: [Select]
if key == terminal.TK_I:
    chosen_item = inventory_menu('Press the key next to an item to use it, or any other to cancel.\n')
        if chosen_item is not None:
            chosen_item.use()
    layer_recompute()

unfortunately, it seems you'd need to call it also after dropping, so it's a bit dirty. But you could try to change the scope, for example - call layer_recompute after testing other keys

Code: [Select]
def handle_keys():
    (...)
    if game_state == 'playing':
        (...)
    else: #test for other keys
        (...)
        if ...
        elif...
        #end of conditional chain
        layer_recompute()

edit: Why do you need
Code: [Select]
a = 'player moved' (...) return a
if in your whole code you are not passing nor checking for 'player moved'?
« Last Edit: February 04, 2017, 02:37:18 PM by Avagart »

KM

  • Newcomer
  • Posts: 13
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #8 on: February 05, 2017, 08:31:00 AM »
Thanks Avagart, but I tried what you suggested and it didn't fix it.

I don't think those lines actually fix the display like I want, they were just shots in the dark from me.

I don't understand why moving refreshes the screen, I thought it would just be fov_recompute =True under line 769, but putting that in anywhere else doesn't seem to have the same effect.

As for having the 'player moved' prompt, it's either because I was working towards having it be turn based when an enemy is in fov, or because the code is cobbled together from various places, I can't really remember which.

I just don't understand why it is drawing the actors regardless, yet the background tiles aren't being drawn upon leaving any kind of menu.

Thanks regardless; I've removed the vestigial 'player moved' notations.

Avagart

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 567
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #9 on: February 05, 2017, 09:09:28 AM »
Which libtcod version are you using, btw?

KM

  • Newcomer
  • Posts: 13
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #10 on: February 05, 2017, 10:54:47 AM »
1.6.0, I believe.  The full .rar for the project I'm working on is here; http://www.filedropper.com/grit

The goal is once I have the basic engine off the ground to work towards creating Robert E. Howard's Conan universe as a roguelike.  I'm setting it before the history of Conan, but I'd like it to be a very low-fantasy game with little magic, no leveling up, no health bars, etc.

It's pretty ambitious considering this is the first thing I've programmed past "hello world" and some GML applications, but there it is.

Thanks a lot, btw, Ava, really appreciate the help.  Still trying to wrap my head around a lot of Python.

Avagart

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 567
  • Karma: +0/-0
    • View Profile
Re: Screen Not Refreshing upon Menu Close
« Reply #11 on: February 05, 2017, 12:22:35 PM »
For me, your code isn't refreshing at all. Menu is OK, after starting new game map in FOV is drawn, but it doesn't re-draw at all. I can move (I prove that by save / load), but whole screen is not refresing at all.

I'm familiar with structure of your roguelike because it's based on libtcod python tutorial from roguebasin, but I don't know bearlibterminal well, unfortunately.

I didn't perform in-depth analysis, but it seems that the source of problems is somewhere in layers management. I can be wrong, but your implementation of rendering is almost the same as the official one, and your changes looks strictly related to blt layers. I was tinkering for a while with these layers, but didn't manage to make it works properly.

Cfyz

  • Rogueliker
  • ***
  • Posts: 194
  • Karma: +0/-0
    • View Profile
    • Email
Re: Screen Not Refreshing upon Menu Close
« Reply #12 on: February 05, 2017, 11:21:06 PM »
Okay, I've looked over the code and I can point out the source of refreshing problem.

First, there is an unnecessary terminal.read() at the end of handle_keys(). It does not break things explicitly, but forces an additional keypress without any visual feedback after non-move action (e. g. inventory), which is wrong and makes behaviour non-intuitive (and probably making it look like setting fov_recompute not always works).

The menu() function uses layer #2 for its output and clears this layer at the start. I do not know if its intentional, but it also clears walls on the map (which also mostly uses layer #2). But neither of menu-popping actions set fov_recompute flag, therefore next render_all() skips drawing walls entirely and only objects are drawn. This leads to walls not being restored after any menu action until any move action (which does set fov_recompute) is taken.

A few other points:
1. Layering is excessive and inconsistent. Very distinct UI elements like map and menu dialog use the same layer which inevitably leads to collisions. On the other hand really similar elements like map and different objects use several different layers. Why do you even need to put the object in a different layer, whether it is fighter or not? >_<
2. Map drawing in render_all() selects a layer only under a certain condition inside the loop. This will put some of the tiles in whatever layer was selected before, which is fragile.
3. The menu() function uses libtcod.console_get_height_rect() to calculate a size of a string, while output is performed via BLT. This is not correct and is not guaranteed to work as they are totally separate functions of different libraries. BearLibTerminal has its own facilities to measure and auto-wrap text:
Code: [Select]
_, header_height = terminal.measure(header, width=width)  # measure returns a (w, h) tuple
...
terminal.print_(x, y, header, width=width)

I suggest to clean up the layering. Layers are to help with logical grouping of output, not to make it messier >_<, there is no need to put everything in different layers. Probably just three will suffice: #0 for in-game objects (ground, walls, objects, etc.), #1 for basic UI (bars and statuses which are always over the map) and #2 for temporary popups like menus. It would also help to give some meaningful names to layers via constants.

As for TK_RESIZED, there is no easy way to introduce screen resizing with the current loop structure. Since user may resize the window in any moment, the application must be ready to handle the new size and update the whole screen in every game state and every dialog, e. g. in the inventory menu. Which will not work since modal menu() can't update the map layout. The easiest way would be to completely separate rendering from input processing so that the whole screen (map, general UI and dialogs) could be redrawn at any time, even during popup processing. But you'll probably have to rewrite from scratch the whole loop/dialog structure.
« Last Edit: February 07, 2017, 12:10:05 AM by Cfyz »