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