Apply the new ground_level method.
[crawl.git] / crawl-ref / source / shopping.cc
blob1fa6cccdaa2440078e7218902b119c1f7838b225
1 /*
2 * File: shopping.cc
3 * Summary: Shop keeper functions.
4 * Written by: Linley Henzell
5 */
7 #include "AppHdr.h"
9 #include "shopping.h"
10 #include "message.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
16 #include "externs.h"
17 #include "options.h"
18 #include "artefact.h"
19 #include "cio.h"
20 #include "describe.h"
21 #include "decks.h"
22 #include "dgn-overview.h"
23 #include "files.h"
24 #include "food.h"
25 #include "invent.h"
26 #include "items.h"
27 #include "itemname.h"
28 #include "itemprop.h"
29 #include "libutil.h"
30 #include "macro.h"
31 #include "menu.h"
32 #include "notes.h"
33 #include "place.h"
34 #include "player.h"
35 #include "spl-book.h"
36 #include "stash.h"
37 #include "stuff.h"
38 #include "travel.h"
39 #include "env.h"
41 #define SHOPPING_LIST_COST_KEY "shopping_list_cost_key"
43 ShoppingList shopping_list;
45 static bool _in_shop_now = false;
47 static bool _purchase(int shop, int item_got, int cost, bool id);
49 static void _shop_print(const char *shoppy, int line)
51 cgotoxy(1, line + 19, GOTO_CRT);
52 cprintf("%s", shoppy);
53 clear_to_end_of_line();
56 static void _shop_more()
58 cgotoxy(65, 20, GOTO_CRT);
59 cprintf("-more-");
60 get_ch();
63 static bool _shop_yesno(const char* prompt, int safeanswer)
65 if (_in_shop_now)
67 textcolor(channel_to_colour(MSGCH_PROMPT));
68 _shop_print(prompt, 1);
70 return yesno(NULL, true, safeanswer, false, false, true);
72 else
73 return yesno(prompt, true, safeanswer, false, false, false);
76 static void _shop_mpr(const char* msg)
78 if (_in_shop_now)
80 _shop_print(msg, 1);
81 _shop_more();
83 else
84 mpr(msg);
87 static std::string _hyphenated_suffix(char prev, char last)
89 std::string s;
90 if (prev > last + 2)
91 s += "</w>-<w>";
92 else if (prev == last + 2)
93 s += (char) (last + 1);
95 if (prev != last)
96 s += prev;
97 return (s);
100 static std::string _purchase_keys(const std::string &s)
102 if (s.empty())
103 return "";
105 std::string list = "<w>" + s.substr(0, 1);
106 char last = s[0];
107 for (unsigned int i = 1; i < s.length(); ++i)
109 if (s[i] == s[i - 1] + 1)
110 continue;
112 char prev = s[i - 1];
113 list += _hyphenated_suffix(prev, last);
114 list += (last = s[i]);
117 list += _hyphenated_suffix(s[s.length() - 1], last);
118 list += "</w>";
119 return (list);
122 static void _list_shop_keys(const std::string &purchasable, bool viewing,
123 int total_stock, int num_selected,
124 int num_in_list)
126 ASSERT(total_stock > 0);
128 const int numlines = get_number_of_lines();
129 formatted_string fs;
131 std::string shop_list = "";
132 if (!viewing && you.level_type == LEVEL_DUNGEON)
134 shop_list = "[<w>$</w>] ";
135 if (num_selected > 0)
136 shop_list += "Selected -> shopping list";
137 else if (num_in_list > 0)
138 shop_list += "Shopping list -> selected";
139 else
140 shop_list = "";
142 if (!shop_list.empty())
144 cgotoxy(1, numlines - 2, GOTO_CRT);
145 fs = formatted_string::parse_string(shop_list);
146 fs.cprintf("%*s", get_number_of_cols() - fs.length() - 1, "");
147 fs.display();
150 cgotoxy(1, numlines - 1, GOTO_CRT);
152 std::string pkeys = "";
153 if (viewing)
155 pkeys = "<w>a</w>";
156 if (total_stock > 1)
158 pkeys += "-<w>";
159 pkeys += 'a' + total_stock - 1;
160 pkeys += "</w>";
163 else
164 pkeys = _purchase_keys(purchasable);
166 if (!pkeys.empty())
168 pkeys = "[" + pkeys + "] Select Item to "
169 + (viewing ? "Examine" : "Buy");
171 fs = formatted_string::parse_string(make_stringf(
172 "[<w>x</w>/<w>Esc</w>"
173 #ifdef USE_TILE
174 "/<w>R-Click</w>"
175 #endif
176 "] exit [<w>!</w>] %s %s",
177 (viewing ? "to buy items " : "to examine items"),
178 pkeys.c_str()));
180 fs.cprintf("%*s", get_number_of_cols() - fs.length() - 1, "");
181 fs.display();
182 cgotoxy(1, numlines, GOTO_CRT);
184 fs = formatted_string::parse_string(
185 "[<w>Enter</w>"
186 #ifdef USE_TILE
187 "/<w>L-Click</w>"
188 #endif
189 "] make purchase [<w>\\</w>] list known items "
190 "[<w>?</w>/<w>*</w>] inventory");
192 fs.cprintf("%*s", get_number_of_cols() - fs.length() - 1, "");
193 fs.display();
196 static std::vector<int> _shop_get_stock(int shopidx)
198 std::vector<int> result;
199 // Shop items are heaped up at this cell.
200 const coord_def stack_location(0, 5 + shopidx);
201 for (stack_iterator si(stack_location); si; ++si)
202 result.push_back(si.link());
203 return result;
206 static int _shop_get_item_value(const item_def& item, int greed, bool id,
207 bool ignore_bargain = false)
209 int result = (greed * item_value(item, id) / 10);
210 if (you.duration[DUR_BARGAIN] && !ignore_bargain) // 20% discount
212 result *= 8;
213 result /= 10;
216 if (result < 1)
217 result = 1;
219 return result;
222 static std::string _shop_print_stock(const std::vector<int>& stock,
223 const std::vector<bool>& selected,
224 const std::vector<bool>& in_list,
225 const shop_struct& shop,
226 int total_cost)
228 ShopInfo &si = StashTrack.get_shop(shop.pos);
229 const bool id = shoptype_identifies_stock(shop.type);
230 std::string purchasable;
231 for (unsigned int i = 0; i < stock.size(); ++i)
233 const item_def& item = mitm[stock[i]];
234 const int gp_value = _shop_get_item_value(item, shop.greed, id);
235 const bool can_afford = (you.gold >= gp_value);
237 cgotoxy(1, i+1, GOTO_CRT);
238 const char c = i + 'a';
239 if (can_afford)
240 purchasable += c;
242 // Colour stock as follows:
243 // * lightcyan, if on the shopping list.
244 // * lightred, if you can't buy all you selected.
245 // * lightgreen, if this item is purchasable along with your selections
246 // * red, if this item is not purchasable even by itself.
247 // * yellow, if this item would be purchasable if you deselected
248 // something else.
250 // Is this too complicated? (jpeg)
252 if (in_list[i])
253 textcolor(LIGHTCYAN);
254 else if (total_cost > you.gold && selected[i])
255 textcolor(LIGHTRED);
256 else if (gp_value <= you.gold - total_cost || selected[i] && can_afford)
257 textcolor(LIGHTGREEN);
258 else if (!can_afford)
259 textcolor(RED);
260 else
261 textcolor(YELLOW);
263 if (in_list[i])
264 cprintf("%c $ ", c);
265 else if (selected[i])
266 cprintf("%c + ", c);
267 else
268 cprintf("%c - ", c);
270 if (Options.menu_colour_shops)
272 // Colour stock according to menu colours.
273 const std::string colprf = menu_colour_item_prefix(item);
274 const int col = menu_colour(item.name(DESC_NOCAP_A),
275 colprf, "shop");
276 textcolor(col != -1 ? col : LIGHTGREY);
278 else
279 textcolor(i % 2 ? LIGHTGREY : WHITE);
281 cprintf("%-56s%5d gold",
282 item.name(DESC_NOCAP_A, false, id).substr(0, 56).c_str(),
283 gp_value);
285 si.add_item(item, gp_value);
287 textcolor(LIGHTGREY);
289 return (purchasable);
292 static int _count_identical(const std::vector<int>& stock,
293 const item_def& item)
295 int count = 0;
296 for (unsigned int i = 0; i < stock.size(); i++)
298 const item_def &other = mitm[stock[i]];
300 if (ShoppingList::items_are_same(item, other))
301 count++;
303 return (count);
306 // Rather than prompting for each individual item, shopping now works more
307 // like multi-pickup, in that pressing a letter only "selects" an item
308 // (changing the '-' next to its name to a '+'). Affordability is shown
309 // via colours that are updated every time the contents of your shopping
310 // cart change.
312 // New, suggested shopping keys:
313 // * letter keys [a-t] (de)select item, as now
314 // * Enter buys (with prompt), as now
315 // * \ shows discovered items, as now
316 // * x exits (also Esc), as now
317 // * ! toggles examination mode (where letter keys view items)
318 // * *, ? lists inventory
320 // For the ? key, the text should read:
321 // [!] switch to examination mode
322 // [!] switch to selection mode
323 static bool _in_a_shop(int shopidx, int &num_in_list)
325 const shop_struct& shop = env.shop[shopidx];
327 unwind_bool in_shop(_in_shop_now, true);
329 cursor_control coff(false);
331 clrscr();
333 const std::string hello = "Welcome to " + shop_name(shop.pos) + "!";
334 bool first = true;
335 int total_cost = 0;
337 std::vector<int> stock = _shop_get_stock(shopidx);
339 // Autoinscribe randarts in the shop.
340 for (unsigned int i = 0; i < stock.size(); i++)
342 item_def& item = mitm[stock[i]];
343 if (Options.autoinscribe_artefacts && is_artefact(item))
344 item.inscription = artefact_auto_inscription(item);
347 std::vector<bool> selected;
348 std::vector<bool> in_list;
350 const bool id_stock = shoptype_identifies_stock(shop.type);
351 bool bought_something = false;
352 bool viewing = false;
353 bool first_iter = true;
355 while (true)
357 ASSERT(total_cost >= 0);
359 StashTrack.get_shop(shop.pos).reset();
361 stock = _shop_get_stock(shopidx);
363 in_list.clear();
364 in_list.resize(stock.size(), false);
365 for (unsigned int i = 0; i < stock.size(); i++)
367 const item_def& item = mitm[stock[i]];
368 in_list[i] = shopping_list.is_on_list(item);
371 // If items have been bought...
372 if (stock.size() != selected.size())
374 total_cost = 0;
375 selected.clear();
376 selected.resize(stock.size(), false);
379 num_in_list = 0;
380 int num_selected = 0;
381 for (unsigned int i = 0; i < stock.size(); i++)
383 if (in_list[i])
384 num_in_list++;
385 if (selected[i])
386 num_selected++;
389 clrscr();
390 if (stock.empty())
392 _shop_print("I'm sorry, my shop is empty now.", 1);
393 _shop_more();
394 return (bought_something);
397 const std::string purchasable = _shop_print_stock(stock, selected,
398 in_list, shop,
399 total_cost);
400 _list_shop_keys(purchasable, viewing, stock.size(), num_selected,
401 num_in_list);
403 // Cull shopping list after shop contents have been displayed, but
404 // only once.
405 if (first_iter)
407 first_iter = false;
409 unsigned int culled = 0;
411 for (unsigned int i = 0; i < stock.size(); i++)
413 const item_def& item = mitm[stock[i]];
414 const int cost = _shop_get_item_value(item, shop.greed,
415 id_stock);
417 unsigned int num = shopping_list.cull_identical_items(item,
418 cost);
419 if (num > 0)
421 in_list[i] = true;
422 num_in_list++;
424 culled += num;
426 if (culled > 0)
428 // Some shopping list items have been moved to this store,
429 // so refresh the display.
430 continue;
434 if (!total_cost)
436 snprintf(info, INFO_SIZE, "You have %d gold piece%s.", you.gold,
437 you.gold != 1 ? "s" : "");
439 textcolor(YELLOW);
441 else if (total_cost > you.gold)
443 snprintf(info, INFO_SIZE, "You have %d gold piece%s. "
444 "You are short %d gold piece%s for the purchase.",
445 you.gold,
446 you.gold != 1 ? "s" : "",
447 total_cost - you.gold,
448 (total_cost - you.gold != 1) ? "s" : "");
450 textcolor(LIGHTRED);
452 else
454 snprintf(info, INFO_SIZE, "You have %d gold piece%s. "
455 "After the purchase, you will have %d gold piece%s.",
456 you.gold,
457 you.gold != 1 ? "s" : "",
458 you.gold - total_cost,
459 (you.gold - total_cost != 1) ? "s" : "");
461 textcolor(YELLOW);
464 _shop_print(info, 0);
466 if (first)
468 first = false;
469 snprintf(info, INFO_SIZE, "%s What would you like to do? ",
470 hello.c_str());
472 else
473 snprintf(info, INFO_SIZE, "What would you like to do? ");
475 textcolor(CYAN);
476 _shop_print(info, 1);
478 textcolor(LIGHTGREY);
480 mouse_control mc(MOUSE_MODE_MORE);
481 int key = getchm();
483 if (key == '\\')
484 check_item_knowledge();
485 else if (key == 'x' || key_is_escape(key) || key == CK_MOUSE_CMD)
486 break;
487 else if (key == '\r' || key == CK_MOUSE_CLICK)
489 std::vector<bool> to_buy;
490 int total_purchase = 0;
492 if (num_selected == 0 && num_in_list > 0)
494 if (_shop_yesno("Buy items on shopping list? (Y/n)", 'y'))
496 to_buy = in_list;
498 for (unsigned int i = 0; i < to_buy.size(); i++)
500 if (to_buy[i])
502 const item_def& item = mitm[stock[i]];
504 total_purchase +=
505 _shop_get_item_value(item, shop.greed,
506 id_stock);
511 else
513 to_buy = selected;
514 total_purchase = total_cost;
517 // Do purchase.
518 if (total_purchase > you.gold)
520 _shop_print("I'm sorry, you don't seem to have enough money.",
523 else if (!total_purchase) // Nothing selected.
524 continue;
525 else
527 snprintf(info, INFO_SIZE, "Purchase for %d gold? (y/n)",
528 total_purchase);
530 if (_shop_yesno(info, 'n'))
532 int num_items = 0, outside_items = 0, quant;
533 for (int i = to_buy.size() - 1; i >= 0; --i)
535 if (to_buy[i])
537 item_def& item = mitm[stock[i]];
539 // Remove from shopping list if it's unique
540 // (i.e., if the shop has multiple scrolls of
541 // identify, don't remove the other scrolls
542 // from the shopping list if there's any
543 // left).
544 if (in_list[i]
545 && _count_identical(stock, item) == 1)
547 shopping_list.del_thing(item);
550 const int gp_value = _shop_get_item_value(item,
551 shop.greed, id_stock);
553 // Take a note of the purchase.
554 take_note(Note(NOTE_BUY_ITEM, gp_value, 0,
555 item.name(DESC_NOCAP_A).c_str()));
557 // But take no further similar notes.
558 item.flags |= ISFLAG_NOTED_GET;
560 if (fully_identified(item))
561 item.flags |= ISFLAG_NOTED_ID;
563 quant = item.quantity;
564 num_items += quant;
566 if (!_purchase(shopidx, stock[i], gp_value,
567 id_stock))
569 // The purchased item didn't fit into your
570 // knapsack.
571 outside_items += quant;
576 if (outside_items)
578 mprf("I'll put %s outside for you.",
579 num_items == 1 ? "it" :
580 num_items == outside_items ? "them"
581 : "part of them");
583 bought_something = true;
586 //_shop_more();
587 continue;
589 else if (key == '!')
591 // Toggle between browsing and shopping.
592 viewing = !viewing;
594 else if (key == '?' || key == '*')
595 browse_inventory(false);
596 else if (key == '$')
598 if (viewing || (num_selected == 0 && num_in_list == 0)
599 || you.level_type != LEVEL_DUNGEON)
601 _shop_print("Huh?", 1);
602 _shop_more();
603 continue;
606 if (num_selected > 0)
608 // Move selected to shopping list.
609 for (unsigned int i = 0; i < stock.size(); i++)
611 const item_def &item = mitm[stock[i]];
612 if (selected[i])
614 if (!shopping_list.is_on_list(item))
616 // Ignore Bargaining.
617 const int cost = _shop_get_item_value(item,
618 shop.greed, id_stock, false);
619 shopping_list.add_thing(item, cost);
621 in_list[i] = true;
622 selected[i] = false;
625 total_cost = 0;
627 else
629 // Move shopping list to selected.
630 for (unsigned int i = 0; i < stock.size(); i++)
632 const item_def &item = mitm[stock[i]];
633 if (in_list[i])
635 in_list[i] = false;
636 selected[i] = true;
638 total_cost += _shop_get_item_value(item, shop.greed,
639 id_stock);
641 if (shopping_list.is_on_list(item))
642 shopping_list.del_thing(item);
647 else if (!isaalpha(key))
649 _shop_print("Huh?", 1);
650 _shop_more();
652 else
654 key = tolower(key) - 'a';
655 if (key >= static_cast<int>(stock.size()))
657 _shop_print("No such item.", 1);
658 _shop_more();
659 continue;
662 item_def& item = mitm[stock[key]];
663 if (viewing)
665 // A hack to make the description more useful.
666 // In theory, the user could kill the process at this
667 // point and end up with valid ID for the item.
668 // That's not very useful, though, because it doesn't set
669 // type-ID and once you can access the item (by buying it)
670 // you have its full ID anyway. Worst case, it won't get
671 // noted when you buy it.
672 const uint64_t old_flags = item.flags;
673 if (id_stock)
675 item.flags |= (ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID
676 | ISFLAG_NOTED_GET);
678 describe_item(item, false, true);
679 if (id_stock)
680 item.flags = old_flags;
682 else
684 const int gp_value = _shop_get_item_value(item, shop.greed,
685 id_stock);
687 if (in_list[key])
689 if (gp_value > you.gold)
691 if (_shop_yesno("Remove from shopping list? (y/N)",
692 'n'))
694 shopping_list.del_thing(item);
695 in_list[key] = false;
696 selected[key] = false;
698 continue;
700 else
702 if (_shop_yesno("Remove item from shopping list and "
703 "buy it? (Y/n)", 'y'))
705 shopping_list.del_thing(item);
706 in_list[key] = false;
707 // Will be toggled to true later
708 selected[key] = false;
710 else
711 continue;
715 selected[key] = !selected[key];
716 if (selected[key])
717 total_cost += gp_value;
718 else
719 total_cost -= gp_value;
721 ASSERT(total_cost >= 0);
726 return (bought_something);
729 bool shoptype_identifies_stock(shop_type type)
731 return (type != SHOP_WEAPON_ANTIQUE
732 && type != SHOP_ARMOUR_ANTIQUE
733 && type != SHOP_GENERAL_ANTIQUE);
736 static bool _purchase(int shop, int item_got, int cost, bool id)
738 you.del_gold(cost);
740 you.attribute[ATTR_PURCHASES] += cost;
742 item_def& item = mitm[item_got];
744 origin_purchased(item);
746 if (id)
748 // Identify the item and its type.
749 // This also takes the ID note if necessary.
750 set_ident_type(item, ID_KNOWN_TYPE);
751 set_ident_flags(item, ISFLAG_IDENT_MASK);
754 const int quant = item.quantity;
755 // Note that item will be invalidated if num == item.quantity.
756 const int num = move_item_to_player(item_got, item.quantity, true);
758 // Shopkeepers will now place goods you can't carry outside the shop.
759 if (num < quant)
761 move_item_to_grid(&item_got, env.shop[shop].pos);
762 return (false);
764 return (true);
767 // This probably still needs some work. Rings used to be the only
768 // artefacts which had a change in price, and that value corresponds
769 // to returning 50 from this function. Good artefacts will probably
770 // be returning just over 30 right now. Note that this isn't used
771 // as a multiple, its used in the old ring way: 7 * ret is added to
772 // the price of the artefact. -- bwr
773 int artefact_value(const item_def &item)
775 ASSERT(is_artefact(item));
777 int ret = 10;
778 artefact_properties_t prop;
779 artefact_wpn_properties(item, prop);
781 // Brands are already accounted for via existing ego checks
783 // This should probably be more complex... but this isn't so bad:
784 ret += 3 * prop[ ARTP_AC ] + 3 * prop[ ARTP_EVASION ]
785 + 3 * prop[ ARTP_ACCURACY ] + 3 * prop[ ARTP_DAMAGE ]
786 + 6 * prop[ ARTP_STRENGTH ] + 6 * prop[ ARTP_INTELLIGENCE ]
787 + 6 * prop[ ARTP_DEXTERITY ];
789 // These resistances have meaningful levels
790 if (prop[ ARTP_FIRE ] > 0)
791 ret += 5 + 5 * (prop[ ARTP_FIRE ] * prop[ ARTP_FIRE ]);
792 else if (prop[ ARTP_FIRE ] < 0)
793 ret -= 10;
795 if (prop[ ARTP_COLD ] > 0)
796 ret += 5 + 5 * (prop[ ARTP_COLD ] * prop[ ARTP_COLD ]);
797 else if (prop[ ARTP_COLD ] < 0)
798 ret -= 10;
800 if (prop[ARTP_PONDEROUS])
801 ret -= 10;
803 // These normally come alone or in resist/susceptible pairs...
804 // we're making items a bit more expensive if they have both positive.
805 if (prop[ ARTP_FIRE ] > 0 && prop[ ARTP_COLD ] > 0)
806 ret += 20;
808 if (prop[ ARTP_NEGATIVE_ENERGY ] > 0)
809 ret += 5 + 5 * (prop[ARTP_NEGATIVE_ENERGY] * prop[ARTP_NEGATIVE_ENERGY]);
811 // only one meaningful level:
812 if (prop[ ARTP_POISON ])
813 ret += 15;
815 // only one meaningful level (hard to get):
816 if (prop[ ARTP_ELECTRICITY ])
817 ret += 30;
819 // magic resistance is from 35-100
820 if (prop[ ARTP_MAGIC ])
821 ret += 5 + prop[ ARTP_MAGIC ] / 15;
823 if (prop[ ARTP_EYESIGHT ])
824 ret += 10;
826 // abilities:
827 if (prop[ ARTP_LEVITATE ])
828 ret += 3;
830 if (prop[ ARTP_BLINK ])
831 ret += 3;
833 if (prop[ ARTP_BERSERK ])
834 ret += 5;
836 if (prop[ ARTP_INVISIBLE ])
837 ret += 20;
839 if (prop[ ARTP_ANGRY ])
840 ret -= 3;
842 if (prop[ ARTP_CAUSE_TELEPORTATION ])
843 ret -= 3;
845 if (prop[ ARTP_NOISES ])
846 ret -= 5;
848 if (prop[ ARTP_PREVENT_TELEPORTATION ])
849 ret -= 8;
851 if (prop[ ARTP_PREVENT_SPELLCASTING ])
852 ret -= 10;
854 // ranges from 2-5
855 if (prop[ ARTP_MUTAGENIC ])
856 ret -= (5 + 3 * prop[ ARTP_MUTAGENIC ]);
858 // ranges from 1-3
859 if (prop[ ARTP_METABOLISM ])
860 ret -= (2 * prop[ ARTP_METABOLISM ]);
862 return ((ret > 0) ? ret : 0);
865 unsigned int item_value(item_def item, bool ident)
867 // Note that we pass item in by value, since we want a local
868 // copy to mangle as necessary.
869 item.flags = (ident) ? (item.flags | ISFLAG_IDENT_MASK) : (item.flags);
871 if (is_unrandom_artefact(item)
872 && item_ident(item, ISFLAG_KNOW_PROPERTIES))
874 const unrandart_entry *entry = get_unrand_entry(item.special);
875 if (entry->value != 0)
876 return (entry->value);
879 int valued = 0;
881 switch (item.base_type)
883 case OBJ_WEAPONS:
884 switch (item.sub_type)
886 case WPN_CLUB:
887 case WPN_KNIFE:
888 valued += 10;
889 break;
891 case WPN_SLING:
892 valued += 15;
893 break;
895 case WPN_GIANT_CLUB:
896 valued += 17;
897 break;
899 case WPN_GIANT_SPIKED_CLUB:
900 valued += 19;
901 break;
903 case WPN_DAGGER:
904 valued += 20;
905 break;
907 case WPN_WHIP:
908 case WPN_BLOWGUN:
909 valued += 25;
910 break;
912 case WPN_HAND_AXE:
913 valued += 28;
914 break;
916 case WPN_HAMMER:
917 case WPN_FALCHION:
918 case WPN_MACE:
919 case WPN_SCYTHE:
920 valued += 30;
921 break;
923 case WPN_BOW:
924 valued += 31;
925 break;
927 case WPN_QUARTERSTAFF:
928 case WPN_SHORT_SWORD:
929 case WPN_SPEAR:
930 valued += 32;
931 break;
933 case WPN_FLAIL:
934 valued += 35;
935 break;
937 case WPN_ANKUS:
938 case WPN_WAR_AXE:
939 case WPN_MORNINGSTAR:
940 case WPN_SABRE:
941 valued += 40;
942 break;
944 case WPN_CROSSBOW:
945 valued += 41;
946 break;
948 case WPN_TRIDENT:
949 valued += 42;
950 break;
952 case WPN_LONG_SWORD:
953 case WPN_LONGBOW:
954 case WPN_SCIMITAR:
955 case WPN_BLESSED_FALCHION:
956 valued += 45;
957 break;
959 case WPN_SPIKED_FLAIL:
960 case WPN_BLESSED_LONG_SWORD:
961 case WPN_BLESSED_SCIMITAR:
962 valued += 50;
964 case WPN_HALBERD:
965 valued += 52;
966 break;
968 case WPN_GLAIVE:
969 valued += 55;
970 break;
972 case WPN_BROAD_AXE:
973 case WPN_GREAT_SWORD:
974 valued += 60;
975 break;
977 case WPN_BATTLEAXE:
978 case WPN_GREAT_MACE:
979 case WPN_EVENINGSTAR:
980 valued += 65;
981 break;
983 case WPN_DIRE_FLAIL:
984 case WPN_BARDICHE:
985 valued += 90;
986 break;
988 case WPN_EXECUTIONERS_AXE:
989 valued += 100;
990 break;
992 case WPN_DOUBLE_SWORD:
993 valued += 100;
994 break;
996 case WPN_DEMON_WHIP:
997 valued += 130;
998 break;
1000 case WPN_QUICK_BLADE:
1001 case WPN_DEMON_TRIDENT:
1002 valued += 150;
1003 break;
1005 case WPN_KATANA:
1006 case WPN_DEMON_BLADE:
1007 case WPN_TRIPLE_SWORD:
1008 case WPN_BLESSED_KATANA:
1009 case WPN_EUDEMON_BLADE:
1010 case WPN_BLESSED_DOUBLE_SWORD:
1011 case WPN_BLESSED_GREAT_SWORD:
1012 case WPN_BLESSED_TRIPLE_SWORD:
1013 case WPN_SACRED_SCOURGE:
1014 case WPN_TRISHULA:
1015 case WPN_LAJATANG:
1016 valued += 200;
1017 break;
1020 if (item_type_known(item))
1022 switch (get_weapon_brand(item))
1024 case SPWPN_NORMAL:
1025 default: // randart
1026 valued *= 10;
1027 break;
1029 case SPWPN_DRAINING:
1030 valued *= 64;
1031 break;
1033 case SPWPN_VAMPIRICISM:
1034 valued *= 60;
1035 break;
1037 case SPWPN_FLAME:
1038 case SPWPN_FROST:
1039 case SPWPN_HOLY_WRATH:
1040 case SPWPN_REACHING:
1041 case SPWPN_RETURNING:
1042 valued *= 50;
1043 break;
1045 case SPWPN_CHAOS:
1046 case SPWPN_SPEED:
1047 valued *= 40;
1048 break;
1050 case SPWPN_DISTORTION:
1051 case SPWPN_ELECTROCUTION:
1052 case SPWPN_PAIN:
1053 valued *= 30;
1054 break;
1056 case SPWPN_FLAMING:
1057 case SPWPN_FREEZING:
1058 case SPWPN_DRAGON_SLAYING:
1059 valued *= 25;
1060 break;
1062 case SPWPN_VENOM:
1063 valued *= 23;
1064 break;
1066 case SPWPN_ORC_SLAYING:
1067 valued *= 21;
1068 break;
1070 case SPWPN_VORPAL:
1071 case SPWPN_PROTECTION:
1072 case SPWPN_EVASION:
1073 valued *= 20;
1074 break;
1077 valued /= 10;
1080 if (get_equip_race(item) == ISFLAG_ELVEN
1081 || get_equip_race(item) == ISFLAG_DWARVEN)
1083 valued *= 12;
1084 valued /= 10;
1087 if (get_equip_race(item) == ISFLAG_ORCISH)
1089 valued *= 8;
1090 valued /= 10;
1093 if (item_ident(item, ISFLAG_KNOW_PLUSES))
1095 if (item.plus >= 0)
1097 valued += item.plus * 2;
1098 valued *= 10 + 3 * item.plus;
1099 valued /= 10;
1102 if (item.plus2 >= 0)
1104 valued += item.plus2 * 2;
1105 valued *= 10 + 3 * item.plus2;
1106 valued /= 10;
1109 if (item.plus < 0)
1111 valued -= 5;
1112 valued += (item.plus * item.plus * item.plus);
1114 if (valued < 1)
1115 valued = 1;
1118 if (item.plus2 < 0)
1120 valued -= 5;
1121 valued += (item.plus2 * item.plus2 * item.plus2);
1123 if (valued < 1)
1124 valued = 1;
1128 if (is_artefact(item))
1130 if (item_type_known(item))
1131 valued += (7 * artefact_value(item));
1132 else
1133 valued += 50;
1135 else if (item_type_known(item)
1136 && get_equip_desc(item) != 0)
1138 valued += 20;
1141 if (item_known_cursed(item))
1143 valued *= 6;
1144 valued /= 10;
1146 break;
1148 case OBJ_MISSILES: // ammunition
1149 switch (item.sub_type)
1151 case MI_DART:
1152 case MI_STONE:
1153 case MI_NONE:
1154 valued++;
1155 break;
1156 case MI_NEEDLE:
1157 case MI_ARROW:
1158 case MI_BOLT:
1159 valued += 2;
1160 break;
1161 case MI_LARGE_ROCK:
1162 valued += 7;
1163 break;
1164 case MI_JAVELIN:
1165 valued += 8;
1166 break;
1167 case MI_THROWING_NET:
1168 valued += 30;
1169 break;
1170 default:
1171 valued += 5;
1172 break;
1175 if (item_type_known(item))
1177 switch (get_ammo_brand(item))
1179 case SPMSL_NORMAL:
1180 default:
1181 valued *= 10;
1182 break;
1184 case SPMSL_RETURNING:
1185 valued *= 50;
1186 break;
1188 case SPMSL_CHAOS:
1189 valued *= 40;
1190 break;
1192 case SPMSL_CURARE:
1193 case SPMSL_PENETRATION:
1194 case SPMSL_REAPING:
1195 case SPMSL_SILVER:
1196 case SPMSL_STEEL:
1197 case SPMSL_DISPERSAL:
1198 case SPMSL_EXPLODING:
1199 valued *= 30;
1200 break;
1202 case SPMSL_FLAME:
1203 case SPMSL_FROST:
1204 valued *= 25;
1205 break;
1207 case SPMSL_POISONED:
1208 case SPMSL_PARALYSIS:
1209 case SPMSL_SLOW:
1210 case SPMSL_SLEEP:
1211 case SPMSL_CONFUSION:
1212 case SPMSL_SICKNESS:
1213 case SPMSL_RAGE:
1214 valued *= 23;
1215 break;
1218 valued /= 10;
1221 if (get_equip_race(item) == ISFLAG_ELVEN
1222 || get_equip_race(item) == ISFLAG_DWARVEN)
1224 valued *= 12;
1225 valued /= 10;
1228 if (get_equip_race(item) == ISFLAG_ORCISH)
1230 valued *= 8;
1231 valued /= 10;
1234 if (item_ident(item, ISFLAG_KNOW_PLUSES))
1236 if (item.plus >= 0)
1237 valued += (item.plus * 2);
1239 if (item.plus < 0)
1241 valued += item.plus * item.plus * item.plus;
1243 if (valued < 1)
1244 valued = 1;
1247 break;
1249 case OBJ_ARMOUR:
1250 switch (item.sub_type)
1252 case ARM_PEARL_DRAGON_ARMOUR:
1253 case ARM_GOLD_DRAGON_ARMOUR:
1254 valued += 1600;
1255 break;
1257 case ARM_PEARL_DRAGON_HIDE:
1258 case ARM_GOLD_DRAGON_HIDE:
1259 valued += 1400;
1260 break;
1262 case ARM_STORM_DRAGON_ARMOUR:
1263 valued += 1050;
1264 break;
1266 case ARM_STORM_DRAGON_HIDE:
1267 valued += 900;
1268 break;
1270 case ARM_DRAGON_ARMOUR:
1271 case ARM_ICE_DRAGON_ARMOUR:
1272 valued += 750;
1273 break;
1275 case ARM_SWAMP_DRAGON_ARMOUR:
1276 valued += 650;
1277 break;
1279 case ARM_DRAGON_HIDE:
1280 case ARM_CRYSTAL_PLATE_MAIL:
1281 case ARM_TROLL_LEATHER_ARMOUR:
1282 case ARM_ICE_DRAGON_HIDE:
1283 valued += 500;
1284 break;
1286 case ARM_MOTTLED_DRAGON_ARMOUR:
1287 case ARM_SWAMP_DRAGON_HIDE:
1288 valued += 400;
1289 break;
1291 case ARM_STEAM_DRAGON_ARMOUR:
1292 case ARM_MOTTLED_DRAGON_HIDE:
1293 valued += 300;
1294 break;
1296 case ARM_PLATE_MAIL:
1297 valued += 230;
1298 break;
1300 case ARM_STEAM_DRAGON_HIDE:
1301 valued += 200;
1302 break;
1304 case ARM_BANDED_MAIL:
1305 case ARM_CENTAUR_BARDING:
1306 case ARM_NAGA_BARDING:
1307 valued += 150;
1308 break;
1310 case ARM_SPLINT_MAIL:
1311 valued += 140;
1312 break;
1314 case ARM_TROLL_HIDE:
1315 valued += 130;
1316 break;
1318 case ARM_CHAIN_MAIL:
1319 valued += 110;
1320 break;
1322 case ARM_SCALE_MAIL:
1323 valued += 83;
1324 break;
1326 case ARM_LARGE_SHIELD:
1327 valued += 75;
1328 break;
1330 case ARM_SHIELD:
1331 valued += 45;
1332 break;
1334 case ARM_RING_MAIL:
1335 valued += 40;
1336 break;
1338 case ARM_HELMET:
1339 case ARM_CAP:
1340 case ARM_WIZARD_HAT:
1341 case ARM_BUCKLER:
1342 valued += 25;
1343 break;
1345 case ARM_LEATHER_ARMOUR:
1346 valued += 20;
1347 break;
1349 case ARM_BOOTS:
1350 valued += 15;
1351 break;
1353 case ARM_GLOVES:
1354 valued += 12;
1355 break;
1357 case ARM_CLOAK:
1358 valued += 10;
1359 break;
1361 case ARM_ROBE:
1362 valued += 7;
1363 break;
1365 case ARM_ANIMAL_SKIN:
1366 valued += 3;
1367 break;
1370 if (item_type_known(item))
1372 const int sparm = get_armour_ego_type(item);
1373 switch (sparm)
1375 case SPARM_NORMAL:
1376 default:
1377 valued *= 10;
1378 break;
1380 case SPARM_ARCHMAGI:
1381 valued *= 100;
1382 break;
1384 case SPARM_DARKNESS:
1385 case SPARM_RESISTANCE:
1386 case SPARM_REFLECTION:
1387 valued *= 60;
1388 break;
1390 case SPARM_POSITIVE_ENERGY:
1391 valued *= 50;
1392 break;
1394 case SPARM_MAGIC_RESISTANCE:
1395 case SPARM_PROTECTION:
1396 case SPARM_RUNNING:
1397 valued *= 40;
1398 break;
1400 case SPARM_COLD_RESISTANCE:
1401 case SPARM_DEXTERITY:
1402 case SPARM_FIRE_RESISTANCE:
1403 case SPARM_SEE_INVISIBLE:
1404 case SPARM_INTELLIGENCE:
1405 case SPARM_LEVITATION:
1406 case SPARM_PRESERVATION:
1407 case SPARM_STEALTH:
1408 case SPARM_STRENGTH:
1409 valued *= 30;
1410 break;
1412 case SPARM_POISON_RESISTANCE:
1413 valued *= 20;
1414 break;
1416 case SPARM_PONDEROUSNESS:
1417 valued *= 5;
1418 break;
1421 valued /= 10;
1424 if (get_equip_race(item) == ISFLAG_ELVEN
1425 || get_equip_race(item) == ISFLAG_DWARVEN)
1427 valued *= 12;
1428 valued /= 10;
1431 if (get_equip_race(item) == ISFLAG_ORCISH)
1433 valued *= 8;
1434 valued /= 10;
1437 if (item_ident(item, ISFLAG_KNOW_PLUSES))
1439 valued += 5;
1440 if (item.plus >= 0)
1442 valued += item.plus * 30;
1443 valued *= 10 + 4 * item.plus;
1444 valued /= 10;
1447 if (item.plus < 0)
1449 valued += item.plus * item.plus * item.plus;
1451 if (valued < 1)
1452 valued = 1;
1456 if (is_artefact(item))
1458 if (item_type_known(item))
1459 valued += (7 * artefact_value(item));
1460 else
1461 valued += 50;
1463 else if (item_type_known(item) && get_equip_desc(item) != 0)
1465 valued += 20;
1468 if (item_known_cursed(item))
1470 valued *= 6;
1471 valued /= 10;
1473 break;
1475 case OBJ_WANDS:
1476 if (!item_type_known(item))
1477 valued += 200;
1478 else
1480 switch (item.sub_type)
1482 case WAND_HASTING:
1483 case WAND_HEALING:
1484 valued += 300;
1485 break;
1487 case WAND_TELEPORTATION:
1488 valued += 250;
1489 break;
1491 case WAND_COLD:
1492 case WAND_FIRE:
1493 case WAND_FIREBALL:
1494 valued += 200;
1495 break;
1497 case WAND_INVISIBILITY:
1498 case WAND_DRAINING:
1499 case WAND_LIGHTNING:
1500 valued += 175;
1501 break;
1503 case WAND_DISINTEGRATION:
1504 valued += 160;
1505 break;
1507 case WAND_DIGGING:
1508 case WAND_PARALYSIS:
1509 valued += 100;
1510 break;
1512 case WAND_FLAME:
1513 case WAND_FROST:
1514 valued += 75;
1515 break;
1517 case WAND_ENSLAVEMENT:
1518 case WAND_POLYMORPH_OTHER:
1519 valued += 90;
1520 break;
1522 case WAND_CONFUSION:
1523 case WAND_SLOWING:
1524 valued += 70;
1525 break;
1527 case WAND_MAGIC_DARTS:
1528 case WAND_RANDOM_EFFECTS:
1529 default:
1530 valued += 45;
1531 break;
1534 if (item_ident(item, ISFLAG_KNOW_PLUSES))
1536 if (item.plus == 0)
1537 valued -= 50;
1538 else
1539 valued = (valued * (item.plus + 45)) / 50;
1542 break;
1544 case OBJ_POTIONS:
1545 if (!item_type_known(item))
1546 valued += 9;
1547 else
1549 switch (item.sub_type)
1551 case POT_EXPERIENCE:
1552 valued += 500;
1553 break;
1555 case POT_GAIN_DEXTERITY:
1556 case POT_GAIN_INTELLIGENCE:
1557 case POT_GAIN_STRENGTH:
1558 valued += 350;
1559 break;
1561 case POT_CURE_MUTATION:
1562 valued += 150;
1563 break;
1565 case POT_MAGIC:
1566 case POT_RESISTANCE:
1567 valued += 70;
1568 break;
1570 case POT_INVISIBILITY:
1571 valued += 55;
1572 break;
1574 case POT_MUTATION:
1575 case POT_RESTORE_ABILITIES:
1576 valued += 50;
1577 break;
1579 case POT_BERSERK_RAGE:
1580 case POT_HEAL_WOUNDS:
1581 valued += 30;
1582 break;
1584 case POT_MIGHT:
1585 case POT_AGILITY:
1586 case POT_BRILLIANCE:
1587 case POT_SPEED:
1588 valued += 25;
1589 break;
1591 case POT_HEALING:
1592 case POT_LEVITATION:
1593 valued += 20;
1594 break;
1596 case POT_BLOOD:
1597 case POT_PORRIDGE:
1598 valued += 10;
1599 break;
1601 case POT_BLOOD_COAGULATED:
1602 valued += 5;
1603 break;
1605 case POT_CONFUSION:
1606 case POT_DECAY:
1607 case POT_DEGENERATION:
1608 case POT_PARALYSIS:
1609 case POT_POISON:
1610 case POT_SLOWING:
1611 case POT_STRONG_POISON:
1612 case POT_WATER:
1613 valued++;
1614 break;
1617 break;
1619 case OBJ_FOOD:
1620 switch (item.sub_type)
1622 case FOOD_ROYAL_JELLY:
1623 valued = 120;
1624 break;
1626 case FOOD_MEAT_RATION:
1627 case FOOD_BREAD_RATION:
1628 valued = 40;
1629 break;
1631 case FOOD_HONEYCOMB:
1632 valued = 25;
1633 break;
1635 case FOOD_BEEF_JERKY:
1636 case FOOD_PIZZA:
1637 valued = 18;
1638 break;
1640 case FOOD_CHEESE:
1641 case FOOD_SAUSAGE:
1642 valued = 15;
1643 break;
1645 case FOOD_LEMON:
1646 case FOOD_ORANGE:
1647 case FOOD_BANANA:
1648 valued = 12;
1649 break;
1651 case FOOD_APPLE:
1652 case FOOD_APRICOT:
1653 case FOOD_PEAR:
1654 valued = 8;
1655 break;
1657 case FOOD_CHUNK:
1658 if (food_is_rotten(item))
1659 break;
1661 case FOOD_CHOKO:
1662 case FOOD_LYCHEE:
1663 case FOOD_RAMBUTAN:
1664 case FOOD_SNOZZCUMBER:
1665 valued = 4;
1666 break;
1668 case FOOD_STRAWBERRY:
1669 case FOOD_GRAPE:
1670 case FOOD_SULTANA:
1671 valued = 1;
1672 break;
1674 break;
1676 case OBJ_SCROLLS:
1677 if (!item_type_known(item))
1678 valued += 10;
1679 else
1681 switch (item.sub_type)
1683 case SCR_ACQUIREMENT:
1684 valued += 520;
1685 break;
1687 case SCR_ENCHANT_WEAPON_III:
1688 case SCR_VORPALISE_WEAPON:
1689 valued += 200;
1690 break;
1692 case SCR_SUMMONING:
1693 valued += 95;
1694 break;
1696 case SCR_TORMENT:
1697 case SCR_HOLY_WORD:
1698 case SCR_SILENCE:
1699 case SCR_VULNERABILITY:
1700 valued += 75;
1701 break;
1703 case SCR_ENCHANT_WEAPON_II:
1704 valued += 55;
1705 break;
1707 case SCR_RECHARGING:
1708 case SCR_AMNESIA:
1709 valued += 50;
1710 break;
1712 case SCR_ENCHANT_ARMOUR:
1713 case SCR_ENCHANT_WEAPON_I:
1714 valued += 48;
1715 break;
1717 case SCR_FEAR:
1718 valued += 45;
1719 break;
1721 case SCR_MAGIC_MAPPING:
1722 valued += 35;
1723 break;
1725 case SCR_BLINKING:
1726 case SCR_REMOVE_CURSE:
1727 case SCR_TELEPORTATION:
1728 valued += 30;
1729 break;
1731 case SCR_DETECT_CURSE:
1732 case SCR_IDENTIFY:
1733 valued += 20;
1734 break;
1736 case SCR_FOG:
1737 valued += 10;
1738 break;
1740 case SCR_NOISE:
1741 case SCR_RANDOM_USELESSNESS:
1742 valued += 2;
1743 break;
1745 case SCR_CURSE_ARMOUR:
1746 case SCR_CURSE_WEAPON:
1747 case SCR_CURSE_JEWELLERY:
1748 case SCR_IMMOLATION:
1749 valued++;
1750 break;
1753 break;
1755 case OBJ_JEWELLERY:
1756 if (item_known_cursed(item))
1757 valued -= 10;
1759 if (!item_type_known(item))
1760 valued += 50;
1761 else
1763 if (item_ident(item, ISFLAG_KNOW_PLUSES)
1764 && (item.sub_type == RING_PROTECTION
1765 || item.sub_type == RING_STRENGTH
1766 || item.sub_type == RING_EVASION
1767 || item.sub_type == RING_DEXTERITY
1768 || item.sub_type == RING_INTELLIGENCE
1769 || item.sub_type == RING_SLAYING))
1771 if (item.plus > 0)
1772 valued += 10 * item.plus;
1774 if (item.sub_type == RING_SLAYING && item.plus2 > 0)
1775 valued += 10 * item.plus2;
1777 if (item.plus < 0)
1778 valued -= 50;
1780 if (item.sub_type == RING_SLAYING && item.plus2 < 0)
1781 valued -= 50;
1784 switch (item.sub_type)
1786 case RING_INVISIBILITY:
1787 valued += 100;
1788 break;
1790 case RING_REGENERATION:
1791 valued += 75;
1792 break;
1794 case RING_FIRE:
1795 case RING_ICE:
1796 valued += 62;
1797 break;
1799 case RING_LIFE_PROTECTION:
1800 valued += 60;
1801 break;
1803 case RING_TELEPORT_CONTROL:
1804 valued += 42;
1805 break;
1807 case RING_MAGICAL_POWER:
1808 case RING_PROTECTION_FROM_MAGIC:
1809 valued += 40;
1810 break;
1812 case RING_WIZARDRY:
1813 valued += 35;
1814 break;
1816 case RING_LEVITATION:
1817 case RING_POISON_RESISTANCE:
1818 case RING_PROTECTION_FROM_COLD:
1819 case RING_PROTECTION_FROM_FIRE:
1820 case RING_SLAYING:
1821 valued += 30;
1822 break;
1824 case RING_SUSTAIN_ABILITIES:
1825 case RING_SUSTENANCE:
1826 case RING_TELEPORTATION: // usually cursed
1827 valued += 25;
1828 break;
1830 case RING_SEE_INVISIBLE:
1831 valued += 20;
1832 break;
1834 case RING_DEXTERITY:
1835 case RING_EVASION:
1836 case RING_INTELLIGENCE:
1837 case RING_PROTECTION:
1838 case RING_STRENGTH:
1839 valued += 10;
1840 break;
1842 case RING_HUNGER:
1843 valued -= 50;
1844 break;
1846 case AMU_THE_GOURMAND:
1847 case AMU_GUARDIAN_SPIRIT:
1848 case AMU_FAITH:
1849 valued += 35;
1850 break;
1852 case AMU_CLARITY:
1853 case AMU_RESIST_CORROSION:
1854 case AMU_RESIST_MUTATION:
1855 case AMU_WARDING:
1856 valued += 30;
1857 break;
1859 case AMU_CONSERVATION:
1860 case AMU_CONTROLLED_FLIGHT:
1861 valued += 25;
1862 break;
1864 case AMU_RAGE:
1865 case AMU_STASIS:
1866 valued += 20;
1867 break;
1869 case AMU_INACCURACY:
1870 valued -= 50;
1871 break;
1872 // got to do delusion!
1875 if (is_artefact(item))
1877 // in this branch we're guaranteed to know
1878 // the item type!
1879 if (valued < 0)
1880 valued = artefact_value(item) - 5;
1881 else
1882 valued += artefact_value(item);
1885 valued *= 7;
1887 break;
1889 case OBJ_MISCELLANY:
1890 if (item_type_known(item))
1892 switch (item.sub_type)
1894 case MISC_RUNE_OF_ZOT: // upped from 1200 to encourage collecting
1895 valued += 10000;
1896 break;
1898 case MISC_HORN_OF_GERYON:
1899 valued += 5000;
1900 break;
1902 case MISC_DISC_OF_STORMS:
1903 valued += 2000;
1904 break;
1906 case MISC_CRYSTAL_BALL_OF_SEEING:
1907 valued += 500;
1908 break;
1910 case MISC_BOTTLED_EFREET:
1911 valued += 400;
1912 break;
1914 case MISC_CRYSTAL_BALL_OF_FIXATION:
1915 case MISC_EMPTY_EBONY_CASKET:
1916 valued += 20;
1917 break;
1918 default:
1919 if (is_deck(item))
1920 valued += 200 + item.special * 150;
1921 else
1922 valued += 500;
1925 else
1927 switch (item.sub_type)
1929 case MISC_RUNE_OF_ZOT:
1930 valued += 5000;
1931 break;
1933 case MISC_HORN_OF_GERYON:
1934 valued += 1000;
1935 break;
1937 case MISC_CRYSTAL_BALL_OF_SEEING:
1938 valued += 450;
1939 break;
1941 case MISC_BOTTLED_EFREET:
1942 valued += 350;
1943 break;
1945 default:
1946 valued += 400;
1949 break;
1951 case OBJ_BOOKS:
1952 valued = 150;
1954 if (item_type_known(item))
1956 double rarity = 0;
1957 if (is_random_artefact(item))
1959 // Consider spellbook as rare as the average of its
1960 // three rarest spells.
1961 int rarities[SPELLBOOK_SIZE];
1962 int count_valid = 0;
1963 for (int i = 0; i < SPELLBOOK_SIZE; i++)
1965 spell_type spell = which_spell_in_book(item, i);
1966 if (spell == SPELL_NO_SPELL)
1968 rarities[i] = 0;
1969 continue;
1972 rarities[i] = spell_rarity(spell);
1973 count_valid++;
1975 ASSERT(count_valid > 0);
1977 if (count_valid > 3)
1978 count_valid = 3;
1980 std::sort(rarities, rarities + SPELLBOOK_SIZE);
1981 for (int i = SPELLBOOK_SIZE - 1;
1982 i >= SPELLBOOK_SIZE - count_valid; i--)
1984 rarity += rarities[i];
1987 rarity /= count_valid;
1989 // Fixed level randarts get a bonus for the really low and
1990 // really high level spells.
1991 if (item.sub_type == BOOK_RANDART_LEVEL)
1992 valued += 50 * abs(5 - item.plus);
1994 else
1995 rarity = book_rarity(item.sub_type);
1997 valued += (int)(rarity * 50.0);
1999 break;
2001 case OBJ_STAVES:
2002 if (!item_type_known(item))
2003 valued = 120;
2004 else if (item.sub_type == STAFF_SMITING
2005 || item.sub_type == STAFF_STRIKING
2006 || item.sub_type == STAFF_WARDING)
2008 valued = 150;
2010 else
2011 valued = 250;
2013 if (item_is_rod(item) && item_ident(item, ISFLAG_KNOW_PLUSES))
2014 valued += 50 * (item.plus2 / ROD_CHARGE_MULT);
2015 break;
2017 case OBJ_ORBS:
2018 valued = 250000;
2019 break;
2021 default:
2022 break;
2023 } // end switch
2025 if (valued < 1)
2026 valued = 1;
2028 valued *= item.quantity;
2030 return (valued);
2031 } // end item_value()
2033 static void _delete_shop(int i)
2035 grd(you.pos()) = DNGN_ABANDONED_SHOP;
2036 unnotice_feature(level_pos(level_id::current(), you.pos()));
2039 void shop()
2041 int i;
2043 for (i = 0; i < MAX_SHOPS; i++)
2044 if (env.shop[i].pos == you.pos())
2045 break;
2047 if (i == MAX_SHOPS)
2049 mpr("Help! Non-existent shop.", MSGCH_ERROR);
2050 return;
2053 // Quick out, if no inventory
2054 if (_shop_get_stock(i).empty())
2056 const shop_struct& shop = env.shop[i];
2057 mprf("%s appears to be closed.", shop_name(shop.pos).c_str());
2058 _delete_shop(i);
2059 return;
2062 int num_in_list = 0;
2063 const bool bought_something = _in_a_shop(i, num_in_list);
2064 const std::string shopname = shop_name(env.shop[i].pos);
2066 // If the shop is now empty, erase it from the overview.
2067 if (_shop_get_stock(i).empty())
2068 _delete_shop(i);
2070 burden_change();
2071 redraw_screen();
2073 if (bought_something)
2074 mprf("Thank you for shopping at %s!", shopname.c_str());
2076 if (num_in_list > 0)
2077 mpr("You can access your shopping list by pressing '$'.");
2080 void destroy_shop(shop_struct *shop)
2082 if (shop)
2084 unnotice_feature(level_pos(level_id::current(), shop->pos));
2086 shop->pos = coord_def(0, 0);
2087 shop->type = SHOP_UNASSIGNED;
2091 void destroy_shop_at(coord_def p)
2093 destroy_shop(get_shop(p));
2096 shop_struct *get_shop(const coord_def& where)
2098 if (grd(where) != DNGN_ENTER_SHOP)
2099 return (NULL);
2101 unsigned short t = env.tgrid(where);
2102 ASSERT(t != NON_ENTITY && t < MAX_SHOPS);
2103 ASSERT(env.shop[t].pos == where && env.shop[t].type != SHOP_UNASSIGNED);
2105 return (&env.shop[t]);
2108 std::string shop_name(const coord_def& where, bool add_stop)
2110 std::string name(shop_name(where));
2111 if (add_stop)
2112 name += ".";
2113 return (name);
2116 std::string shop_type_name (shop_type type)
2118 switch (type)
2120 case SHOP_WEAPON_ANTIQUE:
2121 return "Antique Weapon";
2122 case SHOP_ARMOUR_ANTIQUE:
2123 return "Antique Armour";
2124 case SHOP_WEAPON:
2125 return "Weapon";
2126 case SHOP_ARMOUR:
2127 return "Armour";
2128 case SHOP_JEWELLERY:
2129 return "Jewellery";
2130 case SHOP_WAND:
2131 return "Magical Wand";
2132 case SHOP_BOOK:
2133 return "Book";
2134 case SHOP_FOOD:
2135 return "Food";
2136 case SHOP_SCROLL:
2137 return "Magic Scroll";
2138 case SHOP_GENERAL_ANTIQUE:
2139 return "Assorted Antiques";
2140 case SHOP_DISTILLERY:
2141 return "Distillery";
2142 case SHOP_GENERAL:
2143 return "General Store";
2144 default:
2145 return ("Bug");
2149 std::string shop_type_suffix (shop_type type, const coord_def &where)
2151 if (type == SHOP_GENERAL
2152 || type == SHOP_GENERAL_ANTIQUE
2153 || type == SHOP_DISTILLERY)
2155 return ("");
2158 const char* suffixnames[] = {"Shoppe", "Boutique", "Emporium", "Shop"};
2159 const int temp = (where.x + where.y) % 4;
2161 return std::string(suffixnames[temp]);
2164 std::string shop_name(const coord_def& where)
2166 const shop_struct *cshop = get_shop(where);
2168 // paranoia and shop mimics
2169 if (grd(where) != DNGN_ENTER_SHOP)
2171 if (monster_at(where))
2173 monster* mmimic = monster_at(where);
2174 if (mons_is_feat_mimic(mmimic->type) && mmimic->props.exists("shop_name"))
2175 return mmimic->props["shop_name"].get_string();
2178 return ("");
2181 if (!cshop)
2183 mpr("Help! Non-existent shop.");
2184 return ("Buggy Shop");
2187 const shop_type type = cshop->type;
2189 std::string sh_name = "";
2191 if (!cshop->shop_name.empty())
2193 sh_name += apostrophise(cshop->shop_name) + " ";
2195 else
2197 uint32_t seed = static_cast<uint32_t>(cshop->keeper_name[0])
2198 | (static_cast<uint32_t>(cshop->keeper_name[1]) << 8)
2199 | (static_cast<uint32_t>(cshop->keeper_name[1]) << 16);
2201 sh_name += apostrophise(make_name(seed, false)) + " ";
2204 if (!cshop->shop_type_name.empty())
2205 sh_name += cshop->shop_type_name;
2206 else
2207 sh_name += shop_type_name(type);
2209 if (!cshop->shop_suffix_name.empty())
2211 sh_name += " " + cshop->shop_suffix_name;
2213 else
2215 std::string sh_suffix = shop_type_suffix(type, where);
2216 if (!sh_suffix.empty())
2217 sh_name += " " + sh_suffix;
2220 return (sh_name);
2223 bool is_shop_item(const item_def &item)
2225 return (item.pos.x == 0 && item.pos.y >= 5 && item.pos.y < (MAX_SHOPS + 5));
2228 ////////////////////////////////////////////////////////////////////////
2230 // Setup shopping list after restoring savefile.
2231 static void _callback(bool saving)
2233 if (!saving)
2234 shopping_list.refresh();
2236 static SavefileCallback _register_callback(_callback);
2238 // TODO:
2239 // * Let shopping list be modified from with the stash lister.
2240 // * Warn if buying something not on the shopping list would put
2241 // something on shopping list out of your reach.
2243 #define SHOPPING_LIST_KEY "shopping_list_key"
2244 #define SHOPPING_THING_COST_KEY "cost_key"
2245 #define SHOPPING_THING_ITEM_KEY "item_key"
2246 #define SHOPPING_THING_DESC_KEY "desc_key"
2247 #define SHOPPING_THING_VERB_KEY "verb_key"
2248 #define SHOPPING_THING_POS_KEY "pos_key"
2250 ShoppingList::ShoppingList()
2254 #define SETUP_POS() \
2255 if (list == NULL) \
2257 mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR); \
2258 return (false); \
2260 level_pos pos; \
2261 if (_pos != NULL) \
2262 pos = *_pos; \
2263 else \
2264 pos = level_pos::current(); \
2265 ASSERT(pos.is_valid());
2267 #define SETUP_THING() \
2268 CrawlHashTable *thing = new CrawlHashTable(); \
2269 (*thing)[SHOPPING_THING_COST_KEY] = cost; \
2270 (*thing)[SHOPPING_THING_POS_KEY] = pos;
2272 bool ShoppingList::add_thing(const item_def &item, int cost,
2273 const level_pos* _pos)
2275 ASSERT(item.defined());
2276 ASSERT(cost > 0);
2278 SETUP_POS();
2280 if (pos.id.level_type != LEVEL_DUNGEON)
2282 mprf("The shopping list can only contain things in the dungeon.",
2283 MSGCH_ERROR);
2284 return (false);
2287 if (find_thing(item, pos) != -1)
2289 mprf(MSGCH_ERROR, "%s is already on the shopping list.",
2290 item.name(DESC_CAP_THE).c_str());
2291 return (false);
2294 SETUP_THING();
2295 (*thing)[SHOPPING_THING_ITEM_KEY] = item;
2296 list->push_back(*thing);
2297 refresh();
2299 return (true);
2302 bool ShoppingList::add_thing(std::string desc, std::string buy_verb, int cost,
2303 const level_pos* _pos)
2305 ASSERT(!desc.empty());
2306 ASSERT(!buy_verb.empty());
2307 ASSERT(cost > 0);
2309 SETUP_POS();
2311 if (pos.id.level_type != LEVEL_DUNGEON)
2313 mprf("The shopping list can only contain things in the dungeon.",
2314 MSGCH_ERROR);
2315 return (false);
2318 if (find_thing(desc, pos) != -1)
2320 mprf(MSGCH_ERROR, "%s is already on the shopping list.",
2321 desc.c_str());
2322 return (false);
2325 SETUP_THING();
2326 (*thing)[SHOPPING_THING_DESC_KEY] = desc;
2327 (*thing)[SHOPPING_THING_VERB_KEY] = buy_verb;
2328 list->push_back(*thing);
2329 refresh();
2331 return (true);
2334 #undef SETUP_THING
2336 bool ShoppingList::is_on_list(const item_def &item,
2337 const level_pos* _pos) const
2339 SETUP_POS();
2341 return (find_thing(item, pos) != -1);
2344 bool ShoppingList::is_on_list(std::string desc,
2345 const level_pos* _pos) const
2347 SETUP_POS();
2349 return (find_thing(desc, pos) != -1);
2352 void ShoppingList::del_thing_at_index(int idx)
2354 ASSERT(idx >= 0 && idx < list->size());
2355 list->erase(idx);
2356 refresh();
2359 bool ShoppingList::del_thing(const item_def &item,
2360 const level_pos* _pos)
2362 SETUP_POS();
2364 int idx = find_thing(item, pos);
2366 if (idx == -1)
2368 mprf(MSGCH_ERROR, "%s isn't on shopping list, can't delete it.",
2369 item.name(DESC_CAP_THE).c_str());
2370 return (false);
2373 del_thing_at_index(idx);
2374 return (true);
2377 bool ShoppingList::del_thing(std::string desc, const level_pos* _pos)
2379 SETUP_POS();
2381 int idx = find_thing(desc, pos);
2383 if (idx == -1)
2385 mprf(MSGCH_ERROR, "%s isn't on shopping list, can't delete it.",
2386 desc.c_str());
2387 return (false);
2390 del_thing_at_index(idx);
2391 return (true);
2394 #undef SETUP_POS
2396 #define REMOVE_PROMPTED_KEY "remove_prompted_key"
2397 #define REPLACE_PROMPTED_KEY "replace_prompted_key"
2399 // TODO:
2401 // * If you get a randart which lets you turn invisible, then remove
2402 // any ordinary rings of invisibility from the shopping list.
2404 // * If you collected enough spellbooks that all the spells in a
2405 // shopping list book are covered, then auto-remove it.
2406 unsigned int ShoppingList::cull_identical_items(const item_def& item,
2407 int cost)
2409 // Can't put items in Bazaar shops in the shopping list, so
2410 // don't bother transferring shopping list items to Bazaar shops.
2411 if (cost != -1 && you.level_type != LEVEL_DUNGEON)
2412 return (0);
2414 switch (item.base_type)
2416 case OBJ_JEWELLERY:
2417 case OBJ_BOOKS:
2418 case OBJ_STAVES:
2419 // Only these are really interchangable.
2420 break;
2422 default:
2423 return (0);
2426 if (!item_type_known(item) || is_artefact(item))
2427 return (0);
2429 // Ignore stat-modification rings which reduce a stat, since they're
2430 // worthless.
2431 if (item.base_type == OBJ_JEWELLERY)
2433 if (item.sub_type == RING_SLAYING && item.plus < 0 && item.plus2 < 0)
2434 return (0);
2436 if (item.plus < 0)
2437 return (0);
2440 // Item is already on shopping-list.
2441 const bool on_list = find_thing(item, level_pos::current()) != -1;
2443 const bool do_prompt =
2444 (item.base_type == OBJ_JEWELLERY && !jewellery_is_amulet(item)
2445 && ring_has_stackable_effect(item))
2446 // Manuals and tomes of destruction are consumable.
2447 || (item.base_type == OBJ_BOOKS
2448 && (item.sub_type == BOOK_MANUAL
2449 || item.sub_type == BOOK_DESTRUCTION));
2451 bool add_item = false;
2453 std::vector<level_pos> to_del;
2455 // NOTE: Don't modify the shopping list while iterating over it.
2456 for (unsigned int i = 0; i < list->size(); i++)
2458 CrawlHashTable &thing = (*list)[i];
2460 if (!thing_is_item(thing))
2461 continue;
2463 const item_def& list_item = get_thing_item(thing);
2465 if (list_item.base_type != item.base_type
2466 || list_item.sub_type != item.sub_type)
2468 continue;
2471 if (!item_type_known(list_item) || is_artefact(list_item))
2472 continue;
2474 const level_pos list_pos = thing_pos(thing);
2476 // cost = -1, we just found a shop item which is cheaper than
2477 // one on the shopping list.
2478 if (cost != -1)
2480 int list_cost = thing_cost(thing);
2482 if (cost >= list_cost)
2483 continue;
2485 // Only prompt once.
2486 if (thing.exists(REPLACE_PROMPTED_KEY))
2487 continue;
2488 thing[REPLACE_PROMPTED_KEY] = (bool) true;
2490 std::string prompt =
2491 make_stringf("Shopping-list: replace %dgp %s with cheaper "
2492 "one? (Y/n)", list_cost,
2493 describe_thing(thing).c_str());
2495 if (_shop_yesno(prompt.c_str(), 'y'))
2497 add_item = true;
2498 to_del.push_back(list_pos);
2500 continue;
2503 // cost == -1, we just got an item which is on the shopping list.
2504 if (do_prompt)
2506 // Only prompt once.
2507 if (thing.exists(REMOVE_PROMPTED_KEY))
2508 continue;
2509 thing[REMOVE_PROMPTED_KEY] = (bool) true;
2511 std::string prompt =
2512 make_stringf("Shopping-list: remove %s? (Y/n)",
2513 describe_thing(thing, DESC_NOCAP_A).c_str());
2515 if (_shop_yesno(prompt.c_str(), 'y'))
2516 to_del.push_back(list_pos);
2518 else
2520 std::string str =
2521 make_stringf("Shopping-list: removing %s",
2522 describe_thing(thing, DESC_NOCAP_A).c_str());
2524 _shop_mpr(str.c_str());
2525 to_del.push_back(list_pos);
2529 for (unsigned int i = 0; i < to_del.size(); i++)
2530 del_thing(item, &to_del[i]);
2532 if (add_item && !on_list)
2533 add_thing(item, cost);
2535 return (to_del.size());
2538 int ShoppingList::size() const
2540 if (list == NULL)
2542 mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR);
2543 return (0);
2546 return (list->size());
2549 bool ShoppingList::items_are_same(const item_def& item_a,
2550 const item_def& item_b)
2552 return (item_name_simple(item_a) == item_name_simple(item_b));
2555 void ShoppingList::move_things(const coord_def &_src, const coord_def &_dst)
2557 if (crawl_state.map_stat_gen || crawl_state.test)
2558 // Shopping list is unitialized and uneeded.
2559 return;
2561 const level_pos src(level_id::current(), _src);
2562 const level_pos dst(level_id::current(), _dst);
2564 for (unsigned int i = 0; i < list->size(); i++)
2566 CrawlHashTable &thing = (*list)[i];
2568 if (thing_pos(thing) == src)
2569 thing[SHOPPING_THING_POS_KEY] = dst;
2573 void ShoppingList::forget_pos(const level_pos &pos)
2575 if (!crawl_state.need_save)
2576 // Shopping list is unitialized and uneeded.
2577 return;
2579 for (unsigned int i = 0; i < list->size(); i++)
2581 const CrawlHashTable &thing = (*list)[i];
2583 if (thing_pos(thing) == pos)
2585 list->erase(i);
2586 i--;
2589 refresh();
2592 void ShoppingList::gold_changed(int old_amount, int new_amount)
2594 if (list == NULL)
2596 mpr("SavefileCallback global constructor weirdness!", MSGCH_ERROR);
2597 return;
2600 if (new_amount > old_amount && new_amount >= min_unbuyable_cost)
2602 ASSERT(min_unbuyable_idx < list->size());
2604 std::vector<std::string> descs;
2605 for (unsigned int i = min_unbuyable_idx; i < list->size(); i++)
2607 const CrawlHashTable &thing = (*list)[i];
2608 const int cost = thing_cost(thing);
2610 if (cost > new_amount)
2612 ASSERT(i > (unsigned int) min_unbuyable_idx);
2613 break;
2616 std::string desc;
2618 if (thing.exists(SHOPPING_THING_VERB_KEY))
2619 desc += thing[SHOPPING_THING_VERB_KEY].get_string();
2620 else
2621 desc = "buy";
2622 desc += " ";
2624 desc += describe_thing(thing, DESC_NOCAP_A);
2626 descs.push_back(desc);
2628 ASSERT(!descs.empty());
2630 mpr_comma_separated_list("You now have enough gold to ", descs,
2631 ", or ");
2632 mpr("You can access your shopping list by pressing '$'.");
2634 // Reset max_buyable and min_unbuyable info
2635 refresh();
2637 else if (new_amount < old_amount && new_amount < max_buyable_cost)
2639 // Reset max_buyable and min_unbuyable info
2640 refresh();
2644 class ShoppingListMenu : public Menu
2646 public:
2647 ShoppingListMenu()
2648 : Menu()
2651 protected:
2652 void draw_title();
2655 void ShoppingListMenu::draw_title()
2657 if (title)
2659 const int total_cost = you.props[SHOPPING_LIST_COST_KEY];
2661 cgotoxy(1, 1);
2662 textcolor(title->colour);
2663 cprintf("%d %s%s, total cost %d gp",
2664 title->quantity, title->text.c_str(),
2665 title->quantity > 1? "s" : "",
2666 total_cost);
2668 const char *verb = menu_action == ACT_EXECUTE ? "travel" :
2669 menu_action == ACT_EXAMINE ? "examine" :
2670 "delete";
2671 draw_title_suffix(formatted_string::parse_string(make_stringf(
2672 "<lightgrey> [<w>a-z</w>: %s <w>?</w>/<w>!</w>: change action]",
2673 verb)), false);
2677 void ShoppingList::fill_out_menu(Menu& shopmenu)
2679 menu_letter hotkey;
2680 for (unsigned i = 0; i < list->size(); ++i, ++hotkey)
2682 CrawlHashTable &thing = (*list)[i];
2683 level_pos pos = thing_pos(thing);
2684 int cost = thing_cost(thing);
2686 std::string etitle =
2687 make_stringf("[%s] %s (%d gp)", short_place_name(pos.id).c_str(),
2688 name_thing(thing, DESC_NOCAP_A).c_str(),
2689 cost);
2691 MenuEntry *me = new MenuEntry(etitle, MEL_ITEM, 1, hotkey);
2692 me->data = &thing;
2694 if (cost > you.gold)
2695 me->colour = DARKGREY;
2696 else if (thing_is_item(thing) && Options.menu_colour_shops)
2698 // Colour shopping list item according to menu colours.
2699 const item_def &item = get_thing_item(thing);
2701 const std::string colprf = menu_colour_item_prefix(item);
2702 const int col = menu_colour(item.name(DESC_NOCAP_A),
2703 colprf, "shop");
2705 if (col != -1)
2706 me->colour = col;
2709 shopmenu.add_entry(me);
2713 void ShoppingList::display()
2715 if (list->empty())
2716 return;
2718 const bool travelable = can_travel_interlevel();
2720 ShoppingListMenu shopmenu;
2721 shopmenu.set_tag("shop");
2722 shopmenu.menu_action = travelable ? Menu::ACT_EXECUTE : Menu::ACT_EXAMINE;
2723 shopmenu.action_cycle = travelable ? Menu::CYCLE_CYCLE : Menu::CYCLE_NONE;
2724 std::string title = "thing";
2726 MenuEntry *mtitle = new MenuEntry(title, MEL_TITLE);
2727 // Abuse of the quantity field.
2728 mtitle->quantity = list->size();
2729 shopmenu.set_title(mtitle);
2731 // Don't make a menu so tall that we recycle hotkeys on the same page.
2732 if (list->size() > 52
2733 && (shopmenu.maxpagesize() > 52 || shopmenu.maxpagesize() == 0))
2735 shopmenu.set_maxpagesize(52);
2738 std::string more_str = make_stringf("<yellow>You have %d gp</yellow>",
2739 you.gold);
2740 shopmenu.set_more(formatted_string::parse_string(more_str));
2742 shopmenu.set_flags(MF_SINGLESELECT | MF_ALWAYS_SHOW_MORE
2743 | MF_ALLOW_FORMATTING);
2745 fill_out_menu(shopmenu);
2747 std::vector<MenuEntry*> sel;
2748 while (true)
2750 redraw_screen();
2751 sel = shopmenu.show();
2753 if (sel.empty())
2754 break;
2756 const CrawlHashTable* thing =
2757 static_cast<const CrawlHashTable *>(sel[0]->data);
2759 const bool is_item = thing_is_item(*thing);
2761 if (shopmenu.menu_action == Menu::ACT_EXECUTE)
2763 const int cost = thing_cost(*thing);
2765 if (cost > you.gold)
2767 std::string prompt =
2768 make_stringf("You cannot afford %s; travel there "
2769 "anyway? (y/N)",
2770 describe_thing(*thing, DESC_NOCAP_A).c_str());
2771 clrscr();
2772 if (!yesno(prompt.c_str(), true, 'n'))
2773 continue;
2776 const travel_target lp(thing_pos(*thing), false);
2777 start_translevel_travel(lp);
2778 break;
2780 else if (shopmenu.menu_action == Menu::ACT_EXAMINE)
2782 clrscr();
2783 if (is_item)
2785 const item_def &item = get_thing_item(*thing);
2786 describe_item(const_cast<item_def&>(item));
2788 else // not an item, so we only stored a description.
2790 // HACK: Assume it's some kind of portal vault.
2791 snprintf(info, INFO_SIZE,
2792 "%s with an entry fee of %d gold pieces.",
2793 describe_thing(*thing, DESC_CAP_A).c_str(),
2794 (int) thing_cost(*thing));
2796 print_description(info);
2797 wait_for_keypress();
2800 else if (shopmenu.menu_action == Menu::ACT_MISC)
2802 std::string prompt =
2803 make_stringf("Delete %s from shopping list? (y/N)",
2804 describe_thing(*thing, DESC_NOCAP_A).c_str());
2805 clrscr();
2806 if (!yesno(prompt.c_str(), true, 'n'))
2807 continue;
2809 const int index = shopmenu.get_entry_index(sel[0]);
2810 if (index == -1)
2812 mpr("ERROR: Unable to delete thing from shopping list!",
2813 MSGCH_ERROR);
2814 more();
2815 continue;
2818 del_thing_at_index(index);
2819 if (list->size() == 0)
2820 break;
2822 shopmenu.clear();
2823 fill_out_menu(shopmenu);
2825 else
2826 die("Invalid menu action type");
2828 redraw_screen();
2831 static bool _compare_shopping_things(const CrawlStoreValue& a,
2832 const CrawlStoreValue& b)
2834 const CrawlHashTable& hash_a = a.get_table();
2835 const CrawlHashTable& hash_b = b.get_table();
2837 const int a_cost = hash_a[SHOPPING_THING_COST_KEY];
2838 const int b_cost = hash_b[SHOPPING_THING_COST_KEY];
2840 return (a_cost < b_cost);
2843 void ShoppingList::refresh()
2845 if (!you.props.exists(SHOPPING_LIST_KEY))
2846 you.props[SHOPPING_LIST_KEY].new_vector(SV_HASH, SFLAG_CONST_TYPE);
2847 list = &you.props[SHOPPING_LIST_KEY].get_vector();
2849 std::sort(list->begin(), list->end(), _compare_shopping_things);
2851 min_unbuyable_cost = INT_MAX;
2852 min_unbuyable_idx = -1;
2853 max_buyable_cost = -1;
2854 max_buyable_idx = -1;
2856 int total_cost = 0;
2858 for (unsigned int i = 0; i < list->size(); i++)
2860 const CrawlHashTable &thing = (*list)[i];
2862 const int cost = thing_cost(thing);
2864 if (cost <= you.gold)
2866 max_buyable_cost = cost;
2867 max_buyable_idx = i;
2869 else if (min_unbuyable_idx == -1)
2871 min_unbuyable_cost = cost;
2872 min_unbuyable_idx = i;
2874 total_cost += cost;
2876 you.props[SHOPPING_LIST_COST_KEY].get_int() = total_cost;
2879 int ShoppingList::find_thing(const item_def &item,
2880 const level_pos &pos) const
2882 for (unsigned int i = 0; i < list->size(); i++)
2884 const CrawlHashTable &thing = (*list)[i];
2885 const level_pos _pos = thing_pos(thing);
2887 if (pos != _pos)
2888 continue;
2890 if (!thing_is_item(thing))
2891 continue;
2893 const item_def &_item = get_thing_item(thing);
2895 if (item_name_simple(item) == item_name_simple(_item))
2896 return (i);
2899 return (-1);
2902 int ShoppingList::find_thing(const std::string &desc,
2903 const level_pos &pos) const
2905 for (unsigned int i = 0; i < list->size(); i++)
2907 const CrawlHashTable &thing = (*list)[i];
2908 const level_pos _pos = thing_pos(thing);
2910 if (pos != _pos)
2911 continue;
2913 if (thing_is_item(thing))
2914 continue;
2916 if (desc == name_thing(thing))
2917 return (i);
2920 return (-1);
2923 bool ShoppingList::thing_is_item(const CrawlHashTable& thing)
2925 return thing.exists(SHOPPING_THING_ITEM_KEY);
2928 const item_def& ShoppingList::get_thing_item(const CrawlHashTable& thing)
2930 ASSERT(thing.exists(SHOPPING_THING_ITEM_KEY));
2932 const item_def &item = thing[SHOPPING_THING_ITEM_KEY].get_item();
2933 ASSERT(item.defined());
2935 return (item);
2938 std::string ShoppingList::get_thing_desc(const CrawlHashTable& thing)
2940 ASSERT(thing.exists(SHOPPING_THING_DESC_KEY));
2942 std::string desc = thing[SHOPPING_THING_DESC_KEY].get_string();
2943 return (desc);
2946 int ShoppingList::thing_cost(const CrawlHashTable& thing)
2948 ASSERT(thing.exists(SHOPPING_THING_COST_KEY));
2949 return (thing[SHOPPING_THING_COST_KEY].get_int());
2952 level_pos ShoppingList::thing_pos(const CrawlHashTable& thing)
2954 ASSERT(thing.exists(SHOPPING_THING_POS_KEY));
2955 return (thing[SHOPPING_THING_POS_KEY].get_level_pos());
2958 std::string ShoppingList::name_thing(const CrawlHashTable& thing,
2959 description_level_type descrip)
2961 if (thing_is_item(thing))
2963 const item_def &item = get_thing_item(thing);
2964 return item.name(descrip);
2966 else
2968 std::string desc = get_thing_desc(thing);
2969 return apply_description(descrip, desc);
2973 std::string ShoppingList::describe_thing(const CrawlHashTable& thing,
2974 description_level_type descrip)
2976 const level_pos pos = thing_pos(thing);
2978 std::string desc = name_thing(thing, descrip) + " on ";
2980 if (pos.id == level_id::current())
2981 desc += "this level";
2982 else
2983 desc += pos.id.describe();
2985 return (desc);
2988 // Item name without curse-status or inscription.
2989 std::string ShoppingList::item_name_simple(const item_def& item, bool ident)
2991 return item.name(DESC_PLAIN, false, ident, false, false,
2992 ISFLAG_KNOW_CURSE);