Easier keymaps

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Derakon
    Prophet
    • Dec 2009
    • 9022

    Easier keymaps

    Okay, I guess I'm at least exploring the feasibility of this.

    The goal is that, when the player selects an item from their inventory, one of the options (alongside drop, throw, use, etc.) is "Set Hotkey". When selected, the player is prompted for a key to bind to the item, and a keymap is created that uses the item (as per its default interaction) when pressed.

    Doing this properly requires two things: first, the basic UI, and second, the ability to select an item based on its name rather than the slot it is in or the inscription it has. The UI in principle should be straightforward, I think; there's already UI for creating keymaps, so this would just be an alternate approach to the same. As for selecting items based on name, I think what needs to happen is that we create a "control code" that can be intercepted whenever the player is prompted for a menu selection, and which lets them type in a string which is matched against the items in the menu. For example, if the control code character is @, then typing "@Phase" and hitting Enter should select Phase Door scrolls, assuming that the entered string is not ambiguous. If it is ambiguous, simplest thing to do is just to error out.

    Once this works, the next step is to also allow it for spellbooks. I'm honestly not entirely sure what the best way to go about doing that is. We currently have two different commands for interacting with spellbook contents. We could add a third command; that feels kind of clunky though. We could make it so holding Shift while selecting a spell becomes the "create hotkey" for spells, but that's hacky. Opinions?
  • t4nk
    Swordsman
    • May 2016
    • 336

    #2
    Doing it with keymaps will be a mess. Consider implemening ui-hotkey.c instead, unrelated to keymaps. Briefly:

    1) ui-knowledge.c has do_cmd_inven(), do_cmd_equip() and do_cmd_quiver() ('i', 'e' and '|' commands)
    2) it calls context_menu_object() in ui-context.c, which displays menu where you want to insert the "Hotkey" entry
    3) ui-hotkey.c could have something like:
    Code:
    struct hotkey {
        struct keypress key;
    
        int tval;
        int sval;
    
        int cmd; /* USE_INVEN, USE_EQUIP, USE_QUIVER */
    
        char *substr;    /* selecting using substrings */
        int target;      /* for aiming ammo/spells */
        int spell_index; /* if that's a spell */
    
        /* something else? */
    };
    4) context_menu_object() already has the object (so it has tval and sval). It should ask the user necessary questions (based on what kind of object that is) and create the hotkey. E.g., you can determine that an object is a book by calling obj_can_cast_from() (obj-util.c); spell_index can be obtained by calling textui_get_spell_from_book() (ui-spell.c). Also see do_cmd_use() in cmd-obj.c; most items are easy to handle. The context menu doesn't have working command (USE_INVEN/EQUIP), but do_cmd_inven/equip() do.

    5) A reasonable place to check if a key is a hotkey is in textui_process_command (ui-game.c). Line 291 looks like a decent place to me.
    Code:
    if (do_hotkey(event)) {
        return;
    }
    6) Hotkey code eventually does something along the lines of:
    Code:
    struct hotkey *hk = hotkey_find(event);
    
    if (hk != NULL) {  
        if (hk->spell_index != -1) {
            cmdq_push(CMD_CAST);
            cmd_set_arg_choice(cmdq_peek(), "spell", hk->spell_index);
            
            if (hk->target != 0) {
                int dir = /* see textui_get_aim_dir() (ui-input.c) */
                cmd_set_arg_target(cmdq_peek(), "target", dir);
            }
        } else {
            struct object *obj = NULL;
            
            if (hk->substr != NULL) {
               obj = /* find by substring */;
            } else {
               obj = /* find by tval/sval */
            }
    
            if (obj == NULL) {
                 /* scroll got burned or something */
                 return;
            }
    
            if (do_cmd_useable(obj)) {
                 /* do_cmd_useable() is a fictional function;
                    see do_cmd_use() (cmd-obj.c) */
            } else if (hk->cmd == USE_INVEN && obj_can_wear(obj)) {
                 /* and so on */
            }
        }
    }
    Stuff like that... cmd-core.c, cmd-obj.c and obj-util.c have necessary functions/examples.

    edit: typos.
    Last edited by t4nk; December 17, 2016, 15:02.

    Comment

    • fph
      Veteran
      • Apr 2009
      • 1030

      #3
      I think this would be a great improvement to the game!

      Have you considered making your UI "verb-object" rather than "object-verb"? I mean, press the "create hotkey" key -> prompt for key to bind -> prompt to select an object -> if object is a spellbook, further prompt to select a spell in it.

      This change would also solve another problem, which is: for actions that need a target (spells and projectiles), you probably want to have two or three hotkeyable variants: "cast spell, prompt me for target", "cast spell to the closest target", "cast spell to the already-set target".
      --
      Dive fast, die young, leave a high-CHA corpse.

      Comment

      • Derakon
        Prophet
        • Dec 2009
        • 9022

        #4
        Thanks for the pointers in the code! It would have taken me probably a couple of hours to reconstruct that, so you've saved me much time.

        Doing it with keymaps will be a mess. Consider implemening ui-hotkey.c instead, unrelated to keymaps.
        Why do you say that? Ultimately the purpose of this system is to change the meaning of one of the keys, and keymaps would seem to be exactly the right way to do this. What benefit does a dedicated hotkey system have, and how would it interact with keymaps?

        Originally posted by fph
        Have you considered making your UI "verb-object" rather than "object-verb"? I mean, press the "create hotkey" key -> prompt for key to bind -> prompt to select an object -> if object is a spellbook, further prompt to select a spell in it.

        This change would also solve another problem, which is: for actions that need a target (spells and projectiles), you probably want to have two or three hotkeyable variants: "cast spell, prompt me for target", "cast spell to the closest target", "cast spell to the already-set target".
        It sounds like you're suggesting a "recorder" system where you can input keymaps while playing the game. I definitely think this is a good idea for the more complicated keymaps where you want to integrate targeting, but it's also simply a different project. My goal is to create a discoverable way to simplify input for players who are inexperienced with the game. In order to be discoverable, it shouldn't require new commands, which is why I mentioned specifically that the "Add Hotkey" option should show up when the player selects an item from their inventory.

        That said, I'd love to see someone add such a recorder.

        Comment

        • t4nk
          Swordsman
          • May 2016
          • 336

          #5
          Originally posted by Derakon
          Why do you say that? Ultimately the purpose of this system is to change the meaning of one of the keys, and keymaps would seem to be exactly the right way to do this. What benefit does a dedicated hotkey system have, and how would it interact with keymaps
          Keymaps are just one half of what you talked about; another one is inscriptions. You'll need to determine what command the item works with ('i', 'm', 't', etc - for both keysets); the substring stuff will require adding an inscription (where else are you going to store the substring? and it will be a pretty long one, to distinguish between, e.g., "a Dagger (1d4) (+0, +0)" and "a Dagger (1d4) (+0, +1)"; after getting the item by substring you'll need to manupulate game's command queue to actually use it anyway; are you going to keep track of which items already have inscriptions? (for example, a book in inventory has "@m1", a book in home has "@m2", a book on the floor has "@m3" - what kind of inscription should be added to a uninscribed book number four?
          Note that inscriptions are just a quick hack, a workaround for problems with inventory reordering. See for yourself: inscriptions are handled in get_tag() (ui-object.c) and in menu code (ui-menu.c, get_cursor_key():478).

          Anyway, do what you want. You asked for opinions: that was my opinion.

          Comment

          • Derakon
            Prophet
            • Dec 2009
            • 9022

            #6
            I see, thanks for the explanation. I wasn't trying to challenge your statement, just understand it.

            I'm not planning to automatically add inscriptions to items; rather the plan is to add the ability to address a specific item in a keymap without needing the item to be inscribed.

            As for determining the command to use, if you look at the menu that comes up when you select an item from your inventory (hit 'i', scroll to an item, hit enter), the second item in the menu after 'I'nspect is always the default use command for the item. So the game clearly knows what the most appropriate action for an item is; I'll just piggyback on that logic.

            Comment

            • takkaria
              Veteran
              • Apr 2007
              • 1951

              #7
              Originally posted by t4nk
              Doing it with keymaps will be a mess. Consider implemening ui-hotkey.c instead, unrelated to keymaps. Briefly:
              I think this looks pretty sound, and is the kind of implementation I was imagining would be possible with the command system that Angband now has, and was part of the motivation for introducing the command system in the first place. For clarification, the command system is where the game has an internal representation of commands that is not just simply keypresses.

              Storing the information about what a key is meant to do using the kind of structure t4nk proposes here ('struct hotkey') is just better, I think, than encoding the information into a string. Part of it is aesthetic, but part of it is that you're representing a command in a form you can do useful things with. For example, you can write "Quaff a potion of Cure Light Wounds" instead of "q@Cure Light\n". You could also have a terminal that lists hotkeys and their actions and greys them out if you run out of that item, because it can tell in advance whether the relevant item is present or not. It's also keyset-agnostic, so you can make hotkeys that do the right thing regardless of any key remappings the player might have done.
              takkaria whispers something about options. -more-

              Comment

              • Derakon
                Prophet
                • Dec 2009
                • 9022

                #8
                Well, working on this is on hold as my desktop appears to have a corrupt disk and can't boot. Joy...

                Comment

                Working...
                😀
                😂
                🥰
                😘
                🤢
                😎
                😞
                😡
                👍
                👎