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