/* * File: itemname.cc * Summary: Misc functions. * Written by: Linley Henzell */ #include "AppHdr.h" #include "itemname.h" #include #include #include #include #include "clua.h" #include "externs.h" #include "options.h" #include "artefact.h" #include "colour.h" #include "decks.h" #include "food.h" #include "goditem.h" #include "invent.h" #include "item_use.h" #include "itemprop.h" #include "items.h" #include "macro.h" #include "makeitem.h" #include "mon-util.h" #include "notes.h" #include "player.h" #include "religion.h" #include "quiver.h" #include "shopping.h" #include "showsymb.h" #include "skills2.h" #include "spl-book.h" #include "state.h" #include "stuff.h" #include "env.h" #include "transform.h" id_arr type_ids; static bool _is_random_name_space( char let ); static bool _is_random_name_vowel( char let ); static char _random_vowel(int seed); static char _random_cons(int seed); bool is_vowel( const char chr ) { const char low = tolower( chr ); return (low == 'a' || low == 'e' || low == 'i' || low == 'o' || low == 'u'); } // quant_name is useful since it prints out a different number of items // than the item actually contains. std::string quant_name( const item_def &item, int quant, description_level_type des, bool terse ) { // item_name now requires a "real" item, so we'll mangle a tmp item_def tmp = item; tmp.quantity = quant; return tmp.name(des, terse); } std::string item_def::name(description_level_type descrip, bool terse, bool ident, bool with_inscription, bool quantity_in_words, unsigned long ignore_flags) const { if (crawl_state.arena) { ignore_flags |= ISFLAG_KNOW_PLUSES | ISFLAG_KNOW_CURSE | ISFLAG_COSMETIC_MASK; } if (descrip == DESC_NONE) return (""); std::ostringstream buff; const std::string auxname = this->name_aux(descrip, terse, ident, ignore_flags); const bool startvowel = is_vowel(auxname[0]); if (descrip == DESC_INVENTORY_EQUIP || descrip == DESC_INVENTORY) { if (in_inventory(*this)) // actually in inventory { buff << index_to_letter(this->link); if (terse) buff << ") "; else buff << " - "; } else descrip = DESC_CAP_A; } if (base_type == OBJ_BOOKS && (ident || item_type_known(*this)) && book_has_title(*this)) { if (descrip != DESC_DBNAME) descrip = DESC_PLAIN; } if (terse && descrip != DESC_DBNAME) descrip = DESC_PLAIN; if (base_type == OBJ_CORPSES && is_named_corpse(*this) && !starts_with(get_corpse_name(*this), "shaped ")) { switch (descrip) { case DESC_CAP_A: case DESC_CAP_YOUR: descrip = DESC_CAP_THE; break; case DESC_NOCAP_A: case DESC_NOCAP_YOUR: case DESC_NOCAP_ITS: case DESC_INVENTORY_EQUIP: case DESC_INVENTORY: descrip = DESC_NOCAP_THE; break; default: break; } } if (this->base_type == OBJ_ORBS || (ident || item_type_known( *this )) && (this->base_type == OBJ_MISCELLANY && this->sub_type == MISC_HORN_OF_GERYON || is_artefact(*this))) { // Artefacts always get "the" unless we just want the plain name. switch (descrip) { case DESC_CAP_A: case DESC_CAP_YOUR: case DESC_CAP_THE: buff << "The "; break; case DESC_NOCAP_A: case DESC_NOCAP_YOUR: case DESC_NOCAP_THE: case DESC_NOCAP_ITS: case DESC_INVENTORY_EQUIP: case DESC_INVENTORY: buff << "the "; break; default: case DESC_PLAIN: break; } } else if (this->quantity > 1) { switch (descrip) { case DESC_CAP_THE: buff << "The "; break; case DESC_NOCAP_THE: buff << "the "; break; case DESC_CAP_YOUR: buff << "Your "; break; case DESC_NOCAP_YOUR: buff << "your "; break; case DESC_NOCAP_ITS: buff << "its "; break; case DESC_CAP_A: case DESC_NOCAP_A: case DESC_INVENTORY_EQUIP: case DESC_INVENTORY: case DESC_PLAIN: default: break; } if (descrip != DESC_BASENAME && descrip != DESC_QUALNAME && descrip != DESC_DBNAME) { if (quantity_in_words) buff << number_in_words(this->quantity) << " "; else buff << this->quantity << " "; } } else { switch (descrip) { case DESC_CAP_THE: buff << "The "; break; case DESC_NOCAP_THE: buff << "the "; break; case DESC_CAP_A: buff << (startvowel ? "An " : "A "); break; case DESC_CAP_YOUR: buff << "Your "; break; case DESC_NOCAP_YOUR: buff << "your "; break; case DESC_NOCAP_ITS: buff << "its "; break; case DESC_NOCAP_A: case DESC_INVENTORY_EQUIP: case DESC_INVENTORY: buff << (startvowel ? "an " : "a "); break; case DESC_PLAIN: default: break; } } buff << auxname; bool equipped = false; if (descrip == DESC_INVENTORY_EQUIP && item_is_equipped(*this, true)) { ASSERT( this->link != -1 ); equipped = true; if (!you_tran_can_wear(*this) && you.equip[EQ_WEAPON] != this->link && this->link != you.m_quiver->get_fire_item()) { buff << " (melded)"; } else if (this->link == you.equip[EQ_WEAPON]) { if (this->base_type == OBJ_WEAPONS || item_is_staff(*this)) buff << " (weapon)"; else buff << " (in hand)"; } else if (this->link == you.equip[EQ_CLOAK] || this->link == you.equip[EQ_HELMET] || this->link == you.equip[EQ_GLOVES] || this->link == you.equip[EQ_BOOTS] || this->link == you.equip[EQ_SHIELD] || this->link == you.equip[EQ_BODY_ARMOUR]) { buff << " (worn)"; } else if (this->link == you.equip[EQ_LEFT_RING]) { buff << " (left hand)"; } else if (this->link == you.equip[EQ_RIGHT_RING]) { buff << " (right hand)"; } else if (this->link == you.equip[EQ_AMULET]) { buff << " (around neck)"; } else if (this->link == you.m_quiver->get_fire_item()) { buff << " (quivered)"; } } if (descrip != DESC_BASENAME) { const bool tried = !ident && !equipped && item_type_tried(*this); std::string tried_str; if (tried) { item_type_id_state_type id_type = get_ident_type(*this); if (id_type == ID_MON_TRIED_TYPE) tried_str = "tried by monster"; else if (id_type == ID_TRIED_ITEM_TYPE) tried_str = "tried on item"; else tried_str = "tried"; } if ( with_inscription && !(this->inscription.empty()) ) { buff << " {"; if (tried) buff << tried_str << ", "; buff << this->inscription << "}"; } else if (tried) buff << " {" << tried_str << "}"; } return buff.str(); } const char* weapon_brand_name(const item_def& item, bool terse) { switch (get_weapon_brand(item)) { case SPWPN_NORMAL: return ""; case SPWPN_FLAMING: return ((terse) ? " (flame)" : " of flaming"); case SPWPN_FREEZING: return ((terse) ? " (freeze)" : " of freezing"); case SPWPN_HOLY_WRATH: return ((terse) ? " (holy)" : " of holy wrath"); case SPWPN_ELECTROCUTION: return ((terse) ? " (elec)":" of electrocution"); case SPWPN_ORC_SLAYING: return ((terse) ? " (slay orc)":" of orc slaying"); case SPWPN_DRAGON_SLAYING: return ((terse) ? " (slay drac)":" of dragon slaying"); case SPWPN_VENOM: return ((terse) ? " (venom)" : " of venom"); case SPWPN_PROTECTION: return ((terse) ? " (protect)" : " of protection"); case SPWPN_EVASION: return ((terse) ? " (evade)" : " of evasion"); case SPWPN_DRAINING: return ((terse) ? " (drain)" : " of draining"); case SPWPN_SPEED: return ((terse) ? " (speed)" : " of speed"); case SPWPN_PAIN: return ((terse) ? " (pain)" : " of pain"); case SPWPN_DISTORTION: return ((terse) ? " (distort)" : " of distortion"); case SPWPN_REACHING: return ((terse) ? " (reach)" : " of reaching"); case SPWPN_RETURNING: return ((terse) ? " (return)" : " of returning"); case SPWPN_VAMPIRICISM: return ((terse) ? " (vamp)" : ""); // non-terse already handled case SPWPN_VORPAL: if (is_range_weapon(item)) return ((terse) ? " (velocity)" : " of velocity"); else { switch (get_vorpal_type(item)) { case DVORP_CRUSHING: return ((terse) ? " (crush)" :" of crushing"); case DVORP_SLICING: return ((terse) ? " (slice)" : " of slicing"); case DVORP_PIERCING: return ((terse) ? " (pierce)":" of piercing"); case DVORP_CHOPPING: return ((terse) ? " (chop)" : " of chopping"); case DVORP_SLASHING: return ((terse) ? " (slash)" :" of slashing"); case DVORP_STABBING: return ((terse) ? " (stab)" : " of stabbing"); default: return ""; } } // ranged weapon brands case SPWPN_FLAME: return ((terse) ? " (flame)" : " of flame"); case SPWPN_FROST: return ((terse) ? " (frost)" : " of frost"); case SPWPN_PENETRATION: return ((terse) ? " (penet)" : " of penetration"); case SPWPN_REAPING: return ((terse) ? " (reap)" : " of reaping"); // both ranged and non-ranged case SPWPN_CHAOS: return ((terse) ? " (chaos)" : " of chaos"); // randart brands default: return ""; } } const char* armour_ego_name(const item_def& item, bool terse) { if (!terse) { switch (get_armour_ego_type(item)) { case SPARM_NORMAL: return ""; case SPARM_RUNNING: return "running"; case SPARM_FIRE_RESISTANCE: return "fire resistance"; case SPARM_COLD_RESISTANCE: return "cold resistance"; case SPARM_POISON_RESISTANCE: return "poison resistance"; case SPARM_SEE_INVISIBLE: return "see invisible"; case SPARM_DARKNESS: return "darkness"; case SPARM_STRENGTH: return "strength"; case SPARM_DEXTERITY: return "dexterity"; case SPARM_INTELLIGENCE: return "intelligence"; case SPARM_PONDEROUSNESS: return "ponderousness"; case SPARM_LEVITATION: return "levitation"; case SPARM_MAGIC_RESISTANCE: return "magic resistance"; case SPARM_PROTECTION: return "protection"; case SPARM_STEALTH: return "stealth"; case SPARM_RESISTANCE: return "resistance"; case SPARM_POSITIVE_ENERGY: return "positive energy"; case SPARM_ARCHMAGI: return "the Archmagi"; case SPARM_PRESERVATION: return "preservation"; case SPARM_REFLECTION: return "reflection"; case SPARM_SPIRIT_SHIELD: return "spirit shield"; case SPARM_ARCHERY: return "archery"; default: return "bugginess"; } } else { switch (get_armour_ego_type(item)) { case SPARM_NORMAL: return ""; case SPARM_RUNNING: return " {run}"; case SPARM_FIRE_RESISTANCE: return " {rF+}"; case SPARM_COLD_RESISTANCE: return " {rC+}"; case SPARM_POISON_RESISTANCE: return " {rPois}"; case SPARM_SEE_INVISIBLE: return " {SInv}"; case SPARM_DARKNESS: return " {darkness}"; case SPARM_STRENGTH: return " {Str+3}"; case SPARM_DEXTERITY: return " {Dex+3}"; case SPARM_INTELLIGENCE: return " {Int+3}"; case SPARM_PONDEROUSNESS: return " {ponderous}"; case SPARM_LEVITATION: return " {Lev}"; case SPARM_MAGIC_RESISTANCE: return " {MR}"; case SPARM_PROTECTION: return " {AC+3}"; case SPARM_STEALTH: return " {Stlth+}"; case SPARM_RESISTANCE: return " {rC+ rF+}"; case SPARM_POSITIVE_ENERGY: return " {rN+}"; case SPARM_ARCHMAGI: return " {Archmagi}"; case SPARM_PRESERVATION: return " {rCorr, Cons}"; case SPARM_REFLECTION: return " {rflct}"; case SPARM_SPIRIT_SHIELD: return " {Spirit}"; case SPARM_ARCHERY: return " {archer}"; default: return " {buggy}"; } } } const char* wand_type_name(int wandtype) { switch (static_cast(wandtype)) { case WAND_FLAME: return "flame"; case WAND_FROST: return "frost"; case WAND_SLOWING: return "slowing"; case WAND_HASTING: return "hasting"; case WAND_MAGIC_DARTS: return "magic darts"; case WAND_HEALING: return "healing"; case WAND_PARALYSIS: return "paralysis"; case WAND_FIRE: return "fire"; case WAND_COLD: return "cold"; case WAND_CONFUSION: return "confusion"; case WAND_INVISIBILITY: return "invisibility"; case WAND_DIGGING: return "digging"; case WAND_FIREBALL: return "fireball"; case WAND_TELEPORTATION: return "teleportation"; case WAND_LIGHTNING: return "lightning"; case WAND_POLYMORPH_OTHER: return "polymorph other"; case WAND_ENSLAVEMENT: return "enslavement"; case WAND_DRAINING: return "draining"; case WAND_RANDOM_EFFECTS: return "random effects"; case WAND_DISINTEGRATION: return "disintegration"; default: return "bugginess"; } } static const char* wand_secondary_string(int s) { switch (s) { case 0: return ""; case 1: return "jewelled "; case 2: return "curved "; case 3: return "long "; case 4: return "short "; case 5: return "twisted "; case 6: return "crooked "; case 7: return "forked "; case 8: return "shiny "; case 9: return "blackened "; case 10: return "tapered "; case 11: return "glowing "; case 12: return "worn "; case 13: return "encrusted "; case 14: return "runed "; case 15: return "sharpened "; default: return "buggily "; } } static const char* wand_primary_string(int p) { switch (p) { case 0: return "iron"; case 1: return "brass"; case 2: return "bone"; case 3: return "wooden"; case 4: return "copper"; case 5: return "gold"; case 6: return "silver"; case 7: return "bronze"; case 8: return "ivory"; case 9: return "glass"; case 10: return "lead"; case 11: return "fluorescent"; default: return "buggy"; } } static const char* potion_type_name(int potiontype) { switch ( static_cast(potiontype) ) { case POT_HEALING: return "healing"; case POT_HEAL_WOUNDS: return "heal wounds"; case POT_SPEED: return "speed"; case POT_MIGHT: return "might"; case POT_AGILITY: return "agility"; case POT_BRILLIANCE: return "brilliance"; case POT_GAIN_STRENGTH: return "gain strength"; case POT_GAIN_DEXTERITY: return "gain dexterity"; case POT_GAIN_INTELLIGENCE: return "gain intelligence"; case POT_LEVITATION: return "levitation"; case POT_POISON: return "poison"; case POT_SLOWING: return "slowing"; case POT_PARALYSIS: return "paralysis"; case POT_CONFUSION: return "confusion"; case POT_INVISIBILITY: return "invisibility"; case POT_PORRIDGE: return "porridge"; case POT_DEGENERATION: return "degeneration"; case POT_DECAY: return "decay"; case POT_WATER: return "water"; case POT_EXPERIENCE: return "experience"; case POT_MAGIC: return "magic"; case POT_RESTORE_ABILITIES: return "restore abilities"; case POT_STRONG_POISON: return "strong poison"; case POT_BERSERK_RAGE: return "berserk rage"; case POT_CURE_MUTATION: return "cure mutation"; case POT_MUTATION: return "mutation"; case POT_BLOOD: return "blood"; case POT_BLOOD_COAGULATED: return "coagulated blood"; case POT_RESISTANCE: return "resistance"; default: return "bugginess"; } } static const char* scroll_type_name(int scrolltype) { switch ( static_cast(scrolltype) ) { case SCR_IDENTIFY: return "identify"; case SCR_TELEPORTATION: return "teleportation"; case SCR_FEAR: return "fear"; case SCR_NOISE: return "noise"; case SCR_REMOVE_CURSE: return "remove curse"; case SCR_DETECT_CURSE: return "detect curse"; case SCR_SUMMONING: return "summoning"; case SCR_ENCHANT_WEAPON_I: return "enchant weapon I"; case SCR_ENCHANT_ARMOUR: return "enchant armour"; case SCR_TORMENT: return "torment"; case SCR_RANDOM_USELESSNESS: return "random uselessness"; case SCR_CURSE_WEAPON: return "curse weapon"; case SCR_CURSE_ARMOUR: return "curse armour"; case SCR_IMMOLATION: return "immolation"; case SCR_BLINKING: return "blinking"; case SCR_PAPER: return "paper"; case SCR_MAGIC_MAPPING: return "magic mapping"; case SCR_FOG: return "fog"; case SCR_ACQUIREMENT: return "acquirement"; case SCR_ENCHANT_WEAPON_II: return "enchant weapon II"; case SCR_VORPALISE_WEAPON: return "vorpalise weapon"; case SCR_RECHARGING: return "recharging"; case SCR_ENCHANT_WEAPON_III: return "enchant weapon III"; case SCR_HOLY_WORD: return "holy word"; case SCR_VULNERABILITY: return "vulnerability"; case SCR_SILENCE: return "silence"; default: return "bugginess"; } } static const char* jewellery_type_name(int jeweltype) { switch (static_cast(jeweltype)) { case RING_REGENERATION: return "ring of regeneration"; case RING_PROTECTION: return "ring of protection"; case RING_PROTECTION_FROM_FIRE: return "ring of protection from fire"; case RING_POISON_RESISTANCE: return "ring of poison resistance"; case RING_PROTECTION_FROM_COLD: return "ring of protection from cold"; case RING_STRENGTH: return "ring of strength"; case RING_SLAYING: return "ring of slaying"; case RING_SEE_INVISIBLE: return "ring of see invisible"; case RING_INVISIBILITY: return "ring of invisibility"; case RING_HUNGER: return "ring of hunger"; case RING_TELEPORTATION: return "ring of teleportation"; case RING_EVASION: return "ring of evasion"; case RING_SUSTAIN_ABILITIES: return "ring of sustain abilities"; case RING_SUSTENANCE: return "ring of sustenance"; case RING_DEXTERITY: return "ring of dexterity"; case RING_INTELLIGENCE: return "ring of intelligence"; case RING_WIZARDRY: return "ring of wizardry"; case RING_MAGICAL_POWER: return "ring of magical power"; case RING_LEVITATION: return "ring of levitation"; case RING_LIFE_PROTECTION: return "ring of life protection"; case RING_PROTECTION_FROM_MAGIC: return "ring of protection from magic"; case RING_FIRE: return "ring of fire"; case RING_ICE: return "ring of ice"; case RING_TELEPORT_CONTROL: return "ring of teleport control"; case AMU_RAGE: return "amulet of rage"; case AMU_CLARITY: return "amulet of clarity"; case AMU_WARDING: return "amulet of warding"; case AMU_RESIST_CORROSION: return "amulet of resist corrosion"; case AMU_THE_GOURMAND: return "amulet of the gourmand"; case AMU_CONSERVATION: return "amulet of conservation"; case AMU_CONTROLLED_FLIGHT: return "amulet of controlled flight"; case AMU_INACCURACY: return "amulet of inaccuracy"; case AMU_RESIST_MUTATION: return "amulet of resist mutation"; case AMU_GUARDIAN_SPIRIT: return "amulet of guardian spirit"; case AMU_FAITH: return "amulet of faith"; case AMU_STASIS: return "amulet of stasis"; default: return "buggy jewellery"; } } static const char* ring_secondary_string(int s) { switch (s) { case 1: return "encrusted "; case 2: return "glowing "; case 3: return "tubular "; case 4: return "runed "; case 5: return "blackened "; case 6: return "scratched "; case 7: return "small "; case 8: return "large "; case 9: return "twisted "; case 10: return "shiny "; case 11: return "notched "; case 12: return "knobbly "; default: return ""; } } static const char* ring_primary_string(int p) { switch (p) { case 0: return "wooden"; case 1: return "silver"; case 2: return "golden"; case 3: return "iron"; case 4: return "steel"; case 5: return "bronze"; case 6: return "brass"; case 7: return "copper"; case 8: return "granite"; case 9: return "ivory"; case 10: return "bone"; case 11: return "marble"; case 12: return "jade"; case 13: return "glass"; default: return "buggy"; } } static const char* amulet_secondary_string(int s) { switch (s) { case 0: return "dented "; case 1: return "square "; case 2: return "thick "; case 3: return "thin "; case 4: return "runed "; case 5: return "blackened "; case 6: return "glowing "; case 7: return "small "; case 8: return "large "; case 9: return "twisted "; case 10: return "tiny "; case 11: return "triangular "; case 12: return "lumpy "; default: return ""; } } static const char* amulet_primary_string(int p) { switch (p) { case 0: return "zirconium"; case 1: return "sapphire"; case 2: return "golden"; case 3: return "emerald"; case 4: return "garnet"; case 5: return "bronze"; case 6: return "brass"; case 7: return "copper"; case 8: return "ruby"; case 9: return "ivory"; case 10: return "bone"; case 11: return "platinum"; case 12: return "jade"; case 13: return "fluorescent"; default: return "buggy"; } } static const char* rune_type_name(int p) { switch (static_cast(p)) { case RUNE_DIS: return "iron"; case RUNE_GEHENNA: return "obsidian"; case RUNE_COCYTUS: return "icy"; case RUNE_TARTARUS: return "bone"; case RUNE_SLIME_PITS: return "slimy"; case RUNE_VAULTS: return "silver"; case RUNE_SNAKE_PIT: return "serpentine"; case RUNE_ELVEN_HALLS: return "elven"; case RUNE_TOMB: return "golden"; case RUNE_SWAMP: return "decaying"; case RUNE_SHOALS: return "barnacled"; // pandemonium and abyss runes: case RUNE_DEMONIC: return "demonic"; case RUNE_ABYSSAL: return "abyssal"; // special pandemonium runes: case RUNE_MNOLEG: return "glowing"; case RUNE_LOM_LOBON: return "magical"; case RUNE_CEREBOV: return "fiery"; case RUNE_GLOORX_VLOQ: return "dark"; default: return "buggy"; } } static const char* deck_rarity_name(deck_rarity_type rarity) { switch (rarity) { case DECK_RARITY_COMMON: return "plain"; case DECK_RARITY_RARE: return "ornate"; case DECK_RARITY_LEGENDARY: return "legendary"; } return "buggy rarity"; } static const char* misc_type_name(int type, bool known) { if (known) { switch ( static_cast(type) ) { case MISC_DECK_OF_ESCAPE: return "deck of escape"; case MISC_DECK_OF_DESTRUCTION: return "deck of destruction"; case MISC_DECK_OF_DUNGEONS: return "deck of dungeons"; case MISC_DECK_OF_SUMMONING: return "deck of summonings"; case MISC_DECK_OF_WONDERS: return "deck of wonders"; case MISC_DECK_OF_PUNISHMENT: return "deck of punishment"; case MISC_DECK_OF_WAR: return "deck of war"; case MISC_DECK_OF_CHANGES: return "deck of changes"; case MISC_DECK_OF_DEFENCE: return "deck of defence"; case MISC_CRYSTAL_BALL_OF_ENERGY: return "crystal ball of energy"; case MISC_CRYSTAL_BALL_OF_FIXATION: return "crystal ball of fixation"; case MISC_CRYSTAL_BALL_OF_SEEING: return "crystal ball of seeing"; case MISC_BOX_OF_BEASTS: return "box of beasts"; case MISC_EMPTY_EBONY_CASKET: return "empty ebony casket"; case MISC_AIR_ELEMENTAL_FAN: return "air elemental fan"; case MISC_LAMP_OF_FIRE: return "lamp of fire"; case MISC_LANTERN_OF_SHADOWS: return "lantern of shadows"; case MISC_HORN_OF_GERYON: return "horn of Geryon"; case MISC_DISC_OF_STORMS: return "disc of storms"; case MISC_BOTTLED_EFREET: return "bottled efreet"; case MISC_STONE_OF_EARTH_ELEMENTALS: return "stone of earth elementals"; case MISC_RUNE_OF_ZOT: case NUM_MISCELLANY: return "buggy miscellaneous item"; } } else { switch ( static_cast(type) ) { case MISC_DECK_OF_ESCAPE: case MISC_DECK_OF_DESTRUCTION: case MISC_DECK_OF_DUNGEONS: case MISC_DECK_OF_SUMMONING: case MISC_DECK_OF_WONDERS: case MISC_DECK_OF_PUNISHMENT: case MISC_DECK_OF_WAR: case MISC_DECK_OF_CHANGES: case MISC_DECK_OF_DEFENCE: return "deck of cards"; case MISC_CRYSTAL_BALL_OF_ENERGY: case MISC_CRYSTAL_BALL_OF_FIXATION: case MISC_CRYSTAL_BALL_OF_SEEING: return "crystal ball"; case MISC_BOX_OF_BEASTS: case MISC_EMPTY_EBONY_CASKET: return "small ebony casket"; case MISC_AIR_ELEMENTAL_FAN: return "gauzy fan"; case MISC_LAMP_OF_FIRE: return "blazing lamp"; case MISC_LANTERN_OF_SHADOWS: return "bone lantern"; case MISC_HORN_OF_GERYON: return "silver horn"; case MISC_DISC_OF_STORMS: return "grey disc"; case MISC_STONE_OF_EARTH_ELEMENTALS: return "nondescript stone"; case MISC_BOTTLED_EFREET: return "sealed bronze flask"; case MISC_RUNE_OF_ZOT: case NUM_MISCELLANY: return "buggy miscellaneous item"; } } return "very buggy miscellaneous item"; } static const char* book_secondary_string(int s) { switch (s) { case 0: return ""; case 1: return "chunky "; case 2: return "thick "; case 3: return "thin "; case 4: return "wide "; case 5: return "glowing "; case 6: return "dog-eared "; case 7: return "oblong "; case 8: return "runed "; case 9: return ""; case 10: return ""; case 11: return ""; default: return "buggily "; } } static const char* book_primary_string(int p) { switch (p) { case 0: return "paperback "; case 1: return "hardcover "; case 2: return "leatherbound "; case 3: return "metal-bound "; case 4: return "papyrus "; case 5: return ""; case 6: return ""; default: return "buggy "; } } static const char* book_type_name(int booktype) { switch ( static_cast(booktype) ) { case BOOK_MINOR_MAGIC_I: case BOOK_MINOR_MAGIC_II: case BOOK_MINOR_MAGIC_III: return "Minor Magic"; case BOOK_CONJURATIONS_I: case BOOK_CONJURATIONS_II: return "Conjurations"; case BOOK_FLAMES: return "Flames"; case BOOK_FROST: return "Frost"; case BOOK_SUMMONINGS: return "Summonings"; case BOOK_FIRE: return "Fire"; case BOOK_ICE: return "Ice"; case BOOK_SPATIAL_TRANSLOCATIONS: return "Spatial Translocations"; case BOOK_ENCHANTMENTS: return "Enchantments"; case BOOK_TEMPESTS: return "the Tempests"; case BOOK_DEATH: return "Death"; case BOOK_HINDERANCE: return "Hinderance"; case BOOK_CHANGES: return "Changes"; case BOOK_TRANSFIGURATIONS: return "Transfigurations"; case BOOK_WAR_CHANTS: return "War Chants"; case BOOK_CLOUDS: return "Clouds"; case BOOK_NECROMANCY: return "Necromancy"; case BOOK_CALLINGS: return "Callings"; case BOOK_CHARMS: return "Charms"; case BOOK_DEMONOLOGY: return "Demonology"; case BOOK_AIR: return "Air"; case BOOK_SKY: return "the Sky"; case BOOK_WARP: return "the Warp"; case BOOK_ENVENOMATIONS: return "Envenomations"; case BOOK_ANNIHILATIONS: return "Annihilations"; case BOOK_UNLIFE: return "Unlife"; case BOOK_CONTROL: return "Control"; case BOOK_MUTATIONS: return "Morphology"; case BOOK_TUKIMA: return "Tukima"; case BOOK_GEOMANCY: return "Geomancy"; case BOOK_EARTH: return "the Earth"; case BOOK_WIZARDRY: return "Wizardry"; case BOOK_POWER: return "Power"; case BOOK_CANTRIPS: return "Cantrips"; case BOOK_PARTY_TRICKS: return "Party Tricks"; case BOOK_STALKING: return "Stalking"; case BOOK_BRANDS: return "Brands"; case BOOK_RANDART_LEVEL: return "Fixed Level"; case BOOK_RANDART_THEME: return "Fixed Theme"; default: return "Bugginess"; } } static const char* staff_secondary_string(int p) { switch (p) // general descriptions { case 0: return "crooked "; case 1: return "knobbly "; case 2: return "weird "; case 3: return "gnarled "; case 4: return "thin "; case 5: return "curved "; case 6: return "twisted "; case 7: return "thick "; case 8: return "long "; case 9: return "short "; default: return "buggily "; } } static const char* staff_primary_string(int p) { switch (p) // special attributes { case 0: return "glowing "; case 1: return "jewelled "; case 2: return "runed "; case 3: return "smoking "; default: return "buggy "; } } static const char* staff_type_name(int stafftype) { switch (static_cast(stafftype)) { // staves case STAFF_WIZARDRY: return "wizardry"; case STAFF_POWER: return "power"; case STAFF_FIRE: return "fire"; case STAFF_COLD: return "cold"; case STAFF_POISON: return "poison"; case STAFF_ENERGY: return "energy"; case STAFF_DEATH: return "death"; case STAFF_CONJURATION: return "conjuration"; case STAFF_ENCHANTMENT: return "enchantment"; case STAFF_AIR: return "air"; case STAFF_EARTH: return "earth"; case STAFF_SUMMONING: return "summoning"; // rods case STAFF_SPELL_SUMMONING: return "summoning"; case STAFF_CHANNELING: return "channeling"; case STAFF_WARDING: return "warding"; case STAFF_DISCOVERY: return "discovery"; case STAFF_SMITING: return "smiting"; case STAFF_STRIKING: return "striking"; case STAFF_DEMONOLOGY: return "demonology"; case STAFF_VENOM: return "venom"; case STAFF_DESTRUCTION_I: case STAFF_DESTRUCTION_II: case STAFF_DESTRUCTION_III: case STAFF_DESTRUCTION_IV: return "destruction"; default: return "bugginess"; } } const char* racial_description_string(const item_def& item, bool terse) { switch (get_equip_race( item )) { case ISFLAG_ORCISH: return terse ? "orc " : "orcish "; case ISFLAG_ELVEN: return terse ? "elf " : "elven "; case ISFLAG_DWARVEN: return terse ? "dwarf " : "dwarven "; default: return ""; } } // gcc (and maybe the C standard) says that if you output // 0, even with showpos set, you get 0, not +0. This is a workaround. static void output_with_sign(std::ostream& os, int val) { if (val >= 0) os << '+'; os << val; } // Note that "terse" is only currently used for the "in hand" listing on // the game screen. std::string item_def::name_aux(description_level_type desc, bool terse, bool ident, unsigned long ignore_flags) const { // Shortcuts const int item_typ = sub_type; const int it_plus = plus; const int item_plus2 = plus2; const bool know_type = ident || item_type_known(*this); const bool dbname = (desc == DESC_DBNAME); const bool basename = (desc == DESC_BASENAME || (dbname && !know_type)); const bool qualname = (desc == DESC_QUALNAME); const bool know_curse = !basename && !qualname && !dbname && !testbits(ignore_flags, ISFLAG_KNOW_CURSE) && (ident || item_ident(*this, ISFLAG_KNOW_CURSE)); const bool __know_pluses = !basename && !qualname && !dbname && !testbits(ignore_flags, ISFLAG_KNOW_PLUSES) && (ident || item_ident(*this, ISFLAG_KNOW_PLUSES)); const bool know_brand = !basename && !qualname && !dbname && !testbits(ignore_flags, ISFLAG_KNOW_TYPE) && (ident || item_type_known(*this)); const bool know_ego = know_brand; const bool know_cosmetic = !__know_pluses && !terse & !basename && !qualname && !dbname && !(ignore_flags & ISFLAG_COSMETIC_MASK); // So that know_cosmetic won't be affected by ignore_flags. const bool know_pluses = __know_pluses && !testbits(ignore_flags, ISFLAG_KNOW_PLUSES); const bool know_racial = !(ignore_flags & ISFLAG_RACIAL_MASK); const bool need_plural = !basename && !dbname; int brand; std::ostringstream buff; switch (base_type) { case OBJ_WEAPONS: if (know_curse && !terse) { // We don't bother printing "uncursed" if the item is identified // for pluses (its state should be obvious), this is so that // the weapon name is kept short (there isn't a lot of room // for the name on the main screen). If you're going to change // this behaviour, *please* make it so that there is an option // that maintains this behaviour. -- bwr // Nor for artefacts. Again, the state should be obvious. --jpeg if (cursed()) buff << "cursed "; else if (Options.show_uncursed && !know_pluses && (!know_type || !is_artefact(*this))) buff << "uncursed "; } if (know_pluses) { if (terse && it_plus == item_plus2) output_with_sign(buff, it_plus); else { output_with_sign(buff, it_plus); buff << ','; output_with_sign(buff, item_plus2); } buff << " "; } if (is_artefact(*this) && !dbname) { buff << get_artefact_name(*this); break; } else if (flags & ISFLAG_BLESSED_WEAPON && !dbname) { // Since Angels and Daevas can get blessed base items, we // need a separate flag for this, so they can still have // their holy scourges and blessed eudemon blades. buff << "Blessed "; if (weapon_skill(*this) == SK_MACES_FLAILS) buff << "Scourge"; else buff << "Blade"; break; } // Now that we can have "glowing elven" weapons, it's // probably a good idea to cut out the descriptive // term once it's become obsolete. - bwr if (know_cosmetic) { switch (get_equip_desc(*this)) { case ISFLAG_RUNED: if (!testbits(ignore_flags, ISFLAG_RUNED)) buff << "runed "; break; case ISFLAG_GLOWING: if (!testbits(ignore_flags, ISFLAG_GLOWING)) buff << "glowing "; break; } } if (!basename && !dbname && know_racial) { // Always give racial type (it does have game effects). buff << racial_description_string(*this, terse); } if (know_brand && !terse && get_weapon_brand(*this) == SPWPN_VAMPIRICISM) { buff << "vampiric "; } buff << item_base_name(*this); if (know_brand) buff << weapon_brand_name(*this, terse); if (know_curse && cursed() && terse) buff << " (curse)"; break; case OBJ_MISSILES: brand = get_ammo_brand(*this); if (know_brand) { switch (brand) { case SPMSL_POISONED: buff << ((terse) ? "poison " : "poisoned "); break; case SPMSL_CURARE: buff << ((terse) ? "curare " : "curare-tipped "); break; case SPMSL_EXPLODING: buff << ((terse) ? "explode " : "exploding "); break; case SPMSL_STEEL: buff << "steel "; break; case SPMSL_SILVER: buff << "silver "; break; default: break; } } if (know_cosmetic && !know_brand) { switch (get_equip_desc(*this)) { case ISFLAG_GLOWING: if (!testbits(ignore_flags, ISFLAG_GLOWING)) buff << "glowing "; break; } } if (know_pluses) { output_with_sign(buff, it_plus); buff << ' '; } if (!basename && !dbname) buff << racial_description_string(*this, terse); buff << ammo_name(static_cast(item_typ)); if (know_brand) { switch (brand) { case SPMSL_FLAME: buff << ((terse) ? " (flame)" : " of flame"); break; case SPMSL_FROST: buff << ((terse) ? " (frost)" : " of frost"); break; case SPMSL_NORMAL: case SPMSL_POISONED: case SPMSL_CURARE: case SPMSL_EXPLODING: case SPMSL_STEEL: case SPMSL_SILVER: break; case SPMSL_PARALYSIS: buff << ((terse) ? " (paralysis)" : " of paralysis"); break; case SPMSL_SLOW: buff << ((terse) ? " (slow)" : " of slowing"); break; case SPMSL_SLEEP: buff << ((terse) ? " (sleep)" : " of sleeping"); break; case SPMSL_CONFUSION: buff << ((terse) ? " (conf)" : " of confusion"); break; case SPMSL_SICKNESS: buff << ((terse) ? " (sick)" : " of sickening"); break; case SPMSL_RAGE: buff << ((terse) ? " (frenzy)" : " of frenzy"); break; case SPMSL_RETURNING: buff << ((terse) ? " (return)" : " of returning"); break; case SPMSL_CHAOS: buff << ((terse) ? " (chaos)" : " of chaos"); break; case SPMSL_PENETRATION: buff << ((terse) ? " (penet)" : " of penetration"); break; case SPMSL_REAPING: buff << ((terse) ? " (reap)" : " of reaping"); break; case SPMSL_DISPERSAL: buff << ((terse) ? " (disperse)" : " of dispersal"); break; default: buff << " (buggy)"; } } break; case OBJ_ARMOUR: if (know_curse && !terse) { if (cursed()) buff << "cursed "; else if (Options.show_uncursed && !know_pluses) buff << "uncursed "; } if (know_pluses) { output_with_sign(buff, it_plus); buff << ' '; } if (item_typ == ARM_GLOVES || item_typ == ARM_BOOTS) buff << "pair of "; // When asking for the base item name, randartism is ignored. if (is_artefact(*this) && !basename && !dbname) { buff << get_artefact_name(*this); break; } // Now that we can have "glowing elven" armour, it's // probably a good idea to cut out the descriptive // term once it's become obsolete. - bwr if (know_cosmetic) { switch (get_equip_desc(*this)) { case ISFLAG_EMBROIDERED_SHINY: if (testbits(ignore_flags, ISFLAG_EMBROIDERED_SHINY)) break; if (item_typ == ARM_ROBE || item_typ == ARM_CLOAK || item_typ == ARM_GLOVES || item_typ == ARM_BOOTS || get_armour_slot(*this) == EQ_HELMET && !is_hard_helmet(*this)) { buff << "embroidered "; } else if (item_typ != ARM_LEATHER_ARMOUR && item_typ != ARM_ANIMAL_SKIN) { buff << "shiny "; } else buff << "dyed "; break; case ISFLAG_RUNED: if (!testbits(ignore_flags, ISFLAG_RUNED)) buff << "runed "; break; case ISFLAG_GLOWING: if (!testbits(ignore_flags, ISFLAG_GLOWING)) buff << "glowing "; break; } } if (!basename && !dbname) { // always give racial description (has game effects) buff << racial_description_string(*this, terse); } if (!basename && !dbname && is_hard_helmet(*this)) { const short dhelm = get_helmet_desc(*this); buff << ((dhelm == THELM_DESC_PLAIN) ? "" : (dhelm == THELM_DESC_WINGED) ? "winged " : (dhelm == THELM_DESC_HORNED) ? "horned " : (dhelm == THELM_DESC_CRESTED) ? "crested " : (dhelm == THELM_DESC_PLUMED) ? "plumed " : (dhelm == THELM_DESC_SPIKED) ? "spiked " : (dhelm == THELM_DESC_VISORED) ? "visored " : (dhelm == THELM_DESC_GOLDEN) ? "golden " : "buggy "); } if (!basename && item_typ == ARM_GLOVES) { const short dglov = get_gloves_desc(*this); buff << ((dglov == TGLOV_DESC_GLOVES) ? "gloves" : (dglov == TGLOV_DESC_GAUNTLETS) ? "gauntlets" : (dglov == TGLOV_DESC_BRACERS) ? "bracers" : "bug-ridden gloves"); } else buff << item_base_name(*this); if (know_ego && !is_artefact(*this)) { const special_armour_type sparm = get_armour_ego_type(*this); if (sparm != SPARM_NORMAL) { if (!terse) buff << " of "; // "naga barding of running" doesn't make any sense, and yes, // they are possible. if (sub_type == ARM_NAGA_BARDING && sparm == SPARM_RUNNING) buff << (terse ? "speed" : "speedy slithering"); else buff << armour_ego_name(*this, terse); } } if (know_curse && cursed() && terse) buff << " (curse)"; break; case OBJ_WANDS: if (basename) { buff << "wand"; break; } if (know_type) buff << "wand of " << wand_type_name(item_typ); else { buff << wand_secondary_string(this->special / 12) << wand_primary_string(this->special % 12) << " wand"; } if (know_pluses) buff << " (" << it_plus << ")"; else if (!dbname) { if (item_plus2 == ZAPCOUNT_EMPTY) buff << " {empty}"; else if (item_plus2 == ZAPCOUNT_MAX_CHARGED) buff << " {fully recharged}"; else if (item_plus2 == ZAPCOUNT_RECHARGED) buff << " {recharged}"; else if (item_plus2 > 0) buff << " {zapped: " << item_plus2 << '}'; } break; case OBJ_POTIONS: if (basename) { buff << "potion"; break; } if (know_type) buff << "potion of " << potion_type_name(item_typ); else { const int pqual = PQUAL(this->plus); const int pcolour = PCOLOUR(this->plus); static const char *potion_qualifiers[] = { "", "bubbling ", "fuming ", "fizzy ", "viscous ", "lumpy ", "smoky ", "glowing ", "sedimented ", "metallic ", "murky ", "gluggy ", "oily ", "slimy ", "emulsified " }; COMPILE_CHECK( ARRAYSZ(potion_qualifiers) == PDQ_NQUALS, c1 ); static const char *potion_colours[] = { "clear", "blue", "black", "silvery", "cyan", "purple", "orange", "inky", "red", "yellow", "green", "brown", "pink", "white" }; COMPILE_CHECK( ARRAYSZ(potion_colours) == PDC_NCOLOURS, c1 ); const char *qualifier = (pqual < 0 || pqual >= PDQ_NQUALS) ? "bug-filled " : potion_qualifiers[pqual]; const char *clr = (pcolour < 0 || pcolour >= PDC_NCOLOURS) ? "bogus" : potion_colours[pcolour]; buff << qualifier << clr << " potion"; } break; case OBJ_FOOD: switch (item_typ) { case FOOD_MEAT_RATION: buff << "meat ration"; break; case FOOD_BREAD_RATION: buff << "bread ration"; break; case FOOD_PEAR: buff << "pear"; break; case FOOD_APPLE: buff << "apple"; break; case FOOD_CHOKO: buff << "choko"; break; case FOOD_HONEYCOMB: buff << "honeycomb"; break; case FOOD_ROYAL_JELLY: buff << "royal jelly"; break; case FOOD_SNOZZCUMBER: buff << "snozzcumber"; break; case FOOD_PIZZA: buff << "slice of pizza"; break; case FOOD_APRICOT: buff << "apricot"; break; case FOOD_ORANGE: buff << "orange"; break; case FOOD_BANANA: buff << "banana"; break; case FOOD_STRAWBERRY: buff << "strawberry"; break; case FOOD_RAMBUTAN: buff << "rambutan"; break; case FOOD_LEMON: buff << "lemon"; break; case FOOD_GRAPE: buff << "grape"; break; case FOOD_SULTANA: buff << "sultana"; break; case FOOD_LYCHEE: buff << "lychee"; break; case FOOD_BEEF_JERKY: buff << "beef jerky"; break; case FOOD_CHEESE: buff << "cheese"; break; case FOOD_SAUSAGE: buff << "sausage"; break; case FOOD_CHUNK: if (!basename && !dbname) { if (food_is_rotten(*this)) buff << "rotting "; buff << "chunk of " << mons_type_name(it_plus, DESC_PLAIN) << " flesh"; } else buff << "chunk of flesh"; break; } break; case OBJ_SCROLLS: buff << "scroll"; if (basename) break; else buff << " "; if (know_type) { buff << "of " << scroll_type_name(item_typ); } else { const unsigned long sseed = this->special + (static_cast(it_plus) << 8) + (static_cast(OBJ_SCROLLS) << 16); buff << "labeled " << make_name(sseed, true); } break; case OBJ_JEWELLERY: { if (basename) { if (jewellery_is_amulet(*this)) buff << "amulet"; else buff << "ring"; break; } const bool is_randart = is_artefact(*this); if (know_curse) { if (cursed()) buff << "cursed "; else if (Options.show_uncursed && !terse && (!is_randart || !know_type) && (!ring_has_pluses(*this) || !know_pluses) // If the item is worn, its curse status is known, // no need to belabour the obvious. && get_equip_slot(this) == -1) { buff << "uncursed "; } } if (is_randart && !dbname) { buff << get_artefact_name(*this); break; } if (know_type) { if (know_pluses && ring_has_pluses(*this)) { output_with_sign(buff, it_plus); if (ring_has_pluses(*this) == 2) { buff << ','; output_with_sign(buff, item_plus2); } buff << ' '; } buff << jewellery_type_name(item_typ); } else { if (jewellery_is_amulet(*this)) { buff << amulet_secondary_string(this->special / 13) << amulet_primary_string(this->special % 13) << " amulet"; } else // i.e., a ring { buff << ring_secondary_string(this->special / 13) << ring_primary_string(this->special % 13) << " ring"; } } break; } case OBJ_MISCELLANY: if (item_typ == MISC_RUNE_OF_ZOT) { if (!dbname) buff << rune_type_name(it_plus) << " "; buff << "rune of Zot"; } else { if (is_deck(*this)) { if (basename) { buff << "deck of cards"; break; } else if (bad_deck(*this)) { buff << "BUGGY deck of cards"; break; } if (!dbname) buff << deck_rarity_name(deck_rarity(*this)) << ' '; } buff << misc_type_name(item_typ, know_type); if (is_deck(*this) && !dbname && (top_card_is_known(*this) || this->plus2 != 0)) { buff << " {"; // A marked deck! if (top_card_is_known(*this)) buff << card_name(top_card(*this)); // How many cards have been drawn, or how many are // left. if (this->plus2 != 0) { if (top_card_is_known(*this)) buff << ", "; if (this->plus2 > 0) buff << "drawn: "; else buff << "left: "; buff << abs(this->plus2); } buff << "}"; } } break; case OBJ_BOOKS: if (is_random_artefact(*this) && !dbname && !basename) { buff << get_artefact_name(*this); if (!know_type) buff << "book"; break; } if (basename) buff << (item_typ == BOOK_MANUAL ? "manual" : "book"); else if (!know_type) { if (item_typ == BOOK_DESTRUCTION) buff << "ancient heavily glowing book"; else { buff << book_secondary_string(this->special / 10) << book_primary_string(this->special % 10) << (item_typ == BOOK_MANUAL ? "manual" : "book"); } } else if (item_typ == BOOK_MANUAL) { if (dbname) buff << "manual"; else buff << "manual of " << skill_name(it_plus); } else if (item_typ == BOOK_NECRONOMICON) buff << "Necronomicon"; else if (item_typ == BOOK_DESTRUCTION) buff << "tome of Destruction"; else if (item_typ == BOOK_YOUNG_POISONERS) buff << "Young Poisoner's Handbook"; else if (item_typ == BOOK_BEASTS) buff << "Monster Manual"; else buff << "book of " << book_type_name(item_typ); break; case OBJ_STAVES: if (!know_type) { if (!basename) { buff << staff_secondary_string(this->special / 4) << staff_primary_string(this->special % 4); } buff << (item_is_rod(*this) ? "rod" : "staff"); } else { if (item_is_rod(*this) && know_type && know_pluses && !basename && !qualname && !dbname) { short rmod = 0; if (props.exists("rod_enchantment")) rmod = props["rod_enchantment"]; output_with_sign(buff, rmod); buff << " "; } buff << (item_is_rod(*this) ? "rod" : "staff") << " of " << staff_type_name(item_typ); } break; // rearranged 15 Apr 2000 {dlb}: case OBJ_ORBS: buff.str("Orb of Zot"); break; case OBJ_GOLD: buff << "gold piece"; break; // not implemented case OBJ_GEMSTONES: break; case OBJ_CORPSES: { if (food_is_rotten(*this) && !dbname) buff << "rotting "; unsigned long name_type; const std::string _name = get_corpse_name(*this, &name_type); const bool shaped = starts_with(_name, "shaped "); if (!_name.empty() && name_type == MF_NAME_ADJECTIVE) buff << _name << " "; if (!dbname && !starts_with(_name, "the ")) { buff << mons_type_name(it_plus, DESC_PLAIN) << ' '; if (!_name.empty() && shaped) buff << _name << ' '; } if (item_typ == CORPSE_BODY) buff << "corpse"; else if (item_typ == CORPSE_SKELETON) buff << "skeleton"; else buff << "corpse bug"; if (!_name.empty() && !shaped && name_type != MF_NAME_ADJECTIVE) { if (name_type == MF_NAME_SUFFIX) buff << " " << _name; else buff << " of " << _name; } break; } default: buff << "!"; } // One plural to rule them all. if (need_plural && this->quantity > 1 && !basename && !qualname) buff.str(pluralise(buff.str())); // Disambiguation. if (!terse && !basename && !dbname && know_type && !is_artefact(*this)) { switch (this->base_type) { case OBJ_STAVES: switch (item_typ) { case STAFF_DESTRUCTION_I: buff << " [fire]"; break; case STAFF_DESTRUCTION_II: buff << " [ice]"; break; case STAFF_DESTRUCTION_III: buff << " [lightning,iron,fireball]"; break; case STAFF_DESTRUCTION_IV: buff << " [inacc,magma,cold]"; break; } break; case OBJ_BOOKS: switch (item_typ) { case BOOK_MINOR_MAGIC_I: buff << " [flame]"; break; case BOOK_MINOR_MAGIC_II: buff << " [frost]"; break; case BOOK_MINOR_MAGIC_III: buff << " [summ]"; break; case BOOK_CONJURATIONS_I: buff << " [fire]"; break; case BOOK_CONJURATIONS_II: buff << " [ice]"; break; } break; default: break; } } // Rod charges. if (item_is_rod(*this) && know_type && know_pluses && !basename && !qualname && !dbname) { buff << " (" << (this->plus / ROD_CHARGE_MULT) << "/" << (this->plus2 / ROD_CHARGE_MULT) << ")"; } // debugging output -- oops, I probably block it above ... dang! {dlb} if (buff.str().length() < 3) { buff << "bad item (cl:" << static_cast(this->base_type) << ",ty:" << item_typ << ",pl:" << it_plus << ",pl2:" << item_plus2 << ",sp:" << this->special << ",qu:" << this->quantity << ")"; } return buff.str(); } static item_type_id_type objtype_to_idtype(object_class_type base_type) { switch (base_type) { case OBJ_WANDS: return (IDTYPE_WANDS); case OBJ_SCROLLS: return (IDTYPE_SCROLLS); case OBJ_JEWELLERY: return (IDTYPE_JEWELLERY); case OBJ_POTIONS: return (IDTYPE_POTIONS); case OBJ_STAVES: return (IDTYPE_STAVES); default: return (NUM_IDTYPE); } } bool item_type_known( const item_def& item ) { if (item_ident(item, ISFLAG_KNOW_TYPE)) return (true); // Artefacts have different descriptions from other items, // so we can't use general item knowledge for them. if (is_artefact(item)) return (false); // Missiles that are poisoned or made of obvious materials (steel, // silver) are always identified. if (item.base_type == OBJ_MISSILES) { int ammo_brand = get_ammo_brand(item); if (ammo_brand == SPMSL_POISONED || ammo_brand == SPMSL_CURARE || (ammo_brand >= SPMSL_PARALYSIS && ammo_brand <= SPMSL_RAGE) || ammo_brand == SPMSL_STEEL || ammo_brand == SPMSL_SILVER) { return (true); } } const item_type_id_type idt = objtype_to_idtype(item.base_type); if (idt != NUM_IDTYPE && item.sub_type < 50 ) return (type_ids[idt][item.sub_type] == ID_KNOWN_TYPE); else return (false); } bool item_type_known(const object_class_type base_type, const int sub_type) { const item_type_id_type idt = objtype_to_idtype(base_type); if (idt != NUM_IDTYPE && sub_type < 50 ) return (type_ids[idt][sub_type] == ID_KNOWN_TYPE); else return (false); } bool item_type_tried( const item_def& item ) { if (item_type_known(item)) return (false); if (is_artefact(item) && item.base_type == OBJ_JEWELLERY) { if (item.base_type == OBJ_JEWELLERY && item.props.exists("jewellery_tried") && item.props["jewellery_tried"].get_bool()) { return (true); } return (false); } const item_type_id_type idt = objtype_to_idtype(item.base_type); if (idt != NUM_IDTYPE && item.sub_type < 50) { return (type_ids[idt][item.sub_type] == ID_TRIED_TYPE || type_ids[idt][item.sub_type] == ID_MON_TRIED_TYPE || type_ids[idt][item.sub_type] == ID_TRIED_ITEM_TYPE); } else return (false); } id_arr& get_typeid_array() { return type_ids; } void set_ident_type( item_def &item, item_type_id_state_type setting, bool force ) { if (is_artefact(item) || crawl_state.arena) return; item_type_id_state_type old_setting = get_ident_type(item); set_ident_type(item.base_type, item.sub_type, setting, force); if (in_inventory(item)) shopping_list.cull_identical_items(item); if (setting == ID_KNOWN_TYPE && old_setting != ID_KNOWN_TYPE && notes_are_active() && is_interesting_item(item) && !(item.flags & (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET))) { // Make a note of it. take_note(Note(NOTE_ID_ITEM, 0, 0, item.name(DESC_NOCAP_A).c_str(), origin_desc(item).c_str())); // Sometimes (e.g. shops) you can ID an item before you get it; // don't note twice in those cases. item.flags |= (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET); } } void set_ident_type( object_class_type basetype, int subtype, item_type_id_state_type setting, bool force ) { preserve_quiver_slots p; // Don't allow overwriting of known type with tried unless forced. if (!force && (setting == ID_MON_TRIED_TYPE || setting == ID_TRIED_TYPE) && setting <= get_ident_type( basetype, subtype )) { return; } const item_type_id_type idt = objtype_to_idtype(basetype); if (idt != NUM_IDTYPE) { if (type_ids[idt][subtype] != setting) { type_ids[idt][subtype] = setting; request_autoinscribe(); } } } item_type_id_state_type get_ident_type(const item_def &item) { if (is_artefact(item)) return ID_UNKNOWN_TYPE; return get_ident_type(item.base_type, item.sub_type); } item_type_id_state_type get_ident_type(object_class_type basetype, int subtype) { const item_type_id_type idt = objtype_to_idtype(basetype); if (idt != NUM_IDTYPE && subtype < type_ids.height()) return type_ids[idt][subtype]; else return ID_UNKNOWN_TYPE; } class DiscEntry : public InvEntry { public: DiscEntry(InvEntry* inv) : InvEntry(*inv->item) { } virtual std::string get_text() const { return std::string(" ") + item->name(DESC_PLAIN); } }; static MenuEntry *discoveries_item_mangle(MenuEntry *me) { InvEntry *ie = dynamic_cast(me); DiscEntry *newme = new DiscEntry(ie); delete me; return (newme); } bool item_names( const item_def *it1, const item_def *it2 ) { return it1->name(DESC_PLAIN, false, false, false) < it2->name(DESC_PLAIN, false, false, false); } bool check_item_knowledge(bool quiet) { std::vector items; bool rc = true; const object_class_type idx_to_objtype[5] = { OBJ_WANDS, OBJ_SCROLLS, OBJ_JEWELLERY, OBJ_POTIONS, OBJ_STAVES }; const int idx_to_maxtype[5] = { NUM_WANDS, NUM_SCROLLS, NUM_JEWELLERY, NUM_POTIONS, NUM_STAVES }; for (int i = 0; i < 5; i++) for (int j = 0; j < idx_to_maxtype[i]; j++) { if (type_ids[i][j] == ID_KNOWN_TYPE) { item_def* ptmp = new item_def; if (ptmp != 0) { ptmp->base_type = idx_to_objtype[i]; ptmp->sub_type = j; ptmp->colour = 1; ptmp->quantity = 1; items.push_back(ptmp); } } } if (items.empty()) { rc = false; if (!quiet) mpr("You don't recognise anything yet!"); } else { rc = true; std::sort(items.begin(), items.end(), item_names); InvMenu menu; menu.set_title("You recognise:"); menu.set_flags(MF_NOSELECT); menu.set_type(MT_KNOW); menu.load_items(items, discoveries_item_mangle); menu.show(); redraw_screen(); for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) { delete *iter; } } return (rc); } // Used for: Pandemonium demonlords, shopkeepers, scrolls, random artefacts std::string make_name(unsigned long seed, bool all_cap, int maxlen, char start) { char name[ITEMNAME_SIZE]; int numb[17]; // contains the random seeds used for the name int i = 0; bool want_vowel = false; // Keep track of whether we want a vowel next. bool has_space = false; // Keep track of whether the name contains a space. for (i = 0; i < ITEMNAME_SIZE; ++i) name[i] = '\0'; const int var1 = (seed & 0xFF); const int var2 = ((seed >> 8) & 0xFF); const int var3 = ((seed >> 16) & 0xFF); const int var4 = ((seed >> 24) & 0xFF); numb[0] = 373 * var1 + 409 * var2 + 281 * var3; numb[1] = 163 * var4 + 277 * var2 + 317 * var3; numb[2] = 257 * var1 + 179 * var4 + 83 * var3; numb[3] = 61 * var1 + 229 * var2 + 241 * var4; numb[4] = 79 * var1 + 263 * var2 + 149 * var3; numb[5] = 233 * var4 + 383 * var2 + 311 * var3; numb[6] = 199 * var1 + 211 * var4 + 103 * var3; numb[7] = 139 * var1 + 109 * var2 + 349 * var4; numb[8] = 43 * var1 + 389 * var2 + 359 * var3; numb[9] = 367 * var4 + 101 * var2 + 251 * var3; numb[10] = 293 * var1 + 59 * var4 + 151 * var3; numb[11] = 331 * var1 + 107 * var2 + 307 * var4; numb[12] = 73 * var1 + 157 * var2 + 347 * var3; numb[13] = 379 * var4 + 353 * var2 + 227 * var3; numb[14] = 181 * var1 + 173 * var4 + 193 * var3; numb[15] = 131 * var1 + 167 * var2 + 53 * var4; numb[16] = 313 * var1 + 127 * var2 + 401 * var3 + 337 * var4; int len = 3 + numb[0] % 5 + ((numb[1] % 5 == 0) ? numb[2] % 6 : 1); if (all_cap) // scrolls have longer names len += 6; if (maxlen != -1 && len > maxlen) len = maxlen; ASSERT(len > 0); ASSERT(len <= ITEMNAME_SIZE); int j = numb[3] % 17; const int k = numb[4] % 17; int count = 0; for (i = 0; i < len; ++i) { j = (j + 1) % 17; if (j == 0) { count++; if (count > 9) break; } if (i == 0 && start != 0) { // Start the name with a predefined letter. name[i] = start; want_vowel = _is_random_name_vowel(start); } else if (!has_space && i > 5 && i < len - 4 && (numb[(k + 10 * j) % 17] % 5) != 3) // 4/5 chance of a space { // Hand out a space. want_vowel = true; name[i] = ' '; } else if (i > 0 && (want_vowel || (i > 1 && _is_random_name_vowel( name[i - 1] ) && !_is_random_name_vowel( name[i - 2] ) && (numb[(k + 4 * j) % 17] % 5) <= 1 ))) // 2/5 chance { // Place a vowel. want_vowel = true; name[i] = _random_vowel( numb[(k + 7 * j) % 17] ); if (_is_random_name_space( name[i] )) { if (i == 0) // Shouldn't happen. { want_vowel = false; name[i] = _random_cons( numb[(k + 14 * j) % 17] ); } else if (len < 7 || i <= 2 || i >= len - 3 || _is_random_name_space( name[i - 1] ) || (i > 1 && _is_random_name_space( name[i - 2] )) || i > 2 && !_is_random_name_vowel( name[i - 1] ) && !_is_random_name_vowel( name[i - 2] )) { // Replace the space with something else if ... // * the name is really short // * we're close to the begin/end of the name // * we just got a space, or // * the last two letters were consonants i--; continue; } } else if (i > 1 && name[i] == name[i - 1] && (name[i] == 'y' || name[i] == 'i' || (numb[(k + 12 * j) % 17] % 5) <= 1)) { // Replace the vowel with something else if the previous // letter was the same, and it's a 'y', 'i' or with 2/5 chance. i--; continue; } } else // We want a consonant. { // Use one of number of predefined letter combinations. if ((len > 3 || i != 0) && (numb[(k + 13 * j) % 17] % 7) <= 1 // 2/7 chance && (i < len - 2 || i > 0 && !_is_random_name_space(name[i - 1]))) { // Are we at start or end of the (sub) name? const bool beg = (i < 1 || _is_random_name_space(name[i - 1])); const bool end = (i >= len - 2); const int first = (beg ? 0 : (end ? 14 : 0)); const int last = (beg ? 27 : (end ? 56 : 67)); const int num = last - first; i++; // Pick a random combination of consonants from the set below. // begin -> [0,27] // middle -> [0,67] // end -> [14,56] switch (numb[(k + 11 * j) % 17] % num + first) { // start, middle case 0: strcat(name, "kl"); break; case 1: strcat(name, "gr"); break; case 2: strcat(name, "cl"); break; case 3: strcat(name, "cr"); break; case 4: strcat(name, "fr"); break; case 5: strcat(name, "pr"); break; case 6: strcat(name, "tr"); break; case 7: strcat(name, "tw"); break; case 8: strcat(name, "br"); break; case 9: strcat(name, "pl"); break; case 10: strcat(name, "bl"); break; case 11: strcat(name, "str"); i++; len++; break; case 12: strcat(name, "shr"); i++; len++; break; case 13: strcat(name, "thr"); i++; len++; break; // start, middle, end case 14: strcat(name, "sm"); break; case 15: strcat(name, "sh"); break; case 16: strcat(name, "ch"); break; case 17: strcat(name, "th"); break; case 18: strcat(name, "ph"); break; case 19: strcat(name, "pn"); break; case 20: strcat(name, "kh"); break; case 21: strcat(name, "gh"); break; case 22: strcat(name, "mn"); break; case 23: strcat(name, "ps"); break; case 24: strcat(name, "st"); break; case 25: strcat(name, "sk"); break; case 26: strcat(name, "sch"); i++; len++; break; // middle, end case 27: strcat(name, "ts"); break; case 28: strcat(name, "cs"); break; case 29: strcat(name, "xt"); break; case 30: strcat(name, "nt"); break; case 31: strcat(name, "ll"); break; case 32: strcat(name, "rr"); break; case 33: strcat(name, "ss"); break; case 34: strcat(name, "wk"); break; case 35: strcat(name, "wn"); break; case 36: strcat(name, "ng"); break; case 37: strcat(name, "cw"); break; case 38: strcat(name, "mp"); break; case 39: strcat(name, "ck"); break; case 40: strcat(name, "nk"); break; case 41: strcat(name, "dd"); break; case 42: strcat(name, "tt"); break; case 43: strcat(name, "bb"); break; case 44: strcat(name, "pp"); break; case 45: strcat(name, "nn"); break; case 46: strcat(name, "mm"); break; case 47: strcat(name, "kk"); break; case 48: strcat(name, "gg"); break; case 49: strcat(name, "ff"); break; case 50: strcat(name, "pt"); break; case 51: strcat(name, "tz"); break; case 52: strcat(name, "dgh"); i++; len++; break; case 53: strcat(name, "rgh"); i++; len++; break; case 54: strcat(name, "rph"); i++; len++; break; case 55: strcat(name, "rch"); i++; len++; break; // middle only case 56: strcat(name, "cz"); break; case 57: strcat(name, "xk"); break; case 58: strcat(name, "zx"); break; case 59: strcat(name, "xz"); break; case 60: strcat(name, "cv"); break; case 61: strcat(name, "vv"); break; case 62: strcat(name, "nl"); break; case 63: strcat(name, "rh"); break; case 64: strcat(name, "dw"); break; case 65: strcat(name, "nw"); break; case 66: strcat(name, "khl"); i++; len++; break; default: i--; break; } } else // Place a single letter instead. { if (i == 0) { // Start with any letter. name[i] = 'a' + (numb[(k + 8 * j) % 17] % 26); want_vowel = _is_random_name_vowel( name[i] ); } else { // Pick a random consonant. name[i] = _random_cons( numb[(k + 3 * j) % 17] ); } } } // No letter chosen? if (name[i] == '\0') { i--; continue; } // Picked wrong type? if (want_vowel && !_is_random_name_vowel( name[i] ) || !want_vowel && _is_random_name_vowel( name[i] )) { i--; continue; } if (_is_random_name_space( name[i] )) has_space = true; // If we just got a vowel, we want a consonant next, and vice versa. want_vowel = !_is_random_name_vowel(name[i]); } // Catch break and try to give a final letter. if (i > 0 && !_is_random_name_space( name[i - 1] ) && name[i - 1] != 'y' && _is_random_name_vowel( name[i - 1] ) && (count > 9 || (i < 8 && numb[16] % 3))) { // 2/3 chance of ending in a consonant name[i] = _random_cons( numb[j] ); } len = strlen( name ); if (len) { for (i = len - 1; i > 0; i--) { if (!isspace( name[i] )) break; else { name[i] = '\0'; len--; } } } // Fallback if the name was too short. if (len < 4) { strcpy(name, "plog"); len = 4; } for (i = 0; i < len; i++) if (all_cap || i == 0 || name[i - 1] == ' ') name[i] = toupper( name[i] ); return name; } static bool _is_random_name_space(char let) { return (let == ' '); } // Returns true for vowels, 'y' or space. static bool _is_random_name_vowel( char let ) { return (let == 'a' || let == 'e' || let == 'i' || let == 'o' || let == 'u' || let == 'y' || let == ' '); } // Returns a random vowel (a, e, i, o, u with equal probability) or space // or 'y' with lower chances. static char _random_vowel( int seed ) { static const char vowels[] = "aeiouaeiouaeiouy "; return (vowels[ seed % (sizeof(vowels) - 1) ]); } // Returns a random consonant with not quite equal probability. // Does not include 'y'. static char _random_cons( int seed ) { static const char consonants[] = "bcdfghjklmnpqrstvwxzcdfghlmnrstlmnrst"; return (consonants[ seed % (sizeof(consonants) - 1) ]); } bool is_interesting_item( const item_def& item ) { if (fully_identified(item) && is_artefact(item)) return (true); const std::string iname = menu_colour_item_prefix(item, false) + " " + item.name(DESC_PLAIN); for (unsigned i = 0; i < Options.note_items.size(); ++i) if (Options.note_items[i].matches(iname)) return (true); return (false); } // Returns true if an item is a potential life saver in an emergency // situation. bool is_emergency_item(const item_def &item) { if (!item_type_known(item)) return (false); switch (item.base_type) { case OBJ_WANDS: switch (item.sub_type) { case WAND_HASTING: if (you.religion == GOD_CHEIBRIADOS) return (false); case WAND_HEALING: case WAND_TELEPORTATION: return (true); default: return (false); } case OBJ_SCROLLS: switch (item.sub_type) { case SCR_TELEPORTATION: case SCR_BLINKING: case SCR_FEAR: return (true); default: return (false); } case OBJ_POTIONS: if (you.species == SP_MUMMY) return (false); switch (item.sub_type) { case POT_SPEED: if (you.religion == GOD_CHEIBRIADOS) return (false); case POT_HEALING: case POT_HEAL_WOUNDS: case POT_RESISTANCE: return (true); default: return (false); } default: return (false); } } // Returns true if an item can be considered particularly good. bool is_good_item(const item_def &item) { if (!item_type_known(item)) return (false); if (is_emergency_item(item)) return (true); switch (item.base_type) { case OBJ_SCROLLS: return (item.sub_type == SCR_ACQUIREMENT); case OBJ_POTIONS: switch (item.sub_type) { case POT_BERSERK_RAGE: if (you.religion == GOD_CHEIBRIADOS) return (false); case POT_CURE_MUTATION: case POT_GAIN_STRENGTH: case POT_GAIN_INTELLIGENCE: case POT_GAIN_DEXTERITY: case POT_EXPERIENCE: case POT_MAGIC: case POT_MIGHT: case POT_AGILITY: case POT_BRILLIANCE: case POT_RESTORE_ABILITIES: return (true); default: return (false); } default: return (false); } } // Returns true if using an item only has harmful effects. bool is_bad_item(const item_def &item, bool temp) { if (!item_type_known(item)) return (false); switch (item.base_type) { case OBJ_SCROLLS: switch (item.sub_type) { case SCR_CURSE_ARMOUR: case SCR_CURSE_WEAPON: return (true); case SCR_SUMMONING: // Summoning will always produce hostile monsters if you // worship a good god. (Use temp to allow autopickup to // prevent monsters from reading it.) return (temp && is_good_god(you.religion)); default: return (false); } case OBJ_POTIONS: // Can't be bad if you can't use them. if (you.species == SP_MUMMY) return (false); switch (item.sub_type) { case POT_CONFUSION: case POT_SLOWING: case POT_DEGENERATION: case POT_DECAY: case POT_PARALYSIS: return (true); case POT_POISON: case POT_STRONG_POISON: // Poison is not that bad if you're poison resistant. return (!player_res_poison(false) || !temp && you.species == SP_VAMPIRE); case POT_MUTATION: return (you.is_undead && (temp || you.species != SP_VAMPIRE || you.hunger_state < HS_SATIATED)); default: return (false); } case OBJ_JEWELLERY: switch (item.sub_type) { case AMU_INACCURACY: return (true); case RING_HUNGER: // Even Vampires can use this ring. return (!you.is_undead); default: return (false); } case OBJ_MISCELLANY: return (item.sub_type == MISC_CRYSTAL_BALL_OF_FIXATION); default: return (false); } } // Returns true if using an item is risky but may occasionally be // worthwhile. bool is_dangerous_item(const item_def &item, bool temp) { if (!item_type_known(item)) { // Use-IDing these is extremely dangerous! if (item.base_type == OBJ_MISCELLANY && (item.sub_type == MISC_CRYSTAL_BALL_OF_SEEING || item.sub_type == MISC_CRYSTAL_BALL_OF_ENERGY || item.sub_type == MISC_CRYSTAL_BALL_OF_FIXATION)) { return (true); } return (false); } switch (item.base_type) { case OBJ_SCROLLS: if (!item_type_known(item)) return (false); switch (item.sub_type) { case SCR_IMMOLATION: return (true); case SCR_TORMENT: return (!player_mutation_level(MUT_TORMENT_RESISTANCE) || !temp && you.species == SP_VAMPIRE); default: return (false); } case OBJ_POTIONS: if (!item_type_known(item)) return (false); switch (item.sub_type) { case POT_MUTATION: // Only living characters can mutate. return (!you.is_undead || temp && you.species == SP_VAMPIRE && you.hunger_state >= HS_SATIATED); default: return (false); } case OBJ_BOOKS: // The Tome of Destruction is certainly risky. return (item.sub_type == BOOK_DESTRUCTION || is_dangerous_spellbook(item)); default: return (false); } } bool is_useless_item(const item_def &item, bool temp) { switch (item.base_type) { case OBJ_WEAPONS: if (!you.could_wield(item, true) && !is_throwable(&you, item)) { // Weapon is too large (or small) to be wielded and cannot // be thrown either. return (true); } if (!item_type_known(item)) return (false); if (you.undead_or_demonic() && is_holy_item(item)) { if (!temp && you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH && you.species != SP_DEMONSPAWN) { return (false); } return (true); } return (false); case OBJ_MISSILES: // These are the same checks as in is_throwable(), except that // we don't take launchers into account. switch (item.sub_type) { case MI_LARGE_ROCK: return (you.body_size(PSIZE_BODY, !temp) < SIZE_LARGE || !you.can_throw_large_rocks()); case MI_JAVELIN: case MI_THROWING_NET: return (you.body_size(PSIZE_BODY, !temp) < SIZE_MEDIUM); } return (false); case OBJ_ARMOUR: return (!can_wear_armour(item, false, true)); case OBJ_SCROLLS: if (!item_type_known(item)) return (false); // A bad item is always useless. if (is_bad_item(item, temp)) return (true); switch (item.sub_type) { case SCR_PAPER: case SCR_RANDOM_USELESSNESS: case SCR_NOISE: return (true); case SCR_TORMENT: return (player_mutation_level(MUT_TORMENT_RESISTANCE) || !temp && you.species == SP_VAMPIRE); default: return (false); } case OBJ_WANDS: return (item.plus2 == ZAPCOUNT_EMPTY) || item_ident(item, ISFLAG_KNOW_PLUSES) && !item.plus; case OBJ_POTIONS: { // No potion is useless if it can be used for Evaporate. if (you.has_spell(SPELL_EVAPORATE)) return (false); // Apart from Evaporate, mummies can't use potions. if (you.species == SP_MUMMY) return (true); if (!item_type_known(item)) return (false); // A bad item is always useless. if (is_bad_item(item, temp)) return (true); switch (item.sub_type) { case POT_BERSERK_RAGE: case POT_CURE_MUTATION: case POT_GAIN_STRENGTH: case POT_GAIN_INTELLIGENCE: case POT_GAIN_DEXTERITY: return (you.species == SP_GHOUL || temp && you.species == SP_VAMPIRE && you.hunger_state < HS_SATIATED); case POT_LEVITATION: return (you.permanent_levitation() || you.permanent_flight()); case POT_PORRIDGE: case POT_WATER: case POT_BLOOD: case POT_BLOOD_COAGULATED: return (!can_ingest(item.base_type, item.sub_type, true, true, false)); case POT_POISON: case POT_STRONG_POISON: // If you're poison resistant, poison is only useless. // Spriggans could argue, but it's too small of a gain for // possible player confusion. return (player_res_poison(false)); case POT_INVISIBILITY: // If you're Corona'd or a TSO-ite, this is always useless. return (temp ? you.backlit(true) : you.haloed()); } return (false); } case OBJ_JEWELLERY: if (!item_type_known(item)) return (false); // Potentially useful. if (is_artefact(item)) return (false); if (is_bad_item(item, temp)) return (true); switch (item.sub_type) { case AMU_RAGE: return (you.is_undead && (you.species != SP_VAMPIRE || temp && you.hunger_state <= HS_SATIATED) || you.religion == GOD_TROG); case AMU_THE_GOURMAND: return (player_likes_chunks(true) || (player_mutation_level(MUT_HERBIVOROUS) == 3) || you.species == SP_MUMMY); case AMU_FAITH: return (you.species == SP_DEMIGOD); case RING_LIFE_PROTECTION: return (player_prot_life(false, temp, false) == 3); case RING_HUNGER: case RING_SUSTENANCE: return (you.species == SP_MUMMY || temp && you.species == SP_VAMPIRE && you.hunger_state == HS_STARVING); case RING_REGENERATION: return ((player_mutation_level(MUT_SLOW_HEALING) == 3) || temp && you.species == SP_VAMPIRE && you.hunger_state == HS_STARVING); case RING_SEE_INVISIBLE: return (player_mutation_level(MUT_ACUTE_VISION)); case RING_POISON_RESISTANCE: return (player_res_poison(false, temp, false) && (temp || you.species != SP_VAMPIRE)); case AMU_CONTROLLED_FLIGHT: return (player_genus(GENPC_DRACONIAN) || you.permanent_flight()); case RING_WIZARDRY: return (you.religion == GOD_TROG); case RING_TELEPORT_CONTROL: return (player_control_teleport(true, temp, false)); case RING_INVISIBILITY: return (temp && you.backlit(true)); default: return (false); } case OBJ_STAVES: if (you.religion == GOD_TROG && !item_is_rod(item)) return (true); break; case OBJ_FOOD: if (!is_inedible(item)) return (false); if (item.sub_type == FOOD_CHUNK && (you.has_spell(SPELL_SUBLIMATION_OF_BLOOD) || you.has_spell(SPELL_SIMULACRUM) || !temp && you.attribute[ATTR_TRANSFORMATION] == TRAN_LICH)) { return (false); } return (true); case OBJ_CORPSES: if (item.sub_type != CORPSE_SKELETON) return (false); if (you.has_spell(SPELL_BONE_SHARDS) || you.has_spell(SPELL_ANIMATE_DEAD) || you.has_spell(SPELL_ANIMATE_SKELETON) || player_mutation_level(MUT_RAISE_DEAD) || you.religion == GOD_YREDELEMNUL && you.piety >= piety_breakpoint(0)) { return (false); } return (true); default: return (false); } return (false); } static const std::string _item_prefix(const item_def &item, bool temp, bool filter) { std::vector prefixes; // No identified/unidentified for filtering, since the user might // want to filter on "ident" to find scrolls of identify. if (filter) ; else if (item_ident(item, ISFLAG_KNOW_TYPE)) prefixes.push_back("identified"); else { if (get_ident_type(item) == ID_KNOWN_TYPE) { // Wands are only fully identified if we know the number of // charges. if (item.base_type == OBJ_WANDS) prefixes.push_back("known"); // Rings are fully identified simply by knowing their type, // unless the ring has plusses, like a ring of dexterity. else if (item.base_type == OBJ_JEWELLERY && !jewellery_is_amulet(item)) { if (item.plus == 0 && item.plus2 == 0) prefixes.push_back("identified"); else prefixes.push_back("known"); } // All other types of magical items are fully identified // simply by knowing the type. else prefixes.push_back("identified"); } else prefixes.push_back("unidentified"); } if (good_god_hates_item_handling(item) || god_hates_item_handling(item)) prefixes.push_back("evil_item"); if (is_emergency_item(item)) prefixes.push_back("emergency_item"); if (is_good_item(item)) prefixes.push_back("good_item"); if (is_dangerous_item(item, temp)) prefixes.push_back("dangerous_item"); if (is_bad_item(item, temp)) prefixes.push_back("bad_item"); if (is_useless_item(item, temp)) prefixes.push_back("useless_item"); switch (item.base_type) { case OBJ_CORPSES: // Skeletons cannot be eaten. if (item.sub_type == CORPSE_SKELETON) { prefixes.push_back("inedible"); break; } // intentional fall-through case OBJ_FOOD: if (is_forbidden_food(item)) prefixes.push_back("evil_eating"); if (is_inedible(item)) prefixes.push_back("inedible"); else if (is_preferred_food(item)) prefixes.push_back("preferred"); // Don't include these for filtering, since the user might want // to use "muta" to search for "potion of cure mutation", and // similar. if (filter) ; else if (is_poisonous(item)) prefixes.push_back("poisonous"); else if (is_mutagenic(item)) prefixes.push_back("mutagenic"); else if (is_contaminated(item)) prefixes.push_back("contaminated"); else if (causes_rot(item)) prefixes.push_back("rot-inducing"); break; case OBJ_POTIONS: if (is_good_god(you.religion) && item_type_known(item) && is_blood_potion(item)) { prefixes.push_back("evil_eating"); } if (is_preferred_food(item)) prefixes.push_back("preferred"); break; case OBJ_WEAPONS: case OBJ_ARMOUR: case OBJ_JEWELLERY: if (item_is_equipped(item, true)) prefixes.push_back("equipped"); if (is_artefact(item)) prefixes.push_back("artefact"); break; case OBJ_MISSILES: if (item_is_equipped(item, true)) prefixes.push_back("equipped"); break; default: break; } if (Options.menu_colour_prefix_class && !filter) prefixes.push_back(item_class_name(item.base_type, true)); std::string result = comma_separated_line(prefixes.begin(), prefixes.end(), " ", " "); return result; } std::string menu_colour_item_prefix(const item_def &item, bool temp) { return _item_prefix(item, temp, false); } std::string filtering_item_prefix(const item_def &item, bool temp) { return _item_prefix(item, temp, true); } std::string get_menu_colour_prefix_tags(const item_def &item, description_level_type desc) { std::string cprf = menu_colour_item_prefix(item); std::string colour = ""; std::string colour_off = ""; std::string item_name = item.name(desc); int col = menu_colour(item_name, cprf, "pickup"); if (col != -1) colour = colour_to_str( col ); if (!colour.empty()) { // Order is important here. colour_off = ""; colour = "<" + colour + ">"; item_name = colour + item_name + colour_off; } return (item_name); } std::string get_message_colour_tags(const item_def &item, description_level_type desc, msg_channel_type channel) { std::string cprf = menu_colour_item_prefix(item); std::string colour = ""; std::string colour_off = ""; std::string item_name = item.name(desc); cprf += " " + item_name; int col = -1; const std::vector& mcm = Options.message_colour_mappings; typedef std::vector::const_iterator mcmci; for (mcmci ci = mcm.begin(); ci != mcm.end(); ++ci) { if (ci->message.is_filtered(channel, cprf)) { col = ci->colour; break; } } if (col != -1) colour = colour_to_str( col ); if (!colour.empty()) { // Order is important here. colour_off = ""; colour = "<" + colour + ">"; item_name = colour + item_name + colour_off; } return (item_name); } typedef std::map item_names_map; static item_names_map item_names_cache; typedef std::map > item_names_by_glyph_map; static item_names_by_glyph_map item_names_by_glyph_cache; void init_item_name_cache() { const int sub_type_limits[] = { NUM_WEAPONS, NUM_MISSILES, NUM_ARMOURS, NUM_WANDS, NUM_FOODS, 0, // Unknown I NUM_SCROLLS, NUM_JEWELLERY, NUM_POTIONS, 0, // Unknown II NUM_BOOKS, NUM_STAVES, 1, // Orbs NUM_MISCELLANY, 0, // Corpses 1, // Gold -1 }; item_names_cache.clear(); item_names_by_glyph_cache.clear(); for (int i = 0; sub_type_limits[i] != -1; i++) { object_class_type base_type = static_cast(i); unsigned char num_sub_types = (unsigned char) sub_type_limits[i]; for (unsigned char sub_type = 0; sub_type < num_sub_types; sub_type++) { if (base_type == OBJ_BOOKS) { if (sub_type == BOOK_RANDART_LEVEL || sub_type == BOOK_RANDART_THEME) { // These are randart only and have no fixed names. continue; } } int o = items(0, base_type, sub_type, true, 1, MAKE_ITEM_NO_RACE); if (o == NON_ITEM) continue; item_def &item(mitm[o]); item_types_pair pair = {base_type, sub_type}; // Make sure item isn't an artefact. item.flags &= ~ISFLAG_ARTEFACT_MASK; item.special = 0; std::string name = item.name(DESC_DBNAME, true, true); glyph g = get_item_glyph(&item); destroy_item(o, true); lowercase(name); if (base_type == OBJ_JEWELLERY && name == "buggy jewellery") continue; else if (name.find("buggy") != std::string::npos) { crawl_state.add_startup_error("Bad name for item name " " cache: " + name); continue; } if (item_names_cache.find(name) == item_names_cache.end()) { item_names_cache[name] = pair; if (g.ch) item_names_by_glyph_cache[g.ch].push_back(name); } } } ASSERT(item_names_cache.size() > 0); } item_types_pair item_types_by_name(std::string name) { lowercase(name); item_names_map::iterator i = item_names_cache.find(name); if (i != item_names_cache.end()) return (i->second); item_types_pair err = {OBJ_UNASSIGNED, 0}; return (err); } std::vector item_name_list_for_glyph(unsigned glyph) { item_names_by_glyph_map::iterator i; i = item_names_by_glyph_cache.find(glyph); if (i != item_names_by_glyph_cache.end()) return (i->second); std::vector empty; return empty; } bool is_named_corpse(const item_def &corpse) { ASSERT(corpse.base_type == OBJ_CORPSES); return (corpse.props.exists(CORPSE_NAME_KEY)); } std::string get_corpse_name(const item_def &corpse, unsigned long *name_type) { ASSERT(corpse.base_type == OBJ_CORPSES); if (!corpse.props.exists(CORPSE_NAME_KEY)) return (""); if (name_type != NULL) { *name_type = (unsigned long) corpse.props[CORPSE_NAME_TYPE_KEY].get_long(); } return (corpse.props[CORPSE_NAME_KEY].get_string()); }