1 /**
2  * @file
3  * @brief Misc functions.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "item-name.h"
9 
10 #include <cctype>
11 #include <cstring>
12 #include <iomanip>
13 #include <sstream>
14 
15 #include "areas.h"
16 #include "artefact.h"
17 #include "art-enum.h"
18 #include "branch.h"
19 #include "cio.h"
20 #include "colour.h"
21 #include "decks.h"
22 #include "describe.h"
23 #include "dgn-overview.h"
24 #include "english.h"
25 #include "env.h" // LSTATE_STILL_WINDS
26 #include "errors.h" // sysfail
27 #include "god-item.h"
28 #include "god-passive.h" // passive_t::want_curses, no_haste
29 #include "invent.h"
30 #include "item-prop.h"
31 #include "item-status-flag-type.h"
32 #include "items.h"
33 #include "item-use.h"
34 #include "level-state-type.h"
35 #include "libutil.h"
36 #include "makeitem.h"
37 #include "notes.h"
38 #include "options.h"
39 #include "orb-type.h"
40 #include "player.h"
41 #include "prompt.h"
42 #include "religion.h"
43 #include "shopping.h"
44 #include "showsymb.h"
45 #include "skills.h"
46 #include "spl-book.h"
47 #include "spl-goditem.h"
48 #include "state.h"
49 #include "stringutil.h"
50 #include "tag-version.h"
51 #include "throw.h"
52 #include "transform.h"
53 #include "unicode.h"
54 #include "unwind.h"
55 #include "viewgeom.h"
56 
57 static bool _is_consonant(char let);
58 static char _random_vowel();
59 static char _random_cons();
60 static string _random_consonant_set(size_t seed);
61 
_maybe_identify_pack_item()62 static void _maybe_identify_pack_item()
63 {
64     for (auto &item : you.inv)
65         if (item.defined() && !get_ident_type(item))
66             maybe_identify_base_type(item);
67 }
68 
69 // quant_name is useful since it prints out a different number of items
70 // than the item actually contains.
quant_name(const item_def & item,int quant,description_level_type des,bool terse)71 string quant_name(const item_def &item, int quant,
72                   description_level_type des, bool terse)
73 {
74     // item_name now requires a "real" item, so we'll mangle a tmp
75     item_def tmp = item;
76     tmp.quantity = quant;
77 
78     return tmp.name(des, terse);
79 }
80 
_interesting_origin(const item_def & item)81 static const char* _interesting_origin(const item_def &item)
82 {
83     if (origin_as_god_gift(item) != GOD_NO_GOD)
84         return "god gift";
85 
86     if (item.orig_monnum == MONS_DONALD && get_equip_desc(item)
87         && item.is_type(OBJ_ARMOUR, ARM_KITE_SHIELD))
88     {
89         return "Donald";
90     }
91 
92     return nullptr;
93 }
94 
95 /**
96  * What inscription should be appended to the given item's name?
97  */
_item_inscription(const item_def & item)98 static string _item_inscription(const item_def &item)
99 {
100     vector<string> insparts;
101 
102     if (const char *orig = _interesting_origin(item))
103     {
104         if (Options.show_god_gift == MB_TRUE
105             || Options.show_god_gift == MB_MAYBE && !fully_identified(item))
106         {
107             insparts.push_back(orig);
108         }
109     }
110 
111     if (is_artefact(item))
112     {
113         const string part = artefact_inscription(item);
114         if (!part.empty())
115             insparts.push_back(part);
116     }
117 
118     if (!item.inscription.empty())
119         insparts.push_back(item.inscription);
120 
121     if (insparts.empty())
122         return "";
123 
124     return make_stringf(" {%s}",
125                         comma_separated_line(begin(insparts),
126                                              end(insparts),
127                                              ", ").c_str());
128 }
129 
name(description_level_type descrip,bool terse,bool ident,bool with_inscription,bool quantity_in_words,iflags_t ignore_flags) const130 string item_def::name(description_level_type descrip, bool terse, bool ident,
131                       bool with_inscription, bool quantity_in_words,
132                       iflags_t ignore_flags) const
133 {
134     if (crawl_state.game_is_arena())
135         ignore_flags |= ISFLAG_KNOW_PLUSES | ISFLAG_COSMETIC_MASK;
136 
137     if (descrip == DESC_NONE)
138         return "";
139 
140     ostringstream buff;
141 
142     const string auxname = name_aux(descrip, terse, ident, with_inscription,
143                                     ignore_flags);
144 
145     const bool startvowel     = is_vowel(auxname[0]);
146     const bool qualname       = (descrip == DESC_QUALNAME);
147 
148     if (descrip == DESC_INVENTORY_EQUIP || descrip == DESC_INVENTORY)
149     {
150         if (in_inventory(*this)) // actually in inventory
151         {
152             buff << index_to_letter(link);
153             if (terse)
154                 buff << ") ";
155             else
156                 buff << " - ";
157         }
158         else
159             descrip = DESC_A;
160     }
161 
162     if (base_type == OBJ_BOOKS && book_has_title(*this))
163     {
164         if (descrip != DESC_DBNAME)
165             descrip = DESC_PLAIN;
166     }
167 
168     if (terse && descrip != DESC_DBNAME)
169         descrip = DESC_PLAIN;
170 
171     monster_flags_t corpse_flags;
172 
173     // no "a dragon scales"
174     const bool always_plural = armour_is_hide(*this)
175                                && sub_type != ARM_TROLL_LEATHER_ARMOUR;
176 
177     if ((base_type == OBJ_CORPSES && is_named_corpse(*this)
178          && !(((corpse_flags.flags = props[CORPSE_NAME_TYPE_KEY].get_int64())
179                & MF_NAME_SPECIES)
180               && !(corpse_flags & MF_NAME_DEFINITE))
181          && !(corpse_flags & MF_NAME_SUFFIX)
182          && !starts_with(get_corpse_name(*this), "shaped "))
183         || item_is_orb(*this) || item_is_horn_of_geryon(*this)
184         || (ident || item_type_known(*this)) && is_artefact(*this)
185             && special != UNRAND_OCTOPUS_KING_RING)
186     {
187         // Artefacts always get "the" unless we just want the plain name.
188         switch (descrip)
189         {
190         default:
191             buff << "the ";
192         case DESC_PLAIN:
193         case DESC_DBNAME:
194         case DESC_BASENAME:
195         case DESC_QUALNAME:
196             break;
197         }
198     }
199     else if (quantity > 1 || always_plural)
200     {
201         switch (descrip)
202         {
203         case DESC_THE:        buff << "the "; break;
204         case DESC_YOUR:       buff << "your "; break;
205         case DESC_ITS:        buff << "its "; break;
206         case DESC_A:
207         case DESC_INVENTORY_EQUIP:
208         case DESC_INVENTORY:
209         case DESC_PLAIN:
210         default:
211             break;
212         }
213 
214         if (descrip != DESC_BASENAME && descrip != DESC_QUALNAME
215             && descrip != DESC_DBNAME && !always_plural)
216         {
217             if (quantity_in_words)
218                 buff << number_in_words(quantity) << " ";
219             else
220                 buff << quantity << " ";
221         }
222     }
223     else
224     {
225         switch (descrip)
226         {
227         case DESC_THE:        buff << "the "; break;
228         case DESC_YOUR:       buff << "your "; break;
229         case DESC_ITS:        buff << "its "; break;
230         case DESC_A:
231         case DESC_INVENTORY_EQUIP:
232         case DESC_INVENTORY:
233                               buff << (startvowel ? "an " : "a "); break;
234         case DESC_PLAIN:
235         default:
236             break;
237         }
238     }
239 
240     buff << auxname;
241 
242     if (descrip == DESC_INVENTORY_EQUIP)
243     {
244         equipment_type eq = item_equip_slot(*this);
245         if (eq != EQ_NONE)
246         {
247             if (you.melded[eq])
248                 buff << " (melded)";
249             else
250             {
251                 switch (eq)
252                 {
253                 case EQ_WEAPON:
254                     if (is_weapon(*this))
255                         buff << " (weapon)";
256                     else if (you.has_mutation(MUT_NO_GRASPING))
257                         buff << " (in mouth)";
258                     else
259                         buff << " (in " << you.hand_name(false) << ")";
260                     break;
261                 case EQ_CLOAK:
262                 case EQ_HELMET:
263                 case EQ_GLOVES:
264                 case EQ_BOOTS:
265                 case EQ_SHIELD:
266                 case EQ_BODY_ARMOUR:
267                     buff << " (worn)";
268                     break;
269                 case EQ_LEFT_RING:
270                 case EQ_RIGHT_RING:
271                 case EQ_RING_ONE:
272                 case EQ_RING_TWO:
273                     buff << " (";
274                     buff << ((eq == EQ_LEFT_RING || eq == EQ_RING_ONE)
275                              ? "left" : "right");
276                     buff << " ";
277                     buff << you.hand_name(false);
278                     buff << ")";
279                     break;
280                 case EQ_AMULET:
281                     if (you.species == SP_OCTOPODE && form_keeps_mutations())
282                         buff << " (around mantle)";
283                     else
284                         buff << " (around neck)";
285                     break;
286                 case EQ_RING_THREE:
287                 case EQ_RING_FOUR:
288                 case EQ_RING_FIVE:
289                 case EQ_RING_SIX:
290                 case EQ_RING_SEVEN:
291                 case EQ_RING_EIGHT:
292                     buff << " (on tentacle)";
293                     break;
294                 case EQ_RING_AMULET:
295                     buff << " (on amulet)";
296                     break;
297                 default:
298                     die("Item in an invalid slot");
299                 }
300             }
301         }
302         else if (you.launcher_action.item_is_quivered(*this))
303             buff << " (quivered ammo)";
304         else if (you.quiver_action.item_is_quivered(*this))
305             buff << " (quivered)";
306     }
307 
308     if (descrip != DESC_BASENAME && descrip != DESC_DBNAME && with_inscription)
309         buff << _item_inscription(*this);
310 
311     // These didn't have "cursed " prepended; add them here so that
312     // it comes after the inscription.
313     if (terse && descrip != DESC_DBNAME && descrip != DESC_BASENAME
314         && !qualname
315         && is_artefact(*this) && cursed())
316     {
317         buff << " (curse)";
318     }
319 
320     return buff.str();
321 }
322 
_missile_brand_is_prefix(special_missile_type brand)323 static bool _missile_brand_is_prefix(special_missile_type brand)
324 {
325     switch (brand)
326     {
327     case SPMSL_POISONED:
328     case SPMSL_CURARE:
329     case SPMSL_BLINDING:
330     case SPMSL_FRENZY:
331     case SPMSL_EXPLODING:
332 #if TAG_MAJOR_VERSION == 34
333     case SPMSL_STEEL:
334 #endif
335     case SPMSL_SILVER:
336         return true;
337     default:
338         return false;
339     }
340 }
341 
_missile_brand_is_postfix(special_missile_type brand)342 static bool _missile_brand_is_postfix(special_missile_type brand)
343 {
344     return brand != SPMSL_NORMAL && !_missile_brand_is_prefix(brand);
345 }
346 
missile_brand_name(const item_def & item,mbn_type t)347 const char* missile_brand_name(const item_def &item, mbn_type t)
348 {
349     const special_missile_type brand
350         = static_cast<special_missile_type>(item.brand);
351     switch (brand)
352     {
353 #if TAG_MAJOR_VERSION == 34
354     case SPMSL_FLAME:
355         return "flame";
356     case SPMSL_FROST:
357         return "frost";
358 #endif
359     case SPMSL_POISONED:
360         return t == MBN_NAME ? "poisoned" : "poison";
361     case SPMSL_CURARE:
362         return t == MBN_NAME ? "curare-tipped" : "curare";
363 #if TAG_MAJOR_VERSION == 34
364     case SPMSL_EXPLODING:
365         return t == MBN_TERSE ? "explode" : "exploding";
366     case SPMSL_STEEL:
367         return "steel";
368     case SPMSL_RETURNING:
369         return t == MBN_TERSE ? "return" : "returning";
370     case SPMSL_PENETRATION:
371         return t == MBN_TERSE ? "penet" : "penetration";
372 #endif
373     case SPMSL_SILVER:
374         return "silver";
375 #if TAG_MAJOR_VERSION == 34
376     case SPMSL_PARALYSIS:
377         return "paralysis";
378     case SPMSL_SLOW:
379         return t == MBN_TERSE ? "slow" : "slowing";
380     case SPMSL_SLEEP:
381         return t == MBN_TERSE ? "sleep" : "sleeping";
382     case SPMSL_CONFUSION:
383         return t == MBN_TERSE ? "conf" : "confusion";
384     case SPMSL_SICKNESS:
385         return t == MBN_TERSE ? "sick" : "sickness";
386 #endif
387     case SPMSL_FRENZY:
388         return t == MBN_NAME ? "datura-tipped" : "datura";
389     case SPMSL_CHAOS:
390         return "chaos";
391     case SPMSL_DISPERSAL:
392         return t == MBN_TERSE ? "disperse" : "dispersal";
393     case SPMSL_BLINDING:
394         return t == MBN_NAME ? "atropa-tipped" : "atropa";
395     case SPMSL_NORMAL:
396         return "";
397     default:
398         return t == MBN_TERSE ? "buggy" : "bugginess";
399     }
400 }
401 
402 static const char *weapon_brands_terse[] =
403 {
404     "", "flame", "freeze", "holy", "elec",
405 #if TAG_MAJOR_VERSION == 34
406     "obsolete", "obsolete",
407 #endif
408     "venom", "protect", "drain", "speed", "vorpal",
409 #if TAG_MAJOR_VERSION == 34
410     "obsolete", "obsolete",
411 #endif
412     "vamp", "pain", "antimagic", "distort",
413 #if TAG_MAJOR_VERSION == 34
414     "obsolete", "obsolete",
415 #endif
416     "chaos",
417 #if TAG_MAJOR_VERSION == 34
418     "evade", "confuse",
419 #endif
420     "penet", "reap", "spect", "vorpal", "acid",
421 #if TAG_MAJOR_VERSION > 34
422     "confuse",
423 #endif
424     "debug",
425 };
426 
427 static const char *weapon_brands_verbose[] =
428 {
429     "", "flaming", "freezing", "holy wrath", "electrocution",
430 #if TAG_MAJOR_VERSION == 34
431     "orc slaying", "dragon slaying",
432 #endif
433     "venom", "protection", "draining", "speed", "vorpality",
434 #if TAG_MAJOR_VERSION == 34
435     "flame", "frost",
436 #endif
437     "vampirism", "pain", "antimagic", "distortion",
438 #if TAG_MAJOR_VERSION == 34
439     "reaching", "returning",
440 #endif
441     "chaos",
442 #if TAG_MAJOR_VERSION == 34
443     "evasion", "confusion",
444 #endif
445     "penetration", "reaping", "spectralizing", "vorpal", "acid",
446 #if TAG_MAJOR_VERSION > 34
447     "confusion",
448 #endif
449     "debug",
450 };
451 
452 static const char *weapon_brands_adj[] =
453 {
454     "", "flaming", "freezing", "holy", "electric",
455 #if TAG_MAJOR_VERSION == 34
456     "orc-killing", "dragon-slaying",
457 #endif
458     "venomous", "protective", "draining", "fast", "vorpal",
459 #if TAG_MAJOR_VERSION == 34
460     "flaming", "freezing",
461 #endif
462     "vampiric", "painful", "antimagic", "distorting",
463 #if TAG_MAJOR_VERSION == 34
464     "reaching", "returning",
465 #endif
466     "chaotic",
467 #if TAG_MAJOR_VERSION == 34
468     "evasive", "confusing",
469 #endif
470     "penetrating", "reaping", "spectral", "vorpal", "acidic",
471 #if TAG_MAJOR_VERSION > 34
472     "confusing",
473 #endif
474     "debug",
475 };
476 
477 static const set<brand_type> brand_prefers_adj =
478             { SPWPN_VAMPIRISM, SPWPN_ANTIMAGIC, SPWPN_VORPAL, SPWPN_SPECTRAL };
479 
480 /**
481  * What's the name of a type of weapon brand?
482  *
483  * @param brand             The type of brand in question.
484  * @param bool              Whether to use a terse or verbose name.
485  * @return                  The name of the given brand.
486  */
brand_type_name(brand_type brand,bool terse)487 const char* brand_type_name(brand_type brand, bool terse)
488 {
489     COMPILE_CHECK(ARRAYSZ(weapon_brands_terse) == NUM_SPECIAL_WEAPONS);
490     COMPILE_CHECK(ARRAYSZ(weapon_brands_verbose) == NUM_SPECIAL_WEAPONS);
491 
492     if (brand < 0 || brand >= NUM_SPECIAL_WEAPONS)
493         return terse ? "buggy" : "bugginess";
494 
495     return (terse ? weapon_brands_terse : weapon_brands_verbose)[brand];
496 }
497 
brand_type_adj(brand_type brand)498 const char* brand_type_adj(brand_type brand)
499 {
500     COMPILE_CHECK(ARRAYSZ(weapon_brands_terse) == NUM_SPECIAL_WEAPONS);
501     COMPILE_CHECK(ARRAYSZ(weapon_brands_verbose) == NUM_SPECIAL_WEAPONS);
502 
503     if (brand < 0 || brand >= NUM_SPECIAL_WEAPONS)
504         return "buggy";
505 
506     return weapon_brands_adj[brand];
507 }
508 
509 /**
510  * What's the name of a given weapon's brand?
511  *
512  * @param item              The weapon with the brand.
513  * @param bool              Whether to use a terse or verbose name.
514  * @return                  The name of the given item's brand.
515  */
weapon_brand_name(const item_def & item,bool terse,brand_type override_brand)516 const char* weapon_brand_name(const item_def& item, bool terse,
517                               brand_type override_brand)
518 {
519     const brand_type brand = override_brand ? override_brand : get_weapon_brand(item);
520 
521     return brand_type_name(brand, terse);
522 }
523 
armour_ego_name(const item_def & item,bool terse)524 const char* armour_ego_name(const item_def& item, bool terse)
525 {
526     if (!terse)
527     {
528         switch (get_armour_ego_type(item))
529         {
530         case SPARM_NORMAL:            return "";
531 #if TAG_MAJOR_VERSION == 34
532         case SPARM_RUNNING:           return "running";
533 #endif
534         case SPARM_FIRE_RESISTANCE:   return "fire resistance";
535         case SPARM_COLD_RESISTANCE:   return "cold resistance";
536         case SPARM_POISON_RESISTANCE: return "poison resistance";
537         case SPARM_SEE_INVISIBLE:     return "see invisible";
538         case SPARM_INVISIBILITY:      return "invisibility";
539         case SPARM_STRENGTH:          return "strength";
540         case SPARM_DEXTERITY:         return "dexterity";
541         case SPARM_INTELLIGENCE:      return "intelligence";
542         case SPARM_PONDEROUSNESS:     return "ponderousness";
543         case SPARM_FLYING:            return "flying";
544 
545         case SPARM_WILLPOWER:         return "willpower";
546         case SPARM_PROTECTION:        return "protection";
547         case SPARM_STEALTH:           return "stealth";
548         case SPARM_RESISTANCE:        return "resistance";
549         case SPARM_POSITIVE_ENERGY:   return "positive energy";
550         case SPARM_ARCHMAGI:          return "the Archmagi";
551 #if TAG_MAJOR_VERSION == 34
552         case SPARM_JUMPING:           return "jumping";
553 #endif
554         case SPARM_PRESERVATION:      return "preservation";
555         case SPARM_REFLECTION:        return "reflection";
556         case SPARM_SPIRIT_SHIELD:     return "spirit shield";
557         case SPARM_ARCHERY:           return "archery";
558         case SPARM_REPULSION:         return "repulsion";
559 #if TAG_MAJOR_VERSION == 34
560         case SPARM_CLOUD_IMMUNE:      return "cloud immunity";
561 #endif
562         case SPARM_HARM:              return "harm";
563         case SPARM_SHADOWS:           return "shadows";
564         case SPARM_RAMPAGING:         return "rampaging";
565         default:                      return "bugginess";
566         }
567     }
568     else
569     {
570         switch (get_armour_ego_type(item))
571         {
572         case SPARM_NORMAL:            return "";
573 #if TAG_MAJOR_VERSION == 34
574         case SPARM_RUNNING:           return "obsolete";
575 #endif
576         case SPARM_FIRE_RESISTANCE:   return "rF+";
577         case SPARM_COLD_RESISTANCE:   return "rC+";
578         case SPARM_POISON_RESISTANCE: return "rPois";
579         case SPARM_SEE_INVISIBLE:     return "SInv";
580         case SPARM_INVISIBILITY:      return "+Inv";
581         case SPARM_STRENGTH:          return "Str+3";
582         case SPARM_DEXTERITY:         return "Dex+3";
583         case SPARM_INTELLIGENCE:      return "Int+3";
584         case SPARM_PONDEROUSNESS:     return "ponderous";
585         case SPARM_FLYING:            return "Fly";
586         case SPARM_WILLPOWER:         return "Will+";
587         case SPARM_PROTECTION:        return "AC+3";
588         case SPARM_STEALTH:           return "Stlth+";
589         case SPARM_RESISTANCE:        return "rC+ rF+";
590         case SPARM_POSITIVE_ENERGY:   return "rN+";
591         case SPARM_ARCHMAGI:          return "Archmagi";
592 #if TAG_MAJOR_VERSION == 34
593         case SPARM_JUMPING:           return "obsolete";
594 #endif
595         case SPARM_PRESERVATION:      return "rCorr";
596         case SPARM_REFLECTION:        return "reflect";
597         case SPARM_SPIRIT_SHIELD:     return "Spirit";
598         case SPARM_ARCHERY:           return "archery";
599         case SPARM_REPULSION:         return "repulsion";
600 #if TAG_MAJOR_VERSION == 34
601         case SPARM_CLOUD_IMMUNE:      return "obsolete";
602 #endif
603         case SPARM_HARM:              return "harm";
604         case SPARM_SHADOWS:           return "shadows";
605         case SPARM_RAMPAGING:         return "rampage";
606         default:                      return "buggy";
607         }
608     }
609 }
610 
_wand_type_name(int wandtype)611 static const char* _wand_type_name(int wandtype)
612 {
613     switch (wandtype)
614     {
615     case WAND_FLAME:           return "flame";
616     case WAND_PARALYSIS:       return "paralysis";
617     case WAND_DIGGING:         return "digging";
618     case WAND_ICEBLAST:        return "iceblast";
619     case WAND_POLYMORPH:       return "polymorph";
620     case WAND_CHARMING:     return "charming";
621     case WAND_ACID:            return "acid";
622     case WAND_MINDBURST:       return "mindburst";
623     default:                   return item_type_removed(OBJ_WANDS, wandtype)
624                                     ? "removedness"
625                                     : "bugginess";
626     }
627 }
628 
wand_secondary_string(uint32_t s)629 static const char* wand_secondary_string(uint32_t s)
630 {
631     static const char* const secondary_strings[] = {
632         "", "jewelled ", "curved ", "long ", "short ", "twisted ", "crooked ",
633         "forked ", "shiny ", "blackened ", "tapered ", "glowing ", "worn ",
634         "encrusted ", "runed ", "sharpened "
635     };
636     COMPILE_CHECK(ARRAYSZ(secondary_strings) == NDSC_WAND_SEC);
637     return secondary_strings[s % NDSC_WAND_SEC];
638 }
639 
wand_primary_string(uint32_t p)640 static const char* wand_primary_string(uint32_t p)
641 {
642     static const char* const primary_strings[] = {
643         "iron", "brass", "bone", "wooden", "copper", "gold", "silver",
644         "bronze", "ivory", "glass", "lead", "fluorescent"
645     };
646     COMPILE_CHECK(ARRAYSZ(primary_strings) == NDSC_WAND_PRI);
647     return primary_strings[p % NDSC_WAND_PRI];
648 }
649 
potion_type_name(int potiontype)650 const char* potion_type_name(int potiontype)
651 {
652     switch (static_cast<potion_type>(potiontype))
653     {
654     case POT_CURING:            return "curing";
655     case POT_HEAL_WOUNDS:       return "heal wounds";
656     case POT_HASTE:             return "haste";
657     case POT_MIGHT:             return "might";
658     case POT_ATTRACTION:        return "attraction";
659     case POT_BRILLIANCE:        return "brilliance";
660     case POT_FLIGHT:            return "flight";
661     case POT_CANCELLATION:      return "cancellation";
662     case POT_AMBROSIA:          return "ambrosia";
663     case POT_INVISIBILITY:      return "invisibility";
664     case POT_DEGENERATION:      return "degeneration";
665     case POT_EXPERIENCE:        return "experience";
666     case POT_MAGIC:             return "magic";
667     case POT_BERSERK_RAGE:      return "berserk rage";
668     case POT_MUTATION:          return "mutation";
669     case POT_RESISTANCE:        return "resistance";
670     case POT_LIGNIFY:           return "lignification";
671 
672     // FIXME: Remove this once known-items no longer uses this as a sentinel.
673     default:
674                                 return "bugginess";
675     CASE_REMOVED_POTIONS(potiontype); // TODO: this will crash, is that correct??
676     }
677 }
678 
scroll_type_name(int scrolltype)679 static const char* scroll_type_name(int scrolltype)
680 {
681     switch (static_cast<scroll_type>(scrolltype))
682     {
683     case SCR_IDENTIFY:           return "identify";
684     case SCR_TELEPORTATION:      return "teleportation";
685     case SCR_FEAR:               return "fear";
686     case SCR_NOISE:              return "noise";
687     case SCR_SUMMONING:          return "summoning";
688     case SCR_ENCHANT_WEAPON:     return "enchant weapon";
689     case SCR_ENCHANT_ARMOUR:     return "enchant armour";
690     case SCR_TORMENT:            return "torment";
691     case SCR_IMMOLATION:         return "immolation";
692     case SCR_BLINKING:           return "blinking";
693     case SCR_MAGIC_MAPPING:      return "magic mapping";
694     case SCR_FOG:                return "fog";
695     case SCR_ACQUIREMENT:        return "acquirement";
696     case SCR_BRAND_WEAPON:       return "brand weapon";
697     case SCR_HOLY_WORD:          return "holy word";
698     case SCR_VULNERABILITY:      return "vulnerability";
699     case SCR_SILENCE:            return "silence";
700     case SCR_AMNESIA:            return "amnesia";
701 #if TAG_MAJOR_VERSION == 34
702     case SCR_CURSE_WEAPON:       return "curse weapon";
703     case SCR_CURSE_ARMOUR:       return "curse armour";
704     case SCR_CURSE_JEWELLERY:    return "curse jewellery";
705 #endif
706     default:                     return item_type_removed(OBJ_SCROLLS,
707                                                           scrolltype)
708                                      ? "removedness"
709                                      : "bugginess";
710     }
711 }
712 
713 /**
714  * Get the name for the effect provided by a kind of jewellery.
715  *
716  * @param jeweltype     The jewellery_type of the item in question.
717  * @return              A string describing the effect of the given jewellery
718  *                      subtype.
719  */
jewellery_effect_name(int jeweltype,bool terse)720 const char* jewellery_effect_name(int jeweltype, bool terse)
721 {
722     if (!terse)
723     {
724         switch (static_cast<jewellery_type>(jeweltype))
725         {
726 #if TAG_MAJOR_VERSION == 34
727         case RING_REGENERATION:          return "obsoleteness";
728         case RING_ATTENTION:             return "obsoleteness";
729 #endif
730         case RING_PROTECTION:            return "protection";
731         case RING_PROTECTION_FROM_FIRE:  return "protection from fire";
732         case RING_POISON_RESISTANCE:     return "poison resistance";
733         case RING_PROTECTION_FROM_COLD:  return "protection from cold";
734         case RING_STRENGTH:              return "strength";
735         case RING_SLAYING:               return "slaying";
736         case RING_SEE_INVISIBLE:         return "see invisible";
737         case RING_RESIST_CORROSION:      return "resist corrosion";
738         case RING_EVASION:               return "evasion";
739 #if TAG_MAJOR_VERSION == 34
740         case RING_SUSTAIN_ATTRIBUTES:    return "sustain attributes";
741 #endif
742         case RING_STEALTH:               return "stealth";
743         case RING_DEXTERITY:             return "dexterity";
744         case RING_INTELLIGENCE:          return "intelligence";
745         case RING_WIZARDRY:              return "wizardry";
746         case RING_MAGICAL_POWER:         return "magical power";
747         case RING_FLIGHT:                return "flight";
748         case RING_LIFE_PROTECTION:       return "positive energy";
749         case RING_WILLPOWER: return "willpower";
750         case RING_FIRE:                  return "fire";
751         case RING_ICE:                   return "ice";
752 #if TAG_MAJOR_VERSION == 34
753         case RING_TELEPORTATION:         return "teleportation";
754         case RING_TELEPORT_CONTROL:      return "teleport control";
755 #endif
756         case AMU_MANA_REGENERATION: return "magic regeneration";
757         case AMU_ACROBAT:           return "the acrobat";
758 #if TAG_MAJOR_VERSION == 34
759         case AMU_RAGE:              return "rage";
760         case AMU_THE_GOURMAND:      return "gourmand";
761         case AMU_HARM:              return "harm";
762         case AMU_CONSERVATION:      return "conservation";
763         case AMU_CONTROLLED_FLIGHT: return "controlled flight";
764         case AMU_INACCURACY:        return "inaccuracy";
765 #endif
766         case AMU_NOTHING:           return "nothing";
767         case AMU_GUARDIAN_SPIRIT:   return "guardian spirit";
768         case AMU_FAITH:             return "faith";
769         case AMU_REFLECTION:        return "reflection";
770         case AMU_REGENERATION:      return "regeneration";
771         default: return "buggy jewellery";
772         }
773     }
774     else
775     {
776         if (jewellery_base_ability_string(jeweltype)[0] != '\0')
777             return jewellery_base_ability_string(jeweltype);
778         switch (static_cast<jewellery_type>(jeweltype))
779         {
780 #if TAG_MAJOR_VERSION == 34
781         case RING_REGENERATION:          return "obsoleteness";
782         case RING_ATTENTION:             return "obsoleteness";
783 #endif
784         case RING_PROTECTION:            return "AC";
785         case RING_PROTECTION_FROM_FIRE:  return "rF+";
786         case RING_POISON_RESISTANCE:     return "rPois";
787         case RING_PROTECTION_FROM_COLD:  return "rC+";
788         case RING_STRENGTH:              return "Str";
789         case RING_SLAYING:               return "Slay";
790         case RING_SEE_INVISIBLE:         return "sInv";
791         case RING_RESIST_CORROSION:      return "rCorr";
792         case RING_EVASION:               return "EV";
793         case RING_STEALTH:               return "Stlth+";
794         case RING_DEXTERITY:             return "Dex";
795         case RING_INTELLIGENCE:          return "Int";
796         case RING_MAGICAL_POWER:         return "MP+9";
797         case RING_FLIGHT:                return "Fly";
798         case RING_LIFE_PROTECTION:       return "rN+";
799         case RING_WILLPOWER:             return "Will+";
800         case AMU_REGENERATION:           return "Regen";
801 #if TAG_MAJOR_VERSION == 34
802         case AMU_RAGE:                   return "+Rage";
803 #endif
804         case AMU_ACROBAT:                return "Acrobat";
805         case AMU_NOTHING:                return "";
806         default: return "buggy";
807         }
808     }
809 }
810 
811 /**
812  * Get the name for the category of a type of jewellery.
813  *
814  * @param jeweltype     The jewellery_type of the item in question.
815  * @return              A string describing the kind of jewellery it is.
816  */
_jewellery_class_name(int jeweltype)817 static const char* _jewellery_class_name(int jeweltype)
818 {
819 #if TAG_MAJOR_VERSION == 34
820     if (jeweltype == RING_REGENERATION)
821         return "ring of";
822 #endif
823 
824     if (jeweltype < RING_FIRST_RING || jeweltype >= NUM_JEWELLERY
825         || jeweltype >= NUM_RINGS && jeweltype < AMU_FIRST_AMULET)
826     {
827         return "buggy"; // "buggy buggy jewellery"
828     }
829 
830     if (jeweltype < NUM_RINGS)
831         return "ring of";
832     return "amulet of";
833 }
834 
835 /**
836  * Get the name for a type of jewellery.
837  *
838  * @param jeweltype     The jewellery_type of the item in question.
839  * @return              The full name of the jewellery type in question.
840  */
jewellery_type_name(int jeweltype)841 static string jewellery_type_name(int jeweltype)
842 {
843     return make_stringf("%s %s", _jewellery_class_name(jeweltype),
844                                  jewellery_effect_name(jeweltype));
845 }
846 
847 
ring_secondary_string(uint32_t s)848 static const char* ring_secondary_string(uint32_t s)
849 {
850     static const char* const secondary_strings[] = {
851         "", "encrusted ", "glowing ", "tubular ", "runed ", "blackened ",
852         "scratched ", "small ", "large ", "twisted ", "shiny ", "notched ",
853         "knobbly "
854     };
855     COMPILE_CHECK(ARRAYSZ(secondary_strings) == NDSC_JEWEL_SEC);
856     return secondary_strings[s % NDSC_JEWEL_SEC];
857 }
858 
ring_primary_string(uint32_t p)859 static const char* ring_primary_string(uint32_t p)
860 {
861     static const char* const primary_strings[] = {
862         "wooden", "silver", "golden", "iron", "steel", "tourmaline", "brass",
863         "copper", "granite", "ivory", "ruby", "marble", "jade", "glass",
864         "agate", "bone", "diamond", "emerald", "peridot", "garnet", "opal",
865         "pearl", "coral", "sapphire", "cabochon", "gilded", "onyx", "bronze",
866         "moonstone"
867     };
868     COMPILE_CHECK(ARRAYSZ(primary_strings) == NDSC_JEWEL_PRI);
869     return primary_strings[p % NDSC_JEWEL_PRI];
870 }
871 
amulet_secondary_string(uint32_t s)872 static const char* amulet_secondary_string(uint32_t s)
873 {
874     static const char* const secondary_strings[] = {
875         "dented ", "square ", "thick ", "thin ", "runed ", "blackened ",
876         "glowing ", "small ", "large ", "twisted ", "tiny ", "triangular ",
877         "lumpy "
878     };
879     COMPILE_CHECK(ARRAYSZ(secondary_strings) == NDSC_JEWEL_SEC);
880     return secondary_strings[s % NDSC_JEWEL_SEC];
881 }
882 
amulet_primary_string(uint32_t p)883 static const char* amulet_primary_string(uint32_t p)
884 {
885     static const char* const primary_strings[] = {
886         "sapphire", "zirconium", "golden", "emerald", "garnet", "bronze",
887         "brass", "copper", "ruby", "citrine", "bone", "platinum", "jade",
888         "fluorescent", "amethyst", "cameo", "pearl", "blue", "peridot",
889         "jasper", "diamond", "malachite", "steel", "cabochon", "silver",
890         "soapstone", "lapis lazuli", "filigree", "beryl"
891     };
892     COMPILE_CHECK(ARRAYSZ(primary_strings) == NDSC_JEWEL_PRI);
893     return primary_strings[p % NDSC_JEWEL_PRI];
894 }
895 
rune_type_name(short p)896 const char* rune_type_name(short p)
897 {
898     switch (static_cast<rune_type>(p))
899     {
900     case RUNE_DIS:         return "iron";
901     case RUNE_GEHENNA:     return "obsidian";
902     case RUNE_COCYTUS:     return "icy";
903     case RUNE_TARTARUS:    return "bone";
904     case RUNE_SLIME:       return "slimy";
905     case RUNE_VAULTS:      return "silver";
906     case RUNE_SNAKE:       return "serpentine";
907     case RUNE_ELF:         return "elven";
908     case RUNE_TOMB:        return "golden";
909     case RUNE_SWAMP:       return "decaying";
910     case RUNE_SHOALS:      return "barnacled";
911     case RUNE_SPIDER:      return "gossamer";
912     case RUNE_FOREST:      return "mossy";
913 
914     // pandemonium and abyss runes:
915     case RUNE_DEMONIC:     return "demonic";
916     case RUNE_ABYSSAL:     return "abyssal";
917 
918     // special pandemonium runes:
919     case RUNE_MNOLEG:      return "glowing";
920     case RUNE_LOM_LOBON:   return "magical";
921     case RUNE_CEREBOV:     return "fiery";
922     case RUNE_GLOORX_VLOQ: return "dark";
923     default:               return "buggy";
924     }
925 }
926 
misc_type_name(int type)927 static string misc_type_name(int type)
928 {
929 #if TAG_MAJOR_VERSION == 34
930     if (is_deck_type(type))
931         return "removed deck";
932 #endif
933 
934     switch (static_cast<misc_item_type>(type))
935     {
936 #if TAG_MAJOR_VERSION == 34
937     case MISC_CRYSTAL_BALL_OF_ENERGY:    return "removed crystal ball";
938 #endif
939     case MISC_BOX_OF_BEASTS:             return "box of beasts";
940 #if TAG_MAJOR_VERSION == 34
941     case MISC_BUGGY_EBONY_CASKET:        return "removed ebony casket";
942     case MISC_FAN_OF_GALES:              return "removed fan of gales";
943     case MISC_LAMP_OF_FIRE:              return "removed lamp of fire";
944     case MISC_BUGGY_LANTERN_OF_SHADOWS:  return "removed lantern of shadows";
945 #endif
946     case MISC_HORN_OF_GERYON:            return "horn of Geryon";
947     case MISC_LIGHTNING_ROD:             return "lightning rod";
948 #if TAG_MAJOR_VERSION == 34
949     case MISC_BOTTLED_EFREET:            return "empty flask";
950     case MISC_RUNE_OF_ZOT:               return "obsolete rune of zot";
951     case MISC_STONE_OF_TREMORS:          return "removed stone of tremors";
952 #endif
953     case MISC_QUAD_DAMAGE:               return "quad damage";
954     case MISC_PHIAL_OF_FLOODS:           return "phial of floods";
955 #if TAG_MAJOR_VERSION == 34
956     case MISC_SACK_OF_SPIDERS:           return "removed sack of spiders";
957 #endif
958     case MISC_PHANTOM_MIRROR:            return "phantom mirror";
959     case MISC_ZIGGURAT:                  return "figurine of a ziggurat";
960     case MISC_XOMS_CHESSBOARD:           return "piece from Xom's chessboard";
961     case MISC_TIN_OF_TREMORSTONES:       return "tin of tremorstones";
962     case MISC_CONDENSER_VANE:            return "condenser vane";
963 
964     default:
965         return "buggy miscellaneous item";
966     }
967 }
968 
_book_type_name(int booktype)969 static const char* _book_type_name(int booktype)
970 {
971     switch (static_cast<book_type>(booktype))
972     {
973     case BOOK_MINOR_MAGIC:            return "Minor Magic";
974     case BOOK_CONJURATIONS:           return "Conjurations";
975     case BOOK_FLAMES:                 return "Flames";
976     case BOOK_FROST:                  return "Frost";
977     case BOOK_DRYADS:                 return "the Dryads";
978     case BOOK_FIRE:                   return "Fire";
979     case BOOK_ICE:                    return "Ice";
980     case BOOK_SPATIAL_TRANSLOCATIONS: return "Spatial Translocations";
981     case BOOK_HEXES:                  return "Hexes";
982     case BOOK_LIGHTNING:              return "Lightning";
983     case BOOK_DEATH:                  return "Death";
984     case BOOK_MISFORTUNE:             return "Misfortune";
985     case BOOK_CHANGES:                return "Changes";
986     case BOOK_TRANSFIGURATIONS:       return "Transfigurations";
987 #if TAG_MAJOR_VERSION == 34
988     case BOOK_BATTLE:                 return "Battle";
989 #endif
990     case BOOK_VAPOURS:                return "Vapours";
991     case BOOK_NECROMANCY:             return "Necromancy";
992     case BOOK_CALLINGS:               return "Callings";
993     case BOOK_MALEDICT:               return "Maledictions";
994     case BOOK_AIR:                    return "Air";
995     case BOOK_SKY:                    return "the Sky";
996     case BOOK_WARP:                   return "the Warp";
997 #if TAG_MAJOR_VERSION == 34
998     case BOOK_ENVENOMATIONS:          return "Envenomations";
999 #endif
1000     case BOOK_ANNIHILATIONS:          return "Annihilations";
1001     case BOOK_UNLIFE:                 return "Unlife";
1002 #if TAG_MAJOR_VERSION == 34
1003     case BOOK_CONTROL:                return "Control";
1004 #endif
1005     case BOOK_GEOMANCY:               return "Geomancy";
1006     case BOOK_EARTH:                  return "the Earth";
1007 #if TAG_MAJOR_VERSION == 34
1008     case BOOK_WIZARDRY:               return "Wizardry";
1009 #endif
1010     case BOOK_POWER:                  return "Power";
1011     case BOOK_CANTRIPS:               return "Cantrips";
1012     case BOOK_PARTY_TRICKS:           return "Party Tricks";
1013     case BOOK_DEBILITATION:           return "Debilitation";
1014     case BOOK_DRAGON:                 return "the Dragon";
1015     case BOOK_BURGLARY:               return "Burglary";
1016     case BOOK_DREAMS:                 return "Dreams";
1017     case BOOK_ALCHEMY:                return "Alchemy";
1018     case BOOK_BEASTS:                 return "Beasts";
1019     case BOOK_SPECTACLE:              return "Spectacle";
1020     case BOOK_WINTER:                 return "Winter";
1021     case BOOK_SPHERES:                return "the Spheres";
1022     case BOOK_ARMAMENTS:              return "Armaments";
1023     case BOOK_PAIN:                   return "Pain";
1024     case BOOK_DECAY:                  return "Decay";
1025     case BOOK_DISPLACEMENT:           return "Displacement";
1026     case BOOK_RIME:                   return "Rime";
1027     case BOOK_STONE:                  return "Stone";
1028     case BOOK_SENSES:                 return "the Senses";
1029     case BOOK_BLASTING:               return "Blasting";
1030     case BOOK_IRON:                   return "Iron";
1031     case BOOK_TUNDRA:                 return "the Tundra";
1032     case BOOK_MOON:                   return "the Moon";
1033     case BOOK_STORMS:                 return "Storms";
1034     case BOOK_WEAPONS:                return "Weapons";
1035     case BOOK_SLOTH:                  return "Sloth";
1036     case BOOK_BLOOD:                  return "Blood";
1037     case BOOK_DANGEROUS_FRIENDS:      return "Dangerous Friends";
1038     case BOOK_TOUCH:                  return "Touch";
1039     case BOOK_CHAOS:                  return "Chaos";
1040     case BOOK_HUNTER:                 return "the Hunter";
1041     case BOOK_RANDART_LEVEL:          return "Fixed Level";
1042     case BOOK_RANDART_THEME:          return "Fixed Theme";
1043     default:                          return "Bugginess";
1044     }
1045 }
1046 
staff_secondary_string(uint32_t s)1047 static const char* staff_secondary_string(uint32_t s)
1048 {
1049     static const char* const secondary_strings[] = {
1050         "crooked ", "knobbly ", "weird ", "gnarled ", "thin ", "curved ",
1051         "twisted ", "thick ", "long ", "short ",
1052     };
1053     COMPILE_CHECK(NDSC_STAVE_SEC == ARRAYSZ(secondary_strings));
1054     return secondary_strings[s % ARRAYSZ(secondary_strings)];
1055 }
1056 
staff_primary_string(uint32_t p)1057 static const char* staff_primary_string(uint32_t p)
1058 {
1059     static const char* const primary_strings[] = {
1060         "glowing ", "jewelled ", "runed ", "smoking "
1061     };
1062     COMPILE_CHECK(NDSC_STAVE_PRI == ARRAYSZ(primary_strings));
1063     return primary_strings[p % ARRAYSZ(primary_strings)];
1064 }
1065 
staff_type_name(int stafftype)1066 static const char* staff_type_name(int stafftype)
1067 {
1068     switch ((stave_type)stafftype)
1069     {
1070     case STAFF_FIRE:        return "fire";
1071     case STAFF_COLD:        return "cold";
1072     case STAFF_POISON:      return "poison";
1073     case STAFF_DEATH:       return "death";
1074     case STAFF_CONJURATION: return "conjuration";
1075     case STAFF_AIR:         return "air";
1076     case STAFF_EARTH:       return "earth";
1077     default:                return item_type_removed(OBJ_STAVES, stafftype)
1078                                 ? "removedness"
1079                                 : "bugginess";
1080     }
1081 }
1082 
base_type_string(const item_def & item)1083 const char *base_type_string(const item_def &item)
1084 {
1085     return base_type_string(item.base_type);
1086 }
1087 
base_type_string(object_class_type type)1088 const char *base_type_string(object_class_type type)
1089 {
1090     switch (type)
1091     {
1092     case OBJ_WEAPONS: return "weapon";
1093     case OBJ_MISSILES: return "missile";
1094     case OBJ_ARMOUR: return "armour";
1095     case OBJ_WANDS: return "wand";
1096     case OBJ_SCROLLS: return "scroll";
1097     case OBJ_JEWELLERY: return "jewellery";
1098     case OBJ_POTIONS: return "potion";
1099     case OBJ_BOOKS: return "book";
1100     case OBJ_STAVES: return "staff";
1101 #if TAG_MAJOR_VERSION == 34
1102     case OBJ_RODS: return "removed rod";
1103 #endif
1104     case OBJ_ORBS: return "orb";
1105     case OBJ_MISCELLANY: return "miscellaneous";
1106     case OBJ_CORPSES: return "corpse";
1107     case OBJ_GOLD: return "gold";
1108     case OBJ_RUNES: return "rune";
1109     default: return "";
1110     }
1111 }
1112 
sub_type_string(const item_def & item,bool known)1113 string sub_type_string(const item_def &item, bool known)
1114 {
1115     const object_class_type type = item.base_type;
1116     const int sub_type = item.sub_type;
1117 
1118     switch (type)
1119     {
1120     case OBJ_WEAPONS:  // deliberate fall through, as XXX_prop is a local
1121     case OBJ_MISSILES: // variable to item-prop.cc.
1122     case OBJ_ARMOUR:
1123         return item_base_name(type, sub_type);
1124     case OBJ_WANDS: return _wand_type_name(sub_type);
1125     case OBJ_SCROLLS: return scroll_type_name(sub_type);
1126     case OBJ_JEWELLERY: return jewellery_type_name(sub_type);
1127     case OBJ_POTIONS: return potion_type_name(sub_type);
1128     case OBJ_BOOKS:
1129     {
1130         switch (sub_type)
1131         {
1132         case BOOK_MANUAL:
1133             {
1134             if (!known)
1135                 return "manual";
1136             string bookname = "manual of ";
1137             bookname += skill_name(static_cast<skill_type>(item.plus));
1138             return bookname;
1139             }
1140         case BOOK_NECRONOMICON:
1141             return "Necronomicon";
1142         case BOOK_GRAND_GRIMOIRE:
1143             return "Grand Grimoire";
1144 #if TAG_MAJOR_VERSION == 34
1145         case BOOK_BUGGY_DESTRUCTION:
1146             return "tome of obsoleteness";
1147 #endif
1148         case BOOK_EVERBURNING:
1149             // Aus. English apparently follows the US spelling, not UK.
1150             return "Everburning Encyclopedia";
1151         case BOOK_OZOCUBU:
1152             return "Ozocubu's Autobiography";
1153         case BOOK_YOUNG_POISONERS:
1154             return "Young Poisoner's Handbook";
1155         case BOOK_FEN:
1156             return "Fen Folio";
1157         case BOOK_NEARBY:
1158             return "Inescapable Atlas";
1159         case BOOK_THERE_AND_BACK:
1160             return "There-And-Back Book";
1161         case BOOK_BIOGRAPHIES_II:
1162             return "Great Wizards, Vol. II";
1163         case BOOK_BIOGRAPHIES_VII:
1164             return "Great Wizards, Vol. VII";
1165         case BOOK_TRISMEGISTUS:
1166             return "Trismegistus Codex";
1167         case BOOK_UNRESTRAINED:
1168             return "the Unrestrained Analects";
1169 #if TAG_MAJOR_VERSION == 34
1170         case BOOK_AKASHIC_RECORD:
1171             return "Akashic Record";
1172 #endif
1173         default:
1174             return string("book of ") + _book_type_name(sub_type);
1175         }
1176     }
1177     case OBJ_STAVES: return staff_type_name(static_cast<stave_type>(sub_type));
1178 #if TAG_MAJOR_VERSION == 34
1179     case OBJ_RODS:   return "removed rod";
1180 #endif
1181     case OBJ_MISCELLANY: return misc_type_name(sub_type);
1182     // these repeat as base_type_string
1183     case OBJ_ORBS: return "orb of Zot";
1184     case OBJ_CORPSES: return "corpse";
1185     case OBJ_GOLD: return "gold";
1186     case OBJ_RUNES: return "rune of Zot";
1187     default: return "";
1188     }
1189 }
1190 
1191 /**
1192  * What's the name for the weapon used by a given ghost / pan lord?
1193  *
1194  * There's no actual weapon info, just brand, so we have to improvise...
1195  *
1196  * @param brand     The brand_type used by the ghost or pan lord.
1197  * @param mtype     Monster type; determines whether the fake weapon is
1198  *                  described as a `weapon` or a `touch`.
1199  * @return          The name of the ghost's weapon (e.g. "weapon of flaming",
1200  *                  "antimagic weapon"). SPWPN_NORMAL returns "".
1201  */
ghost_brand_name(brand_type brand,monster_type mtype)1202 string ghost_brand_name(brand_type brand, monster_type mtype)
1203 {
1204     if (brand == SPWPN_NORMAL)
1205         return "";
1206     const bool weapon = mtype != MONS_PANDEMONIUM_LORD;
1207     if (weapon)
1208     {
1209         // n.b. vorpal only works if it is adjectival
1210         if (brand_prefers_adj.count(brand))
1211             return make_stringf("%s weapon", brand_type_adj(brand));
1212         else
1213             return make_stringf("weapon of %s", brand_type_name(brand, false));
1214     }
1215     else
1216         return make_stringf("%s touch", brand_type_adj(brand));
1217 }
1218 
ego_type_string(const item_def & item,bool terse)1219 string ego_type_string(const item_def &item, bool terse)
1220 {
1221     switch (item.base_type)
1222     {
1223     case OBJ_ARMOUR:
1224         return armour_ego_name(item, terse);
1225     case OBJ_WEAPONS:
1226         if (get_weapon_brand(item) != SPWPN_NORMAL)
1227             return weapon_brand_name(item, terse);
1228         else
1229             return "";
1230     case OBJ_MISSILES:
1231         // HACKHACKHACK
1232         if (item.props.exists(DAMNATION_BOLT_KEY))
1233             return "damnation";
1234         return missile_brand_name(item, terse ? MBN_TERSE : MBN_BRAND);
1235     case OBJ_JEWELLERY:
1236         return jewellery_effect_name(item.sub_type, terse);
1237     default:
1238         return "";
1239     }
1240 }
1241 
1242 /**
1243  * When naming the given item, should the base name be used?
1244  */
_use_basename(const item_def & item,description_level_type desc,bool ident)1245 static bool _use_basename(const item_def &item, description_level_type desc,
1246                           bool ident)
1247 {
1248     const bool know_type = ident || item_type_known(item);
1249     return desc == DESC_BASENAME
1250            || desc == DESC_DBNAME && !know_type;
1251 }
1252 
1253 /**
1254  * When naming the given item, should identifiable properties be mentioned?
1255  */
_know_any_ident(const item_def & item,description_level_type desc,bool ident)1256 static bool _know_any_ident(const item_def &item, description_level_type desc,
1257                             bool ident)
1258 {
1259     return desc != DESC_QUALNAME && desc != DESC_DBNAME
1260            && !_use_basename(item, desc, ident);
1261 }
1262 
1263 /**
1264  * When naming the given item, should the specified identifiable property be
1265  * mentioned?
1266  */
_know_ident(const item_def & item,description_level_type desc,bool ident,iflags_t ignore_flags,item_status_flag_type vprop)1267 static bool _know_ident(const item_def &item, description_level_type desc,
1268                         bool ident, iflags_t ignore_flags,
1269                         item_status_flag_type vprop)
1270 {
1271     return _know_any_ident(item, desc, ident)
1272             && !testbits(ignore_flags, vprop)
1273             && (ident || item_ident(item, vprop));
1274 }
1275 
1276 /**
1277  * When naming the given item, should the pluses be mentioned?
1278  */
_know_pluses(const item_def & item,description_level_type desc,bool ident,iflags_t ignore_flags)1279 static bool _know_pluses(const item_def &item, description_level_type desc,
1280                           bool ident, iflags_t ignore_flags)
1281 {
1282     return _know_ident(item, desc, ident, ignore_flags, ISFLAG_KNOW_PLUSES);
1283 }
1284 
1285 /**
1286  * When naming the given item, should the brand be mentioned?
1287  */
_know_ego(const item_def & item,description_level_type desc,bool ident,iflags_t ignore_flags)1288 static bool _know_ego(const item_def &item, description_level_type desc,
1289                          bool ident, iflags_t ignore_flags)
1290 {
1291     return _know_any_ident(item, desc, ident)
1292            && !testbits(ignore_flags, ISFLAG_KNOW_TYPE)
1293            && (ident || item_type_known(item));
1294 }
1295 
1296 /**
1297  * The plus-describing prefix to a weapon's name, including trailing space.
1298  */
_plus_prefix(const item_def & weap)1299 static string _plus_prefix(const item_def &weap)
1300 {
1301     if (is_unrandom_artefact(weap, UNRAND_WOE))
1302         return "+∞ ";
1303     return make_stringf("%+d ", weap.plus);
1304 }
1305 
1306 /**
1307  * Cosmetic text for weapons (e.g. glowing, runed). Includes trailing space,
1308  * if appropriate. (Empty if there is no cosmetic property, or if it's
1309  * marked to be ignored.)
1310  */
_cosmetic_text(const item_def & weap,iflags_t ignore_flags)1311 static string _cosmetic_text(const item_def &weap, iflags_t ignore_flags)
1312 {
1313     const iflags_t desc = get_equip_desc(weap);
1314     if (testbits(ignore_flags, desc))
1315         return "";
1316 
1317     switch (desc)
1318     {
1319         case ISFLAG_RUNED:
1320             return "runed ";
1321         case ISFLAG_GLOWING:
1322             return "glowing ";
1323         default:
1324             return "";
1325     }
1326 }
1327 
1328 /**
1329  * Surrounds a given string with the weapon's brand-describing prefix/suffix
1330  * as appropriate.
1331  */
weapon_brand_desc(const char * body,const item_def & weap,bool terse,brand_type override_brand)1332 string weapon_brand_desc(const char *body, const item_def &weap,
1333                          bool terse, brand_type override_brand)
1334 {
1335 
1336     const string brand_name = weapon_brand_name(weap, terse, override_brand);
1337 
1338     if (brand_name.empty())
1339         return body;
1340 
1341     if (terse)
1342         return make_stringf("%s (%s)", body, brand_name.c_str());
1343 
1344     const brand_type brand = override_brand ? override_brand :
1345                              get_weapon_brand(weap);
1346 
1347     if (brand_prefers_adj.count(brand))
1348         return make_stringf("%s %s", brand_type_adj(brand), body);
1349     else if (brand == SPWPN_NORMAL)
1350     {
1351         if (get_equip_desc(weap))
1352             return make_stringf("enchanted %s", body);
1353         else
1354             return body;
1355     }
1356     else
1357         return make_stringf("%s of %s", body, brand_name.c_str());
1358 }
1359 
1360 /**
1361  * Build the appropriate name for a given weapon.
1362  *
1363  * @param weap          The weapon in question.
1364  * @param desc          The type of name to provide. (E.g. the name to be used
1365  *                      in database lookups for description, or...)
1366  * @param terse         Whether to provide a terse version of the name for
1367  *                      display in the HUD.
1368  * @param ident         Whether the weapon should be named as if it were
1369  *                      identified.
1370  * @param inscr         Whether an inscription will be added later.
1371  * @param ignore_flags  Identification flags on the weapon to ignore.
1372  *
1373  * @return              A name for the weapon.
1374  *                      TODO: example
1375  */
_name_weapon(const item_def & weap,description_level_type desc,bool terse,bool ident,bool inscr,iflags_t ignore_flags)1376 static string _name_weapon(const item_def &weap, description_level_type desc,
1377                            bool terse, bool ident, bool inscr,
1378                            iflags_t ignore_flags)
1379 {
1380     const bool dbname   = (desc == DESC_DBNAME);
1381     const bool basename = _use_basename(weap, desc, ident);
1382     const bool qualname = (desc == DESC_QUALNAME);
1383 
1384     const bool know_pluses = _know_pluses(weap, desc, ident, ignore_flags);
1385     const bool know_ego =    _know_ego(weap, desc, ident, ignore_flags);
1386 
1387     const string curse_prefix = !dbname && !terse && weap.cursed() ? "cursed " : "";
1388     const string plus_text = know_pluses ? _plus_prefix(weap) : "";
1389 
1390     if (is_artefact(weap) && !dbname)
1391     {
1392         const string long_name = curse_prefix + plus_text
1393                                  + get_artefact_name(weap, ident);
1394 
1395         // crop long artefact names when not controlled by webtiles -
1396         // webtiles displays weapon names across multiple lines
1397 #ifdef USE_TILE_WEB
1398         if (!tiles.is_controlled_from_web())
1399 #endif
1400         {
1401             const bool has_inscript = desc != DESC_BASENAME
1402                                    && desc != DESC_DBNAME
1403                                    && inscr;
1404             const string inscription = _item_inscription(weap);
1405 
1406             const int total_length = long_name.size()
1407                                      + (has_inscript ? inscription.size() : 0);
1408             const string inv_slot_text = "x) ";
1409             const int max_length = crawl_view.hudsz.x - inv_slot_text.size();
1410             if (!terse || total_length <= max_length)
1411                 return long_name;
1412         }
1413 #ifdef USE_TILE_WEB
1414         else
1415             return long_name;
1416 #endif
1417 
1418         // special case: these two shouldn't ever have their base name revealed
1419         // (since showing 'eudaemon blade' is unhelpful in the former case, and
1420         // showing 'broad axe' is misleading in the latter)
1421         // could be a flag, but doesn't seem worthwhile for only two items
1422         if (is_unrandom_artefact(weap, UNRAND_ZEALOT_SWORD)
1423             || is_unrandom_artefact(weap, UNRAND_DEMON_AXE))
1424         {
1425             return long_name;
1426         }
1427 
1428         const string short_name
1429             = curse_prefix + plus_text + get_artefact_base_name(weap, true);
1430         return short_name;
1431     }
1432 
1433     const bool show_cosmetic = !basename && !qualname && !dbname
1434                                && !know_pluses && !know_ego
1435                                && !terse
1436                                && !(ignore_flags & ISFLAG_COSMETIC_MASK);
1437 
1438     const string cosmetic_text
1439         = show_cosmetic ? _cosmetic_text(weap, ignore_flags) : "";
1440     const string base_name = item_base_name(weap);
1441     const string name_with_ego
1442         = know_ego ? weapon_brand_desc(base_name.c_str(), weap, terse)
1443         : base_name;
1444     const string curse_suffix
1445         = weap.cursed() && terse && !dbname && !qualname ? " (curse)" :  "";
1446     return curse_prefix + plus_text + cosmetic_text
1447            + name_with_ego + curse_suffix;
1448 }
1449 
1450 // Note that "terse" is only currently used for the "in hand" listing on
1451 // the game screen.
name_aux(description_level_type desc,bool terse,bool ident,bool with_inscription,iflags_t ignore_flags) const1452 string item_def::name_aux(description_level_type desc, bool terse, bool ident,
1453                           bool with_inscription, iflags_t ignore_flags) const
1454 {
1455     // Shortcuts
1456     const int item_typ   = sub_type;
1457 
1458     const bool know_type = ident || item_type_known(*this);
1459 
1460     const bool dbname   = (desc == DESC_DBNAME);
1461     const bool basename = _use_basename(*this, desc, ident);
1462     const bool qualname = (desc == DESC_QUALNAME);
1463 
1464     const bool know_pluses = _know_pluses(*this, desc, ident, ignore_flags);
1465     const bool know_brand =  _know_ego(*this, desc, ident, ignore_flags);
1466 
1467     const bool know_ego = know_brand;
1468 
1469     // Display runed/glowing/embroidered etc?
1470     // Only display this if brand is unknown.
1471     const bool show_cosmetic = !know_pluses && !know_brand
1472                                && !basename && !qualname && !dbname
1473                                && !terse
1474                                && !(ignore_flags & ISFLAG_COSMETIC_MASK);
1475 
1476     const bool need_plural = !basename && !dbname;
1477 
1478     ostringstream buff;
1479 
1480     switch (base_type)
1481     {
1482     case OBJ_WEAPONS:
1483         buff << _name_weapon(*this, desc, terse, ident, with_inscription,
1484                              ignore_flags);
1485         break;
1486 
1487     case OBJ_MISSILES:
1488     {
1489         special_missile_type msl_brand = get_ammo_brand(*this);
1490 
1491         if (!terse && !dbname && !basename)
1492         {
1493             if (props.exists(DAMNATION_BOLT_KEY)) // hack alert
1494                 buff << "damnation ";
1495             else if (_missile_brand_is_prefix(msl_brand)) // see below for postfix brands
1496                 buff << missile_brand_name(*this, MBN_NAME) << ' ';
1497         }
1498 
1499         buff << ammo_name(static_cast<missile_type>(item_typ));
1500 
1501         if (msl_brand != SPMSL_NORMAL
1502             && !basename && !dbname)
1503         {
1504             if (terse)
1505             {
1506                 if (props.exists(DAMNATION_BOLT_KEY)) // still a hack
1507                     buff << " (damnation)";
1508                 else
1509                     buff << " (" <<  missile_brand_name(*this, MBN_TERSE) << ")";
1510             }
1511             else if (_missile_brand_is_postfix(msl_brand)) // see above for prefix brands
1512                 buff << " of " << missile_brand_name(*this, MBN_NAME);
1513         }
1514 
1515         break;
1516     }
1517     case OBJ_ARMOUR:
1518         if (!terse && cursed())
1519             buff << "cursed ";
1520 
1521         // If we know enough to know it has *something* ('shiny' etc),
1522         // but we know it has no ego, it must have a plus. (or maybe a curse.)
1523         // If we don't know what the plus is, call it 'enchanted'.
1524         if (!terse && know_ego && get_armour_ego_type(*this) == SPARM_NORMAL &&
1525             !know_pluses && !is_artefact(*this) && get_equip_desc(*this))
1526         {
1527             buff << "enchanted ";
1528         }
1529 
1530         // Don't list unenchantable armor as +0.
1531         if (know_pluses && armour_is_enchantable(*this))
1532             buff << make_stringf("%+d ", plus);
1533 
1534         if (item_typ == ARM_GLOVES || item_typ == ARM_BOOTS)
1535             buff << "pair of ";
1536 
1537         if (is_artefact(*this) && !dbname)
1538         {
1539             buff << get_artefact_name(*this, ident);
1540             break;
1541         }
1542 
1543         if (show_cosmetic)
1544         {
1545             switch (get_equip_desc(*this))
1546             {
1547             case ISFLAG_EMBROIDERED_SHINY:
1548                 if (testbits(ignore_flags, ISFLAG_EMBROIDERED_SHINY))
1549                     break;
1550                 if (item_typ == ARM_ROBE || item_typ == ARM_CLOAK
1551                     || item_typ == ARM_GLOVES || item_typ == ARM_BOOTS
1552                     || item_typ == ARM_SCARF
1553                     || get_armour_slot(*this) == EQ_HELMET
1554                        && !is_hard_helmet(*this))
1555                 {
1556                     buff << "embroidered ";
1557                 }
1558                 else if (item_typ != ARM_LEATHER_ARMOUR
1559                          && item_typ != ARM_ANIMAL_SKIN)
1560                 {
1561                     buff << "shiny ";
1562                 }
1563                 else
1564                     buff << "dyed ";
1565                 break;
1566 
1567             case ISFLAG_RUNED:
1568                 if (!testbits(ignore_flags, ISFLAG_RUNED))
1569                     buff << "runed ";
1570                 break;
1571 
1572             case ISFLAG_GLOWING:
1573                 if (!testbits(ignore_flags, ISFLAG_GLOWING))
1574                     buff << "glowing ";
1575                 break;
1576             }
1577         }
1578 
1579         buff << item_base_name(*this);
1580 
1581         if (know_ego && !is_artefact(*this))
1582         {
1583             const special_armour_type sparm = get_armour_ego_type(*this);
1584 
1585             if (sparm != SPARM_NORMAL)
1586             {
1587                 if (!terse)
1588                     buff << " of ";
1589                 else
1590                     buff << " {";
1591                 buff << armour_ego_name(*this, terse);
1592                 if (terse)
1593                     buff << "}";
1594             }
1595         }
1596 
1597         if (cursed() && terse && !dbname && !qualname)
1598             buff << " (curse)";
1599         break;
1600 
1601     case OBJ_WANDS:
1602         if (basename)
1603         {
1604             buff << "wand";
1605             break;
1606         }
1607 
1608         if (know_type)
1609             buff << "wand of " << _wand_type_name(item_typ);
1610         else
1611         {
1612             buff << wand_secondary_string(subtype_rnd / NDSC_WAND_PRI)
1613                  << wand_primary_string(subtype_rnd % NDSC_WAND_PRI)
1614                  << " wand";
1615         }
1616 
1617         if (dbname)
1618             break;
1619 
1620         if (know_type && charges > 0)
1621             buff << " (" << charges << ")";
1622 
1623         break;
1624 
1625     case OBJ_POTIONS:
1626         if (basename)
1627         {
1628             buff << "potion";
1629             break;
1630         }
1631 
1632         if (know_type)
1633             buff << "potion of " << potion_type_name(item_typ);
1634         else
1635         {
1636             const int pqual   = PQUAL(subtype_rnd);
1637             const int pcolour = PCOLOUR(subtype_rnd);
1638 
1639             static const char *potion_qualifiers[] =
1640             {
1641                 "",  "bubbling ", "fuming ", "fizzy ", "viscous ", "lumpy ",
1642                 "smoky ", "glowing ", "sedimented ", "metallic ", "murky ",
1643                 "gluggy ", "oily ", "slimy ", "emulsified ",
1644             };
1645             COMPILE_CHECK(ARRAYSZ(potion_qualifiers) == PDQ_NQUALS);
1646 
1647             static const char *potion_colours[] =
1648             {
1649 #if TAG_MAJOR_VERSION == 34
1650                 "clear",
1651 #endif
1652                 "blue", "black", "silvery", "cyan", "purple", "orange",
1653                 "inky", "red", "yellow", "green", "brown", "ruby", "white",
1654                 "emerald", "grey", "pink", "coppery", "golden", "dark", "puce",
1655                 "amethyst", "sapphire",
1656             };
1657             COMPILE_CHECK(ARRAYSZ(potion_colours) == PDC_NCOLOURS);
1658 
1659             const char *qualifier =
1660                 (pqual < 0 || pqual >= PDQ_NQUALS) ? "bug-filled "
1661                                     : potion_qualifiers[pqual];
1662 
1663             const char *clr =  (pcolour < 0 || pcolour >= PDC_NCOLOURS) ?
1664                                    "bogus" : potion_colours[pcolour];
1665 
1666             buff << qualifier << clr << " potion";
1667         }
1668         break;
1669 
1670 #if TAG_MAJOR_VERSION == 34
1671     case OBJ_FOOD:
1672         buff << "removed food"; break;
1673         break;
1674 #endif
1675 
1676     case OBJ_SCROLLS:
1677         buff << "scroll";
1678         if (basename)
1679             break;
1680         else
1681             buff << " ";
1682 
1683         if (know_type)
1684             buff << "of " << scroll_type_name(item_typ);
1685         else
1686             buff << "labelled " << make_name(subtype_rnd, MNAME_SCROLL);
1687         break;
1688 
1689     case OBJ_JEWELLERY:
1690     {
1691         if (basename)
1692         {
1693             if (jewellery_is_amulet(*this))
1694                 buff << "amulet";
1695             else
1696                 buff << "ring";
1697 
1698             break;
1699         }
1700 
1701         const bool is_randart = is_artefact(*this);
1702 
1703         if (!terse && cursed())
1704             buff << "cursed ";
1705 
1706         if (is_randart && !dbname)
1707         {
1708             buff << get_artefact_name(*this, ident);
1709             break;
1710         }
1711 
1712         if (know_type)
1713         {
1714             if (!dbname && jewellery_has_pluses(*this))
1715                 buff << make_stringf("%+d ", plus);
1716 
1717             buff << jewellery_type_name(item_typ);
1718         }
1719         else
1720         {
1721             if (jewellery_is_amulet(*this))
1722             {
1723                 buff << amulet_secondary_string(subtype_rnd / NDSC_JEWEL_PRI)
1724                      << amulet_primary_string(subtype_rnd % NDSC_JEWEL_PRI)
1725                      << " amulet";
1726             }
1727             else  // i.e., a ring
1728             {
1729                 buff << ring_secondary_string(subtype_rnd / NDSC_JEWEL_PRI)
1730                      << ring_primary_string(subtype_rnd % NDSC_JEWEL_PRI)
1731                      << " ring";
1732             }
1733         }
1734         if (cursed() && terse && !dbname && !qualname)
1735             buff << " (curse)";
1736         break;
1737     }
1738     case OBJ_MISCELLANY:
1739     {
1740         if (!dbname && item_typ == MISC_ZIGGURAT && you.zigs_completed > 0)
1741             buff << "+" << you.zigs_completed << " ";
1742 
1743         buff << misc_type_name(item_typ);
1744 
1745         if (is_xp_evoker(*this) && !dbname && !evoker_charges(sub_type))
1746             buff << " (inert)";
1747         else if (is_xp_evoker(*this) &&
1748                  !dbname && evoker_max_charges(sub_type) > 1)
1749         {
1750             buff << " (" << evoker_charges(sub_type) << "/"
1751                  << evoker_max_charges(sub_type) << ")";
1752         }
1753 
1754         break;
1755     }
1756 
1757     case OBJ_BOOKS:
1758         if (is_random_artefact(*this) && !dbname && !basename)
1759         {
1760             buff << get_artefact_name(*this, ident);
1761             break;
1762         }
1763         if (basename)
1764             buff << (item_typ == BOOK_MANUAL ? "manual" : "book");
1765         else
1766             buff << sub_type_string(*this, !dbname);
1767         break;
1768 
1769 #if TAG_MAJOR_VERSION == 34
1770     case OBJ_RODS:
1771         buff << "removed rod";
1772         break;
1773 #endif
1774 
1775     case OBJ_STAVES:
1776         if (!terse && cursed())
1777             buff << "cursed ";
1778 
1779         if (!know_type)
1780         {
1781             if (!basename)
1782             {
1783                 buff << staff_secondary_string(subtype_rnd / NDSC_STAVE_PRI)
1784                      << staff_primary_string(subtype_rnd % NDSC_STAVE_PRI);
1785             }
1786 
1787             buff << "staff";
1788         }
1789         else
1790             buff << "staff of " << staff_type_name(item_typ);
1791 
1792         if (cursed() && terse && !dbname && !qualname)
1793             buff << " (curse)";
1794         break;
1795 
1796     // rearranged 15 Apr 2000 {dlb}:
1797     case OBJ_ORBS:
1798         buff.str("Orb of Zot");
1799         break;
1800 
1801     case OBJ_RUNES:
1802         if (!dbname)
1803             buff << rune_type_name(sub_type) << " ";
1804         buff << "rune of Zot";
1805         break;
1806 
1807     case OBJ_GOLD:
1808         buff << "gold piece";
1809         break;
1810 
1811     case OBJ_CORPSES:
1812     {
1813         if (dbname && item_typ == CORPSE_SKELETON)
1814             return "decaying skeleton";
1815 
1816         monster_flags_t name_flags;
1817         const string _name = get_corpse_name(*this, &name_flags);
1818         const monster_flags_t name_type = name_flags & MF_NAME_MASK;
1819 
1820         const bool shaped = starts_with(_name, "shaped ");
1821 
1822         if (!_name.empty() && name_type == MF_NAME_ADJECTIVE)
1823             buff << _name << " ";
1824 
1825         if ((name_flags & MF_NAME_SPECIES) && name_type == MF_NAME_REPLACE)
1826             buff << _name << " ";
1827         else if (!dbname && !starts_with(_name, "the "))
1828         {
1829             const monster_type mc = mon_type;
1830             if (!(mons_is_unique(mc) && mons_species(mc) == mc))
1831                 buff << mons_type_name(mc, DESC_PLAIN) << ' ';
1832 
1833             if (!_name.empty() && shaped)
1834                 buff << _name << ' ';
1835         }
1836 
1837         if (item_typ == CORPSE_BODY)
1838             buff << "corpse";
1839         else if (item_typ == CORPSE_SKELETON)
1840             buff << "skeleton";
1841         else
1842             buff << "corpse bug";
1843 
1844         if (!_name.empty() && !shaped && name_type != MF_NAME_ADJECTIVE
1845             && !(name_flags & MF_NAME_SPECIES) && name_type != MF_NAME_SUFFIX
1846             && !dbname)
1847         {
1848             buff << " of " << _name;
1849         }
1850         break;
1851     }
1852 
1853     default:
1854         buff << "!";
1855     }
1856 
1857     // One plural to rule them all.
1858     if (need_plural && quantity > 1 && !basename && !qualname)
1859         buff.str(pluralise(buff.str()));
1860 
1861     // debugging output -- oops, I probably block it above ... dang! {dlb}
1862     if (buff.str().length() < 3)
1863     {
1864         buff << "bad item (cl:" << static_cast<int>(base_type)
1865              << ",ty:" << item_typ << ",pl:" << plus
1866              << ",pl2:" << plus2 << ",sp:" << special
1867              << ",qu:" << quantity << ")";
1868     }
1869 
1870     return buff.str();
1871 }
1872 
1873 // WARNING: You can break save compatibility if you edit this without
1874 // amending tags.cc to properly marshall the change.
item_type_has_ids(object_class_type base_type)1875 bool item_type_has_ids(object_class_type base_type)
1876 {
1877     COMPILE_CHECK(NUM_WEAPONS    < MAX_SUBTYPES);
1878     COMPILE_CHECK(NUM_MISSILES   < MAX_SUBTYPES);
1879     COMPILE_CHECK(NUM_ARMOURS    < MAX_SUBTYPES);
1880     COMPILE_CHECK(NUM_WANDS      < MAX_SUBTYPES);
1881     COMPILE_CHECK(NUM_SCROLLS    < MAX_SUBTYPES);
1882     COMPILE_CHECK(NUM_JEWELLERY  < MAX_SUBTYPES);
1883     COMPILE_CHECK(NUM_POTIONS    < MAX_SUBTYPES);
1884     COMPILE_CHECK(NUM_STAVES     < MAX_SUBTYPES);
1885     COMPILE_CHECK(NUM_MISCELLANY < MAX_SUBTYPES);
1886 #if TAG_MAJOR_VERSION == 34
1887     COMPILE_CHECK(NUM_RODS       < MAX_SUBTYPES);
1888     COMPILE_CHECK(NUM_FOODS      < MAX_SUBTYPES);
1889 #endif
1890 
1891     return base_type == OBJ_WANDS || base_type == OBJ_SCROLLS
1892         || base_type == OBJ_JEWELLERY || base_type == OBJ_POTIONS
1893         || base_type == OBJ_STAVES;
1894 }
1895 
item_brand_known(const item_def & item)1896 bool item_brand_known(const item_def& item)
1897 {
1898     return item_ident(item, ISFLAG_KNOW_TYPE)
1899            || is_artefact(item)
1900            && artefact_known_property(item, ARTP_BRAND);
1901 }
1902 
item_type_known(const item_def & item)1903 bool item_type_known(const item_def& item)
1904 {
1905     if (item_ident(item, ISFLAG_KNOW_TYPE))
1906         return true;
1907 
1908     switch (item.base_type)
1909     {
1910     case OBJ_MISCELLANY:
1911     case OBJ_MISSILES:
1912     case OBJ_BOOKS:
1913         return true;
1914     default:
1915         break;
1916     }
1917 
1918     // Artefacts have different descriptions from other items,
1919     // so we can't use general item knowledge for them.
1920     if (is_artefact(item))
1921         return false;
1922 
1923     if (!item_type_has_ids(item.base_type))
1924         return false;
1925     return you.type_ids[item.base_type][item.sub_type];
1926 }
1927 
item_type_unknown(const item_def & item)1928 bool item_type_unknown(const item_def& item)
1929 {
1930     if (item_type_known(item))
1931         return false;
1932 
1933     if (is_artefact(item))
1934         return true;
1935 
1936     return item_type_has_ids(item.base_type);
1937 }
1938 
item_type_known(const object_class_type base_type,const int sub_type)1939 bool item_type_known(const object_class_type base_type, const int sub_type)
1940 {
1941     if (!item_type_has_ids(base_type))
1942         return false;
1943     return you.type_ids[base_type][sub_type];
1944 }
1945 
set_ident_type(item_def & item,bool identify)1946 bool set_ident_type(item_def &item, bool identify)
1947 {
1948     if (is_artefact(item) || crawl_state.game_is_arena())
1949         return false;
1950 
1951     if (!set_ident_type(item.base_type, item.sub_type, identify))
1952         return false;
1953 
1954     if (in_inventory(item))
1955     {
1956         shopping_list.cull_identical_items(item);
1957         if (identify)
1958             item_skills(item, you.skills_to_show);
1959     }
1960 
1961     if (identify && notes_are_active()
1962         && is_interesting_item(item)
1963         && !(item.flags & (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET)))
1964     {
1965         // Make a note of it.
1966         take_note(Note(NOTE_ID_ITEM, 0, 0, item.name(DESC_A),
1967                        origin_desc(item)));
1968 
1969         // Sometimes (e.g. shops) you can ID an item before you get it;
1970         // don't note twice in those cases.
1971         item.flags |= (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET);
1972     }
1973 
1974     return true;
1975 }
1976 
set_ident_type(object_class_type basetype,int subtype,bool identify)1977 bool set_ident_type(object_class_type basetype, int subtype, bool identify)
1978 {
1979     if (!item_type_has_ids(basetype))
1980         return false;
1981 
1982     if (you.type_ids[basetype][subtype] == identify)
1983         return false;
1984 
1985     you.type_ids[basetype][subtype] = identify;
1986     request_autoinscribe();
1987 
1988     // Our item knowledge changed in a way that could possibly affect shop
1989     // prices.
1990     shopping_list.item_type_identified(basetype, subtype);
1991 
1992     // We identified something, maybe we identified other things by process of
1993     // elimination.
1994     if (identify && !(you.pending_revival || crawl_state.updating_scores))
1995         _maybe_identify_pack_item();
1996 
1997     return true;
1998 }
1999 
pack_item_identify_message(int base_type,int sub_type)2000 void pack_item_identify_message(int base_type, int sub_type)
2001 {
2002     for (const auto &item : you.inv)
2003         if (item.defined() && item.is_type(base_type, sub_type))
2004             mprf_nocap("%s", item.name(DESC_INVENTORY_EQUIP).c_str());
2005 }
2006 
get_ident_type(const item_def & item)2007 bool get_ident_type(const item_def &item)
2008 {
2009     if (is_artefact(item))
2010         return false;
2011 
2012     return get_ident_type(item.base_type, item.sub_type);
2013 }
2014 
get_ident_type(object_class_type basetype,int subtype)2015 bool get_ident_type(object_class_type basetype, int subtype)
2016 {
2017     if (!item_type_has_ids(basetype))
2018         return false;
2019     ASSERT(subtype < MAX_SUBTYPES);
2020     return you.type_ids[basetype][subtype];
2021 }
2022 
_fixup_runeorb_entry(MenuEntry * me)2023 static MenuEntry* _fixup_runeorb_entry(MenuEntry* me)
2024 {
2025     auto entry = static_cast<InvEntry*>(me);
2026     ASSERT(entry);
2027 
2028     if (entry->item->base_type == OBJ_RUNES)
2029     {
2030         auto rune = static_cast<rune_type>(entry->item->sub_type);
2031         colour_t colour;
2032         // Make Gloorx's rune more distinguishable from uncollected runes.
2033         if (you.runes[rune])
2034         {
2035             colour = (rune == RUNE_GLOORX_VLOQ) ? colour_t{LIGHTGREY}
2036                                                 : rune_colour(rune);
2037         }
2038         else
2039             colour = DARKGREY;
2040 
2041         string text = "<";
2042         text += colour_to_str(colour);
2043         text += ">";
2044         text += rune_type_name(rune);
2045         text += " rune of Zot";
2046         if (!you.runes[rune])
2047         {
2048             text += " (";
2049             text += branches[rune_location(rune)].longname;
2050             text += ")";
2051         }
2052         text += "</";
2053         text += colour_to_str(colour);
2054         text += ">";
2055         entry->text = text;
2056     }
2057     else if (entry->item->is_type(OBJ_ORBS, ORB_ZOT))
2058     {
2059         if (player_has_orb())
2060             entry->text = "<magenta>The Orb of Zot</magenta>";
2061         else
2062         {
2063             entry->text = "<darkgrey>The Orb of Zot"
2064                           " (the Realm of Zot)</darkgrey>";
2065         }
2066     }
2067 
2068     return entry;
2069 }
2070 
display_runes()2071 void display_runes()
2072 {
2073     auto col = runes_in_pack() < ZOT_ENTRY_RUNES ?  "lightgrey" :
2074                runes_in_pack() < you.obtainable_runes ? "green" :
2075                                                    "lightgreen";
2076 
2077     auto title = make_stringf("<white>Runes of Zot (</white>"
2078                               "<%s>%d</%s><white> collected) & Orbs of Power</white>",
2079                               col, runes_in_pack(), col);
2080 
2081     InvMenu menu(MF_NOSELECT | MF_ALLOW_FORMATTING);
2082 
2083     menu.set_title(title);
2084 
2085     vector<item_def> items;
2086 
2087     if (!crawl_state.game_is_sprint())
2088     {
2089         // Add the runes in order of challenge (semi-arbitrary).
2090         for (branch_iterator it(branch_iterator_type::danger); it; ++it)
2091         {
2092             const branch_type br = it->id;
2093             if (!connected_branch_can_exist(br))
2094                 continue;
2095 
2096             for (auto rune : branches[br].runes)
2097             {
2098                 item_def item;
2099                 item.base_type = OBJ_RUNES;
2100                 item.sub_type = rune;
2101                 item.quantity = you.runes[rune] ? 1 : 0;
2102                 item_colour(item);
2103                 items.push_back(item);
2104             }
2105         }
2106     }
2107     else
2108     {
2109         // We don't know what runes are accessible in the sprint, so just show
2110         // the ones you have. We can't iterate over branches as above since the
2111         // elven rune and mossy rune may exist in sprint.
2112         for (int i = 0; i < NUM_RUNE_TYPES; ++i)
2113         {
2114             if (you.runes[i])
2115             {
2116                 item_def item;
2117                 item.base_type = OBJ_RUNES;
2118                 item.sub_type = i;
2119                 item.quantity = 1;
2120                 item_colour(item);
2121                 items.push_back(item);
2122             }
2123         }
2124     }
2125     item_def item;
2126     item.base_type = OBJ_ORBS;
2127     item.sub_type = ORB_ZOT;
2128     item.quantity = player_has_orb() ? 1 : 0;
2129     items.push_back(item);
2130 
2131     // We've sorted this vector already, so disable menu sorting. Maybe we
2132     // could a menu entry comparator and modify InvMenu::load_items() to allow
2133     // passing this in instead of doing a sort ahead of time.
2134     menu.load_items(items, _fixup_runeorb_entry, 0, false);
2135 
2136     menu.show();
2137 }
2138 
2139 // Seed ranges for _random_consonant_set: (B)eginning and one-past-the-(E)nd
2140 // of the (B)eginning, (E)nding, and (M)iddle cluster ranges.
2141 const size_t RCS_BB = 0;
2142 const size_t RCS_EB = 27;
2143 const size_t RCS_BE = 14;
2144 const size_t RCS_EE = 56;
2145 const size_t RCS_BM = 0;
2146 const size_t RCS_EM = 67;
2147 const size_t RCS_END = RCS_EM;
2148 
2149 #define ITEMNAME_SIZE 200
2150 /**
2151  * Make a random name from the given seed.
2152  *
2153  * Used for: Pandemonium demonlords, shopkeepers, scrolls, random artefacts.
2154  *
2155  * This function is insane, but that might be useful.
2156  *
2157  * @param seed      The seed to generate the name from.
2158  *                  The same seed will always generate the same name.
2159  *                  By default a random number from the current RNG.
2160  * @param name_type The type of name to be generated.
2161  *                  If MNAME_SCROLL, increase length by 6 and force to allcaps.
2162  *                  If MNAME_JIYVA, start with J, do not generate spaces,
2163  *                  recurse instead of ploggifying, and cap length at 8.
2164  *                  Otherwise, no special behaviour.
2165  * @return          A randomly generated name.
2166  *                  E.g. "Joiduir", "Jays Fya", ZEFOKY WECZYXE,
2167  *                  THE GIAGGOSTUONO, etc.
2168  */
make_name(uint32_t seed,makename_type name_type)2169 string make_name(uint32_t seed, makename_type name_type)
2170 {
2171     // use the seed to select sequence, rather than seed per se. This is
2172     // because it is not important that the sequence be randomly distributed
2173     // in uint64_t.
2174     rng::subgenerator subgen(you.game_seed, static_cast<uint64_t>(seed));
2175 
2176     string name;
2177 
2178     bool has_space  = false; // Keep track of whether the name contains a space.
2179 
2180     size_t len = 3;
2181     len += random2(5);
2182     len += (random2(5) == 0) ? random2(6) : 1;
2183 
2184     if (name_type == MNAME_SCROLL)   // scrolls have longer names
2185         len += 6;
2186 
2187     const size_t maxlen = name_type == MNAME_JIYVA ? 8 : SIZE_MAX;
2188     len = min(len, maxlen);
2189 
2190     ASSERT_RANGE(len, 1, ITEMNAME_SIZE + 1);
2191 
2192     static const int MAX_ITERS = 150;
2193     for (int iters = 0; iters < MAX_ITERS && name.length() < len; ++iters)
2194     {
2195         const char prev_char = name.length() ? name[name.length() - 1]
2196                                               : '\0';
2197         const char penult_char = name.length() > 1 ? name[name.length() - 2]
2198                                                     : '\0';
2199         if (name.empty() && name_type == MNAME_JIYVA)
2200         {
2201             // Start the name with a predefined letter.
2202             name += 'j';
2203         }
2204         else if (name.empty() || prev_char == ' ')
2205         {
2206             // Start the word with any letter.
2207             name += 'a' + random2(26);
2208         }
2209         else if (!has_space && name_type != MNAME_JIYVA
2210                  && name.length() > 5 && name.length() < len - 4
2211                  && random2(5) != 0) // 4/5 chance
2212         {
2213              // Hand out a space.
2214             name += ' ';
2215         }
2216         else if (name.length()
2217                  && (_is_consonant(prev_char)
2218                      || (name.length() > 1
2219                          && !_is_consonant(prev_char)
2220                          && _is_consonant(penult_char)
2221                          && random2(5) <= 1))) // 2/5
2222         {
2223             // Place a vowel.
2224             const char vowel = _random_vowel();
2225 
2226             if (vowel == ' ')
2227             {
2228                 if (len < 7
2229                          || name.length() <= 2 || name.length() >= len - 3
2230                          || prev_char == ' ' || penult_char == ' '
2231                          || name_type == MNAME_JIYVA
2232                          || name.length() > 2
2233                             && _is_consonant(prev_char)
2234                             && _is_consonant(penult_char))
2235                 {
2236                     // Replace the space with something else if ...
2237                     // * the name is really short
2238                     // * we're close to the start/end of the name
2239                     // * we just got a space
2240                     // * we're generating a jiyva name, or
2241                     // * the last two letters were consonants
2242                     continue;
2243                 }
2244             }
2245             else if (name.length() > 1
2246                      && vowel == prev_char
2247                      && (vowel == 'y' || vowel == 'i'
2248                          || random2(5) <= 1))
2249             {
2250                 // Replace the vowel with something else if the previous
2251                 // letter was the same, and it's a 'y', 'i' or with 2/5 chance.
2252                 continue;
2253             }
2254 
2255             name += vowel;
2256         }
2257         else // We want a consonant.
2258         {
2259             // Are we at start or end of the (sub) name?
2260             const bool beg = (name.empty() || prev_char == ' ');
2261             const bool end = (name.length() >= len - 2);
2262 
2263             // Use one of number of predefined letter combinations.
2264             if ((len > 3 || !name.empty())
2265                 && random2(7) <= 1 // 2/7 chance
2266                 && (!beg || !end))
2267             {
2268                 const int first = (beg ? RCS_BB : (end ? RCS_BE : RCS_BM));
2269                 const int last  = (beg ? RCS_EB : (end ? RCS_EE : RCS_EM));
2270 
2271                 const int range = last - first;
2272 
2273                 const int cons_seed = random2(range) + first;
2274 
2275                 const string consonant_set = _random_consonant_set(cons_seed);
2276 
2277                 ASSERT(consonant_set.size() > 1);
2278                 len += consonant_set.size() - 2; // triples increase len
2279                 name += consonant_set;
2280             }
2281             else // Place a single letter instead.
2282             {
2283                 // Pick a random consonant.
2284                 name += _random_cons();
2285             }
2286         }
2287 
2288         if (name[name.length() - 1] == ' ')
2289         {
2290             ASSERT(name_type != MNAME_JIYVA);
2291             has_space = true;
2292         }
2293     }
2294 
2295     // Catch early exit and try to give a final letter.
2296     const char last_char = name[name.length() - 1];
2297     if (!name.empty()
2298         && last_char != ' '
2299         && last_char != 'y'
2300         && !_is_consonant(name[name.length() - 1])
2301         && (name.length() < len    // early exit
2302             || (len < 8
2303                 && random2(3) != 0))) // 2/3 chance for other short names
2304     {
2305         // Specifically, add a consonant.
2306         name += _random_cons();
2307     }
2308 
2309     if (maxlen != SIZE_MAX)
2310         name = chop_string(name, maxlen);
2311     trim_string_right(name);
2312 
2313     // Fallback if the name was too short.
2314     if (name.length() < 4)
2315     {
2316         // convolute & recurse
2317         if (name_type == MNAME_JIYVA)
2318             return make_name(rng::get_uint32(), MNAME_JIYVA);
2319 
2320         name = "plog";
2321     }
2322 
2323     string uppercased_name;
2324     for (size_t i = 0; i < name.length(); i++)
2325     {
2326         if (name_type == MNAME_JIYVA)
2327             ASSERT(name[i] != ' ');
2328 
2329         if (name_type == MNAME_SCROLL || i == 0 || name[i - 1] == ' ')
2330             uppercased_name += toupper_safe(name[i]);
2331         else
2332             uppercased_name += name[i];
2333     }
2334 
2335     return uppercased_name;
2336 }
2337 #undef ITEMNAME_SIZE
2338 
2339 /**
2340  * Is the given character a lower-case ascii consonant?
2341  *
2342  * For our purposes, y is not a consonant.
2343  */
_is_consonant(char let)2344 static bool _is_consonant(char let)
2345 {
2346     static const set<char> all_consonants = { 'b', 'c', 'd', 'f', 'g',
2347                                               'h', 'j', 'k', 'l', 'm',
2348                                               'n', 'p', 'q', 'r', 's',
2349                                               't', 'v', 'w', 'x', 'z' };
2350     return all_consonants.count(let);
2351 }
2352 
2353 // Returns a random vowel (a, e, i, o, u with equal probability) or space
2354 // or 'y' with lower chances.
_random_vowel()2355 static char _random_vowel()
2356 {
2357     static const char vowels[] = "aeiouaeiouaeiouy  ";
2358     return vowels[random2(sizeof(vowels) - 1)];
2359 }
2360 
2361 // Returns a random consonant with not quite equal probability.
2362 // Does not include 'y'.
_random_cons()2363 static char _random_cons()
2364 {
2365     static const char consonants[] = "bcdfghjklmnpqrstvwxzcdfghlmnrstlmnrst";
2366     return consonants[random2(sizeof(consonants) - 1)];
2367 }
2368 
2369 /**
2370  * Choose a random consonant tuple/triple, based on the given seed.
2371  *
2372  * @param seed  The index into the consonant array; different seed ranges are
2373  *              expected to correspond with the place in the name being
2374  *              generated where the consonants should be inserted.
2375  * @return      A random length 2 or 3 consonant set; e.g. "kl", "str", etc.
2376  *              If the seed is out of bounds, return "";
2377  */
_random_consonant_set(size_t c)2378 static string _random_consonant_set(size_t c)
2379 {
2380     // Pick a random combination of consonants from the set below.
2381     //   begin  -> [RCS_BB, RCS_EB) = [ 0, 27)
2382     //   middle -> [RCS_BM, RCS_EM) = [ 0, 67)
2383     //   end    -> [RCS_BE, RCS_EE) = [14, 56)
2384 
2385     static const string consonant_sets[] = {
2386         // 0-13: start, middle
2387         "kl", "gr", "cl", "cr", "fr",
2388         "pr", "tr", "tw", "br", "pl",
2389         "bl", "str", "shr", "thr",
2390         // 14-26: start, middle, end
2391         "sm", "sh", "ch", "th", "ph",
2392         "pn", "kh", "gh", "mn", "ps",
2393         "st", "sk", "sch",
2394         // 27-55: middle, end
2395         "ts", "cs", "xt", "nt", "ll",
2396         "rr", "ss", "wk", "wn", "ng",
2397         "cw", "mp", "ck", "nk", "dd",
2398         "tt", "bb", "pp", "nn", "mm",
2399         "kk", "gg", "ff", "pt", "tz",
2400         "dgh", "rgh", "rph", "rch",
2401         // 56-66: middle only
2402         "cz", "xk", "zx", "xz", "cv",
2403         "vv", "nl", "rh", "dw", "nw",
2404         "khl",
2405     };
2406     COMPILE_CHECK(ARRAYSZ(consonant_sets) == RCS_END);
2407 
2408     ASSERT_RANGE(c, 0, ARRAYSZ(consonant_sets));
2409 
2410     return consonant_sets[c];
2411 }
2412 
2413 /**
2414  * Write all possible scroll names to the given file.
2415  */
_test_scroll_names(const string & fname)2416 static void _test_scroll_names(const string& fname)
2417 {
2418     FILE *f = fopen(fname.c_str(), "w");
2419     if (!f)
2420         sysfail("can't write test output");
2421 
2422     string longest;
2423     for (int i = 0; i < 151; i++)
2424     {
2425         for (int j = 0; j < 151; j++)
2426         {
2427             const int seed = i | (j << 8) | (OBJ_SCROLLS << 16);
2428             const string name = make_name(seed, MNAME_SCROLL);
2429             if (name.length() > longest.length())
2430                 longest = name;
2431             fprintf(f, "%s\n", name.c_str());
2432         }
2433     }
2434 
2435     fprintf(f, "\nLongest: %s (%d)\n", longest.c_str(), (int)longest.length());
2436 
2437     fclose(f);
2438 }
2439 
2440 /**
2441  * Write one million random Jiyva names to the given file.
2442  */
_test_jiyva_names(const string & fname)2443 static void _test_jiyva_names(const string& fname)
2444 {
2445     FILE *f = fopen(fname.c_str(), "w");
2446     if (!f)
2447         sysfail("can't write test output");
2448 
2449     string longest;
2450     rng::seed(27);
2451     for (int i = 0; i < 1000000; i++)
2452     {
2453         const string name = make_name(rng::get_uint32(), MNAME_JIYVA);
2454         ASSERT(name[0] == 'J');
2455         if (name.length() > longest.length())
2456             longest = name;
2457         fprintf(f, "%s\n", name.c_str());
2458     }
2459 
2460     fprintf(f, "\nLongest: %s (%d)\n", longest.c_str(), (int)longest.length());
2461 
2462     fclose(f);
2463 }
2464 
2465 /**
2466  * Test make_name().
2467  *
2468  * Currently just a stress test iterating over all possible scroll names.
2469  */
make_name_tests()2470 void make_name_tests()
2471 {
2472     _test_jiyva_names("jiyva_names.out");
2473     _test_scroll_names("scroll_names.out");
2474 
2475     rng::seed(27);
2476     for (int i = 0; i < 1000000; ++i)
2477         make_name();
2478 }
2479 
is_interesting_item(const item_def & item)2480 bool is_interesting_item(const item_def& item)
2481 {
2482     if (fully_identified(item) && is_artefact(item))
2483         return true;
2484 
2485     const string iname = item_prefix(item, false) + " " + item.name(DESC_PLAIN);
2486     for (const text_pattern &pat : Options.note_items)
2487         if (pat.matches(iname))
2488             return true;
2489 
2490     return false;
2491 }
2492 
2493 /**
2494  * Is an item a potentially life-saving consumable in emergency situations?
2495  * Unlike similar functions, this one never takes temporary conditions into
2496  * account. It does, however, take religion and mutations into account.
2497  * Permanently unusable items are in general not considered emergency items.
2498  *
2499  * @param item The item being queried.
2500  * @return True if the item is known to be an emergency item.
2501  */
is_emergency_item(const item_def & item)2502 bool is_emergency_item(const item_def &item)
2503 {
2504     if (!item_type_known(item))
2505         return false;
2506 
2507     switch (item.base_type)
2508     {
2509     case OBJ_SCROLLS:
2510         switch (item.sub_type)
2511         {
2512         case SCR_TELEPORTATION:
2513         case SCR_BLINKING:
2514             return !you.stasis();
2515         case SCR_FEAR:
2516         case SCR_FOG:
2517             return true;
2518         default:
2519             return false;
2520         }
2521     case OBJ_POTIONS:
2522         if (!you.can_drink())
2523             return false;
2524 
2525         switch (item.sub_type)
2526         {
2527         case POT_HASTE:
2528             return !have_passive(passive_t::no_haste)
2529                 && !you.stasis();
2530         case POT_HEAL_WOUNDS:
2531             return you.can_potion_heal();
2532         case POT_CURING:
2533         case POT_RESISTANCE:
2534         case POT_MAGIC:
2535             return true;
2536         default:
2537             return false;
2538         }
2539     case OBJ_MISSILES:
2540         // Missiles won't help Felids.
2541         if (you.has_mutation(MUT_NO_GRASPING))
2542             return false;
2543 
2544         switch (item.sub_type)
2545         {
2546         case MI_THROWING_NET:
2547             return true;
2548         default:
2549             return false;
2550         }
2551     default:
2552         return false;
2553     }
2554 }
2555 
2556 /**
2557  * Is an item a particularly good consumable? Unlike similar functions,
2558  * this one never takes temporary conditions into account. Permanently
2559  * unusable items are in general not considered good.
2560  *
2561  * @param item The item being queried.
2562  * @return True if the item is known to be good.
2563  */
is_good_item(const item_def & item)2564 bool is_good_item(const item_def &item)
2565 {
2566     if (!item_type_known(item))
2567         return false;
2568 
2569     if (is_emergency_item(item))
2570         return true;
2571 
2572     switch (item.base_type)
2573     {
2574     case OBJ_SCROLLS:
2575         if (item.sub_type == SCR_TORMENT)
2576             return you.res_torment();
2577         return item.sub_type == SCR_ACQUIREMENT;
2578     case OBJ_POTIONS:
2579         if (!you.can_drink(false)) // still want to pick them up in lichform?
2580             return false;
2581         switch (item.sub_type)
2582         {
2583         case POT_EXPERIENCE:
2584             return true;
2585         default:
2586             return false;
2587         CASE_REMOVED_POTIONS(item.sub_type)
2588         }
2589     default:
2590         return false;
2591     }
2592 }
2593 
2594 /**
2595  * Is an item strictly harmful?
2596  *
2597  * @param item The item being queried.
2598  * @return True if the item is known to have only harmful effects.
2599  */
is_bad_item(const item_def & item)2600 bool is_bad_item(const item_def &item)
2601 {
2602     if (!item_type_known(item))
2603         return false;
2604 
2605     switch (item.base_type)
2606     {
2607     case OBJ_SCROLLS:
2608         switch (item.sub_type)
2609         {
2610 #if TAG_MAJOR_VERSION == 34
2611         case SCR_CURSE_ARMOUR:
2612             if (you.has_mutation(MUT_NO_ARMOUR))
2613                 return false;
2614         case SCR_CURSE_WEAPON:
2615             if (you.has_mutation(MUT_NO_GRASPING))
2616                 return false;
2617         case SCR_CURSE_JEWELLERY:
2618             return !have_passive(passive_t::want_curses);
2619 #endif
2620         case SCR_NOISE:
2621             return true;
2622         default:
2623             return false;
2624         }
2625     case OBJ_POTIONS:
2626         // Can't be bad if you can't use them.
2627         if (!you.can_drink(false))
2628             return false;
2629 
2630         switch (item.sub_type)
2631         {
2632         case POT_DEGENERATION:
2633             return true;
2634         default:
2635             return false;
2636         CASE_REMOVED_POTIONS(item.sub_type);
2637         }
2638     case OBJ_JEWELLERY:
2639         // Potentially useful. TODO: check the properties.
2640         if (is_artefact(item))
2641             return false;
2642 
2643         switch (item.sub_type)
2644         {
2645         case RING_EVASION:
2646         case RING_PROTECTION:
2647         case RING_STRENGTH:
2648         case RING_DEXTERITY:
2649         case RING_INTELLIGENCE:
2650         case RING_SLAYING:
2651             return item_ident(item, ISFLAG_KNOW_PLUSES) && item.plus <= 0;
2652         default:
2653             return false;
2654         }
2655 
2656     default:
2657         return false;
2658     }
2659 }
2660 
2661 /**
2662  * Is an item dangerous but potentially worthwhile?
2663  *
2664  * @param item The item being queried.
2665  * @param temp Should temporary conditions such as transformations and
2666  *             vampire state be taken into account?  Religion (but
2667  *             not its absence) is considered to be permanent here.
2668  * @return True if using the item is known to be risky but occasionally
2669  *         worthwhile.
2670  */
is_dangerous_item(const item_def & item,bool temp)2671 bool is_dangerous_item(const item_def &item, bool temp)
2672 {
2673     if (!item_type_known(item))
2674         return false;
2675 
2676     // useless items can hardly be dangerous.
2677     if (is_useless_item(item, temp))
2678         return false;
2679 
2680     switch (item.base_type)
2681     {
2682     case OBJ_SCROLLS:
2683         switch (item.sub_type)
2684         {
2685         case SCR_IMMOLATION:
2686         case SCR_VULNERABILITY:
2687             return true;
2688         case SCR_TORMENT:
2689             return !you.res_torment();
2690         case SCR_HOLY_WORD:
2691             return you.undead_or_demonic();
2692         default:
2693             return false;
2694         }
2695 
2696     case OBJ_POTIONS:
2697         switch (item.sub_type)
2698         {
2699         case POT_MUTATION:
2700             if (have_passive(passive_t::cleanse_mut_potions))
2701                 return false;
2702             // intentional fallthrough
2703         case POT_LIGNIFY:
2704         case POT_ATTRACTION:
2705             return true;
2706         default:
2707             return false;
2708         }
2709 
2710     case OBJ_MISCELLANY:
2711         // Tremorstones will blow you right up.
2712         return item.sub_type == MISC_TIN_OF_TREMORSTONES;
2713 
2714     case OBJ_ARMOUR:
2715         if (you.get_mutation_level(MUT_NO_LOVE)
2716             && is_unrandom_artefact(item, UNRAND_RATSKIN_CLOAK))
2717         {
2718             // some people don't like being randomly attacked by rats.
2719             // weird but what can you do.
2720             return true;
2721         }
2722 
2723         // Tilting at windmills can be dangerous.
2724         return get_armour_ego_type(item) == SPARM_RAMPAGING;
2725 
2726     default:
2727         return false;
2728     }
2729 }
2730 
_invisibility_is_useless(const bool temp)2731 static bool _invisibility_is_useless(const bool temp)
2732 {
2733     // If you're Corona'd or a TSO-ite, this is always useless.
2734     return temp ? you.backlit()
2735                 : you.haloed() && will_have_passive(passive_t::halo);
2736 }
2737 
2738 /**
2739  * Is an item (more or less) useless to the player? Uselessness includes
2740  * but is not limited to situations such as:
2741  * \li The item cannot be used.
2742  * \li Using the item would have no effect.
2743  * \li Using the item would have purely negative effects (<tt>is_bad_item</tt>).
2744  * \li Using the item is expected to produce no benefit for a player of their
2745  *     religious standing. For example, magic enhancers for Trog worshippers
2746  *     are "useless", even if the player knows a spell and therefore could
2747  *     benefit.
2748  *
2749  * @param item The item being queried.
2750  * @param temp Should temporary conditions such as transformations and
2751  *             vampire state be taken into account? Religion (but
2752  *             not its absence) is considered to be permanent here.
2753  * @param ident Should uselessness be checked as if the item were already
2754  *              identified?
2755  * @return True if the item is known to be useless.
2756  */
is_useless_item(const item_def & item,bool temp,bool ident)2757 bool is_useless_item(const item_def &item, bool temp, bool ident)
2758 {
2759     // During game startup, no item is useless. If someone re-glyphs an item
2760     // based on its uselessness, the glyph-to-item cache will use the useless
2761     // value even if your god or species can make use of it.
2762     if (you.species == SP_UNKNOWN)
2763         return false;
2764 
2765     // An ash item that is already being worn and is cursed, counts as useful
2766     // even if it would otherwise be useless.
2767     if (will_have_passive(passive_t::bondage_skill_boost)
2768         && item_is_equipped(item)
2769         && bool(item.flags & ISFLAG_CURSED))
2770     {
2771         if (!temp || !item_is_melded(item))
2772             return false;
2773         // if it's melded, just fall through. This might not be accurate in
2774         // all cases.
2775     }
2776 
2777     switch (item.base_type)
2778     {
2779     case OBJ_WEAPONS:
2780         if (you.has_mutation(MUT_NO_GRASPING))
2781             return true;
2782 
2783         if (!you.could_wield(item, true, !temp)
2784             && !is_throwable(&you, item))
2785         {
2786             // Weapon is too large (or small) to be wielded and cannot
2787             // be thrown either.
2788             return true;
2789         }
2790 
2791         if (you.undead_or_demonic() && is_holy_item(item, false))
2792         {
2793             if (!temp && you.form == transformation::lich
2794                 && you.species != SP_DEMONSPAWN)
2795             {
2796                 return false;
2797             }
2798             return true;
2799         }
2800 
2801         return false;
2802 
2803     case OBJ_MISSILES:
2804         if ((you.has_spell(SPELL_SANDBLAST)
2805                 || !you.num_turns && you.char_class == JOB_EARTH_ELEMENTALIST)
2806                 && item.sub_type == MI_STONE)
2807         {
2808             return false;
2809         }
2810 
2811         // Save for the above spell, all missiles are useless for felids.
2812         if (you.has_mutation(MUT_NO_GRASPING))
2813             return true;
2814 
2815         // These are the same checks as in is_throwable(), except that
2816         // we don't take launchers into account.
2817         switch (item.sub_type)
2818         {
2819         case MI_LARGE_ROCK:
2820             return !you.can_throw_large_rocks();
2821         case MI_JAVELIN:
2822             return you.body_size(PSIZE_BODY, !temp) < SIZE_MEDIUM
2823                    && !you.can_throw_large_rocks();
2824         case MI_ARROW:
2825             return you.has_mutation(MUT_MISSING_HAND)
2826                    && !you.has_mutation(MUT_QUADRUMANOUS);
2827         }
2828 
2829         return false;
2830 
2831     case OBJ_ARMOUR:
2832         if (!can_wear_armour(item, false, true))
2833             return true;
2834 
2835         if (is_shield(item) && you.get_mutation_level(MUT_MISSING_HAND))
2836             return true;
2837 
2838         if (is_artefact(item))
2839             return false;
2840 
2841         if (item.sub_type == ARM_SCARF && (ident || item_type_known(item)))
2842         {
2843             special_armour_type ego = get_armour_ego_type(item);
2844             switch (ego)
2845             {
2846             case SPARM_SPIRIT_SHIELD:
2847                 return you.spirit_shield(false, false);
2848             case SPARM_REPULSION:
2849                 return temp && have_passive(passive_t::upgraded_storm_shield)
2850                        || you.get_mutation_level(MUT_DISTORTION_FIELD) == 3;
2851             case SPARM_INVISIBILITY:
2852                 return you.has_mutation(MUT_NO_ARTIFICE);
2853             default:
2854                 return false;
2855             }
2856         }
2857         return false;
2858 
2859     case OBJ_SCROLLS:
2860         if (temp && silenced(you.pos()))
2861             return true; // can't use scrolls while silenced
2862 
2863         if (!ident && !item_type_known(item))
2864             return false;
2865 
2866         // A bad item is always useless.
2867         if (is_bad_item(item))
2868             return true;
2869 
2870         switch (item.sub_type)
2871         {
2872         case SCR_TELEPORTATION:
2873             return you.stasis()
2874                    || crawl_state.game_is_sprint()
2875                    || temp && player_in_branch(BRANCH_GAUNTLET);
2876         case SCR_BLINKING:
2877             return you.stasis();
2878         case SCR_AMNESIA:
2879             return you_worship(GOD_TROG) || you.has_mutation(MUT_INNATE_CASTER);
2880 #if TAG_MAJOR_VERSION == 34
2881         case SCR_CURSE_WEAPON: // for non-Ashenzari, already handled
2882         case SCR_CURSE_ARMOUR:
2883 #endif
2884         case SCR_ENCHANT_WEAPON:
2885         case SCR_ENCHANT_ARMOUR:
2886         case SCR_BRAND_WEAPON:
2887             return you.has_mutation(MUT_NO_GRASPING);
2888         case SCR_SUMMONING:
2889             return you.get_mutation_level(MUT_NO_LOVE) > 0;
2890         case SCR_FOG:
2891             return temp && (env.level_state & LSTATE_STILL_WINDS);
2892         case SCR_IDENTIFY:
2893             return you_worship(GOD_ASHENZARI);
2894         default:
2895             return false;
2896         }
2897 
2898     case OBJ_WANDS:
2899         if (you.get_mutation_level(MUT_NO_ARTIFICE))
2900             return true;
2901 
2902 #if TAG_MAJOR_VERSION == 34
2903         if (is_known_empty_wand(item))
2904             return true;
2905 #endif
2906         if (!ident && !item_type_known(item))
2907             return false;
2908 
2909         if (item.sub_type == WAND_CHARMING)
2910             return you.get_mutation_level(MUT_NO_LOVE);
2911 
2912         return false;
2913 
2914     case OBJ_POTIONS:
2915     {
2916         // Mummies and liches can't use potions.
2917         if (!you.can_drink(temp))
2918             return true;
2919 
2920         if (!ident && !item_type_known(item))
2921             return false;
2922 
2923         // A bad item is always useless.
2924         if (is_bad_item(item))
2925             return true;
2926 
2927         switch (item.sub_type)
2928         {
2929         case POT_BERSERK_RAGE:
2930             return !you.can_go_berserk(true, true, true, nullptr, temp);
2931         case POT_HASTE:
2932             return you.stasis();
2933         case POT_MUTATION:
2934             return !you.can_safely_mutate(temp);
2935         case POT_LIGNIFY:
2936             return you.is_lifeless_undead(temp);
2937         case POT_FLIGHT:
2938             return you.permanent_flight();
2939         case POT_HEAL_WOUNDS:
2940             return !you.can_potion_heal();
2941         case POT_INVISIBILITY:
2942             return _invisibility_is_useless(temp);
2943         case POT_BRILLIANCE:
2944             return you_worship(GOD_TROG)
2945                    || temp && player_equip_unrand(UNRAND_FOLLY);
2946         case POT_MAGIC:
2947             return you.has_mutation(MUT_HP_CASTING);
2948         CASE_REMOVED_POTIONS(item.sub_type)
2949         }
2950 
2951         return false;
2952     }
2953     case OBJ_JEWELLERY:
2954         if (!ident && !item_type_known(item))
2955             return false;
2956 
2957         // Potentially useful. TODO: check the properties.
2958         if (is_artefact(item))
2959             return false;
2960 
2961         if (is_bad_item(item))
2962             return true;
2963 
2964         switch (item.sub_type)
2965         {
2966         case RING_RESIST_CORROSION:
2967             return you.res_corr(false, false);
2968 
2969         case AMU_FAITH:
2970             return (you.has_mutation(MUT_FORLORN) && !you.religion) // ??
2971                     || you_worship(GOD_GOZAG) || you_worship(GOD_ASHENZARI)
2972                     || (you_worship(GOD_RU) && you.piety == piety_breakpoint(5));
2973 
2974         case AMU_GUARDIAN_SPIRIT:
2975             return you.spirit_shield(false, false) || you.has_mutation(MUT_HP_CASTING);
2976 
2977         case RING_LIFE_PROTECTION:
2978             return player_prot_life(false, temp, false) == 3;
2979 
2980         case AMU_REGENERATION:
2981             return you.get_mutation_level(MUT_NO_REGENERATION) > 0
2982                    || (temp
2983                        && (you.get_mutation_level(MUT_INHIBITED_REGENERATION) > 0
2984                            || you.has_mutation(MUT_VAMPIRISM))
2985                        && regeneration_is_inhibited());
2986 
2987         case AMU_MANA_REGENERATION:
2988 #if TAG_MAJOR_VERSION == 34
2989             if (have_passive(passive_t::no_mp_regen)
2990                 || player_under_penance(GOD_PAKELLAS))
2991             {
2992                 return true;
2993             }
2994 #endif
2995             return !you.max_magic_points;
2996 
2997         case RING_MAGICAL_POWER:
2998             return you.has_mutation(MUT_HP_CASTING);
2999 
3000         case RING_SEE_INVISIBLE:
3001             return you.innate_sinv();
3002 
3003         case RING_POISON_RESISTANCE:
3004             return player_res_poison(false, temp, false) > 0;
3005 
3006         case RING_WIZARDRY:
3007             return you_worship(GOD_TROG);
3008 
3009         case RING_FLIGHT:
3010             return you.permanent_flight(false);
3011 
3012         case RING_STEALTH:
3013             return you.get_mutation_level(MUT_NO_STEALTH);
3014 
3015         default:
3016             return false;
3017         }
3018 
3019 #if TAG_MAJOR_VERSION == 34
3020     case OBJ_RODS:
3021             return true;
3022 #endif
3023 
3024     case OBJ_STAVES:
3025         if (you.has_mutation(MUT_NO_GRASPING))
3026             return true;
3027         if (!you.could_wield(item, true, !temp))
3028         {
3029             // Weapon is too large (or small) to be wielded and cannot
3030             // be thrown either.
3031             return true;
3032         }
3033         if (!ident && !item_type_known(item))
3034             return false;
3035 
3036         return false;
3037 
3038     case OBJ_CORPSES:
3039         if (you.has_spell(SPELL_ANIMATE_DEAD)
3040             || you.has_spell(SPELL_ANIMATE_SKELETON)
3041             || you.has_spell(SPELL_SIMULACRUM)
3042             || you_worship(GOD_YREDELEMNUL) && !you.penance[GOD_YREDELEMNUL]
3043                && you.piety >= piety_breakpoint(0))
3044         {
3045             return false;
3046         }
3047 
3048         return true;
3049 
3050     case OBJ_MISCELLANY:
3051         switch (item.sub_type)
3052         {
3053 #if TAG_MAJOR_VERSION == 34
3054         case MISC_BUGGY_EBONY_CASKET:
3055             return item_type_known(item);
3056 #endif
3057         // These can always be used.
3058 #if TAG_MAJOR_VERSION == 34
3059         case MISC_BUGGY_LANTERN_OF_SHADOWS:
3060 #endif
3061         case MISC_ZIGGURAT:
3062             return false;
3063 
3064         // Purely summoning misc items don't work w/ sac love
3065         case MISC_BOX_OF_BEASTS:
3066         case MISC_HORN_OF_GERYON:
3067         case MISC_PHANTOM_MIRROR:
3068             return you.get_mutation_level(MUT_NO_LOVE)
3069                    || you.get_mutation_level(MUT_NO_ARTIFICE);
3070 
3071         case MISC_CONDENSER_VANE:
3072             if (temp && (env.level_state & LSTATE_STILL_WINDS))
3073                 return true;
3074             // Intentional fallthrough to check artifice
3075 
3076         default:
3077             return you.get_mutation_level(MUT_NO_ARTIFICE);
3078         }
3079 
3080     case OBJ_BOOKS:
3081         if (you.has_mutation(MUT_INNATE_CASTER) && item.sub_type != BOOK_MANUAL)
3082             return true;
3083         if (item.sub_type == NUM_BOOKS)
3084             return false;
3085         if (item.sub_type != BOOK_MANUAL)
3086         {
3087             // Spellbooks are useless if all spells are either in the library
3088             // already or are uncastable.
3089             bool useless = true;
3090             for (spell_type st : spells_in_book(item))
3091                 if (!you.spell_library[st] && you_can_memorise(st))
3092                     useless = false;
3093             return useless;
3094         }
3095         // If we're here, it's a manual.
3096         if (you.skills[item.plus] >= 27)
3097             return true;
3098         return is_useless_skill((skill_type)item.plus);
3099 
3100     default:
3101         return false;
3102     }
3103     return false;
3104 }
3105 
item_prefix(const item_def & item,bool temp)3106 string item_prefix(const item_def &item, bool temp)
3107 {
3108     vector<const char *> prefixes;
3109 
3110     if (!item.defined())
3111         return "";
3112 
3113     if (fully_identified(item))
3114         prefixes.push_back("identified");
3115     else if (item_ident(item, ISFLAG_KNOW_TYPE)
3116              || get_ident_type(item))
3117     {
3118         prefixes.push_back("known");
3119     }
3120     else
3121         prefixes.push_back("unidentified");
3122 
3123     if (god_hates_item(item))
3124     {
3125         prefixes.push_back("evil_item");
3126         prefixes.push_back("forbidden");
3127     }
3128 
3129     if (is_emergency_item(item))
3130         prefixes.push_back("emergency_item");
3131     if (is_good_item(item))
3132         prefixes.push_back("good_item");
3133     if (is_dangerous_item(item, temp))
3134         prefixes.push_back("dangerous_item");
3135     if (is_bad_item(item))
3136         prefixes.push_back("bad_item");
3137     if (is_useless_item(item, temp))
3138         prefixes.push_back("useless_item");
3139 
3140     if (item_is_stationary(item))
3141         prefixes.push_back("stationary");
3142 
3143     if (!is_artefact(item) && (item.base_type == OBJ_WEAPONS
3144                                || item.base_type == OBJ_ARMOUR))
3145     {
3146         if (item_ident(item, ISFLAG_KNOW_PLUSES) && item.plus > 0)
3147             prefixes.push_back("enchanted");
3148         if (item_ident(item, ISFLAG_KNOW_TYPE) && item.brand)
3149             prefixes.push_back("ego");
3150     }
3151 
3152     switch (item.base_type)
3153     {
3154     case OBJ_STAVES:
3155     case OBJ_WEAPONS:
3156         if (is_range_weapon(item))
3157             prefixes.push_back("ranged");
3158         else if (is_melee_weapon(item)) // currently redundant
3159             prefixes.push_back("melee");
3160         // fall through
3161 
3162     case OBJ_ARMOUR:
3163     case OBJ_JEWELLERY:
3164         if (is_artefact(item))
3165             prefixes.push_back("artefact");
3166         // fall through
3167 
3168     case OBJ_MISSILES:
3169         if (item_is_equipped(item, true))
3170             prefixes.push_back("equipped");
3171         break;
3172 
3173     case OBJ_BOOKS:
3174         if (item.sub_type != BOOK_MANUAL && item.sub_type != NUM_BOOKS)
3175             prefixes.push_back("spellbook");
3176         break;
3177 
3178     default:
3179         break;
3180     }
3181 
3182     prefixes.push_back(item_class_name(item.base_type, true));
3183 
3184     string result = comma_separated_line(prefixes.begin(), prefixes.end(),
3185                                          " ", " ");
3186 
3187     return result;
3188 }
3189 
3190 /**
3191  * Return an item's name surrounded by colour tags, using menu colouring
3192  *
3193  * @param item The item being queried
3194  * @param desc The description level to use for the name string
3195  * @return A string containing the item's name surrounded by colour tags
3196  */
menu_colour_item_name(const item_def & item,description_level_type desc)3197 string menu_colour_item_name(const item_def &item, description_level_type desc)
3198 {
3199     const string cprf      = item_prefix(item);
3200     const string item_name = item.name(desc);
3201 
3202     const int col = menu_colour(item_name, cprf, "pickup");
3203     if (col == -1)
3204         return item_name;
3205 
3206     const string colour = colour_to_str(col);
3207     const char * const colour_z = colour.c_str();
3208     return make_stringf("<%s>%s</%s>", colour_z, item_name.c_str(), colour_z);
3209 }
3210 
3211 typedef map<string, item_kind> item_names_map;
3212 static item_names_map item_names_cache;
3213 
3214 typedef map<unsigned, vector<string> > item_names_by_glyph_map;
3215 static item_names_by_glyph_map item_names_by_glyph_cache;
3216 
init_item_name_cache()3217 void init_item_name_cache()
3218 {
3219     item_names_cache.clear();
3220     item_names_by_glyph_cache.clear();
3221 
3222     for (int i = 0; i < NUM_OBJECT_CLASSES; i++)
3223     {
3224         const object_class_type base_type = static_cast<object_class_type>(i);
3225 
3226         for (const auto sub_type : all_item_subtypes(base_type))
3227         {
3228             if (base_type == OBJ_BOOKS)
3229             {
3230                 if (sub_type == BOOK_RANDART_LEVEL
3231                     || sub_type == BOOK_RANDART_THEME)
3232                 {
3233                     // These are randart only and have no fixed names.
3234                     continue;
3235                 }
3236             }
3237 
3238             int npluses = 0;
3239             if (base_type == OBJ_BOOKS && sub_type == BOOK_MANUAL)
3240                 npluses = NUM_SKILLS;
3241 
3242             item_def item;
3243             item.base_type = base_type;
3244             item.sub_type = sub_type;
3245             for (int plus = 0; plus <= npluses; plus++)
3246             {
3247                 if (plus > 0)
3248                     item.plus = max(0, plus - 1);
3249                 string name = item.name(plus || item.base_type == OBJ_RUNES ? DESC_PLAIN : DESC_DBNAME,
3250                                         true, true);
3251                 lowercase(name);
3252                 cglyph_t g = get_item_glyph(item);
3253 
3254                 if (base_type == OBJ_JEWELLERY && sub_type >= NUM_RINGS
3255                     && sub_type < AMU_FIRST_AMULET)
3256                 {
3257                     continue;
3258                 }
3259                 else if (name.find("buggy") != string::npos)
3260                 {
3261                     mprf(MSGCH_ERROR, "Bad name for item name cache: %s",
3262                                                                 name.c_str());
3263                     continue;
3264                 }
3265 
3266                 if (!item_names_cache.count(name))
3267                 {
3268                     item_names_cache[name] = { base_type, (uint8_t)sub_type,
3269                                                (int8_t)item.plus, 0 };
3270                     if (g.ch)
3271                         item_names_by_glyph_cache[g.ch].push_back(name);
3272                 }
3273             }
3274         }
3275     }
3276 
3277     ASSERT(!item_names_cache.empty());
3278 }
3279 
item_kind_by_name(const string & name)3280 item_kind item_kind_by_name(const string &name)
3281 {
3282     return lookup(item_names_cache, lowercase_string(name),
3283                   { OBJ_UNASSIGNED, 0, 0, 0 });
3284 }
3285 
item_name_list_for_glyph(char32_t glyph)3286 vector<string> item_name_list_for_glyph(char32_t glyph)
3287 {
3288     return lookup(item_names_by_glyph_cache, glyph, {});
3289 }
3290 
is_named_corpse(const item_def & corpse)3291 bool is_named_corpse(const item_def &corpse)
3292 {
3293     ASSERT(corpse.base_type == OBJ_CORPSES);
3294 
3295     return corpse.props.exists(CORPSE_NAME_KEY);
3296 }
3297 
get_corpse_name(const item_def & corpse,monster_flags_t * name_type)3298 string get_corpse_name(const item_def &corpse, monster_flags_t *name_type)
3299 {
3300     ASSERT(corpse.base_type == OBJ_CORPSES);
3301 
3302     if (!corpse.props.exists(CORPSE_NAME_KEY))
3303         return "";
3304 
3305     if (name_type != nullptr)
3306         name_type->flags = corpse.props[CORPSE_NAME_TYPE_KEY].get_int64();
3307 
3308     return corpse.props[CORPSE_NAME_KEY].get_string();
3309 }
3310