Automatically update the shopping list if you see the same item for less cost in another shop, or if you get an item identical to one on the shopping list (currently only applies to jewellery, books and staves).
RSVDMFN7LVPYBYCWI3IF3GNIMSSVWVXANOQMH5DN2PGVP3VAOGQAC OFYW2YRIRSE4TJBFEZ4RROHYVS22T6SJLJXX3FQEBNMWENMBPM4AC LUSG5HYFRMFNS3RACRCUJNQXJNXPL4SYKHHOIEG5RBQG2DKQXPDAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC GYRKOLZFYXWJTPEV35USSHCJNA6Y4XMDHSTEZWEBM57WQP2PT6UQC 4DEFHDNO2GUBYL4EGYEAR2IP3KBDXRU7UL7L4P7HEZY2UNR6IYJAC 25EF5X4H3LURXFZ35ZGYGUB6ND7NFQVH4M2XX2SI33I4XRGYG5HAC Q4TULVRLLNAHZNURPKNAR2K3GBVCEY6KY6ZXKPIJVWVSSZ6R7PEQC YFIVTYI7PMVAXV23DUPXPAQNEY3YSFIXQGSN32I3WVHMMD5XS5DQC EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC BDFIS53HAIHOCXQ5BE7WCO2MEOFCUQPFY4JGUWVLWY6JO3IFMEKQC U6OTXM3JN7SGPVIGQ5F6NR2I7J5V7KOWFQ7AVNNRQQDNLBEDMYFQC SZBMBNW34N2SM7Y6QBKBSA7OMLEMLFGCE4NSMHCBH6ORU2MYY2MQC static std::string name_thing(const CrawlHashTable& thing);static std::string describe_thing(const CrawlHashTable& thing);
static std::string name_thing(const CrawlHashTable& thing,description_level_type descrip = DESC_PLAIN);static std::string describe_thing(const CrawlHashTable& thing,description_level_type descrip = DESC_PLAIN);static std::string item_name_simple(const item_def& item,bool ident = false);
}static bool _shop_yesno(const char* prompt, int safeanswer){if (_in_shop_now){textcolor(channel_to_colour(MSGCH_PROMPT));_shop_print(prompt, 1);return yesno(NULL, true, safeanswer, false, false, true);}elsereturn yesno(prompt, true, safeanswer, false, false, false);}static void _shop_mpr(const char* msg){if (_in_shop_now){_shop_print(msg, 1);_shop_more();}elsempr(msg);
// Cull shopping list after shop contents have been displayed, but// only once.if (first_iter){first_iter = false;unsigned int culled = 0;for (unsigned int i = 0; i < stock.size(); i++){const item_def& item = mitm[stock[i]];const int cost = _shop_get_item_value(item, shop.greed,id_stock);unsigned int num = shopping_list.cull_identical_items(item,(long) cost);if (num > 0){in_list[i] = true;num_in_list++;}culled += num;}if (culled > 0){// Some shopping list items have been moved to this store,// so refresh the display.mesclr();continue;}}
std::vector<bool> to_buy;int total_purchase = 0;if (num_selected == 0 && num_in_list > 0){if (_shop_yesno("Buy items on shopping list? (Y/n)", 'y')){to_buy = in_list;for (unsigned int i = 0; i < to_buy.size(); i++){if (to_buy[i]){const item_def& item = mitm[stock[i]];total_purchase +=_shop_get_item_value(item, shop.greed,id_stock);}}}}else{to_buy = selected;total_purchase = total_cost;}
#define REMOVE_PROMPTED_KEY "remove_prompted_key"#define REPLACE_PROMPTED_KEY "replace_prompted_key"// TODO://// * If you get a randart which lets you turn invisible, then remove// any ordinary rings of invisiblity from the shopping list.//// * If you collected enough spellbooks that all the spells in a// shopping list book are covered, then auto-remove it.unsigned int ShoppingList::cull_identical_items(const item_def& item,long cost){// Can't put items in Bazaar shops in the shopping list, so// don't bother transfering shopping list items to Bazaar shops.if (cost != -1 && you.level_type != LEVEL_DUNGEON)return (0);switch(item.base_type){case OBJ_JEWELLERY:case OBJ_BOOKS:case OBJ_STAVES:// Only these are really interchangable.break;default:return (0);}if (!item_type_known(item) || is_artefact(item))return (0);// Ignore stat-modification rings which reduce a stat, since they're// worthless.if (item.plus < 0 && item.base_type == OBJ_JEWELLERY)return (0);// Item is already on shopping-list.const bool on_list = find_thing(item, level_pos::current()) != -1;const bool do_prompt =(item.base_type == OBJ_JEWELLERY && !jewellery_is_amulet(item)&& ring_has_stackable_effect(item))// Manuals and tomes of destruction are consumable.|| (item.base_type == OBJ_BOOKS&& (item.sub_type == BOOK_MANUAL|| item.sub_type == BOOK_DESTRUCTION));bool add_item = false;std::vector<level_pos> to_del;// NOTE: Don't modify the shopping list while iterating over it.for (unsigned int i = 0; i < list->size(); i++){if (_in_shop_now)mesclr();CrawlHashTable &thing = (*list)[i];if (!thing_is_item(thing))continue;const item_def& list_item = get_thing_item(thing);if (list_item.base_type != item.base_type|| list_item.sub_type != item.sub_type){continue;}if (!item_type_known(list_item) || is_artefact(list_item))continue;const level_pos list_pos = thing_pos(thing);// cost = -1, we just found a shop item which is cheaper than// one on the shopping list.if (cost != -1){long list_cost = thing_cost(thing);if (cost >= list_cost)continue;// Only prompt once.if (thing.exists(REPLACE_PROMPTED_KEY))continue;thing[REPLACE_PROMPTED_KEY] = (bool) true;std::string prompt =make_stringf("Shopping-list: replace %dgp %s with cheaper ""one? (Y/n)", list_cost,describe_thing(thing).c_str());if (_shop_yesno(prompt.c_str(), 'y')){add_item = true;to_del.push_back(list_pos);}continue;}// cost == -1, we just got an item which is on the shopping list.if (do_prompt){// Only prompt once.if (thing.exists(REMOVE_PROMPTED_KEY))continue;thing[REMOVE_PROMPTED_KEY] = (bool) true;std::string prompt =make_stringf("Shopping-list: remove %s? (Y/n)",describe_thing(thing, DESC_NOCAP_A).c_str());if (_shop_yesno(prompt.c_str(), 'y'))to_del.push_back(list_pos);}else{std::string str =make_stringf("Shopping-list: removing %s",describe_thing(thing, DESC_NOCAP_A).c_str());_shop_mpr(str.c_str());to_del.push_back(list_pos);}}for (unsigned int i = 0; i < to_del.size(); i++)del_thing(item, &to_del[i]);if (add_item && !on_list)add_thing(item, cost);return (to_del.size());}
// Item name without plusses, curse-status or inscription.std::string ShoppingList::item_name_simple(const item_def& item, bool ident){return item.name(DESC_PLAIN, false, ident, false, false,ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES);}
// Returns true if having two rings of the same type on at the same// has more effect than just having one on.bool ring_has_stackable_effect( const item_def &item ){ASSERT (item.base_type == OBJ_JEWELLERY);ASSERT (!jewellery_is_amulet(item));if (!item_type_known(item))return (false);if (ring_has_pluses(item))return (true);switch (item.sub_type){case RING_PROTECTION_FROM_FIRE:case RING_PROTECTION_FROM_COLD:case RING_LIFE_PROTECTION:case RING_SUSTENANCE:case RING_WIZARDRY:case RING_FIRE:case RING_ICE:return (true);default:break;}return (false);}