From 9c717124d2f48858824a1bfdf3fe4ff62f223e72 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Thu, 19 Nov 2009 20:32:18 -0800 Subject: explore_stop: greedy_pickup_smart, pickup_ignore * Added the explore_stop option "greedy_pickup_smart", which is like greedy_pickup, but only stops for thrown items and items different than any in your inventory (and for fruit if you worship Fedhas). * Added the option explore_stop_pickup_ignore. Any items matching any of the regexes in the list will *not* cause "explore_stop = greedy_pickup" (or greedy_pickup_smart) to stop auto-explore. * "explore_stop = greedy_pickup" no longer stops when picking up gold. * "explore_stop = greedy_pickup" (or greedy_pickup_smart) now stops auto-explore after auto-pickup has happened, rather than right before it happens. * Removed obsolete ES_PICKUP. --- crawl-ref/docs/options_guide.txt | 24 ++++- crawl-ref/settings/init.txt | 2 + crawl-ref/source/initfile.cc | 11 +- crawl-ref/source/items.cc | 223 ++++++++++++++++++++++++++++++++++++++- crawl-ref/source/options.h | 4 + crawl-ref/source/travel.cc | 38 +------ crawl-ref/source/travel.h | 25 ++--- 7 files changed, 272 insertions(+), 55 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/docs/options_guide.txt b/crawl-ref/docs/options_guide.txt index b2acca0d55..f527db358b 100644 --- a/crawl-ref/docs/options_guide.txt +++ b/crawl-ref/docs/options_guide.txt @@ -48,8 +48,8 @@ The contents of this text are: scroll_margin 4-g Travel and Exploration. travel_delay, explore_delay, travel_avoid_terrain, - explore_greedy, explore_stop, explore_improved, - tc_reachable, tc_dangerous, tc_disconnected, + explore_greedy, explore_stop, explore_stop_pickup_ignore, + explore_improved, tc_reachable, tc_dangerous, tc_disconnected, tc_excluded, tc_exclude_circle, travel_stop_message, runrest_ignore_message, runrest_ignore_poison, runrest_ignore_monster, trapwalk_safe_hp, @@ -845,8 +845,15 @@ explore_stop = items,greedy_pickup,stairs,shops,altars,gates greedy_items: stop when items that are eligible for autopickup come into view. - greedy_pickup: stop when you arrive at a square which contains - an item eligble for autopickup. + greedy_pickup: stop after you automatically pick up any item + eligible for autopickup (except for gold). You can make + certain items *not* trigger this with the option + explore_stop_pickup_ignore + + greedy_pickup_smart: Similar to greedy_pickup, but tries to be + smart about it, meaning only stopping for thrown items and + items which aren't similar to any you already have in your + inventory. glowing_items: like items, but only for items which are glowing/runed/embroidered/etc. @@ -855,6 +862,15 @@ explore_stop = items,greedy_pickup,stairs,shops,altars,gates runes: like items, but only for runes. +explore_stop_pickup_ignore = + If explore_stop has greedy_pickup or greedy_pickup_smart set, + then picking up any items matching any of the regexes in the list + will *not* stop auto-explore. For example, by default curare- + tipped needles are automatically picked up to keep them out of + the hands of monsters, even if you don't have a blowgun, so to + not stop auto-explore because of this use + "explore_stop_pickup_ignore = curare". + explore_improved = false If set to true explore will attempt to reduce zig-zagging during auto-explore. On average it increases the number of turns taken diff --git a/crawl-ref/settings/init.txt b/crawl-ref/settings/init.txt index 73e317e72d..8c8068bc43 100644 --- a/crawl-ref/settings/init.txt +++ b/crawl-ref/settings/init.txt @@ -166,6 +166,8 @@ drop_filter = useless_item # explore_greedy = false # explore_stop = items,greedy_items,stairs,shops,altars,gates # explore_improved = true +# +# explore_stop_pickup_ignore = curare auto_exclude = oklob plant,silver statue,orange crystal statue,ice statue auto_exclude = curse skull,roxanne diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 37dfd8f952..30ade48c03 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -755,6 +755,8 @@ void game_options::reset_options() // reading options. explore_stop_prompt = ES_NONE; + explore_stop_pickup_ignore.clear(); + explore_item_greed = 10; explore_greedy = true; @@ -1598,10 +1600,10 @@ int game_options::read_explore_stop_conditions(const std::string &field) const const std::string &c = stops[i]; if (c == "item" || c == "items") conditions |= ES_ITEM; - else if (c == "pickup") - conditions |= ES_PICKUP; else if (c == "greedy_pickup" || c == "greedy pickup") conditions |= ES_GREEDY_PICKUP; + else if (c == "greedy_pickup_smart" || c == "greedy pickup smart") + conditions |= ES_GREEDY_PICKUP_SMART; else if (c == "shop" || c == "shops") conditions |= ES_SHOP; else if (c == "stair" || c == "stairs") @@ -1975,6 +1977,7 @@ void game_options::read_option_line(const std::string &str, bool runscript) if (key != "name" && key != "crawl_dir" && key != "macro_dir" && key != "species" && key != "job" && key != "ban_pickup" && key != "autopickup_exceptions" + && key != "explore_stop_pickup_ignore" && key != "stop_travel" && key != "sound" && key != "travel_stop_message" && key != "force_more_message" && key != "drop_filter" && key != "lua_file" && key != "terp_file" @@ -2869,6 +2872,10 @@ void game_options::read_option_line(const std::string &str, bool runscript) else explore_stop_prompt |= new_conditions; } + else if (key == "explore_stop_pickup_ignore") + { + append_vector(explore_stop_pickup_ignore, split_string(",", field)); + } else if (key == "explore_item_greed") { explore_item_greed = atoi( field.c_str() ); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 6ad9fb2dfe..46a7fb5fc8 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -2323,10 +2323,215 @@ bool can_autopickup() return (true); } +typedef bool (*item_comparer)(const item_def& pickup_item, + const item_def& inv_item); + +static bool _identical_types(const item_def& pickup_item, + const item_def& inv_item) +{ + return ((pickup_item.base_type == inv_item.base_type) + && (pickup_item.sub_type == inv_item.sub_type)); +} + +static bool _edible_food(const item_def& pickup_item, + const item_def& inv_item) +{ + return (inv_item.base_type == OBJ_FOOD && !is_inedible(inv_item)); +} + +static bool _similar_equip(const item_def& pickup_item, + const item_def& inv_item) +{ + const equipment_type inv_slot = get_item_slot(inv_item); + + if (inv_slot == EQ_NONE) + return (false); + + // If it's an unequipped cursed item the player might be looking + // for a replacement. + if (item_known_cursed(inv_item) && !item_is_equipped(inv_item)) + return (false); + + if (get_item_slot(pickup_item) != inv_slot) + return (false); + + // Just filling the same slot is enough for armour to be considered + // similar. + if (pickup_item.base_type == OBJ_ARMOUR) + return (true); + + // Launchers of the same type are similar. + if ((pickup_item.sub_type >= WPN_BLOWGUN && + pickup_item.sub_type <= WPN_LONGBOW) + || pickup_item.sub_type == WPN_SLING) + { + return (pickup_item.sub_type != inv_item.sub_type); + } + + return ((weapon_skill(pickup_item) == weapon_skill(inv_item)) + && (get_damage_type(pickup_item) == get_damage_type(inv_item))); +} + +static bool _similar_wands(const item_def& pickup_item, + const item_def& inv_item) +{ + if (inv_item.base_type != OBJ_WANDS) + return (false); + + if (pickup_item.sub_type != inv_item.sub_type) + return (false); + + // Not similar if wand in inventory is known to be empty. + return (inv_item.plus2 != ZAPCOUNT_EMPTY + || (item_ident(inv_item, ISFLAG_KNOW_PLUSES) + && inv_item.plus > 0)); +} + +static bool _similar_jewellery(const item_def& pickup_item, + const item_def& inv_item) +{ + if (inv_item.base_type != OBJ_JEWELLERY) + return (false); + + if (pickup_item.sub_type != inv_item.sub_type) + return (false); + + // For jewellery of the same sub-type, unidentified jewellery is + // always considered similar, as is identified jewellery whose + // effect doesn't stack. + return (!item_type_known(inv_item) + || (!jewellery_is_amulet(inv_item) + && !ring_has_stackable_effect(inv_item))); +} + +static bool _item_different_than_inv(const item_def& pickup_item, + item_comparer comparer) +{ + for (int i = 0; i < ENDOFPACK; i++) + { + const item_def& inv_item(you.inv[i]); + + if (!inv_item.is_valid()) + continue; + + if ( (*comparer)(pickup_item, inv_item) ) + return (false); + } + + return (true); +} + +static bool _interesting_explore_pickup(const item_def& item) +{ + if (!(Options.explore_stop & ES_GREEDY_PICKUP_MASK)) + return (false); + + // Gold is boring. + if (item.base_type == OBJ_GOLD) + return (false); + + std::vector &ignore = Options.explore_stop_pickup_ignore; + if (!ignore.empty()) + { + const std::string name = item.name(DESC_PLAIN); + + for (unsigned int i = 0; i < ignore.size(); i++) + if (ignore[i].matches(name)) + return (false); + } + + if (!(Options.explore_stop & ES_GREEDY_PICKUP_SMART)) + return (true); + + // "Smart" code follows. + if (item.flags & ISFLAG_THROWN) + return (true); + + if (is_artefact(item)) + return (true); + + // Possbible ego items. + if (!item_type_known(item) & (item.flags & ISFLAG_COSMETIC_MASK)) + return (true); + + switch(item.base_type) + { + case OBJ_WEAPONS: + case OBJ_MISSILES: + case OBJ_ARMOUR: + // Ego items. + if (item.special != 0) + return (true); + break; + + default: + break; + } + + switch(item.base_type) + { + case OBJ_WEAPONS: + case OBJ_ARMOUR: + return _item_different_than_inv(item, _similar_equip); + + case OBJ_WANDS: + return _item_different_than_inv(item, _similar_wands); + + case OBJ_JEWELLERY: + return _item_different_than_inv(item, _similar_jewellery); + + case OBJ_FOOD: + if (you.religion == GOD_FEDHAS && is_fruit(item)) + return (true); + + if (is_inedible(item)) + return (false); + + // Interesting if we don't have any other edible food. + return _item_different_than_inv(item, _edible_food); + + case OBJ_STAVES: + // Rods are always interesting, even if you already have one of + // the same type, since each rod has its own mana. + if (item_is_rod(item)) + return (true); + + // Intentional fall-through. + case OBJ_MISCELLANY: + // Runes are always interesting. + if (is_rune(item)) + return (true); + + // Decks always start out unidentified. + if (is_deck(item)) + return (true); + + // Intentional fall-through. + case OBJ_SCROLLS: + case OBJ_POTIONS: + // Item is boring only if there's an identical one in inventory. + return _item_different_than_inv(item, _identical_types); + + case OBJ_BOOKS: + // Books always start out unidentified. + return (true); + + case OBJ_ORBS: + // Orb is always interesting. + return (true); + + default: + break; + } + + return (false); +} + static void _do_autopickup() { - int n_did_pickup = 0; - int n_tried_pickup = 0; + bool did_pickup = false; + int n_did_pickup = 0; + int n_tried_pickup = 0; will_autopickup = false; @@ -2370,6 +2575,12 @@ static void _do_autopickup() } } + // Do this before it's picked up, otherwise the picked up + // item will be in inventory and _interesting_explore_pickup() + // will always return false. + const bool interesting_pickup + = _interesting_explore_pickup(mitm[o]); + const unsigned long iflags(mitm[o].flags); mitm[o].flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED); @@ -2385,7 +2596,11 @@ static void _do_autopickup() mitm[o].flags = iflags; } else - n_did_pickup++; + { + did_pickup = true; + if (interesting_pickup) + n_did_pickup++; + } } o = next; @@ -2394,7 +2609,7 @@ static void _do_autopickup() if (!pickup_warning.empty()) mpr(pickup_warning.c_str()); - if (n_did_pickup) + if (did_pickup) you.turn_is_over = true; item_check(false); diff --git a/crawl-ref/source/options.h b/crawl-ref/source/options.h index 4e37f4352d..9d0bc6d3d6 100644 --- a/crawl-ref/source/options.h +++ b/crawl-ref/source/options.h @@ -245,6 +245,10 @@ public: int explore_stop_prompt; + // Don't stop greedy explore when picking up an item which matches + // any of these patterns. + std::vector explore_stop_pickup_ignore; + bool explore_greedy; // Explore goes after items as well. // How much more eager greedy-explore is for items than to explore. diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 7af3080f09..f0965784ce 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -795,8 +795,8 @@ void explore_pickup_event(int did_pickup, int tried_pickup) if (did_pickup) { const int estop = - (you.running == RMODE_EXPLORE_GREEDY) ? ES_GREEDY_PICKUP - : ES_PICKUP; + (you.running == RMODE_EXPLORE_GREEDY) ? ES_GREEDY_PICKUP_MASK + : ES_NONE; if ((Options.explore_stop & estop) && prompt_stop_explore(estop)) { @@ -932,35 +932,6 @@ command_type travel() prev_travel_index = !prev_travel_index; } - if ((*move_x || *move_y) && you.running == RMODE_EXPLORE_GREEDY) - { - // Greedy explore should cut off on reaching an item. We can't - // check after reaching the item, because at that point the stash - // tracker will have verified the stash and say "false" to - // needs_visit. - const coord_def newpos = you.pos() + coord_def(*move_x, *move_y); - - if (newpos == you.running.pos) - { - const LevelStashes *lev = StashTrack.find_current_level(); - if (lev && lev->needs_visit(newpos) - && !lev->shop_needs_visit(newpos)) - { - const int estop = - (you.running == RMODE_EXPLORE_GREEDY) ? - ES_GREEDY_PICKUP : ES_PICKUP; - - if ((Options.explore_stop & estop) - && prompt_stop_explore(estop)) - { - explore_stopped_pos = newpos; - stop_running(); - } - return direction_to_command( *move_x, *move_y ); - } - } - } - if (!*move_x && !*move_y) { // If we've reached the square we were traveling towards, travel @@ -4053,8 +4024,9 @@ void explore_discoveries::found_item(const coord_def &pos, const item_def &i) } // if (you.running == RMODE_EXPLORE_GREEDY) add_item(i); - es_flags |= (you.running == RMODE_EXPLORE_GREEDY) ? ES_GREEDY_PICKUP - : ES_PICKUP; + // MATT + es_flags |= (you.running == RMODE_EXPLORE_GREEDY) ? ES_GREEDY_PICKUP_MASK + : ES_NONE; } // Expensive O(n^2) duplicate search, but we can live with that. diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index 5a79e6b046..2b0b8240b9 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -157,18 +157,19 @@ extern travel_distance_grid_t travel_point_distance; enum explore_stop_type { - ES_NONE = 0x000, - ES_ITEM = 0x001, - ES_PICKUP = 0x002, - ES_GREEDY_PICKUP = 0x004, - ES_GREEDY_ITEM = 0x008, - ES_STAIR = 0x010, - ES_SHOP = 0x020, - ES_ALTAR = 0x040, - ES_PORTAL = 0x080, - ES_GLOWING_ITEM = 0x100, - ES_ARTEFACT = 0x200, - ES_RUNE = 0x400 + ES_NONE = 0x000, + ES_ITEM = 0x001, + ES_GREEDY_PICKUP = 0x002, + ES_GREEDY_PICKUP_SMART = 0x004, + ES_GREEDY_PICKUP_MASK = (ES_GREEDY_PICKUP | ES_GREEDY_PICKUP_SMART), + ES_GREEDY_ITEM = 0x008, + ES_STAIR = 0x010, + ES_SHOP = 0x020, + ES_ALTAR = 0x040, + ES_PORTAL = 0x080, + ES_GLOWING_ITEM = 0x100, + ES_ARTEFACT = 0x200, + ES_RUNE = 0x400 }; //////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3-54-g00ecf