The basics of a wish-list/shopping-list. While in a shop the shopping-list can be modified, and the player is notified as soon as they have enough money to buy things on the shopping-list.
OFYW2YRIRSE4TJBFEZ4RROHYVS22T6SJLJXX3FQEBNMWENMBPM4AC AK73N24BCYLHPTVYVO562AUM6KGLD5DUM572EPX43XYUUKBVOOXQC T53JH5GFABPQXENOAMN2C2FAMALAMUAMWNEMGKRSO2YEYALLB3TAC ASXBSZVXJCWVX5VQSRWXL5BWQ4NA7JLYXP6LWQTRGYW6DC2DZZPQC GWTFRNIDL5TNFFDUENSRVE2EOPSMOAPFBZLESQ3LDDSTSG6EJ33AC QUXUAWYOV5F333UJDENSORWXQ4DP5XYJATGXSWDOAVSQPKL4FV5AC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC GYRKOLZFYXWJTPEV35USSHCJNA6Y4XMDHSTEZWEBM57WQP2PT6UQC 25EF5X4H3LURXFZ35ZGYGUB6ND7NFQVH4M2XX2SI33I4XRGYG5HAC Q4TULVRLLNAHZNURPKNAR2K3GBVCEY6KY6ZXKPIJVWVSSZ6R7PEQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC 4DEFHDNO2GUBYL4EGYEAR2IP3KBDXRU7UL7L4P7HEZY2UNR6IYJAC BYSGVGW655QV7SRUP73ZW4UOSFFRA6BV2MYLAIM6QK5CAXSJKGEQC GP7RUHLNB4KISSZAENEYVNY3MB5YRCFRWRWYAROBZIQ5MR4DXB7QC DTJQJWFSCI3P6UFRJJXLDIL3DHP3LSFXJKS647VPRWI2DIYZLHFAC 3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC FNXXWDRU5PS3AOL4PLMWBDKJQ2TJOFAWRHTOMEEA6PJOQ7UN566AC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC 2LJ3PLU4DNUUCK7SYPTK4G4BTDMJ6UEKOKWML6WOIPJKWLFCD5FQC YFIVTYI7PMVAXV23DUPXPAQNEY3YSFIXQGSN32I3WVHMMD5XS5DQC DCZMEKDHQWSQCQYQD6ZXB3XOMWLVLPSPVSBVVMPXMSZF7GO3BVCAC FAVME2A2U4OUKN2BTISAG5PCI5Y4BN6YVFKCSQQHHZLEVVVF4LKAC EI7H4ZAWPCJX4SJTRTOULJQHE2UJG746KFLRND7FLZTNG3QIOP4QC 2KTJHQUX2LTU2BCLS5YXVRRKMOYKKIZAPF2LBKORFGSHEN5IO3IAC NCSALY7HYRVCKTPS5TWZBRE2C3OCANYU3LBPIZ4RRVEI6GOZL2EQC BMKL2AB2HBBBVAHWDYXPYZHSCO345QWOQHFSICFRN5BCYZ3UEK3AC DK362IHKSDADMUPD35NOTKM4WESQM37KG2PNOJRV2FGELDWULYPQC RDOOG5LBE5TCTFYCKJIB7TGGTRFX4HBLMJZYXS5TCFWNCU3QII5QC LPTP6ZL7U4OVXLZ56TJKJ6HENDHE7ITFMFBXC5BKEBVXEGXPW44AC PS3OYZOHCD464IMPYTISQO2NDD4WLHZHKAT5TBB2VMAU2JBNPYRQC IGBJ3ZY5G73GTHPRNWKC6XMQDINRGCTIXKBHTEZ7JLUJS6H4JRBAC /////////////////////////////////////////////////////////////////////struct level_pos;class ShoppingList{public:ShoppingList();bool add_thing(const item_def &item, int cost, level_pos* pos = NULL);bool add_thing(std::string desc, std::string buy_verb, int cost,level_pos* pos = NULL);bool is_on_list(const item_def &item, level_pos* pos = NULL) const;bool is_on_list(std::string desc, level_pos* pos = NULL) const;bool del_thing(const item_def &item, level_pos* pos = NULL);bool del_thing(std::string desc, level_pos* pos = NULL);int size() const;void move_things(const coord_def &src, const coord_def &dst);void gold_changed(int old_amount, int new_amount);void display_list();void refresh();private:CrawlVector* list;int min_unbuyable_cost;int min_unbuyable_idx;int max_buyable_cost;int max_buyable_idx;private:int find_thing(const item_def &item, const level_pos &pos) const;int find_thing(const std::string &desc, const level_pos &pos) const;static bool thing_is_item(const CrawlHashTable& thing);static const item_def& get_thing_item(const CrawlHashTable& thing);static std::string get_thing_desc(const CrawlHashTable& thing);static long thing_cost(const CrawlHashTable& thing);static level_pos thing_pos(const CrawlHashTable& thing);static std::string name_thing(const CrawlHashTable& thing);static std::string describe_thing(const CrawlHashTable& thing);};extern ShoppingList shopping_list;
const bool id_stock = shoptype_identifies_stock(shop.type);
std::vector<int> stock = _shop_get_stock(shopidx);// Autoinscribe randarts in the shop.for (unsigned int i = 0; i < stock.size(); i++){item_def& item = mitm[stock[i]];if (Options.autoinscribe_artefacts && is_artefact(item))item.inscription = artefact_auto_inscription(item);}
// Autoinscribe randarts in the shop.for (unsigned int i = 0; i < stock.size(); i++){item_def& item = mitm[stock[i]];if (Options.autoinscribe_artefacts && is_artefact(item))item.inscription = artefact_auto_inscription(item);}
stock = _shop_get_stock(shopidx);
else if (key == '@'){if (viewing || (num_selected == 0 && num_in_list == 0)){_shop_print("Huh?", 1);_shop_more();continue;}if (num_selected > 0){// Move selected to shopping list.for (unsigned int i = 0; i < stock.size(); i++){if (selected[i]){in_list[i] = true;selected[i] = false;}}total_cost = 0;}else{// Move shopping list to selected.for (unsigned int i = 0; i < stock.size(); i++){if (in_list[i]){in_list[i] = false;selected[i] = true;const item_def& item = mitm[stock[i]];total_cost += _shop_get_item_value(item, shop.greed,id_stock);}}}}
if (in_list[key]){if (gp_value > you.gold){_shop_print("Remove from shopping list? (y/N)",1);if ( yesno(NULL, true, 'n', false, false, true) ){in_list[key] = false;selected[key] = false;}continue;}else{_shop_print("Remove item from shopping list and buy ""it? (Y/n)", 1);if ( yesno(NULL, true, 'y', false, false, true) ){in_list[key] = false;// Will be toggled to true laterselected[key] = false;}elsecontinue;}}
ASSERT(total_cost > 0);}}}// Actually change shopping list.for (unsigned int i = 0; i < stock.size(); i++){const item_def& item = mitm[stock[i]];bool on_list = shopping_list.is_on_list(item);if (on_list != in_list[i]){if (in_list[i]){// Ignore Bargaining.const int cost = _shop_get_item_value(item, shop.greed,id_stock, false);shopping_list.add_thing(item, cost);
////////////////////////////////////////////////////////////////////////// Setup shopping list after restoring savefile.static void _callback(bool saving){if (!saving)shopping_list.refresh();}static SavefileCallback _register_callback(_callback);// TODO:// * Let shopping list be modified from with the stash lister.// * Warn if buying something not on the shopping list would put// something on shopping list out of your reach.#define SHOPPING_LIST_KEY "shopping_list_key"#define SHOPPING_THING_COST_KEY "cost_key"#define SHOPPING_THING_ITEM_KEY "item_key"#define SHOPPING_THING_POS_KEY "pos_key"ShoppingList::ShoppingList(){}#define SETUP_POS() \if (list == NULL) \{ \mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR); \return (false); \} \level_pos pos; \if (_pos != NULL) \pos = *_pos; \else \pos = level_pos::current(); \ASSERT(pos.is_valid());#define SETUP_THING() \CrawlHashTable *thing = new CrawlHashTable(); \(*thing)[SHOPPING_THING_COST_KEY] = (long) cost; \(*thing)[SHOPPING_THING_POS_KEY] = pos;bool ShoppingList::add_thing(const item_def &item, int cost,level_pos* _pos){ASSERT(is_valid_item(item));ASSERT(cost > 0);SETUP_POS();if (find_thing(item, pos) != -1){mprf(MSGCH_ERROR, "%s is already on the shopping list.",item.name(DESC_CAP_THE).c_str());return (false);}SETUP_THING();(*thing)[SHOPPING_THING_ITEM_KEY] = item;list->push_back(*thing);refresh();return (true);}bool ShoppingList::add_thing(std::string desc, std::string buy_verb, int cost,level_pos* _pos){ASSERT(false); // Not implemented yetSETUP_POS();return (false);}#undef SETUP_THINGbool ShoppingList::is_on_list(const item_def &item, level_pos* _pos) const{SETUP_POS();return (find_thing(item, pos) != -1);}bool ShoppingList::is_on_list(std::string desc, level_pos* _pos) const{ASSERT(false); // Not implemented yetSETUP_POS();return (false);}bool ShoppingList::del_thing(const item_def &item, level_pos* _pos){SETUP_POS();int idx = find_thing(item, pos);if (idx == -1){mprf(MSGCH_ERROR, "%s isn't on shopping list, can't delete it.",item.name(DESC_CAP_THE).c_str());return (false);}list->erase(idx);refresh();return (true);}bool ShoppingList::del_thing(std::string desc, level_pos* _pos){ASSERT(false); // Not implemented yetSETUP_POS();return (false);}#undef SETUP_POSint ShoppingList::size() const{if (list == NULL){mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR);return (0);}return ( list->size() );}void ShoppingList::move_things(const coord_def &src, const coord_def &dst){ASSERT(false); // Not implemented yet}void ShoppingList::gold_changed(int old_amount, int new_amount){if (list == NULL){mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR);return;}if (new_amount > old_amount && new_amount >= min_unbuyable_cost){ASSERT(min_unbuyable_idx < list->size());std::vector<std::string> descs;for (unsigned int i = min_unbuyable_idx; i < list->size(); i++){const CrawlHashTable &thing = (*list)[i];const long cost = thing_cost(thing);if (cost > new_amount){ASSERT(i > (unsigned int) min_unbuyable_idx);break;}std::string desc;if (thing_is_item(thing))desc = "buy ";desc += describe_thing(thing);descs.push_back(desc);}ASSERT(!descs.empty());mpr_comma_separated_list("You now have enough gold to ", descs,", or ");// Reset max_buyable and min_unbuyable inforefresh();}else if (new_amount < old_amount && new_amount < max_buyable_cost){// Reset max_buyable and min_unbuyable inforefresh();}}void ShoppingList::display_list(){ASSERT(false); // Not implemented yet}bool _compare_shopping_things(const CrawlStoreValue& a,const CrawlStoreValue& b){const CrawlHashTable& hash_a = a.get_table();const CrawlHashTable& hash_b = b.get_table();const long a_cost = hash_a[SHOPPING_THING_COST_KEY];const long b_cost = hash_b[SHOPPING_THING_COST_KEY];return (a_cost < b_cost);}void ShoppingList::refresh(){if (!you.props.exists(SHOPPING_LIST_KEY))you.props[SHOPPING_LIST_KEY].new_vector(SV_HASH, SFLAG_CONST_TYPE);list = &you.props[SHOPPING_LIST_KEY].get_vector();std::sort(list->begin(), list->end(), _compare_shopping_things);min_unbuyable_cost = INT_MAX;min_unbuyable_idx = -1;max_buyable_cost = -1;max_buyable_idx = -1;for (unsigned int i = 0; i < list->size(); i++){const CrawlHashTable &thing = (*list)[i];const long cost = thing_cost(thing);if (cost <= you.gold){max_buyable_cost = cost;max_buyable_idx = i;}else{min_unbuyable_cost = cost;min_unbuyable_idx = i;break;}}}int ShoppingList::find_thing(const item_def &item,const level_pos &pos) const{for (unsigned int i = 0; i < list->size(); i++){const CrawlHashTable &thing = (*list)[i];const level_pos _pos = thing_pos(thing);if (pos != _pos)continue;if (item.name(DESC_NOCAP_A) == name_thing(thing))return (i);}return (-1);}int ShoppingList::find_thing(const std::string &desc,const level_pos &pos) const{ASSERT(false); // Not implemented yetreturn (-1);}bool ShoppingList::thing_is_item(const CrawlHashTable& thing){return thing.exists(SHOPPING_THING_ITEM_KEY);}const item_def& ShoppingList::get_thing_item(const CrawlHashTable& thing){ASSERT(thing.exists(SHOPPING_THING_ITEM_KEY));const item_def &item = thing[SHOPPING_THING_ITEM_KEY].get_item();ASSERT(is_valid_item(item));return (item);}std::string ShoppingList::get_thing_desc(const CrawlHashTable& thing){ASSERT(false); // Not implemented yetreturn("");}long ShoppingList::thing_cost(const CrawlHashTable& thing){ASSERT(thing.exists(SHOPPING_THING_COST_KEY));return (thing[SHOPPING_THING_COST_KEY].get_long());}level_pos ShoppingList::thing_pos(const CrawlHashTable& thing){ASSERT(thing.exists(SHOPPING_THING_POS_KEY));return (thing[SHOPPING_THING_POS_KEY].get_level_pos());}std::string ShoppingList::name_thing(const CrawlHashTable& thing){if (thing_is_item(thing)){const item_def &item = get_thing_item(thing);return item.name(DESC_NOCAP_A);}elseASSERT(false);return ("");}std::string ShoppingList::describe_thing(const CrawlHashTable& thing){const level_pos pos = thing_pos(thing);std::string desc = name_thing(thing) + " on ";if (pos.id == level_id::current())desc += "this level";elsedesc += pos.id.describe();return (desc);}
void player::set_gold(int amount){ASSERT(amount >= 0);if (amount != gold){shopping_list.gold_changed(gold, amount);gold = amount;}}