From: <gi...@cr...> - 2025-07-22 13:25:11
|
via 4fc8f02bfa39827397055988515b67ff3ca55e0c (commit) via dbd2f4b8c060380bc8d59ec69a30aea0192dc57b (commit) via f9775fd51fe3878c43635c7d5d9fa0acd03a33b7 (commit) via e90cadbcb8f0cc142a6890a646eb6b130b59ad46 (commit) via 5d75d46d45b505725b9357c564b7d6a098626e1a (commit) via e02c2b2bd47e38273f95c7b2855e43783a19ae70 (commit) via 71121d73083e7990fc9f998d1267559f973b1be6 (commit) via 9293a925f68b232922f3ae264e51006b2183b0ca (commit) from 561764f35a2c1a202ac98321f5b5af6fc4d2b119 (commit) ----------------------------------------------------------------------- commit 4fc8f02bfa39827397055988515b67ff3ca55e0c Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:43:34 2025 -0230 Give a more helpful message when the player is trapped behind allies The situation where a player cannot swap with their allies is a rare one, but often confusing when it happens (usually due to a pileup of zombies that cannot cross deep water and a player who can). Try to give a more specific message, along with a helpful suggestion. (While it ordinarily would not be ideal to give the player advice instead of solving a problem directly, I don't think it would be appropriate for swapping to behave differently in this specific scenario than all others - eg: by blinking the monster away or displacing the entire crowd backwards - especially when it's easy to miss that one has gotten into this situation in the first place.) commit dbd2f4b8c060380bc8d59ec69a30aea0192dc57b Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:06:30 2025 -0230 Improve wording of Bane artprop slightly (Flugkiller) commit f9775fd51fe3878c43635c7d5d9fa0acd03a33b7 Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:06:11 2025 -0230 Prefer not to remove a Bane item when gear is forced off In the same way that ^Drain and ^Contam were already handled. commit e90cadbcb8f0cc142a6890a646eb6b130b59ad46 Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:49:41 2025 -0230 Change 'i' menu hotkey behavior yet again (Acrobat) Instead of 'first match below the cursor' do 'first match within the current sub-section in which the cursor is located'. (ie: if the player is hovering a potion, (c) will first select a potion on (c), if one exists, regardless of whether the cursor is below it. I apologize for how unstable the interface has been these past few days, but I hope we're narrowing in on a stable final version of everything now. commit 5d75d46d45b505725b9357c564b7d6a098626e1a Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:25:19 2025 -0230 Allow ',' to work on all pages of the drop menu at once (particleface) If the player wants to drop all useless items, they can do so without needing to cycle through pages at all. (The implementation is a little hacky - as perhaps this all is - but hopefully still clear and functional enough.) commit e02c2b2bd47e38273f95c7b2855e43783a19ae70 Author: DracoOmega <dra...@gm...> Date: Tue Jul 22 10:05:41 2025 -0230 Allow monster_unusual_items to hilight dangerous brands in some scenarios Holy wrath weapons are wildly more dangerous than other brands against those they work on, and remain dangerous even into lategame. But they are also harmless to most characters, making including them in monster_unusual_items awkward. Some players have resorted to custom lua to add/remove holy wrath from that list depending on what they're playing, but it feels like this should be supported by default, so I have made the following simple addition to the option: "vulnerable:" followed by the name of a brand can now be used to mark a monster as unusual only while non-immune to this brand. Additionally, it can optionally be used to specify an XL above which to stop marking the monster. For instance, "vulnerable:holy_wrath" will hilight monsters with holy wrath weapons, only while the player is vulnerable to them. "vulnerable:venom:5" will hilight monsters with venom weapons while the player is non-immune to them and XL 5 or below. While unnoticed venom weapons are a common souce of earlygame deaths, the threshold at which they stop mattering is subjective enough that I have not set this by default, but "vulnerable:holy_wrath" now *is* default, since they are always very dangerous (moreso than most default-marked items, in fact!) commit 71121d73083e7990fc9f998d1267559f973b1be6 Author: DracoOmega <dra...@gm...> Date: Mon Jul 21 23:18:59 2025 -0230 New command: CMD_EXPLORE_NO_REST Causes the player to autoexplore *without* resting for their HP/MP/status to heal, even if those options are normally set to true. This is useful in multiple situations where the player is just a little injured, but wants to capitalize on temporary statuses like Animate Dead / Death Channel or temporary god allies, rather than rest up and let those expire. This sort of thing happens somewhat commonly to certain characters and typically means having to manually explore for a while (even if you don't otherwise care where you go), so I think this might be helpful. ...it's not currently bound to anything since I'm genuinely unsure what reasonable default keybind is still available (I'm open to suggestions!) Though perhaps it's somewhat risky to end up anywhere it could be hit by accident since it is a button that bypasses normal 'safeties'? commit 9293a925f68b232922f3ae264e51006b2183b0ca Author: DracoOmega <dra...@gm...> Date: Mon Jul 21 18:40:17 2025 -0230 Change spelling for consistency All other player-facing places apparently use 'evocable items' even if the codebase itself tends to prefer 'evokable' ----------------------------------------------------------------------- Summary of changes: crawl-ref/source/adjust.cc | 2 +- crawl-ref/source/command-type.h | 1 + crawl-ref/source/dat/defaults/misc.txt | 1 + crawl-ref/source/dat/descript/commands.txt | 12 ++++++++++ crawl-ref/source/describe.cc | 2 +- crawl-ref/source/externs.h | 1 + crawl-ref/source/initfile.cc | 33 +++++++++++++++++++++++++++- crawl-ref/source/invent.cc | 16 ++++++++++++++ crawl-ref/source/invent.h | 1 + crawl-ref/source/items.cc | 35 ++++++++++++++++++++++++++++++ crawl-ref/source/main.cc | 1 + crawl-ref/source/menu.cc | 27 +++++++++++++++++------ crawl-ref/source/menu.h | 2 +- crawl-ref/source/options.h | 3 +++ crawl-ref/source/player-equip.cc | 6 +++-- crawl-ref/source/player.cc | 8 ++++--- crawl-ref/source/travel.cc | 24 +++++++++++++++----- crawl-ref/source/travel.h | 4 ++-- 18 files changed, 155 insertions(+), 24 deletions(-) diff --git a/crawl-ref/source/adjust.cc b/crawl-ref/source/adjust.cc index 8db16402ab..a0a2113e17 100644 --- a/crawl-ref/source/adjust.cc +++ b/crawl-ref/source/adjust.cc @@ -24,7 +24,7 @@ static void _adjust_ability(); void adjust() { mprf(MSGCH_PROMPT, "Adjust (g)ear, (s)pells, (a)bilities, " - "(p)otions, sc(r)olls or e(v)okables? "); + "(p)otions, sc(r)olls or e(v)ocables? "); const int keyin = toalower(get_ch()); diff --git a/crawl-ref/source/command-type.h b/crawl-ref/source/command-type.h index 318f7704df..3d89bb3395 100644 --- a/crawl-ref/source/command-type.h +++ b/crawl-ref/source/command-type.h @@ -114,6 +114,7 @@ enum command_type CMD_SEARCH_STASHES, CMD_EXPLORE, + CMD_EXPLORE_NO_REST, CMD_INTERLEVEL_TRAVEL, CMD_FIX_WAYPOINT, diff --git a/crawl-ref/source/dat/defaults/misc.txt b/crawl-ref/source/dat/defaults/misc.txt index 63034c74e2..5b2e782772 100644 --- a/crawl-ref/source/dat/defaults/misc.txt +++ b/crawl-ref/source/dat/defaults/misc.txt @@ -26,5 +26,6 @@ unusual_monster_items = wand unusual_monster_items += disto,chaos unusual_monster_items += curare,atropa,datura,dispersal,disjunction unusual_monster_items += throwing net +unusual_monster_teism += vulnerable:holy_wrath # For regular items and artefacts unusual_monster_items += reflect,Reflect diff --git a/crawl-ref/source/dat/descript/commands.txt b/crawl-ref/source/dat/descript/commands.txt index dff8c8e893..b040774a2e 100644 --- a/crawl-ref/source/dat/descript/commands.txt +++ b/crawl-ref/source/dat/descript/commands.txt @@ -19,6 +19,18 @@ Automatically explores the current level, collecting items on the way. Exploration stops as soon as a hostile monster comes into view, or when you encounter new items or features. %%%% +CMD_EXPLORE_NO_REST + +Autoexplore the current level without resting first +%%%% +CMD_EXPLORE_NO_REST + +Automatically explores the current level, collecting items on the way. +Exploration stops as soon as a hostile monster comes into view, or when you +encounter new items or features. Unlike CMD_EXPLORE, will treat +explore_auto_rest as if it were false and explore_auto_rest_status as if it were +empty. +%%%% CMD_INTERLEVEL_TRAVEL Travel to distant levels diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 1094894d5c..9fdca3be43 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -451,7 +451,7 @@ static const vector<property_descriptor> & _get_all_artp_desc_data() "It may silence you when you take damage.", prop_note::plain }, { ARTP_BANE, - "It inflicts you with a random bane when first equipped.", + "It inflicts you with a random bane when you equip it.", prop_note::plain }, }; return data; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index b6f76ffd54..9dc958b5ea 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -173,6 +173,7 @@ public: coord_def pos; int direction; int turns_passed; + bool skip_autorest; FixedVector<run_check_dir,3> run_check; // array of grids to check diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 075faf32f1..eb3d9dc4e1 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -600,7 +600,8 @@ const vector<GameOption*> game_options::build_options_list() #endif ), - new ListGameOption<text_pattern>(SIMPLE_NAME(unusual_monster_items), {}, true), + new ListGameOption<text_pattern>(SIMPLE_NAME(unusual_monster_items), {}, true, + {[this]() { process_unusual_items(); }}), new BoolGameOption(SIMPLE_NAME(arena_dump_msgs), false), new BoolGameOption(SIMPLE_NAME(arena_dump_msgs_all), false), @@ -3119,6 +3120,36 @@ void game_options::update_consumable_shortcuts() } } +// Extract 'vulnerable brand' options from unusual_monster_items +void game_options::process_unusual_items() +{ + for (int i = (int)unusual_monster_items.size() - 1; i >= 0; --i) + { + text_pattern& pattern = unusual_monster_items[i]; + string str = pattern.tostring(); + + if (!starts_with(str, "vulnerable:")) + continue; + + vector<string> splits = split_string(":", str, true, true, -1, true); + + if (splits.size() >= 2) + { + int brand = str_to_ego(OBJ_WEAPONS, splits[1]); + if (brand <= 0) + continue; + + int xl = 27; + if (splits.size() >= 3) + parse_int(splits[2].c_str(), xl); + + vulnerable_brand_warning.push_back({static_cast<brand_type>(brand), xl}); + } + + unusual_monster_items.erase(unusual_monster_items.begin() + i); + } +} + void game_options::update_use_animations() { static const std::map<const string, use_animation_type> ANIMATION_TYPES = diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc index eb88157d80..1d6d059788 100644 --- a/crawl-ref/source/invent.cc +++ b/crawl-ref/source/invent.cc @@ -485,6 +485,22 @@ bool InvMenu::process_command(command_type cmd) return Menu::process_command(cmd); } +void InvMenu::select_index(int index, int qty) +{ + // XXX: Apply drop_filter to all pages at once. + if (flags & MF_PAGED_INVENTORY && qty == MENU_SELECT_ALL) + { + int start_osel = cur_osel; + do + { + Menu::select_index(index, qty); + cycle_page(1); + } while (cur_osel != start_osel); + } + else + Menu::select_index(index, qty); +} + string InvMenu::get_select_count_string(int) const { if (flags & MF_PAGED_INVENTORY) diff --git a/crawl-ref/source/invent.h b/crawl-ref/source/invent.h index af663e06d8..683e1e7a2f 100644 --- a/crawl-ref/source/invent.h +++ b/crawl-ref/source/invent.h @@ -178,6 +178,7 @@ protected: virtual bool skip_process_command(int keyin) override; virtual bool is_selectable(int index) const override; virtual string help_key() const override; + void select_index(int index, int qty) override; protected: menu_type type; diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index b2a5ca8f87..07fd5741b2 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -750,8 +750,43 @@ bool item_is_branded(const item_def& item) } } +static bool _immune_to_brand(brand_type brand) +{ + switch (brand) + { + case SPWPN_HOLY_WRATH: + return !you.holy_wrath_susceptible(); + + case SPWPN_VENOM: + return you.res_poison() == 3; + + case SPWPN_DRAINING: + case SPWPN_PAIN: + return you.res_negative_energy() == 3; + + case SPWPN_ELECTROCUTION: + return you.res_elec() >= 1; + + default: + return false; + } +} + bool item_is_unusual(const item_def& item) { + if (item.base_type == OBJ_WEAPONS) + { + for (auto& match : Options.vulnerable_brand_warning) + { + if (get_weapon_brand(item) == match.first + && you.experience_level <= match.second + && !_immune_to_brand(match.first)) + { + return true; + } + } + } + const auto &patterns = Options.unusual_monster_items; const string name = item.name(DESC_A, false, false, true, false); diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index dc4e252131..a4866d2c2b 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -2315,6 +2315,7 @@ void process_command(command_type cmd, command_type prev_cmd) case CMD_INTERLEVEL_TRAVEL: do_interlevel_travel(); break; case CMD_ANNOTATE_LEVEL: do_annotate(); break; case CMD_EXPLORE: do_explore_cmd(); break; + case CMD_EXPLORE_NO_REST: do_explore_cmd(true); break; // Mouse commands. case CMD_MOUSE_MOVE: diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index 3b77de488e..37e7729a91 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -2192,12 +2192,25 @@ int Menu::hotkey_to_index(int key, bool primary_only) // Process all items, in case user hits hotkey for an // item not on the current page. - // We first check for the first matching hotkey from the cursor's current - // position to the end of the menu. If no match is found, we next check from - // the start of the menu to the current position. (This means that in cases - // where a menu has multiple entries with the same letter, we will select - // the first one below the cursor, if one exists, and then wrap around if not.) - for (int i = max(0, last_hovered); i < final; ++i) + // We first check for the first matching hotkey, starting from the top of + // the current menu subsection the cursor is in. If no match is found, we + // next check from the start of the menu to the current position. (This + // means that in cases where a menu has multiple entries with the same + // letter, we will select one within the current subsection, if one exists, + // and then check elsewhere if not.) + + // First, determine the top of our current section. + int top = 0; + for (int i = last_hovered; i >= 0; --i) + { + if (items[i]->level != MEL_ITEM) + { + top = i; + break; + } + } + + for (int i = top; i < final; ++i) { if (is_hotkey(i, key) && (!primary_only || items[i]->hotkeys[0] == key)) @@ -2205,7 +2218,7 @@ int Menu::hotkey_to_index(int key, bool primary_only) return i; } } - for (int i = 0; i < last_hovered; ++i) + for (int i = 0; i < top; ++i) { if (is_hotkey(i, key) && (!primary_only || items[i]->hotkeys[0] == key)) diff --git a/crawl-ref/source/menu.h b/crawl-ref/source/menu.h index 07e65d6585..63538da166 100644 --- a/crawl-ref/source/menu.h +++ b/crawl-ref/source/menu.h @@ -473,7 +473,7 @@ protected: void deselect_all(bool update_view = true); virtual void select_items(int key, int qty = MENU_SELECT_INVERT); // XX why is the default invert? virtual void select_item_index(int idx, int qty = MENU_SELECT_INVERT); - void select_index(int index, int qty = -1); + virtual void select_index(int index, int qty = -1); virtual bool examine_index(int i); bool examine_by_key(int keyin); int hotkey_to_index(int key, bool primary_only); diff --git a/crawl-ref/source/options.h b/crawl-ref/source/options.h index d474e1c534..07c9a6fb47 100644 --- a/crawl-ref/source/options.h +++ b/crawl-ref/source/options.h @@ -554,6 +554,8 @@ public: vector<text_pattern> unusual_monster_items; // which monster items to // highlight as unusual + vector<pair<brand_type, int>> vulnerable_brand_warning; // Monster brands to hilight the monster + // as having, below a given XL, while vulnerable int hp_warning; // percentage hp for danger warning int magic_point_warning; // percentage mp for danger warning @@ -1009,6 +1011,7 @@ private: void remove_force_ability_targeter(const string &s); void update_consumable_shortcuts(); + void process_unusual_items(); static const string interrupt_prefix; diff --git a/crawl-ref/source/player-equip.cc b/crawl-ref/source/player-equip.cc index dcdfa38165..054505b901 100644 --- a/crawl-ref/source/player-equip.cc +++ b/crawl-ref/source/player-equip.cc @@ -836,12 +836,14 @@ static bool _forced_removal_goodness(player_equip_entry* entry1, player_equip_en else if (is_artefact(item2) && artefact_property(item2, ARTP_FRAGILE)) return true; else if (is_artefact(item1) && (artefact_property(item1, ARTP_CONTAM) - || artefact_property(item1, ARTP_DRAIN))) + || artefact_property(item1, ARTP_DRAIN) + || artefact_property(item1, ARTP_BANE))) { return false; } else if (is_artefact(item2) && (artefact_property(item2, ARTP_CONTAM) - || artefact_property(item2, ARTP_DRAIN))) + || artefact_property(item2, ARTP_DRAIN) + || artefact_property(item2, ARTP_BANE))) { return true; } diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 55e5d30d5b..4ff137ba01 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -505,9 +505,11 @@ bool swap_check(monster* mons, coord_def &loc, bool quiet) if (!swap && !quiet) { - // Might not be ideal, but it's better than insta-killing - // the monster... maybe try for a short blink instead? - bwr - simple_monster_message(*mons, " cannot make way for you."); + // Might not be ideal, but it's better than insta-killing the monster. + mprf("There is no room for %s to move out of your way! " + "(Try telling them to retreat with <w>%sr</w> instead.)", + mons->name(DESC_THE).c_str(), + command_to_string(CMD_SHOUT).c_str()); // FIXME: activity_interrupt::hit_monster isn't ideal. interrupt_activity(activity_interrupt::hit_monster, mons); } diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 4847b59a18..9d774a0867 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -1096,14 +1096,19 @@ command_type travel() return CMD_NO_CMD; } - if (Options.explore_auto_rest && !you.is_sufficiently_rested() - || you.duration[DUR_NO_MOMENTUM]) + if (you.duration[DUR_NO_MOMENTUM] + || (Options.explore_auto_rest && !you.running.skip_autorest + && !you.is_sufficiently_rested()) + ) { return CMD_WAIT; } for (unsigned int i = 0; i < Options.explore_auto_rest_status.size(); ++i) { + if (you.running.skip_autorest) + break; + duration_type type = Options.explore_auto_rest_status[i]; if (you.duration[type] == 0) @@ -1135,8 +1140,11 @@ command_type travel() return CMD_WAIT; } - if (Options.explore_auto_rest_contam && you.magic_contamination) + if (Options.explore_auto_rest_contam && you.magic_contamination + && !you.running.skip_autorest) + { return CMD_WAIT; + } // Exploring. if (env.grid(you.pos()) == DNGN_ENTER_SHOP @@ -3415,7 +3423,7 @@ void start_travel(const coord_def& p) start_translevel_travel(level_target); } -void start_explore(bool grab_items) +void start_explore(bool grab_items, bool skip_autorest) { if (Hints.hints_explored) Hints.hints_explored = false; @@ -3436,15 +3444,16 @@ void start_explore(bool grab_items) env.map_seen.set(*ri); you.running.pos.reset(); + you.running.skip_autorest = skip_autorest; _start_running(); } -void do_explore_cmd() +void do_explore_cmd(bool skip_autorest) { if (you.berserk()) mpr("Calm down first, please."); else // Start exploring - start_explore(Options.explore_greedy); + start_explore(Options.explore_greedy, skip_autorest); } ////////////////////////////////////////////////////////////////////////// @@ -4595,6 +4604,7 @@ void runrest::initialise(int dir, int mode) notified_mp_full = false; notified_ancestor_hp_full = false; turns_passed = 0; + skip_autorest = false; if (dir == RDIR_REST) { @@ -4731,6 +4741,7 @@ void runrest::stop(bool clear_delays) (runmode > 0 || runmode < 0 && Options.travel_delay == -1); _userdef_run_stoprunning_hook(); runmode = RMODE_NOT_RUNNING; + skip_autorest = false; // Kill the delay; this is fine because it's not possible to stack // run/rest/travel on top of other delays. @@ -4803,6 +4814,7 @@ void runrest::clear() notified_hp_full = false; notified_mp_full = false; notified_ancestor_hp_full = false; + skip_autorest = false; } ///////////////////////////////////////////////////////////////////////////// diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index 19807a6d1e..b7f63c147b 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -89,8 +89,8 @@ bool is_stair_exclusion(const coord_def &p); * grabs items that are eligible for autopickup and visits (previously * unvisited) shops. */ -void start_explore(bool grab_items = false); -void do_explore_cmd(); +void start_explore(bool grab_items = false, bool skip_autorest = false); +void do_explore_cmd(bool skip_autorest = false); struct level_pos; class level_id; -- Dungeon Crawl Stone Soup |