From: <gi...@cr...> - 2025-07-17 17:50:19
|
via 2aa8828f32cc0e6f1aafcf435c2fb752a8f2e421 (commit) via 6a5dc71c24c1e395d8ad98fd1a4cc6eac2ba07b9 (commit) via ff86fb1ae44d103b91982ed79f9937f9eb3fe2b8 (commit) via 2ee0592cccb24955cec6c80e3ae889d945327bb3 (commit) via a240211e49849f1eed3e4f922af07cda789f0406 (commit) via 95e1f2edf6e36a5583acb9d0f88f69bdfb581deb (commit) via 8f0873f1e596a738b6ce32dc17ea38cc34384c58 (commit) via 39c613d83245634ac3c12b0620e139d0b26bd03c (commit) via 928708bbf42150c8dcb9939b884021976306e65a (commit) via d6fc47bd0f42f45846781ac688f3c1cc1316fcfe (commit) via 70df15b1d4c8e5c30d5b2590723c9032006f4607 (commit) via b50b00bb3c40d1d7cfc3f0a903d9104de0a104a4 (commit) from 1673ddcb0ae94647088d2a3d4b12af2567f572dd (commit) ----------------------------------------------------------------------- commit 2aa8828f32cc0e6f1aafcf435c2fb752a8f2e421 Author: DracoOmega <dra...@gm...> Date: Thu Jul 17 15:02:55 2025 -0230 Change webtiles action panel sort order Now also sorts each sub-category by 'usefulness' to more closely mimic the default ordering in the inventory menus. (Also, I feel like 'letter' is less useful with the new default consumable_slot behavior.) Hopefully this doesn't end up being too controversial. commit 6a5dc71c24c1e395d8ad98fd1a4cc6eac2ba07b9 Author: DracoOmega <dra...@gm...> Date: Thu Jul 17 12:45:20 2025 -0230 Let command repeat work in local tiles while having an unaffordable ability This was a bit of work to track down, but essentially: in order to grey out unusable abilities on the local tiles ability bar, each time the screen is redrawn, check_ability_possible() is called. And enough_mp() and enough_hp() are both called from that function with abort_macros = true, which means that any time the usability of an ability is queried and you don't have enough HP or MP for it, macros and key-repeat are automatically cancelled. While that makes some sense when it's called during you actually trying to *use* the ability (and failing), it doesn't make sense when merely checking whether or not you *could*. And as the code for handling command repeat is piped through the normal input loop, this means that it redraws the screen at the start of each new command, which redraws the ability icons, which checks their usability, which then aborts the in-progress command repeat before it can even do anything. Now, it should not. I don't *think* making silent check_ability_possible() calls never interrupt macros on its own should cause any further problems - checking spell usability already didn't do so - and actually trying to use the ability and failing will still do so. commit ff86fb1ae44d103b91982ed79f9937f9eb3fe2b8 Author: DracoOmega <dra...@gm...> Date: Wed Jul 16 05:54:35 2025 -0230 Automatically disable autopickup of dropped consumables Since there's no longer any reason to drop them unless you don't want to see them in your inventory, do this automatically. commit 2ee0592cccb24955cec6c80e3ae889d945327bb3 Author: DracoOmega <dra...@gm...> Date: Wed Jul 16 05:46:42 2025 -0230 Make the 'next page' button in the local webtiles inventory more obvious It wasn't clear that clicking on it would do anything. (Also make it so that the display updates immediately when you click on it and not 'The next time you move the mouse after clicking on it') commit a240211e49849f1eed3e4f922af07cda789f0406 Author: DracoOmega <dra...@gm...> Date: Wed Jul 16 05:45:20 2025 -0230 Add a couple additional rows to the local tiles item panel Now that players are more likely to carry more items around at once. commit 95e1f2edf6e36a5583acb9d0f88f69bdfb581deb Author: DracoOmega <dra...@gm...> Date: Tue Jul 15 13:58:44 2025 -0230 Fix a minor text wrapping issue with the % screen commit 8f0873f1e596a738b6ce32dc17ea38cc34384c58 Author: DracoOmega <dra...@gm...> Date: Tue Jul 15 13:57:34 2025 -0230 Make talismans something you (P)up on instead of evoke Remaining on e(V)oke after the consumable inventory change would result in both consumables and non-consumables being on the same use screen, which could lead to key conflicts (and in general I feel is something that should be avoided as much as possible). So they are now something the player has to (P)ut on. This means they also must be in the player's inventory at all times (but revised inventory limits should make this a complete non-issue). Dropping a talisman automatically leaves the form, as one might expect, and the Begin Untransform ability has been removed. Save compat will put a copy of the player's current talisman into their inventory (which will sometimes duplicate it, but that is harmless; there's nothing you can *do* with a second identical one.). In the incredibly unlikely case someone has 52 pieces of equipment already in their inventory, it will untransform them and drop the appropriate talisman at their feet. But this would require them to have had nothing in their inventory *but* equipment, which seems profoudly unlikely. Your current talisman will also show up in % and dumps, which seems a nice minor benefit. I'm not touching Ash's Curse of Devices right now, pending planned Ash curse changes that will make that unnecessary. commit 39c613d83245634ac3c12b0620e139d0b26bd03c Author: DracoOmega <dra...@gm...> Date: Mon Jul 14 15:14:42 2025 -0230 Allow quick-scrolling between item categories with left/right arrows While this works in general inventory menus, it was foremost intended for the drop menu (where the 'jump to item category' shortcuts aren't really functional for that purpose, since they will also select all items of that category to be dropped). commit 928708bbf42150c8dcb9939b884021976306e65a Author: DracoOmega <dra...@gm...> Date: Mon Jul 14 13:29:38 2025 -0230 Expand inventory to alleviate most remaining inventory pressures Crawl's inventory limit wasn't very restrictive in a gameplay-affecting sense (players can carry an enormous number of tactical tools at once, and freely return to pick up strategic tools whenever they want), but just small enough that butting up against it still happened potentially many times a game, as autoexplore tries to grab items you don't especially care about and the player is forced to stop and figure out which of multiple items they'll never use is the one they'll never use *the most*. This interrupts the flow of gameplay and is generally a minor nuisance without much resulting gameplay value (as you can still carry *almost* everything you'd ever want to). However, Crawl's inventory system was very married to its 52 item limit in multiple ways, not least of which being: that's how many letters there are. Some previous proposals suggested expanding that in minor ways, but this is an attempt to have the final word on inventory limits, by splitting each consumable verb into its own category and essentially allowing you to hold every single consumable in the game at once *on top* of 52 pieces of equipment. This means it is now possible to have multiple items on (a), so long as each of those belongs to a different category: equipment (including throwables), potions, scrolls, and wands/evokabes. Since each of these is primarily used via separate commands, there is typically no risk of ambiguity (eg: ra, qa, Va, Wa will all unambiguously grab the single matching item). In fact, this very property allows for mapping specific consumables to specific letters via option, consistently from game to game (eg: qc can be made to always quaff curing), which I think may be a solid QoL improvement once players get used to it. For menus that show the entire inventory at once (eg: 'd'rop), pressing letters will now select the *nearest* item matching that letter. However there should be much less need to quickly drop things, so I hope this won't be a large inconvenience (and well worth the gain in other areas). And the game tries very, very hard to make sure no unidentified scroll and potions ever end up on the same letter, so the ?id menu should also be unambiguous. On a backend level, this expands you.inv[] to 127 slots, reserving all beyond [51] for consumables (in any order). While not strictly unlimited, this is enough room to simultaneously store every consumable currently in the game at once (including disjoint item sets) with room to spare. If, in future, this becomes untrue, it should be simple to expand that number. The first 52 slots retain their current behavior (ie: rearranging themselves when items change letter), while slots beyond 52 do not require their link and slot members to match (ie: they can change letter without being moved in the array). The item_slot option has been renamed gear_slot and functions only on equipment. A simpler consumable_shortcut option replaces it for consumables - mapping a single item to a single letter. This is enabled by default, with a full set of default values for all potions, scrolls, and wands. An important aspect of this option's behavior is that it will *never* map unidentified items to any letter reserved for a specific item. So one can ensure that, eg, blinking scrolls are always on rb and pressing rb could never result in reading a different scroll under any circumstance (beside the player manually putting it on b themselves). I think, once players get used to it, that this will be a meaningful QoL improvement. And overall, having to almost never care about inventory limits again, should be good for everyone. commit d6fc47bd0f42f45846781ac688f3c1cc1316fcfe Author: DracoOmega <dra...@gm...> Date: Sat Jul 12 10:40:19 2025 -0230 New sort_menus option: usefulness This sorts consumables by their current usefulness in descending order of Emergency, Good, Normal, Dangerous, Bad, Useless. It is enabled by default for actions like quaff and read, in anticipation of upcoming consumable inventory changes. commit 70df15b1d4c8e5c30d5b2590723c9032006f4607 Author: DracoOmega <dra...@gm...> Date: Sat Jul 12 10:32:09 2025 -0230 Mark ?silence as a 'dangerous' item It is likely even more double-edged than many scrolls the game aready marks as such, especially by lategame. commit b50b00bb3c40d1d7cfc3f0a903d9104de0a104a4 Author: DracoOmega <dra...@gm...> Date: Sat Jul 12 10:17:21 2025 -0230 Make the 'charged' sort_menus option work for evokers Empty wands haven't been a thing for several years, but evokers *are* something that can be 'empty' in one's inventory, so let's use it to for them instead. ----------------------------------------------------------------------- Summary of changes: crawl-ref/docs/crawl_manual.rst | 12 +- crawl-ref/docs/options_guide.txt | 36 ++- crawl-ref/source/ability-type.h | 2 + crawl-ref/source/ability.cc | 22 +- crawl-ref/source/acquire.cc | 4 +- crawl-ref/source/adjust.cc | 95 +++++-- crawl-ref/source/adjust.h | 8 +- crawl-ref/source/command.cc | 2 +- .../source/dat/defaults/consumable_shortcuts.txt | 49 ++++ crawl-ref/source/dat/descript/items.txt | 70 +++--- crawl-ref/source/dbg-asrt.cc | 2 +- crawl-ref/source/defines.h | 5 +- crawl-ref/source/describe.cc | 9 +- crawl-ref/source/evoke.cc | 80 ------ crawl-ref/source/files.cc | 5 + crawl-ref/source/initfile.cc | 45 +++- crawl-ref/source/invent.cc | 117 +++++++-- crawl-ref/source/invent.h | 1 + crawl-ref/source/item-def.h | 8 +- crawl-ref/source/item-name.cc | 14 +- crawl-ref/source/item-prop.cc | 21 ++ crawl-ref/source/item-use.cc | 234 ++++++++++------- crawl-ref/source/item-use.h | 5 + crawl-ref/source/items.cc | 280 +++++++++++++++++++-- crawl-ref/source/items.h | 15 +- crawl-ref/source/l-item.cc | 4 +- crawl-ref/source/menu.cc | 35 +-- crawl-ref/source/mutation.cc | 6 +- crawl-ref/source/ng-setup.cc | 12 +- crawl-ref/source/object-selector-type.h | 3 +- crawl-ref/source/options.h | 11 +- crawl-ref/source/output.cc | 63 +++-- crawl-ref/source/player-equip.cc | 6 +- crawl-ref/source/player.cc | 51 ++-- crawl-ref/source/player.h | 6 +- crawl-ref/source/quiver.cc | 11 +- crawl-ref/source/rltiles/dc-item.txt | 5 + .../commands/page_next.png} | Bin 4306 -> 4385 bytes .../commands/page_previous.png} | Bin 4306 -> 4386 bytes crawl-ref/source/skills.cc | 4 +- crawl-ref/source/tag-version.h | 2 + crawl-ref/source/tags.cc | 53 +++- crawl-ref/source/tiledoll.cc | 2 +- crawl-ref/source/tilepick.cc | 1 - crawl-ref/source/tilereg-inv.cc | 11 +- crawl-ref/source/tilesdl.cc | 2 +- crawl-ref/source/tileweb.cc | 14 +- crawl-ref/source/transform.cc | 53 ++-- crawl-ref/source/transform.h | 2 +- .../webserver/game_data/static/action_panel.js | 6 +- crawl-ref/source/wiz-fsim.cc | 4 +- crawl-ref/source/wiz-you.cc | 2 +- 52 files changed, 1050 insertions(+), 460 deletions(-) create mode 100644 crawl-ref/source/dat/defaults/consumable_shortcuts.txt copy crawl-ref/source/rltiles/{effect/shadow_shot2.png => gui/commands/page_next.png} (65%) copy crawl-ref/source/rltiles/{effect/shadow_shot0.png => gui/commands/page_previous.png} (65%) diff --git a/crawl-ref/docs/crawl_manual.rst b/crawl-ref/docs/crawl_manual.rst index 65ef639009..dcdc514207 100644 --- a/crawl-ref/docs/crawl_manual.rst +++ b/crawl-ref/docs/crawl_manual.rst @@ -710,7 +710,7 @@ adventures, how they are displayed, and what commands there are to use them: " amulets (use 'P'ut on and 'R'emove) \| staves (use 'w'ield) : spellbooks (use 'M'emorise and 'z'ap, 'Q' to quiver) -% talismans (use 'V' to evoke) +% talismans (use 'P'ut on and 'R'remove) } miscellaneous (use 'V' to evoke, 'Q' to quiver) $ gold (use 'g' to pick up) ======= ============= ================================================ @@ -949,10 +949,10 @@ Talismans allow their user to shift into a different form. Entering or leaving a form with a talisman requires a brief period of concentration, but otherwise, forms last until the user chooses to leave them. -More powerful talismans require some amount of Shapeshifting skill, without -which a user will find their maximum health reduced until they leave the form. -Shapeshifting skill also increases other benefits provided by talismans' forms, -though weaker talismans have a limit to how helpful skill can be. +Most talismans require some amount of Shapeshifting skill, without which a user +will find their maximum health reduced until they leave the form. Shapeshifting +skill also increases other benefits provided by talismans' forms, though weaker +talismans have a limit to how helpful skill can be. { Miscellaneous ======================================== @@ -2086,7 +2086,7 @@ Artificers Shapeshifters Shapeshifters use talismans to shift their body into different forms, granting them uncanny power but making them unable to use some items. - They enter the dungeon with two talismans, some flux baubles, and a + They enter the dungeon with two talismans, some flux baubles, and a potion of lignification. Wanderers diff --git a/crawl-ref/docs/options_guide.txt b/crawl-ref/docs/options_guide.txt index d0c1f42cc0..debe155740 100644 --- a/crawl-ref/docs/options_guide.txt +++ b/crawl-ref/docs/options_guide.txt @@ -1327,9 +1327,15 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order] items on the floor. * charged: - Makes wands known or assumed to have some charges left appear - before wands known to be empty; irrelevant for all other item - types. + Makes evokers with available charges appear before those which + are empty; irrelevant for all other item types. + + * usefulness: + Sorts consumables by their current 'usefulness' in the + following order: Emergency (eg: ?blinking, !heal wounds), + Good (eg: ?acquirement), Normal, Dangerous (eg: !lignification), + Bad (eg: ?torment while worshipping a good god), and finally + permanently useless. You can ask for a descending order sort by prefixing one or more sort criteria with > as: @@ -1342,10 +1348,6 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order] (Menu types must be specified as name:, with no space between name and colon.) - By default only pickup menus are sorted, and the sort criteria are: - "equipped, basename, qualname, curse, qty". - All other menus (drop, inv) will be sorted by inventory letter. - The menu selectors available are: pickup: All pickup menus, stash-search menus, etc. for items not @@ -1365,6 +1367,10 @@ sort_menus = [menu:](true | false | auto:X)[:sort_order] the last one matching will always take precedence, i.e. "any" as last setting would override any of the others. + By default pickup menus are sorted, and the sort criteria are: + "equipped, basename, qualname, curse, qty". + Inv menus are sorted by "equipped, charged, usefulness". + spell_slot ^= <regex>:<list of spell letters> (Ordered list option, one value per line) When you memorise any spell that matches the regex, it will assign @@ -1392,15 +1398,23 @@ spell_slot ^= <regex>:<list of spell letters> spell_slot lines): spell_slot += .*:ABCDEFGHIJKLMNOPQRSTUVWXYZ -item_slot ^= <regex>:<inventory letters> +gear_slot ^= <regex>:<inventory letters> (Ordered list option, one value per line) Uses the same interface as spell_slot, except that overwrite mode is on by default; overwrite mode can be disabled with a - in the list of letters. - Additionally, the item_slot option is applied on an item when it is - identified, so it can be moved to the right place even if it was - picked up unidentified. +consumable_shortcut ^= <item name>:<inventory letter> + (Ordered list option, one value per line) + Similar to gear_slot, but accepts only a single letter per consumable + name and does not handle regex. + + The game will try very hard to automatically assign a consumable to + any letter given a mapping by this option, unless it is an identified + item of a different category. (eg: 'potion of curing:c' will result + in no other potion ever being auto-assigned to 'c' and unidentified + scrolls also avoiding it where possible, since they share the ?id menu + together.) ability_slot ^= <regex>:<ability letters> (Ordered list option, one value per line) diff --git a/crawl-ref/source/ability-type.h b/crawl-ref/source/ability-type.h index 0df3439658..252bbd9b7e 100644 --- a/crawl-ref/source/ability-type.h +++ b/crawl-ref/source/ability-type.h @@ -59,7 +59,9 @@ enum ability_type // Death Form ABIL_SIPHON_ESSENCE, // Talismans +#if TAG_MAJOR_VERSION == 34 ABIL_BEGIN_UNTRANSFORM, +#endif ABIL_MUD_BREATH, // Coglins ABIL_INVENT_GIZMO, diff --git a/crawl-ref/source/ability.cc b/crawl-ref/source/ability.cc index 81231ddb77..c0662e2b0d 100644 --- a/crawl-ref/source/ability.cc +++ b/crawl-ref/source/ability.cc @@ -394,8 +394,6 @@ static vector<ability_def> &_get_ability_list() 0, 0, 0, -1, {}, abflag::delay }, { ABIL_END_TRANSFORMATION, "End Transformation", 0, 0, 0, -1, {}, abflag::none }, - { ABIL_BEGIN_UNTRANSFORM, "Begin Untransformation", - 0, 0, 0, -1, {}, abflag::none }, { ABIL_INVENT_GIZMO, "Invent Gizmo", 0, 0, 0, -1, {}, abflag::none }, @@ -1907,11 +1905,11 @@ static bool _check_ability_possible(const ability_def& abil, bool quiet = false) // Check that we can afford to pay the costs. // Note that mutation shenanigans might leave us with negative MP, // so don't fail in that case if there's no MP cost. - if (abil.get_mp_cost() > 0 && !enough_mp(abil.get_mp_cost(), quiet, true)) + if (abil.get_mp_cost() > 0 && !enough_mp(abil.get_mp_cost(), quiet, !quiet)) return false; const int hpcost = abil.get_hp_cost(); - if (hpcost > 0 && !enough_hp(hpcost, quiet)) + if (hpcost > 0 && !enough_hp(hpcost, quiet, !quiet)) return false; switch (abil.ability) @@ -2704,7 +2702,6 @@ unique_ptr<targeter> find_ability_targeter(ability_type ability) #endif case ABIL_EVOKE_TURN_INVISIBLE: case ABIL_END_TRANSFORMATION: - case ABIL_BEGIN_UNTRANSFORM: case ABIL_ZIN_VITALISATION: case ABIL_TSO_DIVINE_SHIELD: case ABIL_YRED_RECALL_UNDEAD_HARVEST: @@ -3351,17 +3348,6 @@ static spret _do_ability(const ability_def& abil, bool fail, dist *target, return_to_default_form(); break; - case ABIL_BEGIN_UNTRANSFORM: - if (transforming_is_unsafe(transformation::none)) - return spret::abort; - if (!i_feel_safe(true) && !yesno("Still begin untransforming?", true, 'n')) - { - canned_msg(MSG_OK); - return spret::abort; - } - start_delay<TransformDelay>(transformation::none, nullptr); - break; - case ABIL_INVENT_GIZMO: if (!coglin_invent_gizmo()) return spret::abort; @@ -4338,9 +4324,6 @@ bool player_has_ability(ability_type abil, bool include_unusable) && (!silenced(you.pos()) || include_unusable); case ABIL_END_TRANSFORMATION: return you.form != you.default_form && !you.transform_uncancellable; - case ABIL_BEGIN_UNTRANSFORM: - return you.form == you.default_form - && you.default_form != transformation::none; // TODO: other god abilities case ABIL_RENOUNCE_RELIGION: return !you_worship(GOD_NO_GOD); @@ -4415,7 +4398,6 @@ vector<talent> your_talents(bool check_confused, bool include_unusable, bool ign ABIL_IMBUE_SERVITOR, ABIL_IMPRINT_WEAPON, ABIL_END_TRANSFORMATION, - ABIL_BEGIN_UNTRANSFORM, ABIL_RENOUNCE_RELIGION, ABIL_CONVERT_TO_BEOGH, ABIL_EVOKE_BLINK, diff --git a/crawl-ref/source/acquire.cc b/crawl-ref/source/acquire.cc index d85413ca27..d90fc65c3c 100644 --- a/crawl-ref/source/acquire.cc +++ b/crawl-ref/source/acquire.cc @@ -1494,7 +1494,7 @@ static void _create_acquirement_item(item_def &item, string items_key, // XXX: This is ugly and only works because there can never be another // gizmo in our inventory, but move_item_to_inv() doesn't actually // return an index or anything else we can use. - for (int i = 0; i < ENDOFPACK; ++i) + for (int i = 0; i < MAX_GEAR; ++i) { if (you.inv[i].base_type == OBJ_GIZMOS) { @@ -1957,7 +1957,7 @@ static void _make_coglin_gizmos() bool coglin_invent_gizmo() { - if (inv_count() >= ENDOFPACK) + if (inv_count(INVENT_GEAR) >= MAX_GEAR) { mpr("You don't have room to hold a gizmo! Drop something first."); return false; diff --git a/crawl-ref/source/adjust.cc b/crawl-ref/source/adjust.cc index 2be422e456..8a76f84e96 100644 --- a/crawl-ref/source/adjust.cc +++ b/crawl-ref/source/adjust.cc @@ -10,6 +10,7 @@ #include "ability.h" #include "libutil.h" #include "invent.h" +#include "item-use.h" #include "items.h" #include "macro.h" #include "message.h" @@ -22,12 +23,19 @@ static void _adjust_ability(); void adjust() { - mprf(MSGCH_PROMPT, "Adjust (i)tems, (s)pells, or (a)bilities? "); + mprf(MSGCH_PROMPT, "Adjust (g)ear, (s)pells, (a)bilities, " + "(p)otions, sc(r)olls or e(v)okables? "); const int keyin = toalower(get_ch()); - if (keyin == 'i') - adjust_item(); + if (keyin == 'g') + adjust_item(OPER_EQUIP); + else if (keyin == 'p') + adjust_item(OPER_QUAFF); + else if (keyin == 'r') + adjust_item(OPER_READ); + else if (keyin == 'v') + adjust_item(OPER_EVOKE); else if (keyin == 's') _adjust_spell(); else if (keyin == 'a') @@ -38,7 +46,7 @@ void adjust() canned_msg(MSG_HUH); } -void adjust_item(int from_slot) +void adjust_item(operation_types oper, item_def* to_adjust) { #ifdef USE_TILE_WEB ui::cutoff_point ui_cutoff_point; @@ -49,29 +57,42 @@ void adjust_item(int from_slot) return; } - if (from_slot == -1) + // If asked to adjust a specific item, make sure we have the right category. + if (to_adjust) { - from_slot = prompt_invent_item("Adjust which item?", - menu_type::invlist, OSEL_ANY); + if (inventory_category_for(*to_adjust) == INVENT_CONSUMABLE) + oper = item_to_oper(to_adjust); + else + oper = OPER_EQUIP; + } + + if (!to_adjust) + { + const int from_slot = prompt_invent_item("Adjust which item?", + menu_type::invlist, default_osel(oper), + oper); if (prompt_failed(from_slot)) return; - mprf_nocap("%s", you.inv[from_slot].name(DESC_INVENTORY_EQUIP).c_str()); + to_adjust = &you.inv[from_slot]; + + mprf_nocap("%s", to_adjust->name(DESC_INVENTORY_EQUIP).c_str()); } const int to_slot = prompt_invent_item("Adjust to which letter? ", menu_type::invlist, - OSEL_ANY, OPER_ANY, + default_osel(oper), oper, invprompt_flag::unthings_ok | invprompt_flag::manual_list); if (to_slot == PROMPT_ABORT - || from_slot == to_slot) + || to_adjust->link == to_slot) { canned_msg(MSG_OK); return; } - swap_inv_slots(from_slot, to_slot, true); + ASSERT(to_adjust); + swap_inv_slots(*to_adjust, to_slot, true); you.wield_change = true; quiver::set_needs_redraw(); } @@ -192,22 +213,63 @@ static void _adjust_ability() swap_ability_slots(index1, letter_to_index(keyin)); } -void swap_inv_slots(int from_slot, int to_slot, bool verbose) +void swap_inv_slots(item_def& to_adjust, int to_slot, bool verbose) { + // Consumable adjustments are easiest. We only need to change letters and + // not move anything in the inventory array. + if (inventory_category_for(to_adjust) == INVENT_CONSUMABLE) + { + // Find if the new letter is used for any current item of the same + // operation type (ie: quaff), so that we can adjust the keybind on that + // item too. + const operation_types oper = item_to_oper(&to_adjust); + item_def* item2 = nullptr; + const int new_letter = index_to_letter(to_slot); + for (int i = MAX_GEAR; i < ENDOFPACK; ++i) + { + if (!you.inv[i].defined() || item_to_oper(&you.inv[i]) != oper) + continue; + + if (you.inv[i].slot == new_letter) + { + item2 = &you.inv[i]; + break; + } + } + + if (item2) + item2->slot = to_adjust.slot; + to_adjust.slot = index_to_letter(to_slot); + + if (verbose) + { + mprf_nocap("%s", to_adjust.name(DESC_INVENTORY_EQUIP).c_str()); + if (item2) + mprf_nocap("%s", item2->name(DESC_INVENTORY_EQUIP).c_str()); + } + + return; + } + + // Gear changes require moving items in the inventory array, which can + // invalidate many references that will need updating. + int new_quiver = -1; - if (you.quiver_action.item_is_quivered(from_slot)) + if (you.quiver_action.item_is_quivered(to_adjust)) new_quiver = to_slot; else if (you.quiver_action.item_is_quivered(to_slot)) - new_quiver = from_slot; + new_quiver = to_adjust.link; // Swap items. + const int from_slot = to_adjust.link; + item_def tmp = you.inv[to_slot]; you.inv[to_slot] = you.inv[from_slot]; you.inv[from_slot] = tmp; // Slot switching. tmp.slot = you.inv[to_slot].slot; - you.inv[to_slot].slot = index_to_letter(to_slot);//you.inv[from_slot].slot is 0 when 'from_slot' contains no item. + you.inv[to_slot].slot = index_to_letter(to_slot); //you.inv[from_slot].slot is 0 when 'from_slot' contains no item. you.inv[from_slot].slot = tmp.slot; you.inv[from_slot].link = from_slot; @@ -265,4 +327,7 @@ void swap_inv_slots(int from_slot, int to_slot, bool verbose) } if (you.last_unequip == from_slot) you.last_unequip = to_slot; + + if (you.cur_talisman == from_slot) + you.cur_talisman = to_slot; } diff --git a/crawl-ref/source/adjust.h b/crawl-ref/source/adjust.h index 85ef6986c1..90df87bdf6 100644 --- a/crawl-ref/source/adjust.h +++ b/crawl-ref/source/adjust.h @@ -5,6 +5,10 @@ #pragma once +#include "operation-types.h" + +struct item_def; + void adjust(); -void adjust_item(int from_slot = -1); -void swap_inv_slots(int slot1, int slot2, bool verbose); +void adjust_item(operation_types oper = OPER_ANY, item_def* to_adjust = nullptr); +void swap_inv_slots(item_def& to_adjust, int new_letter, bool verbose); diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index bc5cf64cc1..eed717b1a2 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -951,7 +951,7 @@ static void _add_formatted_keyhelp(column_composer &cols) _add_insert_commands(cols, 0, "<red>\"</red> : amulets (<w>%</w>ut on and <w>%</w>emove)", { CMD_WEAR_JEWELLERY, CMD_REMOVE_JEWELLERY }); _add_insert_commands(cols, 0, "<lightred>percent</lightred> : talismans (e<w>%</w>oke)", - { CMD_EVOKE }); + { CMD_WEAR_JEWELLERY, CMD_REMOVE_JEWELLERY }); _add_insert_commands(cols, 0, "<lightgrey>/</lightgrey> : wands (e<w>%</w>oke)", { CMD_EVOKE }); diff --git a/crawl-ref/source/dat/defaults/consumable_shortcuts.txt b/crawl-ref/source/dat/defaults/consumable_shortcuts.txt new file mode 100644 index 0000000000..ad186388bd --- /dev/null +++ b/crawl-ref/source/dat/defaults/consumable_shortcuts.txt @@ -0,0 +1,49 @@ +consumable_shortcut ^= scroll of identify:i +consumable_shortcut ^= scroll of teleportation:t +consumable_shortcut ^= scroll of fear:f +consumable_shortcut ^= scroll of noise:N +consumable_shortcut ^= scroll of summoning:s +consumable_shortcut ^= scroll of enchant weapon:w +consumable_shortcut ^= scroll of enchant armour:a +consumable_shortcut ^= scroll of torment:T +consumable_shortcut ^= scroll of immolation:I +consumable_shortcut ^= scroll of blinking:b +consumable_shortcut ^= scroll of revelation:r +consumable_shortcut ^= scroll of fog:g +consumable_shortcut ^= scroll of acquirement:A +consumable_shortcut ^= scroll of brand weapon:W +consumable_shortcut ^= scroll of vulnerability:V +consumable_shortcut ^= scroll of silence:S +consumable_shortcut ^= scroll of amnesia:x +consumable_shortcut ^= scroll of poison:p +consumable_shortcut ^= scroll of butterflies:s + +consumable_shortcut ^= potion of curing:c +consumable_shortcut ^= potion of heal wounds:w +consumable_shortcut ^= potion of haste:h +consumable_shortcut ^= potion of might:m +consumable_shortcut ^= potion of brilliance:b +consumable_shortcut ^= potion of attraction:A +consumable_shortcut ^= potion of enlightenment:e +consumable_shortcut ^= potion of cancellation:C +consumable_shortcut ^= potion of ambrosia:a +consumable_shortcut ^= potion of invisibility:i +consumable_shortcut ^= potion of experience:E +consumable_shortcut ^= potion of magic:m +consumable_shortcut ^= potion of berserk rage:B +consumable_shortcut ^= potion of mutation:M +consumable_shortcut ^= potion of resistance:r +consumable_shortcut ^= potion of lignification:L + +consumable_shortcut ^= wand of flame:a +consumable_shortcut ^= wand of acid:b +consumable_shortcut ^= wand of quicksilver:b +consumable_shortcut ^= wand of light:b +consumable_shortcut ^= wand of roots:c +consumable_shortcut ^= wand of warping:c +consumable_shortcut ^= wand of iceblast:c +consumable_shortcut ^= wand of mindburst:f +consumable_shortcut ^= wand of digging:d +consumable_shortcut ^= wand of charming:e +consumable_shortcut ^= wand of paralysis:e +consumable_shortcut ^= wand of polymorph:p diff --git a/crawl-ref/source/dat/descript/items.txt b/crawl-ref/source/dat/descript/items.txt index 56cc3a6cd8..0b7c64e760 100644 --- a/crawl-ref/source/dat/descript/items.txt +++ b/crawl-ref/source/dat/descript/items.txt @@ -87,7 +87,7 @@ A jagged cluster of blades, almost impossible to grasp without injury. {{ local hands = you.hand() .. "s" return "Causes long, needle-thin blades to grow from the " .. - "user's " .. hands + "wearer's " .. hands }}, and smaller fragments of metal to grow inside their body, deforming them and reducing the effectiveness of body armour. Shapeshifting skill mitigates and eventually eliminates the latter effect, as well as increasing damage @@ -588,14 +588,14 @@ A fearsome weapon with a forked, razor-sharp blade. dragon-coil talisman An intricate carving, inlaid with dragon tooth and scale. {{ - local desc = "Transforms the user into a mighty" + local desc = "Transforms the wearer into a mighty" if you.race():find("Draconian") then - desc = desc .. " dragon. The user retains their innate colour, " .. + desc = desc .. " dragon. The wearer retains their innate colour, " .. "becomes resistant to poison, and their breath weapon's " .. "power and recharge rate are greatly increased." else - desc = desc .. " golden dragon. The user becomes resistant to fire, " .. + desc = desc .. " golden dragon. The wearer becomes resistant to fire, " .. "cold, and poison, and gains a powerful breath attack " .. "that inflicts all three types of damage at once, but " .. "only recharges as you gain XP." @@ -676,7 +676,7 @@ spreading it to enemies, you will return to your previous form. %%%% fortress talisman -A miniature battlement, carved from a piece of shell. Transforms the user into a +A miniature battlement, carved from a piece of shell. Transforms the wearer into a heavily armoured crab, fusing whatever body armour they are wearing into the shell in the process. In this form, they are slow-moving, but well-defended and even capable of wielding a weapon in their large main claw. They can also @@ -732,7 +732,7 @@ A pile of glittering gold coins. granite talisman A heavy stone icon, bearing the countenance of some long-forgotten king or god. -Transforms the user into a slow, stone statue. The user's stone body is +Transforms the wearer into a slow, stone statue. The wearer's stone body is immune to poison and miasma, and gains resistance to electricity, negative energy, and torment. Shapeshifting skill increases armour granted. %%%% @@ -799,8 +799,8 @@ A piece of metal headgear. hive talisman A preserved and decorated hive, still dripping with ambrosial nectar. Transforms -the user into a living beehive, filled with the buzz of countless insects -labouring inside them. The nectar produced within greatly increases the user's +the wearer into a living beehive, filled with the buzz of countless insects +labouring inside them. The nectar produced within greatly increases the wearer's health and magic regeneration and if they become seriously injured, angry bees will swarm out to defend their hive. %%%% @@ -822,7 +822,7 @@ while rendering its wearer more susceptible to fire. %%%% inkwell talisman -A small bottle filled with mystical ink. Transforms the user into a walking +A small bottle filled with mystical ink. Transforms the wearer into a walking scroll whose body is tattooed with the knowledge of a hundred mages. Being an omnibus of magical techniques gives them increased skill with all spell schools, which improves with Shapeshifting skill, but the form's ability to channel such @@ -901,7 +901,7 @@ A long, strong bow made of yew. %%%% lupine talisman -A painted eyepatch made from a scrap of wolf pelt. Transforms the user into a +A painted eyepatch made from a scrap of wolf pelt. Transforms the wearer into a vicious werewolf, muscles surging with predatory instinct. Killing enemies in this form will give a stacking bonus to your damage and accuracy, and slaying enough of them in a row will cause you to unleash a vicious howl that makes @@ -925,16 +925,16 @@ hated rivals, a patient reader can discover spells of electrifying power. maw talisman A miniature, desiccated head of some ferocious and hopefully extinct creature. -Transforms the user's midsection into a giant mouth, gnashing and ready to devour -foes. The mouth may devour slain creatures, healing the user to an extent increased -by the user's Shapeshifting skill and the power of the creature eaten. Skill also +Transforms the wearer's midsection into a giant mouth, gnashing and ready to devour +foes. The mouth may devour slain creatures, healing the wearer to an extent increased +by the wearer's Shapeshifting skill and the power of the creature eaten. Skill also increases the damage done by the maw. %%%% medusa talisman A fossilised jellyfish polyp, inscribed with sigils. Causes a mane of long -stinging tendrils to sprout from the user's head which lash out at nearby -enemies whenever the user attacks, poisoning them. When they feel their host's +stinging tendrils to sprout from the wearer's head which lash out at nearby +enemies whenever the wearer attacks, poisoning them. When they feel their host's life is in danger, they can even turn these poisoned foes to stone. %%%% midnight gem @@ -1143,8 +1143,8 @@ An ever-changing fragment of something primordial; its substance seems to undulate between flesh and bone and perhaps even metal. A sufficiently skilled shapeshifter can stabilise it into a useable - if unpredictable - form. -(If your Shapeshifting skill is at least 6, you can evoke this to transform it -into a random one of: Rimehorn, Scarab, Medusa, or Maw talismans.) +(If your Shapeshifting skill is at least 6, attempting to put this one will +transform it into a random one of: Rimehorn, Scarab, Medusa, or Maw talismans.) %%%% quad damage @@ -1171,7 +1171,7 @@ for every blow its wielder makes. quill talisman A spiny trinket reminiscent of a cactus. Causes sharp quills to grow all over -the user's body which may cause injury to anyone unwise enough to attack them +the wearer's body which may cause injury to anyone unwise enough to attack them in melee. %%%% rapier @@ -1180,7 +1180,7 @@ A slender, sharply pointed sword, with an uncommonly elegant design. %%%% riddle talisman -An intricate puzzlebox containing an unknowable prize. Transforms the user into +An intricate puzzlebox containing an unknowable prize. Transforms the wearer into a riddle-loving sphinx. In this form, they are {{ if you.race() == "Felid" then return "normally capable of wearing a cloak and barding (though your" .. @@ -1200,10 +1200,10 @@ matter how unwise this may be. rimehorn talisman A crude ornament carved from the horn of a rare arctic beast - so cold to the -touch that ice still clings to it. Transforms the user into a rime yak, a hardy +touch that ice still clings to it. Transforms the wearer into a rime yak, a hardy ungulate that is highly resistant to cold and whose breath is so frigid that it freezes the walls around itself as it fights. Being so attuned to arctic -temperatures also makes it easier for the user to cast Ice magic. +temperatures also makes it easier for the wearer to cast Ice magic. %%%% ring mail @@ -1311,7 +1311,7 @@ a favoured weapon of the Shining One's servants. sanguine talisman A vial of roiling blood that pulses with the beat of an unseen heart. Transforms -the user into a fearsome vampire - a creature that straddles the border between +the wearer into a fearsome vampire - a creature that straddles the border between life and undeath. They can drink the lifeblood of the living to heal themselves, and even turn those they slay stealthily into vampiric thralls, but do not heal in the presence of monsters. At great effort, they may scatter into a swarm of @@ -1334,13 +1334,13 @@ movement. %%%% scarab talisman -A small golden cameo of a beetle. Transforms the user into a sun scarab, a +A small golden cameo of a beetle. Transforms the wearer into a sun scarab, a fiery insect that carries around a mote of searing heat and light outside itself, like a tiny sun. This solar ember burns adjacent enemies whenever the scarab attacks, and can be healed by swapping with it. In addition, the scarab's own mandibles can reduce -enemies' fire resistance and Fire spells are easier for the user to cast. +enemies' fire resistance and Fire spells are easier for the wearer to cast. %%%% scarf @@ -1481,7 +1481,7 @@ it's quite similar to a halberd. %%%% serpent talisman -A jade snake coiled around a fossilised egg. Transforms the user into an +A jade snake coiled around a fossilised egg. Transforms the wearer into an amphisbaena - a legendary two-headed serpent. It is capable of wearing two pieces of headgear at once and its powerful coils can wind around foes and crush them to death, but its cold blood leaves it succeptible to being slowed by cold @@ -1536,7 +1536,7 @@ fastened on one end. spider talisman A strange charm made from shed arachnid exoskeletons bound together with silk. -Transforms the user into an agile jumping spider who can move swiftly towards +Transforms the wearer into an agile jumping spider who can move swiftly towards foes and inflict grievous damage on any it catches unaware. Its attacks can also ensnare its enemies in webs and it can leap briskly away from many dangers. %%%% @@ -1616,9 +1616,9 @@ scale armours, and gives its wearer resistance to electrical discharges. %%%% storm talisman -Lightning trapped, impossibly, in a bottle. Lets the user walk through the air -as a raging, lightning-filled tempest. The user's melee attacks are electrified -and strike all adjacent foes. The user also flies, gains immunity to poison, +Lightning trapped, impossibly, in a bottle. Lets the wearer walk through the air +as a raging, lightning-filled tempest. The wearer's melee attacks are electrified +and strike all adjacent foes. The wearer also flies, gains immunity to poison, miasma, petrification, constriction, and sticky flame, and also resists electricity. They can launch themselves as a lightning bolt, blasting through everything in their way. @@ -1630,14 +1630,14 @@ The scales of a swamp dragon. It confers resistance to poison on its wearer. talisman of death A grey-black vessel, infused with dark power through a sickening ritual. -Transforms the user into an undying offence against life itself. +Transforms the wearer into an undying offence against life itself. -Foes struck by user's melee weapons or hands are weakened, slowed, and drained. -The user can also heal themself by tormenting living foes nearby; Shapeshifting -skill increases the amount healed. Further, the user resists cold, has enhanced +Foes struck by wearer's melee weapons or hands are weakened, slowed, and drained. +The wearer can also heal themself by tormenting living foes nearby; Shapeshifting +skill increases the amount healed. Further, the wearer resists cold, has enhanced willpower, and is immune to poison, miasma, negative energy, and torment. -The user also gains some of the more dubious benefits of having an undead body. +The wearer also gains some of the more dubious benefits of having an undead body. They are vulnerable to holy damage and Dispel Undead, and cannot consume potions. %%%% there-and-back book @@ -1787,7 +1787,7 @@ A military axe with a long haft and a single-bladed head. wellspring talisman A small amphora from which pours a seemingly unending quantity of water. -Transforms the user's flesh into elemental water, allowing them to move flexibly +Transforms the wearer's flesh into elemental water, allowing them to move flexibly and reach to attack from a great distance. From time to time, they can even cause the water around them to rise up and drown their enemies. diff --git a/crawl-ref/source/dbg-asrt.cc b/crawl-ref/source/dbg-asrt.cc index 47d77fc973..ea4d9b829f 100644 --- a/crawl-ref/source/dbg-asrt.cc +++ b/crawl-ref/source/dbg-asrt.cc @@ -359,7 +359,7 @@ static void _dump_player(FILE *file) for (player_equip_entry& entry : you.equipment.items) { fprintf(file, " eq slot #%d, inv slot #%d", entry.slot, entry.item); - if (entry.item < 0 || entry.item >= ENDOFPACK) + if (entry.item < 0 || entry.item >= MAX_GEAR) { fprintf(file, " <invalid>\n"); continue; diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 68d15561f3..9945934dc2 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -37,8 +37,9 @@ #endif #endif -// max size of inventory array {dlb}: -#define ENDOFPACK 52 +#define ENDOFPACK 127 // Max size of player inventory array +constexpr int MAX_GEAR = 52; // Max number of slots of gear inventory + // (and start of consumable inventory). // Max ghosts in a bones file. const int MAX_GHOSTS = 127; diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 2e6327e3f0..88fffed13a 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -2506,10 +2506,8 @@ static string _describe_lignify_ac() // Turn into a tree, check our resulting AC, and then turn back without // anyone being the wiser. unwind_var<player_equip_set> unwind_eq(you.equipment); - unwind_var<item_def> unwind_talisman(you.active_talisman); - unwind_var<transformation> unwind_form(you.form); - you.active_talisman.clear(); - you.form = transformation::tree; + unwind_var<int8_t> unwind_talisman(you.cur_talisman, -1); + unwind_var<transformation> unwind_form(you.form, transformation::tree); you.equipment.unmeld_all_equipment(true); you.equipment.meld_equipment(tree_form->blocked_slots, true); @@ -4010,7 +4008,8 @@ static bool _do_action(item_def &item, const command_type action) return true; drop_item(slot, item.quantity); break; - case CMD_ADJUST_INVENTORY: adjust_item(slot); break; + case CMD_ADJUST_INVENTORY: adjust_item(OPER_ANY, &you.inv[slot]); + break; case CMD_EVOKE: if (!check_warning_inscriptions(you.inv[slot], OPER_EVOKE)) return true; diff --git a/crawl-ref/source/evoke.cc b/crawl-ref/source/evoke.cc index 6d0bd35aa6..6d2bf4e4ea 100644 --- a/crawl-ref/source/evoke.cc +++ b/crawl-ref/source/evoke.cc @@ -163,12 +163,6 @@ int wand_power(spell_type wand_spell) void zap_wand(int slot, dist *_target) { - if (inv_count() < 1) - { - canned_msg(MSG_NOTHING_CARRIED); // why is this handled here?? - return; - } - if (!item_currently_evokable(slot == -1 ? nullptr : &you.inv[slot])) return; @@ -978,48 +972,6 @@ static bool _gravitambourine(dist *target) return true; } -static transformation _form_for_talisman(const item_def &talisman) -{ - if (you.using_talisman(talisman)) - return transformation::none; - return form_for_talisman(talisman); -} - -static bool _evoke_talisman(item_def &talisman) -{ - if (talisman.sub_type == TALISMAN_PROTEAN) - { - const talisman_type new_type = random_choose(TALISMAN_RIMEHORN, - TALISMAN_SCARAB, - TALISMAN_MEDUSA, - TALISMAN_MAW); - - mprf("%s responds to your shapeshifting skill and transforms into a %s!", - talisman.name(DESC_YOUR).c_str(), talisman_type_name(new_type).c_str()); - - talisman.sub_type = new_type; - return true; - } - - const transformation trans = _form_for_talisman(talisman); - if (!check_transform_into(trans, false, &talisman)) - return false; - if (transforming_is_unsafe(trans)) - return false; - if (!i_feel_safe(true) && !yesno("Still begin transforming?", true, 'n')) - { - canned_msg(MSG_OK); - return false; - } - - count_action(CACT_FORM, (int)trans); - start_delay<TransformDelay>(trans, &talisman); - if (god_despises_item(talisman, you.religion)) - excommunication(); - you.turn_is_over = true; - return true; -} - /// Does the item only serve to produce summons or allies? static bool _evoke_ally_only(const item_def &item, bool ident) { @@ -1063,35 +1015,6 @@ string cannot_evoke_item_reason(const item_def *item, bool temp, bool ident) return ""; } - if (item->base_type == OBJ_TALISMANS) - { - if (item->sub_type == TALISMAN_PROTEAN) - { - if (temp && you.skill(SK_SHAPESHIFTING) < 6) - { - return "you lack the shapeshifting skill to coax this " - "talisman into a stable form."; - } - else if (species_apt(SK_SHAPESHIFTING) == UNUSABLE_SKILL) - return "you can never gain the skill to use this talisman."; - else - return ""; - } - - const transformation trans = _form_for_talisman(*item); - const string form_unreason = cant_transform_reason(trans, false, temp); - if (!form_unreason.empty()) - return lowercase_first(form_unreason); - - if (you.form != you.default_form && temp) - return "you need to leave your temporary form first."; - - if (trans == transformation::hive && you_worship(GOD_OKAWARU)) - return "you have forsworn all allies in Okawaru's name."; - - return ""; - } - if (item->is_type(OBJ_BAUBLES, BAUBLE_FLUX)) { if (you.form == transformation::flux && temp) @@ -1174,9 +1097,6 @@ bool evoke_item(item_def& item, dist *preselect) zap_wand(item.link, preselect); return true; - case OBJ_TALISMANS: - return _evoke_talisman(item); - case OBJ_BAUBLES: mprf("You crush the flux bauble in your %s and feel its energy " "flooding your body.", you.hand_name(false).c_str()); diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 3b87f02d8e..34d011bb47 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -2059,6 +2059,11 @@ static void _fixup_transmuters() move_item_to_grid(&obj, you.pos(), true); del_spell_from_memory(p.first); } + if (you.props.exists("consolation_talisman")) + { + copy_item_to_grid(you.props["consolation_talisman"].get_item(), you.pos()); + you.props.erase("consolation_talisman"); + } } #endif diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 1dd920756d..1eb04127bf 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -130,6 +130,7 @@ static bool _force_allow_explore(); static species_type _str_to_species(const string &str); static sound_mapping _interrupt_sound_mapping(const string &s); static pair<text_pattern,string> _slot_mapping(const string &s); +static pair<string, char> _consumable_mapping(const string &s); #ifdef USE_TILE static tag_pref _str_to_tag_pref(const string &opt) @@ -709,8 +710,10 @@ const vector<GameOption*> game_options::build_options_list() {"message_colour", "message_color"}, {}, true), new ListGameOption<colour_mapping>(menu_colour_mappings, {"menu_colour", "menu_color"}, {}, true), - new ListGameOption<pair<text_pattern,string>, OPTFUN(_slot_mapping)>(auto_item_letters, - {"item_slot"}, {}, true), + new ListGameOption<pair<text_pattern,string>, OPTFUN(_slot_mapping)>(auto_gear_letters, + {"gear_slot"}, {}, true), + new ListGameOption<pair<string, char>, OPTFUN(_consumable_mapping)>(auto_consumable_letters, + {"consumable_shortcut"}, {}, true, {[this]() { update_consumable_shortcuts(); }}), new ListGameOption<pair<text_pattern,string>, OPTFUN(_slot_mapping)>(auto_spell_letters, {"spell_slot"}, {}, true), new ListGameOption<pair<text_pattern,string>, OPTFUN(_slot_mapping)>(auto_ability_letters, @@ -2213,6 +2216,7 @@ static const char* config_defaults[] = "defaults/glyph_colours.txt", "defaults/messages.txt", "defaults/misc.txt", + "defaults/consumable_shortcuts.txt", }; void base_game_options::reset_loaded_state() @@ -3090,6 +3094,29 @@ void game_options::update_travel_terrain() } } +void game_options::update_consumable_shortcuts() +{ + for (const auto& entry : auto_consumable_letters) + { + item_kind kind = item_kind_by_name(entry.first); + if (kind.base_type == OBJ_UNASSIGNED) + { + report_error("Unknown consumable type: %s\n", entry.first.c_str()); + continue; + } + else + string str = string(1, entry.second); + + if (kind.base_type == OBJ_POTIONS) + potion_shortcuts[kind.sub_type] = entry.second; + else if (kind.base_type == OBJ_SCROLLS) + scroll_shortcuts[kind.sub_type] = entry.second; + else if (kind.base_type == OBJ_WANDS) + evokable_shortcuts[kind.sub_type] = entry.second; + else if (kind.base_type == OBJ_MISCELLANY) + evokable_shortcuts[kind.sub_type] = entry.second + NUM_WANDS; + } +} void game_options::update_use_animations() { @@ -3367,6 +3394,18 @@ static pair<text_pattern,string> _slot_mapping(const string &s) return make_pair(text_pattern(thesplit[0], true), thesplit[1]); } +static pair<string, char> _consumable_mapping(const string &s) +{ + vector<string> thesplit = split_string(":", s, true, false, 1); + if (thesplit.size() != 2) + { + mprf(MSGCH_ERROR, "Error parsing consumable mapping: '%s'\n", + s.c_str()); + return make_pair("", '-'); // pattern is marked as invalid + } + return make_pair(thesplit[0], thesplit[1][0]); +} + // Option syntax is: // sort_menu = [menu_type:]yes|no|auto:n[:sort_conditions] void game_options::set_menu_sort(const string &field) @@ -3378,7 +3417,7 @@ void game_options::set_menu_sort(const string &field) { sort_menus.clear(); set_menu_sort("pickup: true"); - set_menu_sort("inv: true : equipped, charged"); + set_menu_sort("inv: true : equipped, charged, identified, usefulness, slot"); return; } diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc index 00ea7137a6..aa455871a4 100644 --- a/crawl-ref/source/invent.cc +++ b/crawl-ref/source/invent.cc @@ -97,7 +97,7 @@ InvEntry::InvEntry(const item_def &i) } if (i.base_type != OBJ_GOLD && in_inventory(i)) - add_hotkey(index_to_letter(i.link)); + add_hotkey(i.slot); else add_hotkey(' '); // dummy hotkey @@ -345,7 +345,7 @@ void InvMenu::set_preselect(const vector<SelItem> *pre) string slot_description() { - return make_stringf("%d/%d slots", inv_count(), ENDOFPACK); + return make_stringf("%d/%d gear slots", inv_count(INVENT_GEAR), MAX_GEAR); } void InvMenu::set_title(const string &s) @@ -385,6 +385,59 @@ int InvMenu::pre_process(int key) return key; } +bool InvMenu::process_key(int key) +{ + // Allow tab to move between item categories (since using item category + // hotkeys in the drop menu doesn't really work for this purpose as it will + // select many things at once instead). + if (key == CK_RIGHT || key == CK_LEFT) + { + // Find the first category below our current cursor position. + int start = last_hovered >= 0 ? last_hovered : 0; + int target = -1; + if (key == CK_RIGHT) + { + for (size_t i = start; i < items.size(); ++i) + { + if (items[i]->level == MEL_SUBTITLE) + { + target = i+1; + break; + } + } + } + // Find the first category above our current cursor position. + else if (key == CK_LEFT) + { + for (int i = start - 2; i >= 0; --i) + { + if (items[i]->level == MEL_SUBTITLE) + { + target = i+1; + break; + } + } + } + + // Stop if we didn't find any. + if (target < 0) + return true; + + // Otherwise, hover the first item of this category and try to display + // the entire category on screen (or as much as we can, anyway.) + auto snap_range = hotkey_range(items[target]->hotkeys.back()); + snap_in_page(snap_range.second); + set_hovered(snap_range.first); +#ifdef USE_TILE_WEB + webtiles_update_scroll_pos(true); +#endif + + return true; + } + + return Menu::process_key(key); +} + static bool _item_is_permadrop_candidate(const item_def &item) { // Known, non-artefact items of the types you see on the '\' menu proper. @@ -440,8 +493,7 @@ bool InvMenu::examine_index(int i) { // default behavior: examine inv item. You must override or use on_examine // if your items come from somewhere else, or this will cause crashes! - unsigned char select = ie->hotkeys[0]; - const int invidx = letter_to_index(select); + const int invidx = ie->item->link; ASSERT(you.inv[invidx].defined()); return describe_item(you.inv[invidx], nullptr, do_actions); } @@ -511,6 +563,8 @@ string no_selectables_message(int item_selector) return "You aren't carrying any pieces of jewellery."; case OSEL_AMULET: return "You aren't carrying any amulets."; + case OSEL_JEWELLERY_OR_TALISMAN: + return "You aren't carrying any jewllery or talismans."; case OSEL_LAUNCHING: return "You aren't carrying any items that might be thrown or fired."; case OSEL_EVOKABLE: @@ -521,8 +575,8 @@ string no_selectables_message(int item_selector) return "None of your equipped items are c... [truncated message content] |