/* * File: describe.cc * Summary: Functions used to print information about various game objects. * Written by: Linley Henzell * * Modified for Crawl Reference by $Author$ on $Date$ * * Change History (most recent first): * * <4> 10/14/99 BCR enummed describe_god() * <3> 10/13/99 BCR Added GOD_NO_GOD case in describe_god() * <2> 5/20/99 BWR Replaced is_artifact with * is_dumpable_artefact * <1> 4/20/99 JDJ Reformatted, uses string objects, * split out 10 new functions from * describe_item(), added * get_item_description and * is_artifact. */ #include "AppHdr.h" #include "describe.h" #include "database.h" #include #include #include #include #ifdef DOS #include #endif #include "externs.h" #include "abl-show.h" #include "debug.h" #include "decks.h" #include "fight.h" #include "itemname.h" #include "itemprop.h" #include "macro.h" #include "mon-util.h" #include "player.h" #include "randart.h" #include "religion.h" #include "skills2.h" #include "spl-book.h" #include "stuff.h" #include "spl-util.h" // ======================================================================== // Internal Functions // ======================================================================== //--------------------------------------------------------------- // // append_value // // Appends a value to the string. If plussed == 1, will add a + to // positive values (itoa always adds - to -ve ones). // //--------------------------------------------------------------- static void append_value( std::string & description, int valu, bool plussed ) { if (valu >= 0 && plussed == 1) description += "+"; char value_str[80]; itoa( valu, value_str, 10 ); description += value_str; } // end append_value() //--------------------------------------------------------------- // // print_description // // Takes a descrip string filled up with stuff from other functions, // and displays it with minor formatting to avoid cut-offs in mid // word and such. The character $ is interpreted as a CR. // //--------------------------------------------------------------- static void print_description( const std::string &d ) { std::string::size_type nextLine = std::string::npos; unsigned int currentPos = 0; const unsigned int lineWidth = get_number_of_cols() - 1; textcolor(LIGHTGREY); while(currentPos < d.length()) { if (currentPos != 0) gotoxy(1, wherey() + 1); // see if $ sign is within one lineWidth nextLine = d.find('$', currentPos); if (nextLine >= currentPos && nextLine < currentPos + lineWidth) { cprintf("%s", (d.substr(currentPos, nextLine-currentPos)).c_str()); currentPos = nextLine + 1; continue; } // Handle real line breaks. No substitutions necessary, just update // the counts. nextLine = d.find('\n', currentPos); if (nextLine >= currentPos && nextLine < currentPos + lineWidth) { cprintf("%s", (d.substr(currentPos, nextLine-currentPos)).c_str()); currentPos = nextLine +1; continue; } // no newline -- see if rest of string will fit. if (currentPos + lineWidth >= d.length()) { cprintf((d.substr(currentPos)).c_str()); return; } // ok.. try to truncate at space. nextLine = d.rfind(' ', currentPos + lineWidth); if (nextLine > 0) { cprintf((d.substr(currentPos, nextLine - currentPos)).c_str()); currentPos = nextLine + 1; continue; } // oops. just truncate. nextLine = currentPos + lineWidth; if (nextLine > d.length()) nextLine = d.length(); cprintf((d.substr(currentPos, nextLine - currentPos)).c_str()); currentPos = nextLine; } } //--------------------------------------------------------------- // // randart_descrip // // Appends the various powers of a random artefact to the description // string. // //--------------------------------------------------------------- static void randart_descrip( std::string &description, const item_def &item ) { unsigned int old_length = description.length(); randart_properties_t proprt; randart_wpn_properties( item, proprt ); if (proprt[ RAP_AC ]) { description += "$It affects your AC ("; append_value(description, proprt[ RAP_AC ], true); description += ")."; } if (proprt[ RAP_EVASION ]) { description += "$It affects your evasion ("; append_value(description, proprt[ RAP_EVASION ], true); description += ")."; } if (proprt[ RAP_STRENGTH ]) { description += "$It affects your strength ("; append_value(description, proprt[ RAP_STRENGTH ], true); description += ")."; } if (proprt[ RAP_INTELLIGENCE ]) { description += "$It affects your intelligence ("; append_value(description, proprt[ RAP_INTELLIGENCE ], true); description += ")."; } if (proprt[ RAP_DEXTERITY ]) { description += "$It affects your dexterity ("; append_value(description, proprt[ RAP_DEXTERITY ], true); description += ")."; } if (proprt[ RAP_ACCURACY ]) { description += "$It affects your accuracy ("; append_value(description, proprt[ RAP_ACCURACY ], true); description += ")."; } if (proprt[ RAP_DAMAGE ]) { description += "$It affects your damage-dealing abilities ("; append_value(description, proprt[ RAP_DAMAGE ], true); description += ")."; } if (proprt[ RAP_FIRE ] < -2) description += "$It makes you extremely vulnerable to fire. "; else if (proprt[ RAP_FIRE ] == -2) description += "$It makes you very vulnerable to fire. "; else if (proprt[ RAP_FIRE ] == -1) description += "$It makes you vulnerable to fire. "; else if (proprt[ RAP_FIRE ] == 1) description += "$It protects you from fire. "; else if (proprt[ RAP_FIRE ] == 2) description += "$It greatly protects you from fire. "; else if (proprt[ RAP_FIRE ] > 2) description += "$It renders you almost immune to fire. "; if (proprt[ RAP_COLD ] < -2) description += "$It makes you extremely vulnerable to cold. "; else if (proprt[ RAP_COLD ] == -2) description += "$It makes you very vulnerable to cold. "; else if (proprt[ RAP_COLD ] == -1) description += "$It makes you vulnerable to cold. "; else if (proprt[ RAP_COLD ] == 1) description += "$It protects you from cold. "; else if (proprt[ RAP_COLD ] == 2) description += "$It greatly protects you from cold. "; else if (proprt[ RAP_COLD ] > 2) description += "$It renders you almost immune to cold. "; if (proprt[ RAP_ELECTRICITY ]) description += "$It insulates you from electricity. "; if (proprt[ RAP_POISON ]) description += "$It protects you from poison. "; if (proprt[ RAP_NEGATIVE_ENERGY ] == 1) description += "$It partially protects you from negative energy. "; else if (proprt[ RAP_NEGATIVE_ENERGY ] == 2) description += "$It protects you from negative energy. "; else if (proprt[ RAP_NEGATIVE_ENERGY ] > 2) description += "$It renders you almost immune to negative energy. "; if (proprt[ RAP_MAGIC ]) description += "$It amplifies your intrinsic magic resistance. "; if (proprt[ RAP_STEALTH ] < 0) { if (proprt[ RAP_STEALTH ] < -20) description += "$It makes you much less stealthy. "; else description += "$It makes you less stealthy. "; } else if (proprt[ RAP_STEALTH ] > 0) { if (proprt[ RAP_STEALTH ] > 20) description += "$It makes you much more stealthy. "; else description += "$It makes you more stealthy. "; } if (proprt[ RAP_EYESIGHT ]) description += "$It enhances your eyesight. "; if (proprt[ RAP_INVISIBLE ]) description += "$It lets you turn invisible. "; if (proprt[ RAP_LEVITATE ]) description += "$It lets you levitate. "; if (proprt[ RAP_BLINK ]) description += "$It lets you blink. "; if (proprt[ RAP_CAN_TELEPORT ]) description += "$It lets you teleport. "; if (proprt[ RAP_BERSERK ]) description += "$It lets you go berserk. "; if (proprt[ RAP_MAPPING ]) description += "$It lets you sense your surroundings. "; if (proprt[ RAP_NOISES ]) description += "$It makes noises. "; if (proprt[ RAP_PREVENT_SPELLCASTING ]) description += "$It prevents spellcasting. "; if (proprt[ RAP_CAUSE_TELEPORTATION ]) description += "$It causes teleportation. "; if (proprt[ RAP_PREVENT_TELEPORTATION ]) description += "$It prevents most forms of teleportation. "; if (proprt[ RAP_ANGRY ]) description += "$It makes you angry. "; if (proprt[ RAP_METABOLISM ] >= 3) description += "$It greatly speeds your metabolism. "; else if (proprt[ RAP_METABOLISM ]) description += "$It speeds your metabolism. "; if (proprt[ RAP_MUTAGENIC ] > 3) description += "$It glows with mutagenic radiation."; else if (proprt[ RAP_MUTAGENIC ]) description += "$It emits mutagenic radiation."; if (old_length != description.length()) description += "$"; if (is_unrandom_artefact( item )) { const char *desc = unrandart_descrip( 0, item ); if (strlen( desc ) > 0) { description += desc; description += "$"; } } } static const char *trap_names[] = { "dart", "arrow", "spear", "axe", "teleport", "amnesia", "blade", "bolt", "zot", "needle", }; const char *trap_name(trap_type trap) { ASSERT(NUM_TRAPS == sizeof(trap_names) / sizeof(*trap_names)); if (trap >= TRAP_DART && trap < NUM_TRAPS) return trap_names[ static_cast( trap ) ]; return (NULL); } int str_to_trap(const std::string &s) { ASSERT(NUM_TRAPS == sizeof(trap_names) / sizeof(*trap_names)); if (s == "random" || s == "any") return (TRAP_RANDOM); else if (s == "suitable") return (TRAP_INDEPTH); for (int i = 0; i < NUM_TRAPS; ++i) { if (trap_names[i] == s) return (i); } return (-1); } //--------------------------------------------------------------- // // describe_demon // // Describes the random demons you find in Pandemonium. // //--------------------------------------------------------------- static std::string describe_demon(const monsters &mons) { ASSERT(mons.ghost.get()); long globby = 0; const ghost_demon &ghost = *mons.ghost; for (unsigned i = 0; i < ghost.name.length(); i++) globby += ghost.name[i]; globby *= ghost.name.length(); rng_save_excursion exc; seed_rng( globby ); std::string description = "A powerful demon, "; description += ghost.name; description += " has a"; switch (random2(31)) { case 0: description += " huge, barrel-shaped "; break; case 1: description += " wispy, insubstantial "; break; case 2: description += " spindly "; break; case 3: description += " skeletal "; break; case 4: description += " horribly deformed "; break; case 5: description += " spiny "; break; case 6: description += " waif-like "; break; case 7: description += " scaly "; break; case 8: description += " sickeningly deformed "; break; case 9: description += " bruised and bleeding "; break; case 10: description += " sickly "; break; case 11: description += " mass of writhing tentacles for a "; break; case 12: description += " mass of ropey tendrils for a "; break; case 13: description += " tree trunk-like "; break; case 14: description += " hairy "; break; case 15: description += " furry "; break; case 16: description += " fuzzy "; break; case 17: description += "n obese "; break; case 18: description += " fat "; break; case 19: description += " slimy "; break; case 20: description += " wrinkled "; break; case 21: description += " metallic "; break; case 22: description += " glassy "; break; case 23: description += " crystalline "; break; case 24: description += " muscular "; break; case 25: description += "n icky "; break; case 26: description += " swollen "; break; case 27: description += " lumpy "; break; case 28: description += "n armoured "; break; case 29: description += " carapaced "; break; case 30: description += " slender "; break; } description += "body"; switch (ghost.values[GVAL_DEMONLORD_FLY]) { case 1: // proper flight switch (random2(10)) { case 0: description += " with small insectoid wings"; break; case 1: description += " with large insectoid wings"; break; case 2: description += " with moth-like wings"; break; case 3: description += " with butterfly wings"; break; case 4: description += " with huge, bat-like wings"; break; case 5: description += " with fleshy wings"; break; case 6: description += " with small, bat-like wings"; break; case 7: description += " with hairy wings"; break; case 8: description += " with great feathered wings"; break; case 9: description += " with shiny metal wings"; break; default: break; } break; case 2: // levitation if (coinflip()) description += " which hovers in mid-air"; else description += " with sacs of gas hanging from its back"; break; default: // does not fly switch (random2(40)) { default: break; case 12: description += " covered in tiny crawling spiders"; break; case 13: description += " covered in tiny crawling insects"; break; case 14: description += " and the head of a crocodile"; break; case 15: description += " and the head of a hippopotamus"; break; case 16: description += " and a cruel curved beak for a mouth"; break; case 17: description += " and a straight sharp beak for a mouth"; break; case 18: description += " and no head at all"; break; case 19: description += " and a hideous tangle of tentacles for a mouth"; break; case 20: description += " and an elephantine trunk"; break; case 21: description += " and an evil-looking proboscis"; break; case 22: description += " and dozens of eyes"; break; case 23: description += " and two ugly heads"; break; case 24: description += " and a long serpentine tail"; break; case 25: description += " and a pair of huge tusks growing from its jaw"; break; case 26: description += " and a single huge eye, in the centre of its forehead"; break; case 27: description += " and spikes of black metal for teeth"; break; case 28: description += " and a disc-shaped sucker for a head"; break; case 29: description += " and huge, flapping ears"; break; case 30: description += " and a huge, toothy maw in the centre of its chest"; break; case 31: description += " and a giant snail shell on its back"; break; case 32: description += " and a dozen heads"; break; case 33: description += " and the head of a jackal"; break; case 34: description += " and the head of a baboon"; break; case 35: description += " and a huge, slobbery tongue"; break; case 36: description += " which is covered in oozing lacerations"; break; case 37: description += " and the head of a frog"; break; case 38: description += " and the head of a yak"; break; case 39: description += " and eyes out on stalks"; break; } break; } description += "."; switch (random2(40) + (player_can_smell() ? 0 : 3)) { case 0: description += " It stinks of brimstone."; break; case 1: description += " It smells like rotting flesh"; if (you.species == SP_GHOUL) description += " - yum!"; else description += "."; break; case 2: description += " It is surrounded by a sickening stench."; break; case 3: description += " It seethes with hatred of the living."; break; case 4: description += " Tiny orange flames dance around it."; break; case 5: description += " Tiny purple flames dance around it."; break; case 6: description += " It is surrounded by a weird haze."; break; case 7: description += " It glows with a malevolent light."; break; case 8: description += " It looks incredibly angry."; break; case 9: description += " It oozes with slime."; break; case 10: description += " It dribbles constantly."; break; case 11: description += " Mould grows all over it."; break; case 12: description += " It looks diseased."; break; case 13: description += " It looks as frightened of you as you are of it."; break; case 14: description += " It moves in a series of hideous convulsions."; break; case 15: description += " It moves with an unearthly grace."; break; case 16: description += " It hungers for your soul!"; break; case 17: description += " It leaves a glistening oily trail."; break; case 18: description += " It shimmers before your eyes."; break; case 19: description += " It is surrounded by a brilliant glow."; break; case 20: description += " It radiates an aura of extreme power."; break; default: break; } return description; } // end describe_demon() //--------------------------------------------------------------- // // describe_weapon // //--------------------------------------------------------------- static std::string describe_weapon( const item_def &item, bool verbose) { std::string description; description.reserve(200); description = ""; if (is_fixed_artefact( item )) { if (item_ident( item, ISFLAG_KNOW_PROPERTIES )) { description += "$"; switch (item.special) { case SPWPN_SINGING_SWORD: description += "This blessed weapon loves nothing more " "than to sing to its owner, " "whether they want it to or not. "; break; case SPWPN_WRATH_OF_TROG: description += "This was the favourite weapon of " "the old god Trog, before it was lost one day. " "It induces a bloodthirsty berserker rage in " "anyone who uses it to strike another. "; break; case SPWPN_SCYTHE_OF_CURSES: description += "This weapon carries a " "terrible and highly irritating curse. "; break; case SPWPN_MACE_OF_VARIABILITY: description += "It is rather unreliable. "; break; case SPWPN_GLAIVE_OF_PRUNE: description += "It is the creation of a mad god, and " "carries a curse which transforms anyone " "possessing it into a prune. Fortunately, " "the curse works very slowly, and one can " "use it briefly with no consequences " "worse than slightly purple skin and a few wrinkles. "; break; case SPWPN_SCEPTRE_OF_TORMENT: description += "This truly accursed weapon is " "an instrument of Hell. "; break; case SPWPN_SWORD_OF_ZONGULDROK: description += "This dreadful weapon is used " "at the user's peril. "; break; case SPWPN_SWORD_OF_CEREBOV: description += "Eerie flames cover its twisted blade. "; break; case SPWPN_STAFF_OF_DISPATER: description += "This legendary item can unleash " "the fury of Hell. "; break; case SPWPN_SCEPTRE_OF_ASMODEUS: description += "It carries some of the powers of " "the arch-fiend Asmodeus. "; break; case SPWPN_SWORD_OF_POWER: description += "It rewards the powerful with power " "and the meek with weakness. "; break; case SPWPN_KNIFE_OF_ACCURACY: description += "It is almost unerringly accurate. "; break; case SPWPN_STAFF_OF_OLGREB: description += "It was the magical weapon wielded by the " "mighty wizard Olgreb before he met his " "fate somewhere within these dungeons. It " "grants its wielder resistance to the " "effects of poison and increases their " "ability to use venomous magic, and " "carries magical powers which can be evoked. "; break; case SPWPN_VAMPIRES_TOOTH: description += "It is lethally vampiric. "; break; case SPWPN_STAFF_OF_WUCAD_MU: description += "Its power varies in proportion to " "its wielder's intelligence. " "Using it can be a bit risky. "; break; } description += "$"; } else if (item_type_known(item)) { // We know it's an artefact type weapon, but not what it does. description += "$This weapon may have some hidden properties.$"; } } else if (is_unrandom_artefact( item ) && strlen(unrandart_descrip(1, item)) != 0) { description += unrandart_descrip(1, item); description += "$"; } else { if (verbose) { switch (item.sub_type) { case WPN_CLUB: description += "A heavy piece of wood. "; break; case WPN_MACE: description += "A long handle " "with a heavy lump on one end. "; break; case WPN_FLAIL: description += "Like a mace, but with a length of chain " "between the handle and the lump of metal. "; break; case WPN_DAGGER: description += "A long knife or a very short sword, " "which can be held or thrown. "; break; case WPN_KNIFE: description += "A simple survival knife. " "Designed more for utility than combat, " "it looks quite capable of butchering a corpse. "; break; case WPN_MORNINGSTAR: description += "A mace covered in spikes. "; break; case WPN_SHORT_SWORD: description += "A sword with a short, slashing blade. "; break; case WPN_LONG_SWORD: description += "A sword with a long, slashing blade. "; break; case WPN_GREAT_SWORD: description += "A sword with a very long, heavy blade " "and a long handle. "; break; case WPN_SCIMITAR: description += "A long sword with a curved blade. "; break; case WPN_HAND_AXE: description += "A small axe designed for either hand combat " "or throwing. "; break; case WPN_BATTLEAXE: description += "A large axe with a double-headed blade. "; break; case WPN_SPEAR: description += "A long stick with a pointy blade on one end, " "to be held or thrown. "; break; case WPN_TRIDENT: description += "A hafted weapon with three points at one end. "; break; case WPN_HALBERD: description += "A long pole with a spiked axe head on one end. "; break; case WPN_SLING: description += "A piece of cloth and leather for launching stones, " "which do a small amount of damage on impact. "; break; case WPN_BOW: description += "A curved piece of wood and string, " "for shooting arrows. It does good damage in combat, " "and a skilled user can use it to great effect. "; break; case WPN_LONGBOW: description += "A long, strong bow made of yew. " "It does excellent damage in combat " "and a skilled archer can use it to great effect. "; break; case WPN_BLOWGUN: description += "A long, light tube, open at both ends. Doing " "very little damage, its main use is to fire poisoned " "needles from afar. It makes very little noise. "; break; case WPN_CROSSBOW: description += "A piece of machinery used for firing bolts, " "which takes some time to load and fire. " "It does very good damage in combat. "; break; case WPN_HAND_CROSSBOW: description += "A small crossbow, for firing darts. "; break; case WPN_GLAIVE: description += "A pole with a large, heavy blade on one end. "; break; case WPN_QUARTERSTAFF: description += "A sturdy wooden pole. "; break; case WPN_SCYTHE: description += "A farm implement, usually unsuited to combat. "; break; case WPN_GIANT_CLUB: description += "A giant lump of wood, " "shaped for an ogre's hands. "; break; case WPN_GIANT_SPIKED_CLUB: description += "A giant lump of wood with sharp spikes at one end. "; break; case WPN_EVENINGSTAR: description += "The opposite of a morningstar. "; break; case WPN_QUICK_BLADE: description += "A small and magically quick sword. "; break; case WPN_KATANA: description += "A very rare and extremely effective " "imported weapon, featuring a long " "single-edged blade. "; break; case WPN_LAJATANG: description += "A very rare and extremely effective " "imported weapon, featuring a pole with half-moon blades " "at both ends. "; break; case WPN_LOCHABER_AXE: description += "An enormous combination of a pike " "and a battle axe."; break; case WPN_EXECUTIONERS_AXE: description += "A huge axe. "; break; case WPN_DOUBLE_SWORD: description += "A magical weapon with two razor-sharp blades. "; break; case WPN_TRIPLE_SWORD: description += "A magical weapon with three " "great razor-sharp blades. "; break; case WPN_HAMMER: description += "The kind of thing you hit nails with, " "adapted for battle. "; break; case WPN_ANCUS: description += "A large and vicious toothed club. "; break; case WPN_WHIP: description += "A whip. "; break; case WPN_SABRE: description += "A sword with a medium length slashing blade. "; break; case WPN_DEMON_BLADE: description += "A terrible weapon, forged in the fires of Hell. "; break; case WPN_BLESSED_BLADE: description += "A blade blessed by the Shining One. "; break; case WPN_DEMON_WHIP: description += "A terrible weapon, woven " "in the depths of the inferno. "; break; case WPN_DEMON_TRIDENT: description += "A terrible weapon, molded by fire and brimstone. "; break; case WPN_BROAD_AXE: description += "An axe with a large blade. "; break; case WPN_WAR_AXE: description += "An axe intended for hand to hand combat. "; break; case WPN_SPIKED_FLAIL: description += "A flail with large spikes on the metal lump. "; break; case WPN_GREAT_MACE: description += "A large and heavy mace. "; break; case WPN_DIRE_FLAIL: description += "A flail with spiked lumps on both ends."; break; case WPN_FALCHION: description += "A sword with a broad slashing blade. "; break; default: DEBUGSTR("Unknown weapon"); } description += "$"; } } if (verbose) { description += "$Damage rating: "; append_value(description, property( item, PWPN_DAMAGE ), false); description += "$Accuracy rating: "; append_value(description, property( item, PWPN_HIT ), true); description += "$Base attack delay: "; append_value(description, property( item, PWPN_SPEED ) * 10, false); description += "%"; } description += "$"; if (!is_fixed_artefact( item )) { int spec_ench = get_weapon_brand( item ); if (!is_random_artefact( item ) && !verbose) spec_ench = SPWPN_NORMAL; // special weapon descrip if (spec_ench != SPWPN_NORMAL && item_type_known(item)) { description += "$"; switch (spec_ench) { case SPWPN_FLAMING: description += "It emits flame when wielded, " "causing extra injury to most foes " "and up to double damage against " "particularly susceptible opponents. "; break; case SPWPN_FREEZING: description += "It has been specially enchanted to " "freeze those struck by it, causing " "extra injury to most foes and " "up to double damage against " "particularly susceptible opponents. "; break; case SPWPN_HOLY_WRATH: description += "It has been blessed by the Shining One " "to harm undead and cause great damage to " "the unholy creatures of Hell or Pandemonium. "; break; case SPWPN_ELECTROCUTION: description += "Occasionally upon striking a foe " "it will discharge some electrical energy " "and cause terrible harm. "; break; case SPWPN_ORC_SLAYING: description += "It is especially effective against " "all of orcish descent. "; break; case SPWPN_VENOM: if (is_range_weapon(item)) description += "It poisons the unbranded ammo it fires. "; else description += "It poisons the flesh of those it strikes. "; break; case SPWPN_PROTECTION: description += "It protects the one who wields it against " "injury (+5 to AC). "; break; case SPWPN_DRAINING: description += "A truly terrible weapon, " "it drains the life of those it strikes. "; break; case SPWPN_SPEED: if (is_range_weapon(item)) { description += "It allows its wielder to fire twice when " "they would otherwise have fired only once. "; } else { description += "It allows its wielder to attack twice when " "they would otherwise have struck only once. "; } break; case SPWPN_VORPAL: if (is_range_weapon(item)) { description += "Any "; description += ammo_name( item ); description += " fired from it inflicts extra damage."; } else { description += "It inflicts extra damage upon your enemies. "; } break; case SPWPN_FLAME: description += "It turns projectiles fired from it into " "bolts of fire. "; break; case SPWPN_FROST: description += "It turns projectiles fired from it into " "bolts of frost. "; break; case SPWPN_VAMPIRICISM: description += "It inflicts no extra harm, " "but heals its wielder somewhat when " "it strikes a living foe. "; break; case SPWPN_DISRUPTION: description += "It is a weapon blessed by Zin, " "and can inflict up to fourfold damage " "when used against the undead. "; break; case SPWPN_PAIN: description += "In the hands of one skilled in " "necromantic magic it inflicts " "extra damage on living creatures. "; break; case SPWPN_DISTORTION: description += "It warps and distorts space around it. "; break; case SPWPN_REACHING: description += "It can be evoked to extend its reach. "; break; } } if (is_random_artefact( item )) { if (item_ident( item, ISFLAG_KNOW_PROPERTIES )) { unsigned int old_length = description.length(); randart_descrip( description, item ); if (description.length() == old_length) description += "$"; } else if (item_type_known(item)) { description += "$This weapon may have some hidden properties.$"; } } else if (spec_ench != SPWPN_NORMAL && item_type_known(item)) { description += "$"; } } if (item_known_cursed( item )) { description += "$It has a curse placed upon it."; } if (verbose && !is_range_weapon(item)) { #ifdef USE_NEW_COMBAT_STATS const int str_weight = weapon_str_weight( item.base_type, item.sub_type ); if (str_weight >= 8) description += "$This weapon is best used by the strong."; else if (str_weight > 5) description += "$This weapon is better for the strong."; else if (str_weight <= 2) description += "$This weapon is best used by the dexterous."; else if (str_weight < 5) description += "$This weapon is better for the dexterous."; #endif switch (hands_reqd(item, player_size())) { case HANDS_ONE: description += "$It is a one handed weapon."; break; case HANDS_HALF: description += "$It can be used with one hand, or more " "effectively with two (i.e. when not using a shield)."; break; case HANDS_TWO: description += "$It is a two handed weapon."; break; default: description += "$It is a buggy weapon."; break; } } if (!is_random_artefact( item )) { switch (get_equip_race( item )) { case ISFLAG_DWARVEN: description += "$It is well-crafted and very durable."; description += "$Dwarves are more deadly with it."; break; case ISFLAG_ELVEN: description += "$Elves are more accurate with it."; break; case ISFLAG_ORCISH: description += "$Orcs are more deadly with it."; break; } if (is_range_weapon(item)) { switch (get_equip_race( item )) { case ISFLAG_DWARVEN: description += "$It is most deadly when used with " "dwarven ammunition."; break; case ISFLAG_ELVEN: description += "$It is most deadly when used with " "elven ammunition."; break; case ISFLAG_ORCISH: description += "$It is most deadly when used with " "orcish ammunition."; break; } } } if (verbose) { description += "$It falls into the"; switch (item.sub_type) { case WPN_SLING: description += " 'slings' category. "; break; case WPN_BOW: case WPN_LONGBOW: description += " 'bows' category. "; break; case WPN_HAND_CROSSBOW: case WPN_CROSSBOW: description += " 'crossbows' category. "; break; case WPN_BLOWGUN: description += " 'darts' category. "; break; default: // Melee weapons switch (weapon_skill(item.base_type, item.sub_type)) { case SK_SHORT_BLADES: description += " 'short blades' category. "; break; case SK_LONG_SWORDS: description += " 'long swords' category. "; break; case SK_AXES: description += " 'axes' category. "; break; case SK_MACES_FLAILS: description += " 'maces and flails' category. "; break; case SK_POLEARMS: description += " 'polearms' category. "; break; case SK_STAVES: description += " 'staves' category. "; break; default: description += " 'bug' category. "; DEBUGSTR("Unknown weapon type"); break; } } } return (description); } //--------------------------------------------------------------- // // describe_ammo // //--------------------------------------------------------------- static std::string describe_ammo( const item_def &item ) { std::string description; description.reserve(64); switch (item.sub_type) { case MI_STONE: description += "A stone. It can be thrown by hand " "or fired with a sling. "; break; case MI_ARROW: description += "An arrow, to be shot with a bow. "; break; case MI_NEEDLE: description += "A needle. It can be fired with a blowgun. "; break; case MI_BOLT: description += "A crossbow bolt. "; break; case MI_DART: description += "A small throwing weapon. "; break; case MI_LARGE_ROCK: description += "A rock, used by giants as a missile. "; break; case MI_SLING_BULLET: description += "A small heavy projectile made of lead. " "It can be fired with a sling, or thrown by hand."; break; case MI_JAVELIN: description += "A long, light polearm that can be thrown by hand. "; if (!is_throwable(item, you.body_size())) description += "Unfortunately, it is too long and awkward " "for you to use."; break; case MI_NONE: // was eggplant description += "A purple vegetable. " "The presence of this object in the game indicates a bug. "; break; default: DEBUGSTR("Unknown ammo type"); break; } switch ( get_equip_race(item) ) { case ISFLAG_DWARVEN: description += "$It is more effective in conjunction with dwarven launchers."; break; case ISFLAG_ELVEN: description += "$It is more effective in conjunction with elven launchers."; break; case ISFLAG_ORCISH: description += "$It is more effective in conjunction with orcish launchers."; break; } if (item.special != 0 && item_type_known(item)) { switch (item.special) { case 1: description += "$When fired from an appropriate launcher, " "it turns into a bolt of flame. "; break; case 2: description += "$When fired from an appropriate launcher, " "it turns into a bolt of ice. "; break; case 3: case 4: description += "$It is coated with poison. "; break; } } description += "$"; return (description); } //--------------------------------------------------------------- // // describe_armour // //--------------------------------------------------------------- static std::string describe_armour( const item_def &item, bool verbose ) { std::string description; description.reserve(200); if (is_unrandom_artefact( item ) && strlen(unrandart_descrip(1, item)) != 0) { description += unrandart_descrip(1, item); description += "$"; } else { if (verbose) { switch (item.sub_type) { case ARM_ROBE: description += "A cloth robe. "; break; case ARM_LEATHER_ARMOUR: description += "A suit made of hardened leather. "; break; case ARM_RING_MAIL: description += "A leather suit covered in little rings. "; break; case ARM_SCALE_MAIL: description += "A leather suit covered in little metal plates. "; break; case ARM_CHAIN_MAIL: description += "A suit made of interlocking metal rings. "; break; case ARM_SPLINT_MAIL: description += "A suit made of splints of metal. "; break; case ARM_BANDED_MAIL: description += "A suit made of bands of metal. "; break; case ARM_PLATE_MAIL: description += "A suit of mail and large plates of metal. "; break; case ARM_SHIELD: description += "A piece of metal, to be strapped on one's arm. " "It is cumbersome to wear, and slightly slows " "the rate at which you may attack. "; break; case ARM_CLOAK: description += "A cloth cloak. "; break; case ARM_HELMET: switch (get_helmet_type( item )) { case THELM_HELMET: case THELM_HELM: description += "A piece of metal headgear. "; break; case THELM_CAP: description += "A cloth or leather cap. "; break; case THELM_WIZARD_HAT: description += "A conical cloth hat. "; break; } break; case ARM_GLOVES: description += "A pair of gloves. "; break; case ARM_CENTAUR_BARDING: description += "An armour made for centaurs, " "to wear over their equine half."; break; case ARM_NAGA_BARDING: description += "A special armour made for nagas, " "to wear over their tails."; break; case ARM_BOOTS: description += "A pair of boots."; break; case ARM_BUCKLER: description += "A small shield. "; break; case ARM_LARGE_SHIELD: description += "Like a normal shield, only larger. "; if (you.species == SP_TROLL || you.species == SP_OGRE || you.species == SP_OGRE_MAGE || player_genus(GENPC_DRACONIAN)) { description += "It looks like it would fit you well. "; } else { description += "It is very cumbersome to wear, and " "slows the rate at which you may attack. "; } break; case ARM_DRAGON_HIDE: description += "The scaly skin of a dragon. I suppose " "you could wear it if you really wanted to. "; break; case ARM_TROLL_HIDE: description += "The stiff and knobbly hide of a troll. " "I suppose you could wear it " "if you really wanted to. "; break; case ARM_CRYSTAL_PLATE_MAIL: description += "An incredibly heavy but extremely effective " "suit of crystalline armour. " "It is somewhat resistant to corrosion. "; break; case ARM_DRAGON_ARMOUR: description += "A magical armour, made from the scales of " "a fire-breathing dragon. It provides " "great protection from the effects of fire, " "but renders its wearer more susceptible to " "the effects of cold. "; break; case ARM_TROLL_LEATHER_ARMOUR: description += "A magical armour, made from the stiff and " "knobbly skin of a common troll. It magically regenerates " "its wearer's flesh at a fairly slow rate " "(unless already a troll). "; break; case ARM_ICE_DRAGON_HIDE: description += "The scaly skin of a dragon. I suppose " "you could wear it if you really wanted to. "; break; case ARM_ICE_DRAGON_ARMOUR: description += "A magical armour, made from the scales of " "a cold-breathing dragon. It provides " "great protection from the effects of cold, " "but renders its wearer more susceptible to " "the effects of fire and heat. "; break; case ARM_STEAM_DRAGON_HIDE: description += "The soft and supple scaly skin of " "a steam dragon. I suppose you could " "wear it if you really wanted to. "; break; case ARM_STEAM_DRAGON_ARMOUR: description += "A magical armour, made from the scales of " "a steam-breathing dragon. Although unlike " "the armour made from the scales of some " "larger dragons it does not provide its wearer " "with much in the way of special magical " "protection, it is extremely light and " "as supple as cloth. "; break; /* Protects from steam */ case ARM_MOTTLED_DRAGON_HIDE: description += "The weirdly-patterned scaley skin of " "a mottled dragon. I suppose you could " "wear it if you really wanted to. "; break; case ARM_MOTTLED_DRAGON_ARMOUR: description += "A magical armour made from the scales of a " "mottled dragon. Although unlike the armour " "made from the scales of some larger dragons " "it does not provide its wearer with much in " "the way of special magical protection, it is " "as light and relatively uncumbersome as " "leather armour. "; break; /* Protects from napalm */ case ARM_STORM_DRAGON_HIDE: description += "The hide of a storm dragon, covered in " "extremely hard blue scales. I suppose " "you could wear it if you really wanted to. "; break; case ARM_STORM_DRAGON_ARMOUR: description += "A magical armour made from the scales of " "a lightning-breathing dragon. It is heavier " "than most dragon scale armours, but gives " "its wearer great resistance to " "electrical discharges. "; break; case ARM_GOLD_DRAGON_HIDE: description += "The extremely tough and heavy skin of a " "golden dragon, covered in shimmering golden " "scales. I suppose you could wear it if " "you really wanted to. "; break; case ARM_GOLD_DRAGON_ARMOUR: description += "A magical armour made from the golden scales " "of a golden dragon. It is extremely heavy and " "cumbersome, but confers resistances to fire, " "cold, and poison on its wearer. "; break; case ARM_ANIMAL_SKIN: description += "The skins of several animals. "; break; case ARM_SWAMP_DRAGON_HIDE: description += "The slimy"; if (player_can_smell()) description += ", smelly"; description += " skin of a swamp-dwelling dragon. I suppose " "you could wear it if you really wanted to. "; break; case ARM_SWAMP_DRAGON_ARMOUR: description += "A magical armour made from the scales of " "a swamp dragon. It confers resistance to " "poison on its wearer. "; break; default: DEBUGSTR("Unknown armour"); } description += "$"; } } if (verbose && item.sub_type != ARM_SHIELD && item.sub_type != ARM_BUCKLER && item.sub_type != ARM_LARGE_SHIELD) { description += "$Armour rating: "; if (item.sub_type == ARM_HELMET && (get_helmet_type( item ) == THELM_CAP || get_helmet_type( item ) == THELM_WIZARD_HAT)) { // caps and wizard hats don't have a base AC append_value(description, 0, false); } else if (item.sub_type == ARM_NAGA_BARDING || item.sub_type == ARM_CENTAUR_BARDING) { // Barding has AC value 4. append_value(description, 4, false); } else { append_value(description, property( item, PARM_AC ), false); } description += "$Evasion modifier: "; append_value(description, property( item, PARM_EVASION ), true); description += "$"; } const int ego = get_armour_ego_type( item ); if (ego != SPARM_NORMAL && item_type_known(item) && verbose) { description += "$"; switch (ego) { case SPARM_RUNNING: description += "It allows its wearer to run at a great speed. "; break; case SPARM_FIRE_RESISTANCE: description += "It protects its wearer from heat and fire. "; break; case SPARM_COLD_RESISTANCE: description += "It protects its wearer from cold. "; break; case SPARM_POISON_RESISTANCE: description += "It protects its wearer from poison. "; break; case SPARM_SEE_INVISIBLE: description += "It allows its wearer to see invisible things. "; break; case SPARM_DARKNESS: description += "When activated it hides its wearer from " "the sight of others, but also increases " "their metabolic rate by a large amount. "; break; case SPARM_STRENGTH: description += "It increases the physical power of its wearer (+3 to strength). "; break; case SPARM_DEXTERITY: description += "It increases the dexterity of its wearer (+3 to dexterity). "; break; case SPARM_INTELLIGENCE: description += "It makes you more clever (+3 to intelligence). "; break; case SPARM_PONDEROUSNESS: description += "It is very cumbersome (-2 to EV, slows movement). "; break; case SPARM_LEVITATION: description += "It can be activated to allow its wearer to " "float above the ground and remain so indefinitely. "; break; case SPARM_MAGIC_RESISTANCE: description += "It increases its wearer's resistance " "to enchantments. "; break; case SPARM_PROTECTION: description += "It protects its wearer from harm (+3 to AC). "; break; case SPARM_STEALTH: description += "It enhances the stealth of its wearer. "; break; case SPARM_RESISTANCE: description += "It protects its wearer from the effects " "of both cold and heat. "; break; // these two are robes only: case SPARM_POSITIVE_ENERGY: description += "It partially protects its wearer from " "the effects of negative energy. "; break; case SPARM_ARCHMAGI: description += "It greatly increases the power of its " "wearer's magical spells, but is only " "intended for those who have " "very little left to learn. "; break; case SPARM_PRESERVATION: description += "It protects its wearer's possessions " "from damage and destruction. "; break; } description += "$"; } if (is_random_artefact( item )) { if (item_ident( item, ISFLAG_KNOW_PROPERTIES )) randart_descrip( description, item ); else if (item_type_known(item)) description += "$This armour may have some hidden properties.$"; } else { switch (get_equip_race( item )) { case ISFLAG_ELVEN: description += "$It is well-crafted and unobstructive"; if (item.sub_type == ARM_CLOAK || item.sub_type == ARM_BOOTS) description += ", and helps its wearer avoid being noticed"; description += "."; description += "$It fits elves well."; break; case ISFLAG_DWARVEN: description += "$It is well-crafted and very durable."; description += "$It fits dwarves well."; break; case ISFLAG_ORCISH: description += "$It fits orcs well."; break; default: break; } } if (verbose && get_armour_slot(item) == EQ_BODY_ARMOUR) { if ( is_light_armour(item) ) description += "$This is a light armour. Wearing it will " "exercise Dodging and Stealth."; else description += "$This is a heavy armour. Wearing it will " "exercise Armour."; } if (item_known_cursed( item )) { description += "$It has a curse placed upon it."; } return description; } //--------------------------------------------------------------- // // describe_stick // //--------------------------------------------------------------- static std::string describe_stick( const item_def &item ) { std::string description; description.reserve(64); if (get_ident_type( OBJ_WANDS, item.sub_type ) != ID_KNOWN_TYPE) description += "A stick. Maybe it's magical. "; else { description += "A magical device which "; switch (item.sub_type) { case WAND_FLAME: description += "throws little bits of flame. "; break; case WAND_FROST: description += "throws little bits of frost. "; break; case WAND_SLOWING: description += "casts enchantments to slow down the actions of " "a creature at which it is directed. "; break; case WAND_HASTING: description += "casts enchantments to speed up the actions of " "a creature at which it is directed. "; break; case WAND_MAGIC_DARTS: description += "throws small bolts of destructive energy. "; break; case WAND_HEALING: description += "can heal a creature's wounds. "; break; case WAND_PARALYSIS: description += "can render a creature immobile. "; break; case WAND_FIRE: description += "throws great bolts of fire. "; break; case WAND_COLD: description += "throws great bolts of cold. "; break; case WAND_CONFUSION: description += "induces confusion and bewilderment in " "a target creature. "; break; case WAND_INVISIBILITY: description += "hides a creature from the view of others. "; break; case WAND_DIGGING: description += "drills tunnels through unworked rock. "; break; case WAND_FIREBALL: description += "throws exploding blasts of flame. "; break; case WAND_TELEPORTATION: description += "causes a creature to be randomly translocated. "; break; case WAND_LIGHTNING: description += "throws great bolts of lightning. "; break; case WAND_POLYMORPH_OTHER: description += "causes a creature to be transmogrified into " "another form. " "It doesn't work on you, so don't even try. "; break; case WAND_ENSLAVEMENT: description += "causes slavish obedience in a creature. "; break; case WAND_DRAINING: description += "throws a bolt of negative energy which " "drains the life essences of living creatures, " "but is useless against the undead. "; break; case WAND_RANDOM_EFFECTS: description += "can produce a variety of effects. "; break; case WAND_DISINTEGRATION: description += "disrupts the physical structure of " "anything but the hardest walls -- even rigid " "statues, to say nothing of flesh. "; break; default: DEBUGSTR("Unknown stick"); } if (item_ident( item, ISFLAG_KNOW_PLUSES ) && item.plus == 0) description += "Unfortunately, it has no charges left. "; } return description; } //--------------------------------------------------------------- // // describe_food // //--------------------------------------------------------------- static std::string describe_food( const item_def &item ) { std::string description; description.reserve(100); switch (item.sub_type) { // rations case FOOD_MEAT_RATION: case FOOD_BREAD_RATION: description += "A filling ration of "; switch (item.sub_type) { case FOOD_MEAT_RATION: description += "dried and preserved meats"; break; case FOOD_BREAD_RATION: description += "breads"; break; } description += ". "; break; // fruits case FOOD_PEAR: case FOOD_APPLE: case FOOD_APRICOT: case FOOD_ORANGE: case FOOD_BANANA: case FOOD_STRAWBERRY: case FOOD_RAMBUTAN: case FOOD_LEMON: case FOOD_GRAPE: case FOOD_LYCHEE: case FOOD_SULTANA: description += "A"; switch (item.sub_type) { case FOOD_PEAR: description += " delicious juicy"; break; case FOOD_APPLE: description += " delicious red or green"; break; case FOOD_APRICOT: description += " delicious orange"; break; case FOOD_ORANGE: description += " delicious juicy orange"; break; case FOOD_BANANA: description += " delicious yellow"; break; case FOOD_STRAWBERRY: description += " small but delicious red"; break; case FOOD_RAMBUTAN: description += " small but delicious tropical"; break; case FOOD_LEMON: description += " yellow"; break; case FOOD_GRAPE: description += " small"; break; case FOOD_LYCHEE: description += " tropical"; break; case FOOD_SULTANA: description += " dried"; break; } description += " fruit"; switch (item.sub_type) { case FOOD_BANANA: description += ", probably grown and imported by " "some amoral multinational as the " "result of a corrupt trade deal"; break; case FOOD_RAMBUTAN: description += ". How it got into this dungeon " "is anyone's guess"; break; case FOOD_SULTANA: description += " of some sort, possibly a grape"; break; } description += ". "; break; // vegetables case FOOD_CHOKO: case FOOD_SNOZZCUMBER: description += "A"; switch (item.sub_type) { case FOOD_CHOKO: description += "n almost tasteless green"; break; case FOOD_SNOZZCUMBER: description += " repulsive cucumber-shaped"; break; } description += " vegetable"; switch (item.sub_type) { case FOOD_CHOKO: description += ", which grows on a vine"; break; } description += ". "; break; // lumps, slices, chunks, and strips case FOOD_HONEYCOMB: case FOOD_ROYAL_JELLY: case FOOD_PIZZA: case FOOD_CHEESE: case FOOD_BEEF_JERKY: case FOOD_SAUSAGE: case FOOD_CHUNK: description += "A"; switch (item.sub_type) { case FOOD_SAUSAGE: description += "n elongated"; break; } switch (item.sub_type) { case FOOD_HONEYCOMB: case FOOD_ROYAL_JELLY: case FOOD_CHEESE: case FOOD_SAUSAGE: description += " lump"; break; case FOOD_PIZZA: description += " slice"; break; case FOOD_BEEF_JERKY: description += " strip"; break; case FOOD_CHUNK: description += " piece"; } description += " of "; switch (item.sub_type) { case FOOD_SAUSAGE: description += "low-grade gristle, entrails and " "cereal products encased in an intestine"; break; case FOOD_HONEYCOMB: description += "the delicious honeycomb made by giant bees"; break; case FOOD_ROYAL_JELLY: description += "the magical substance produced by giant bees " "to be fed to their queens"; break; case FOOD_PIZZA: description += "pizza"; break; case FOOD_CHEESE: description += "cheese"; break; case FOOD_BEEF_JERKY: description += "preserved dead cow or bull"; break; case FOOD_CHUNK: description += "dungeon meat"; break; } description += ". "; switch (item.sub_type) { case FOOD_SAUSAGE: description += "Yum! "; break; case FOOD_PIZZA: description += "Don't tell me you don't know what that is! "; break; case FOOD_CHUNK: if (you.species != SP_GHOUL) description += "It looks rather unpleasant. "; if (item.special < 100) { if (you.species == SP_GHOUL) description += "It looks nice and ripe. "; else if (you.species != SP_MUMMY) { description += "In fact, it is " "rotting away before your eyes. " "Eating it would probably be unwise. "; } } break; } break; default: DEBUGSTR("Unknown food"); } description += "$"; return (description); } //--------------------------------------------------------------- // // describe_potion // //--------------------------------------------------------------- static const char* describe_potion( const item_def &item ) { if (get_ident_type( OBJ_POTIONS, item.sub_type ) != ID_KNOWN_TYPE) return "A small bottle of liquid.$"; switch (static_cast(item.sub_type)) { case POT_HEALING: return "A blessed fluid which heals some wounds, clears the mind, " "and cures diseases. If one uses it when they are at or near " "full health, it can also slightly repair permanent injuries.$"; case POT_HEAL_WOUNDS: return "A magical healing elixir which causes wounds to close and " "heal almost instantly. If one uses it when they are at or near " "full health, it can also repair permanent injuries.$"; case POT_SPEED: return "An enchanted beverage which speeds the actions of anyone who " "drinks it.$"; case POT_MIGHT: return "A magic potion which greatly increases the strength and " "physical power of one who drinks it.$"; case POT_GAIN_STRENGTH: return "A potion of beneficial mutation.$"; case POT_GAIN_DEXTERITY: return "A potion of beneficial mutation.$"; case POT_GAIN_INTELLIGENCE: return "A potion of beneficial mutation.$"; case POT_LEVITATION: return "A potion which confers great buoyancy " "on one who consumes it.$"; case POT_POISON: return "A nasty poisonous liquid.$"; case POT_SLOWING: return "A potion which slows your actions.$"; case POT_PARALYSIS: return "A potion which eliminates your control over your own body.$"; case POT_CONFUSION: return "A potion which confuses your perceptions and " "reduces your control over your own actions.$"; case POT_INVISIBILITY: return "A potion which hides you from the sight of others.$"; case POT_PORRIDGE: return "A filling potion of sludge, high in cereal fibre.$"; case POT_DEGENERATION: return "A noxious concoction which can do terrible things " "to your body, brain and reflexes.$"; case POT_DECAY: return "A vile and putrid cursed liquid which causes your " "flesh to decay before your very eyes.$"; case POT_WATER: return "A unique substance, vital for the existence of most life.$"; case POT_EXPERIENCE: return "A truly wonderful and very rare drink.$"; case POT_MAGIC: return "A valuable potion which grants a person with an " "infusion of magical energy.$"; case POT_RESTORE_ABILITIES: return "A potion which restores the abilities of one who drinks it.$"; case POT_STRONG_POISON: return "A terribly venomous potion.$"; case POT_BERSERK_RAGE: return "A potion which can send one into an incoherent rage.$"; case POT_CURE_MUTATION: return "A potion which removes some or all of any mutations " "which may be afflicting you.$"; case POT_MUTATION: return "A potion which does very strange things to you.$"; case NUM_POTIONS: return "A buggy potion."; } return "A very buggy potion."; } //--------------------------------------------------------------- // // describe_scroll // //--------------------------------------------------------------- static std::string describe_scroll( const item_def &item ) { std::string description; description.reserve(64); if (get_ident_type( OBJ_SCROLLS, item.sub_type ) != ID_KNOWN_TYPE) description += "A scroll of paper covered in magical writing."; else { switch (item.sub_type) { case SCR_IDENTIFY: description += "This useful magic scroll allows you to " "determine the properties of any object. "; break; case SCR_TELEPORTATION: description += "Reading the words on this scroll " "translocates you to a random position. "; break; case SCR_FEAR: description += "This scroll causes great fear in those " "who see the one who reads it. "; break; case SCR_NOISE: description += "This prank scroll, often slipped into a wizard's " "backpack by a devious apprentice, causes a loud noise. " "It is not otherwise noted for its usefulness. "; break; case SCR_REMOVE_CURSE: description += "Reading this scroll removes curses from " "the items you are using. "; break; case SCR_DETECT_CURSE: description += "This scroll allows you to detect the presence " "of cursed items among your possessions. "; break; case SCR_SUMMONING: description += "This scroll opens a conduit to the Abyss " "and draws a terrible beast to this world " "for a limited time. "; break; case SCR_ENCHANT_WEAPON_I: description += "This scroll places an enchantment on a weapon, " "making it more accurate in combat. It may fail " "to affect weapons already heavily enchanted. "; break; case SCR_ENCHANT_ARMOUR: description += "This scroll places an enchantment " "on a piece of armour. "; break; case SCR_TORMENT: description += "This scroll calls on the powers of Hell to " "inflict great pain on any nearby creature - " "including you! "; break; case SCR_RANDOM_USELESSNESS: description += "It is easy to be blinded to the essential " "uselessness of this scroll by the sense of achievement " "you get from getting it to work at all."; // -- The Hitchhiker's Guide to the Galaxy (paraphrase) break; case SCR_CURSE_WEAPON: description += "This scroll places a curse on a weapon. "; break; case SCR_CURSE_ARMOUR: description += "This scroll places a curse " "on a piece of armour. "; break; case SCR_IMMOLATION: description += "Small writing on the back of the scroll reads: " "\"Warning: contents under pressure. Do not use near" " flammable objects.\""; break; case SCR_BLINKING: description += "This scroll allows its reader to teleport " "a short distance, with precise control. Be wary that " "controlled teleports will cause the subject to " "become contaminated with magical energy. "; break; case SCR_PAPER: description += "Apart from a label, this scroll is blank. "; break; case SCR_MAGIC_MAPPING: description += "This scroll reveals the nearby surroundings " "of one who reads it. "; break; case SCR_FORGETFULNESS: description += "This scroll induces " "an irritating disorientation. "; break; case SCR_ACQUIREMENT: description += "This wonderful scroll causes the " "creation of a valuable item to " "appear before the reader. " "It is especially treasured by specialist " "magicians, as they can use it to obtain " "the powerful spells of their specialty. "; break; case SCR_ENCHANT_WEAPON_II: description += "This scroll places an enchantment on a weapon, " "making it inflict greater damage in combat. " "It may fail to affect weapons already " "heavily enchanted. "; break; case SCR_VORPALISE_WEAPON: description += "This scroll enchants a weapon so as to make " "it far more effective at inflicting harm on " "its wielder's enemies. Using it on a weapon " "already affected by some kind of special " "enchantment (other than that produced by a " "normal scroll of enchant weapon) is not advised. "; break; case SCR_RECHARGING: description += "This scroll restores the charges of " "any magical wand wielded by its reader. "; break; case SCR_ENCHANT_WEAPON_III: description += "This scroll enchants a weapon to be " "far more effective in combat. Although " "it can be used in the creation of especially " "enchanted weapons, it may fail to affect those " "already heavily enchanted. "; break; default: DEBUGSTR("Unknown scroll"); } } description += "$"; return (description); } //--------------------------------------------------------------- // // describe_jewellery // //--------------------------------------------------------------- static std::string describe_jewellery( const item_def &item, bool verbose) { std::string description; description.reserve(200); if (is_unrandom_artefact( item ) && strlen(unrandart_descrip(1, item)) != 0) { description += unrandart_descrip(1, item); description += "$"; } else if ((!is_random_artefact( item ) && get_ident_type( OBJ_JEWELLERY, item.sub_type ) != ID_KNOWN_TYPE) || (is_random_artefact( item ) && !item_type_known(item))) { description += "A piece of jewellery."; } else if (verbose || is_random_artefact( item )) { switch (item.sub_type) { case RING_REGENERATION: description += "This wonderful ring greatly increases the " "recuperative powers of its wearer, but also " "considerably speeds his or her metabolism. "; break; case RING_PROTECTION: description += "This ring either protects its wearer from harm or makes " "them more vulnerable to injury, to a degree dependent " "on its power. "; break; case RING_PROTECTION_FROM_FIRE: description += "This ring provides protection from heat and fire. "; break; case RING_POISON_RESISTANCE: description += "This ring provides protection from the effects of poisons and venom. "; break; case RING_PROTECTION_FROM_COLD: description += "This ring provides protection from cold. "; break; case RING_STRENGTH: description += "This ring increases or decreases the physical strength " "of its wearer, to a degree dependent on its power. "; break; case RING_SLAYING: description += "This ring increases the hand-to-hand and missile combat " "skills of its wearer."; break; case RING_SEE_INVISIBLE: description += "This ring allows its wearer to see those things hidden " "from view by magic. "; break; case RING_INVISIBILITY: description += "This powerful ring can be activated to hide its wearer " "from the view of others, but increases the speed of his " "or her metabolism greatly while doing so. "; break; case RING_HUNGER: description += "This accursed ring causes its wearer to hunger " "considerably more quickly. "; break; case RING_TELEPORTATION: description += "This ring occasionally exerts its power to randomly " "translocate its wearer to another place, and can be " "deliberately activated for the same effect. "; break; case RING_EVASION: description += "This ring makes its wearer either more or less capable " "of avoiding attacks, depending on its degree " "of enchantment. "; break; case RING_SUSTAIN_ABILITIES: description += "This ring protects its wearer from the loss of their " "strength, dexterity and intelligence. "; break; case RING_SUSTENANCE: description += "This ring provides energy to its wearer, so that they " "need eat less often. "; break; case RING_DEXTERITY: description += "This ring increases or decreases the dexterity of its " "wearer, depending on the degree to which it has been " "enchanted. "; break; case RING_INTELLIGENCE: description += "This ring increases or decreases the mental ability of " "its wearer, depending on the degree to which it has " "been enchanted. "; break; case RING_WIZARDRY: description += "This ring increases the ability of its wearer to use " "magical spells. "; break; case RING_MAGICAL_POWER: description += "This ring increases its wearer's reserves of magical " "power. "; break; case RING_LEVITATION: description += "This ring allows its wearer to hover above the floor. "; break; case RING_LIFE_PROTECTION: description += "This blessed ring protects the life-force of its wearer " "from negative energy, making them partially immune to " "the draining effects of undead and necromantic magic. "; break; case RING_PROTECTION_FROM_MAGIC: description += "This ring increases its wearer's resistance to " "hostile enchantments. "; break; case RING_FIRE: description += "This ring brings its wearer more in contact with " "the powers of fire. He or she gains resistance to " "heat and can use fire magic more effectively, but " "becomes more vulnerable to the effects of cold. "; break; case RING_ICE: description += "This ring brings its wearer more in contact with " "the powers of cold and ice. He or she gains resistance " "to cold and can use ice magic more effectively, but " "becomes more vulnerable to the effects of fire. "; break; case RING_TELEPORT_CONTROL: description += "This ring allows its wearer to control the " "destination of any teleportation, although without " "perfect accuracy. Trying to teleport into a solid " "object will result in a random teleportation, at " "least in the case of a normal teleportation. Also " "be wary that controlled teleports will contaminate " "the subject with residual magical energy."; break; case AMU_RAGE: description += "This amulet enables its wearer to attempt to enter " "a state of berserk rage, and increases their chance " "of successfully doing so. It also partially protects " "the user from passing out when coming out of that rage. "; break; case AMU_RESIST_SLOW: description += "This amulet protects its wearer from some magically " "induced forms of slowness, and increases the duration " "of enchantments which speed his or her actions. "; break; case AMU_CLARITY: description += "This amulet protects its wearer from some forms of " "mental confusion. "; break; case AMU_WARDING: description += "This amulet repels some of the attacks of creatures " "which have been magically summoned, and also " "makes the wearer more resistant to draining attacks. "; break; case AMU_RESIST_CORROSION: description += "This amulet protects the wearer and their equipment " "from corrosion caused by acids, although not " "infallibly so. "; break; case AMU_THE_GOURMAND: description += "This amulet protects its wearer from " "sickness from eating fresh raw meat and allows them to " "digest it when not hungry, but its effects on the wearer's " "digestion are cumulative over time, and are initially " "small."; break; case AMU_CONSERVATION: description += "This amulet protects some of the possessions of " "its wearer from outright destruction, but not " "infallibly so. "; break; case AMU_CONTROLLED_FLIGHT: description += "Should the wearer of this amulet be levitated " "by magical means, he or she will be able to exercise " "some control over the resulting motion. This allows " "the descent of staircases and the retrieval of items " "lying on the ground, for example, but does not " "deprive the wearer of the benefits of levitation. "; break; case AMU_INACCURACY: description += "This amulet makes its wearer less accurate in hand combat. "; break; case AMU_RESIST_MUTATION: description += "This amulet protects its wearer from mutations, " "although not infallibly so. "; break; default: DEBUGSTR("Unknown jewellery"); } description += "$"; } if ((verbose || is_random_artefact( item )) && item_ident( item, ISFLAG_KNOW_PLUSES )) { // Explicit description of ring power (useful for randarts) // Note that for randarts we'll print out the pluses even // in the case that its zero, just to avoid confusion. -- bwr if (item.plus != 0 || (item.sub_type == RING_SLAYING && item.plus2 != 0) || is_random_artefact( item )) { switch (item.sub_type) { case RING_PROTECTION: description += "$It affects your AC ("; append_value( description, item.plus, true ); description += ")."; break; case RING_EVASION: description += "$It affects your evasion ("; append_value( description, item.plus, true ); description += ")."; break; case RING_STRENGTH: description += "$It affects your strength ("; append_value( description, item.plus, true ); description += ")."; break; case RING_INTELLIGENCE: description += "$It affects your intelligence ("; append_value( description, item.plus, true ); description += ")."; break; case RING_DEXTERITY: description += "$It affects your dexterity ("; append_value( description, item.plus, true ); description += ")."; break; case RING_SLAYING: if (item.plus != 0 || is_random_artefact( item )) { description += "$It affects your accuracy ("; append_value( description, item.plus, true ); description += ")."; } if (item.plus2 != 0 || is_random_artefact( item )) { description += "$It affects your damage-dealing abilities ("; append_value( description, item.plus2, true ); description += ")."; } break; default: break; } } } // randart properties if (is_random_artefact( item )) { if (item_ident( item, ISFLAG_KNOW_PROPERTIES )) randart_descrip( description, item ); else if (item_type_known(item)) { if (item.sub_type >= AMU_RAGE) description += "$This amulet may have hidden properties.$"; else description += "$This ring may have hidden properties.$"; } } if (item_known_cursed( item )) { description += "$It has a curse placed upon it."; } return (description); } // end describe_jewellery() //--------------------------------------------------------------- // // describe_staff // //--------------------------------------------------------------- static std::string describe_staff( const item_def &item ) { std::string description; description.reserve(200); if (item_type_known(item)) { // NB: the leading space is here {dlb} description += "This " + std::string( item_is_staff( item ) ? "staff " : "rod " ); switch (item.sub_type) { case STAFF_WIZARDRY: description += "significantly increases the ability of its wielder to use " "magical spells. "; break; case STAFF_POWER: description += "provides a reservoir of magical power to its wielder. "; break; case STAFF_FIRE: description += "increases the power of fire spells cast by its wielder, " "and protects him or her from the effects of heat and fire. " "It can burn those struck by it. "; break; case STAFF_COLD: description += "increases the power of ice spells cast by its wielder, " "and protects him or her from the effects of cold. It can " "freeze those struck by it. "; break; case STAFF_POISON: description += "increases the power of poisoning spells cast by its " "wielder, and protects him or her from the effects of " "poison. It can poison those struck by it. "; break; case STAFF_ENERGY: description += "allows its wielder to cast magical spells without " "hungering as a result. "; break; case STAFF_DEATH: description += "increases the power of necromantic spells cast by its " "wielder. It can cause great pain in those living souls " "its wielder strikes. "; break; case STAFF_CONJURATION: description += "increases the power of conjurations cast by its wielder. "; break; case STAFF_ENCHANTMENT: description += "increases the power of enchantments cast by its wielder. "; break; case STAFF_SUMMONING: description += "increases the power of summonings cast by its wielder. "; break; case STAFF_SMITING: description += "allows its wielder to smite foes from afar. The wielder " "must be at least level four to safely use this ability, " "which drains four charges. "; break; case STAFF_STRIKING: description += "allows its wielder to strike foes from afar " "with force bolts. "; break; case STAFF_SPELL_SUMMONING: description += "contains spells of summoning. "; break; case STAFF_WARDING: description += "contains spells designed to repel one's enemies. "; break; case STAFF_DISCOVERY: description += "contains spells which reveal various aspects of " "an explorer's surroundings to them. "; break; case STAFF_AIR: description += "increases the power of air spells cast by its wielder. " "It can shock those struck by it. "; break; case STAFF_EARTH: description += "increases the power of earth spells cast by its wielder. " "It can crush those struck by it. "; break; case STAFF_CHANNELING: description += "allows its caster to channel ambient magical energy for " "his or her own purposes. "; break; default: description += "contains spells of mayhem and destruction. "; break; } if (item_is_rod( item )) { description += "$$It uses its own mana reservoir for casting spells, and " "recharges automatically by channeling mana from its " "wielder."; } else { description += "$$Damage rating: 7 $Accuracy rating: +6 $Attack delay: 120%"; description += "$$It falls into the 'staves' category. "; } } else { description += "A stick imbued with magical properties.$"; } return (description); } //--------------------------------------------------------------- // // describe_misc_item // //--------------------------------------------------------------- static std::string describe_misc_item( const item_def &item ) { std::string description; description.reserve(100); const misc_item_type subtype = static_cast(item.sub_type); if (item_type_known(item)) { switch (subtype) { case MISC_BOTTLED_EFREET: description += "A mighty efreet, captured by some wizard and bound into " "a bronze flask. Breaking the flask's seal will release it " "to wreak havoc - possibly on you. "; break; case MISC_CRYSTAL_BALL_OF_SEEING: description += "A magical device which allows one to see the layout of " "their surroundings. It requires a degree of magical " "ability to be used reliably, otherwise it can produce " "unpredictable and possibly harmful results. "; break; case MISC_AIR_ELEMENTAL_FAN: description += "A magical device for summoning air " "elementals. It is rather unreliable, and usually requires " "several attempts to function correctly. Using it carries " "an element of risk, which is reduced if one is skilled in " "the appropriate elemental magic. "; break; case MISC_LAMP_OF_FIRE: description += "A magical device for summoning fire " "elementals. It is rather unreliable, and usually " "requires several attempts to function correctly. Using " "it carries an element of risk, which is reduced if one " "is skilled in the appropriate elemental magic."; break; case MISC_STONE_OF_EARTH_ELEMENTALS: description += "A magical device for summoning earth " "elementals. It is rather unreliable, and usually " "requires several attempts to function correctly. " "Using it carries an element of risk, which is reduced " "if one is skilled in the appropriate elemental magic."; break; case MISC_LANTERN_OF_SHADOWS: description += "An unholy device which calls on the powers of darkness " "to assist its user, with a small cost attached. "; break; case MISC_HORN_OF_GERYON: description += "The horn belonging to Geryon, guardian of the Vestibule " "of Hell. Legends say that a mortal who desires access " "into one of the Hells must use it in order to gain entry. "; break; case MISC_BOX_OF_BEASTS: description += "A magical box containing many wild beasts. One may " "allow them to escape by opening the box's lid. "; break; case MISC_DECK_OF_ESCAPE: description += "A deck of magical cards, mainly dealing with various " "forms of escape. Incautious use may lead to being " "dumped from the frying pan into the fire! "; break; case MISC_DECK_OF_DESTRUCTION: description += "A deck of magical cards, most of which hurl death " "and destruction at one's foes (or, if unlucky, at oneself.) "; break; case MISC_DECK_OF_DUNGEONS: description += "A deck of magical cards which deal with shaping the " "dungeon. Unlike most other decks, the cards from this deck " "tend to be ignored by Nemelex, who prefers more amusing " "pursuits. "; break; case MISC_DECK_OF_SUMMONING: description += "A deck of magical cards, depicting a range of weird and " "wondrous creatures. "; break; case MISC_DECK_OF_WONDERS: description += "A deck of highly mysterious and magical cards, which can " "permanently alter the drawer's physical and mental " "condition, for better or worse. "; break; case MISC_DECK_OF_PUNISHMENT: description += "A deck of magical cards which wreak havoc on the user. "; break; case MISC_DECK_OF_WAR: description += "A deck of magical cards which are useful before and during " "battle. "; break; case MISC_DECK_OF_CHANGES: description += "A deck of magical cards which induce changes in the user " "or his environment. "; break; case MISC_DECK_OF_DEFENSE: description += "A deck of magical cards, most of which defend the user " "from harm in various ways. "; break; case MISC_CRYSTAL_BALL_OF_ENERGY: description += "A magical device which can be used to restore one's " "reserves of magical energy, but the use of which carries " "the risk of draining all of those energies completely. " "This risk varies inversely with the proportion of their " "maximum energy which the user possesses; a user near his " "or her full potential will find this item most beneficial. "; break; case MISC_EMPTY_EBONY_CASKET: description += "A magical box after its power is spent. "; break; case MISC_CRYSTAL_BALL_OF_FIXATION: description += "A dangerous item which hypnotises anyone so unwise as " "to gaze into it, leaving them helpless for a significant " "length of time. "; break; case MISC_DISC_OF_STORMS: description += "This extremely powerful item can unleash a destructive " "storm of electricity. It is especially effective in the " "hands of one skilled in air elemental magic, but cannot " "be used by one who is not a conductor. "; break; case MISC_RUNE_OF_ZOT: description += "A talisman which allows entry into Zot's domain. "; break; case NUM_MISCELLANY: description += "A buggy miscellaneous item."; break; } } else { switch (subtype) { case MISC_BOTTLED_EFREET: description += "A heavy bronze flask, warm to the touch. "; break; case MISC_CRYSTAL_BALL_OF_ENERGY: case MISC_CRYSTAL_BALL_OF_FIXATION: case MISC_CRYSTAL_BALL_OF_SEEING: description += "A sphere of clear crystal. "; break; case MISC_AIR_ELEMENTAL_FAN: description += "A fan. "; break; case MISC_LAMP_OF_FIRE: description += "A lamp. "; break; case MISC_STONE_OF_EARTH_ELEMENTALS: description += "A lump of rock. "; break; case MISC_LANTERN_OF_SHADOWS: description += "A strange lantern made out of ancient bones. "; break; case MISC_HORN_OF_GERYON: description += "A great silver horn, radiating unholy energies. "; break; case MISC_BOX_OF_BEASTS: case MISC_EMPTY_EBONY_CASKET: description += "A small black box. I wonder what's inside? "; break; 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_DEFENSE: description += "A deck of cards. "; break; case MISC_RUNE_OF_ZOT: description += "A talisman of some sort. "; break; case MISC_DISC_OF_STORMS: description += "A grey disc. "; break; case NUM_MISCELLANY: description += "A buggy miscellaneous item. "; break; } } description += "$"; if ( is_deck(item) && item.plus2 != 0 ) { description += "$Next card(s): "; description += card_name(static_cast(item.plus2 - 1)); long spec = item.special; while ( spec ) { description += ", "; description += card_name(static_cast((spec & 0xFF)-1)); spec >>= 8; } description += "$"; } return (description); } // ======================================================================== // Public Functions // ======================================================================== bool is_dumpable_artefact( const item_def &item, bool verbose) { bool ret = false; if (is_random_artefact( item ) || is_fixed_artefact( item )) { ret = item_ident( item, ISFLAG_KNOW_PROPERTIES ); } else if (item.base_type == OBJ_ARMOUR && (verbose && item_type_known(item))) { const int spec_ench = get_armour_ego_type( item ); ret = (spec_ench >= SPARM_RUNNING && spec_ench <= SPARM_PRESERVATION); } else if (item.base_type == OBJ_JEWELLERY && (verbose && get_ident_type(OBJ_JEWELLERY, item.sub_type) == ID_KNOWN_TYPE)) { ret = true; } return (ret); } //--------------------------------------------------------------- // // get_item_description // // Note that the string will include dollar signs which should // be interpreted as carriage returns. // //--------------------------------------------------------------- std::string get_item_description( const item_def &item, bool verbose, bool dump ) { std::ostringstream description; if (!dump) description << item.name(DESC_INVENTORY_EQUIP); description << "$$"; #if DEBUG_DIAGNOSTICS if (!dump) { description << std::setfill('0'); description << "base: " << static_cast(item.base_type) << " sub: " << static_cast(item.sub_type) << " plus: " << item.plus << " plus2: " << item.plus2 << " special: " << item.special << "$" << "quant: " << item.quantity << " colour: " << static_cast(item.colour) << " flags: " << std::hex << std::setw(8) << item.flags << std::dec << "$" << "x: " << item.x << " y: " << item.y << " link: " << item.link << " ident_type: " << static_cast(get_ident_type(item.base_type, item.sub_type)) << "$$"; } #endif switch (item.base_type) { case OBJ_WEAPONS: description << describe_weapon( item, verbose ); break; case OBJ_MISSILES: description << describe_ammo( item ); break; case OBJ_ARMOUR: description << describe_armour( item, verbose ); break; case OBJ_WANDS: description << describe_stick( item ); break; case OBJ_FOOD: description << describe_food( item ); break; case OBJ_SCROLLS: description << describe_scroll( item ); break; case OBJ_JEWELLERY: description << describe_jewellery( item, verbose ); break; case OBJ_POTIONS: description << describe_potion( item ); break; case OBJ_STAVES: description << describe_staff( item ); break; case OBJ_BOOKS: switch (item.sub_type) { case BOOK_DESTRUCTION: description << "An extremely powerful but unpredictable book " "of magic. "; break; case BOOK_MANUAL: description << "A valuable book of magic which allows one to " "practise a certain skill greatly. As it is used, it " "gradually disintegrates and will eventually fall apart. "; break; default: description << "A book of magic spells. Beware, for some of the " "more powerful grimoires are not to be toyed with. "; break; } break; case OBJ_ORBS: description << "Once you have escaped to the surface with " "this invaluable artefact, your quest is complete. "; break; case OBJ_MISCELLANY: description << describe_misc_item( item ); break; case OBJ_CORPSES: if ( item.sub_type == CORPSE_BODY) description << "A corpse. "; else description << "A decaying skeleton. "; break; case OBJ_GOLD: description << "A pile of glittering gold coins. "; break; default: DEBUGSTR("Bad item class"); description << "This item should not exist. Mayday! Mayday! "; } if (verbose) { const int mass = item_mass( item ); description << "$It weighs around " << (mass / 10) << "." << (mass % 10) << " aum. "; // arbitrary unit of mass if ( is_dumpable_artefact(item, false) ) { if (item.base_type == OBJ_ARMOUR || item.base_type == OBJ_WEAPONS) description << "$$This ancient artefact cannot be changed " "by magic or mundane means."; else description << "$$It is an ancient artefact."; } } return description.str(); } // end get_item_description() static std::string get_feature_description_wide(int feat) { switch ( feat ) { case DNGN_DEEP_WATER: if (you.species != SP_MERFOLK) return "This deep, misty water will drown any who set foot in it, " "unless they feel at home in water. Nothing in the dungeon " "-- not even you! -- is dumb enough to go there without " "thinking twice. Except when they're really confused..."; else return "This is the deep, misty water which you call home."; case DNGN_FLOOR: switch (random2(6)) { default: case 0: case 1: case 2: return "A plain floor space, for walking on."; case 3: return "Just a floor. Walk on it. Fly over it. I don't care."; case 4: return "A plain floor space, for walking on. " "It could contain a nasty trap, but " "who would be paranoid enough to believe that?"; case 5: return "A plain floor space, for walking on. " "Perhaps an invisible creature is lurking there, " "but then, the dungeon is no playground for the " "superstitious."; } case DNGN_ENTER_SHOP: return "A shop! Here, of all places! Some souls question the " "wisdom of the dungeon's shopkeepers, who import wares to " "hawk among a populace nearly as penniless as it is merciless. " "But then, you're here and itching to spend, so... " "what's the problem?"; default: return std::string(); } } void describe_feature_wide(int x, int y) { std::string desc = feature_description(x, y); desc += "$$"; // Get rid of trailing .$$ before lookup desc += getLongDescription(desc.substr(0, desc.length() - 3)); // For things which require logic desc += get_feature_description_wide(grd[x][y]); clrscr(); print_description(desc); if ( getch() == 0 ) getch(); } static void show_item_description(const item_def &item) { clrscr(); const std::string description = get_item_description( item, 1 ); print_description(description); if (item.has_spells()) { formatted_string fs; item_def dup = item; spellbook_contents( dup, item.base_type == OBJ_BOOKS? RBOOK_READ_SPELL : RBOOK_USE_STAFF, &fs ); fs.display(2, -2); } } static bool describe_spells(const item_def &item) { int c = getch(); if (c < 'a' || c > 'h') //jmf: was 'g', but 8=h { mesclr( true ); return (false); } const int spell_index = letter_to_index(c); spell_type nthing = which_spell_in_book(item.book_number(), spell_index); if (nthing == SPELL_NO_SPELL) return (false); describe_spell( nthing ); return (true); } //--------------------------------------------------------------- // // describe_item // // Describes all items in the game. // //--------------------------------------------------------------- void describe_item( const item_def &item ) { for (;;) { show_item_description(item); if (item.has_spells()) { gotoxy(1, wherey()); textcolor(LIGHTGREY); cprintf("Select a spell to read its description."); if (!describe_spells(item)) return; continue; } break; } if (getch() == 0) getch(); } //--------------------------------------------------------------- // // describe_spell // // Describes (most) every spell in the game. // //--------------------------------------------------------------- void describe_spell(spell_type spelled) { std::string description; description.reserve(500); description += spell_title( spelled ); description += "$$"; const std::string long_descrip = getLongDescription(spell_title(spelled)); if ( !long_descrip.empty() ) description += long_descrip; else { description += "This spell has no description. " "Casting it may therefore be unwise. " #if DEBUG "Instead, go fix it. "; #else "Please file a bug report."; #endif // DEBUG } clrscr(); print_description(description); if (getch() == 0) getch(); } // end describe_spell() static std::string describe_draconian_role(const monsters *mon) { switch (mon->type) { case MONS_DRACONIAN_SHIFTER: return "It darts around disconcertingly without taking a step."; case MONS_DRACONIAN_SCORCHER: return "Its scales are sooty black from years of magical pyrotechnics."; case MONS_DRACONIAN_ZEALOT: return "In its gaze you see all the malefic power of its " "terrible god."; case MONS_DRACONIAN_ANNIHILATOR: return "Crackling balls of pure energy hum and spark up and down its " "scaled fists and arms."; case MONS_DRACONIAN_CALLER: return "It looks especially reptilian, and eager for company."; case MONS_DRACONIAN_MONK: return "It looks unnaturally strong and dangerous with its fists."; case MONS_DRACONIAN_KNIGHT: return "It wields a deadly weapon with menacing efficiency."; } return (""); } static std::string describe_draconian_colour(int species) { switch (species) { case MONS_BLACK_DRACONIAN: return "Sparks crackle and flare out of its mouth and nostrils."; case MONS_MOTTLED_DRACONIAN: return "Liquid flames drip from its mouth."; case MONS_YELLOW_DRACONIAN: return "Acid fumes swirl around it."; case MONS_GREEN_DRACONIAN: return "Venom steams and drips from its jaws."; case MONS_PURPLE_DRACONIAN: return "Its outline shimmers with wild energies."; case MONS_RED_DRACONIAN: return "Smoke pours from its nostrils."; case MONS_WHITE_DRACONIAN: return "Frost pours from its nostrils."; case MONS_PALE_DRACONIAN: return "It is cloaked in a pall of superheated steam."; } return (""); } static std::string describe_draconian(const monsters *mon) { std::string description; const int subsp = draco_subspecies( mon ); if (subsp == MONS_DRACONIAN) description += "A "; else description += "A muscular "; switch (subsp) { case MONS_DRACONIAN: description += "brown-"; break; case MONS_BLACK_DRACONIAN: description += "black-"; break; case MONS_MOTTLED_DRACONIAN: description += "mottled-"; break; case MONS_YELLOW_DRACONIAN: description += "yellow-"; break; case MONS_GREEN_DRACONIAN: description += "green-"; break; case MONS_PURPLE_DRACONIAN: description += "purple-"; break; case MONS_RED_DRACONIAN: description += "red-"; break; case MONS_WHITE_DRACONIAN: description += "white-"; break; case MONS_PALE_DRACONIAN: description += "pale-"; break; default: break; } description += "scaled humanoid with wings."; if (subsp != MONS_DRACONIAN) description += " " + describe_draconian_colour(subsp); if (subsp != mon->type) description += " " + describe_draconian_role(mon); return (description); } //--------------------------------------------------------------- // // describe_monsters // // Contains sketchy descriptions of every monster in the game. // //--------------------------------------------------------------- void describe_monsters(monsters& mons) { std::ostringstream description; description << str_monam( mons, DESC_CAP_A ) << "$$"; // Note: Nearly all of the "long" descriptions have moved to // mon-data.h, in an effort to give them some locality with the // rest of the monster definition data, and to get them out of // the control logic. The only sorts of descriptions that should // go here are those that require active decisions about what // sort of message to print (eg "It's beautiful" or "It's ugly" // depending on player class). And just between you and me: that's // sort of a dumb idea anyway. So don't add any more of those. // // In my fantasy world, the long descriptions (and monster data) // wouldn't live in a header file, but in a simple text file // that's easier to edit and easy to read. Even XML would be better // than what we have today. // // -peterb 4/14/07 description << getLongDescription(str_monam(mons, DESC_PLAIN)); // Now that the player has examined it, he knows it's a mimic. if (mons_is_mimic(mons.type)) mons.flags |= MF_KNOWN_MIMIC; switch (mons.type) { case MONS_ROTTING_DEVIL: if (you.species == SP_GHOUL) description << "It smells great!"; else if (player_can_smell()) description << "It stinks."; break; case MONS_SWAMP_DRAKE: if (player_can_smell()) description << "It smells horrible."; break; case MONS_GREATER_MUMMY: description << "The embalmed and undead corpse of an ancient ruler."; break; case MONS_MUMMY_PRIEST: description << "The embalmed and undead corpse of an ancient " "servant of darkness."; break; case MONS_NAGA: case MONS_NAGA_MAGE: case MONS_NAGA_WARRIOR: case MONS_GUARDIAN_NAGA: case MONS_GREATER_NAGA: switch (mons.type) { case MONS_GUARDIAN_NAGA: description << "These nagas are " "often used as guardians by powerful creatures."; break; case MONS_GREATER_NAGA: description << "It looks strong and aggressive."; break; case MONS_NAGA_MAGE: description << "An eldritch nimbus trails its motions."; break; case MONS_NAGA_WARRIOR: description << "It bears scars of many past battles."; break; } if (you.species == SP_NAGA) description << "It is particularly attractive."; else description << "It is strange and repulsive."; break; case MONS_VAMPIRE: case MONS_VAMPIRE_KNIGHT: case MONS_VAMPIRE_MAGE: if (you.is_undead == US_ALIVE) description << " It wants to drink your blood! "; break; case MONS_REAPER: if (you.is_undead == US_ALIVE) description << "It has come for your soul!"; break; case MONS_ELF: // These are only possible from polymorphing or shapeshifting. description << "This one is remarkably plain looking."; break; case MONS_DRACONIAN: case MONS_RED_DRACONIAN: case MONS_WHITE_DRACONIAN: case MONS_GREEN_DRACONIAN: case MONS_PALE_DRACONIAN: case MONS_MOTTLED_DRACONIAN: case MONS_BLACK_DRACONIAN: case MONS_YELLOW_DRACONIAN: case MONS_PURPLE_DRACONIAN: case MONS_DRACONIAN_SHIFTER: case MONS_DRACONIAN_SCORCHER: case MONS_DRACONIAN_ZEALOT: case MONS_DRACONIAN_ANNIHILATOR: case MONS_DRACONIAN_CALLER: case MONS_DRACONIAN_MONK: case MONS_DRACONIAN_KNIGHT: { description << describe_draconian( &mons ); break; } case MONS_PLAYER_GHOST: description << "The apparition of " << ghost_description(mons) << ".$"; break; case MONS_PANDEMONIUM_DEMON: description << describe_demon(mons); break; case MONS_URUG: if (player_can_smell()) description << "He smells terrible."; break; case MONS_SHUGGOTH: description << "A vile creature with an elongated head, spiked tail " "and wicked six-fingered claws. Its awesome strength is matched " "by its umbrage at being transported to this backwater dimension."; break; case MONS_PROGRAM_BUG: description << "If this monster is a \"program bug\", then it's " "recommended that you save your game and reload. Please report " "monsters who masquerade as program bugs or run around the " "dungeon without a proper description to the authorities."; break; default: break; } #if DEBUG_DIAGNOSTICS if (mons_class_flag( mons.type, M_SPELLCASTER )) { const monster_spells &hspell_pass = mons.spells; bool found_spell = false; for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++) { if (hspell_pass[i] != SPELL_NO_SPELL) { if (!found_spell) { description << "$$Monster Spells:$"; found_spell = true; } description << " " << i << ": " << mons_spell_name(hspell_pass[i]) << " (" << static_cast(hspell_pass[i]) << ")$"; } } } bool has_item = false; for (int i = 0; i < NUM_MONSTER_SLOTS; i++) { if (mons.inv[i] != NON_ITEM) { if (!has_item) { description << "$Monster Inventory:$"; has_item = true; } description << " " << i << ") " << mitm[mons.inv[i]].name(DESC_NOCAP_A, false, true); } } #endif clrscr(); print_description(description.str()); if (getch() == 0) getch(); } // end describe_monsters //--------------------------------------------------------------- // // ghost_description // // Describes the current ghost's previous owner. The caller must // prepend "The apparition of" or whatever and append any trailing // punctuation that's wanted. // //--------------------------------------------------------------- std::string ghost_description(const monsters &mons, bool concise) { ASSERT(mons.ghost.get()); std::ostringstream gstr; const ghost_demon &ghost = *(mons.ghost); // We're fudging stats so that unarmed combat gets based off // of the ghost's species, not the player's stats... exact // stats aren't required anyways, all that matters is whether // dex >= str. -- bwr const int dex = 10; int str; switch (ghost.values[GVAL_SPECIES]) { case SP_MOUNTAIN_DWARF: case SP_TROLL: case SP_OGRE: case SP_OGRE_MAGE: case SP_MINOTAUR: case SP_HILL_ORC: case SP_CENTAUR: case SP_NAGA: case SP_MUMMY: case SP_GHOUL: str = 15; break; case SP_HUMAN: case SP_DEMIGOD: case SP_DEMONSPAWN: str = 10; break; default: str = 5; break; } gstr << ghost.name << " the " << skill_title( ghost.values[GVAL_BEST_SKILL], ghost.values[GVAL_SKILL_LEVEL], ghost.values[GVAL_SPECIES], str, dex, GOD_NO_GOD ) << ", a" << ((ghost.values[GVAL_EXP_LEVEL] < 4) ? " weakling" : (ghost.values[GVAL_EXP_LEVEL] < 7) ? "n average" : (ghost.values[GVAL_EXP_LEVEL] < 11) ? "n experienced" : (ghost.values[GVAL_EXP_LEVEL] < 16) ? " powerful" : (ghost.values[GVAL_EXP_LEVEL] < 22) ? " mighty" : (ghost.values[GVAL_EXP_LEVEL] < 26) ? " great" : (ghost.values[GVAL_EXP_LEVEL] < 27) ? "n awesomely powerful" : " legendary") << " "; if ( concise ) gstr << get_species_abbrev(ghost.values[GVAL_SPECIES]) << get_class_abbrev(ghost.values[GVAL_CLASS]); else gstr << species_name(ghost.values[GVAL_SPECIES], ghost.values[GVAL_EXP_LEVEL]) << " " << get_class_name(ghost.values[GVAL_CLASS]); return gstr.str(); } extern ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES]; static bool print_god_abil_desc( int god, int numpower ) { const char* pmsg = god_gain_power_messages[god][numpower]; // if no message then no power if ( !pmsg[0] ) return false; std::ostringstream buf; if ( isupper(pmsg[0]) ) buf << pmsg; // complete sentence given else buf << "You can " << pmsg << "."; // this might be ABIL_NON_ABILITY for passive abilities const ability_type abil = god_abilities[god][numpower]; if ( abil != ABIL_NON_ABILITY ) { const int spacesleft = 79 - buf.str().length(); const std::string cost = "(" + make_cost_description(abil) + ")"; buf << std::setw(spacesleft) << cost; } cprintf( "%s\n", buf.str().c_str() ); return true; } static std::string describe_favour_generic(god_type which_god) { std::string godname = god_name(which_god); return (you.piety > 130) ? "A prized avatar of " + godname + ".": (you.piety > 100) ? "A shining star in the eyes of " + godname + "." : (you.piety > 70) ? "A rising star in the eyes of " + godname + "." : (you.piety > 40) ? godname + " is most pleased with you." : (you.piety > 20) ? godname + " has noted your presence." : (you.piety > 5) ? godname + " is noncommittal." : "You are beneath notice."; } //--------------------------------------------------------------- // // describe_god // // Describes the player's standing with his deity. // //--------------------------------------------------------------- std::string describe_favour(god_type which_god) { if (player_under_penance()) { const int penance = you.penance[which_god]; return (penance >= 50) ? "Godly wrath is upon you!" : (penance >= 20) ? "You've transgressed heavily! Be penitent!" : (penance >= 5 ) ? "You are under penance." : "You should show more discipline."; } return (which_god == GOD_XOM)? describe_xom_favour() : describe_favour_generic(which_god); } void describe_god( god_type which_god, bool give_title ) { const char *description; // mv: tmp string used for printing description int colour; // mv: colour used for some messages clrscr(); if (give_title) { textcolor( WHITE ); cprintf( " Religion" EOL ); textcolor( LIGHTGREY ); } if (which_god == GOD_NO_GOD) //mv:no god -> say it and go away { cprintf( EOL "You are not religious." ); getch(); return; } colour = god_colour(which_god); //mv: print god's name and title - if you can think up better titles //I have nothing against textcolor(colour); cprintf( "%s", god_name(which_god,true)); //print long god's name cprintf (EOL EOL); //mv: print god's description textcolor (LIGHTGRAY); switch (which_god) { case GOD_ZIN: description = "Zin is an ancient and revered God, dedicated to the establishment of order" EOL "and the destruction of the forces of chaos and night. Valued worshippers " EOL "can gain sustenance in times of need, blessings on their weapons, and a " EOL "variety of powers useful in the fight against evil, but must abstain " EOL "from the use of necromancy and other forms of unholy magic. Zin appreciates " EOL "long-standing faith as well as sacrifices of valued objects."; break; case GOD_SHINING_ONE: description = "The Shining One is a powerful crusading deity, allied with Zin in the fight" EOL "against evil. Followers may be granted blessings on their weapons and the " EOL "ability to summarily dispense the wrath of heaven, but must never use any " EOL "form of evil magic and should fight honourably. The Shining One appreciates" EOL "long-standing persistence in the endless crusade, as well as the dedicated " EOL "destruction of unholy creatures."; break; case GOD_KIKUBAAQUDGHA: description = "Kikubaaqudgha is a terrible Demon-God, served by those who seek knowledge of" EOL "the powers of death. Followers gain special powers over the undead, and " EOL "especially favoured servants can call on mighty demons to slay their foes." EOL "Kikubaaqudgha requires the deaths of living creatures as often as possible," EOL "but is not interested in the offering of corpses except at an appropriate" EOL "altar."; break; case GOD_YREDELEMNUL: description = "Yredelemnul is worshipped by those who seek powers over death and the undead" EOL "without having to learn to use necromancy. Followers can raise legions of " EOL "servile undead and gain a number of other useful (if unpleasant) powers." EOL "Yredelemnul appreciates killing, but prefers corpses to be put to use rather" EOL "than sacrificed."; break; case GOD_XOM: description = "Xom is a wild and unpredictable God of chaos, who seeks not worshippers but" EOL "playthings to toy with. Many choose to follow Xom in the hope of receiving" EOL "fabulous rewards and mighty powers, but Xom is nothing if not capricious. "; break; case GOD_VEHUMET: description = "Vehumet is a God of the destructive powers of magic. Followers gain various" EOL "useful powers to enhance their command of the hermetic arts, and the most" EOL "favoured stand to gain access to some of the fearsome spells in Vehumet's" EOL "library. One's devotion to Vehumet can be proved by the causing of as much" EOL "carnage and destruction as possible."; break; case GOD_OKAWARU: description = "Okawaru is a dangerous and powerful God of battle. Followers can gain a " EOL "number of powers useful in combat as well as various rewards, but must " EOL "constantly prove themselves through battle and the sacrifice of corpses" EOL "and valuable items. Okawaru despises those who harm their allies."; break; case GOD_MAKHLEB: description = "Makhleb the Destroyer is a fearsome God of chaos and violent death. Followers," EOL "who must constantly appease Makhleb with blood, stand to gain various powers " EOL "of death and destruction. The Destroyer appreciates sacrifices of corpses and" EOL "valuable items."; break; case GOD_SIF_MUNA: description = "Sif Muna is a contemplative but powerful deity, served by those who seek" EOL "magical knowledge. Sif Muna appreciates sacrifices of valuable items, and" EOL "the casting of spells as often as possible."; break; case GOD_TROG: description = "Trog is an ancient God of anger and violence. Followers are expected to kill" EOL "in Trog's name and sacrifice the dead, and in return gain power in battle and" EOL "occasional rewards. Trog hates wizards, and followers are forbidden the use" EOL "of spell magic. "; break; case GOD_NEMELEX_XOBEH: description = "Nemelex is a strange and unpredictable trickster God, whose powers can be" EOL "invoked through the magical packs of cards which Nemelex paints in the ichor" EOL "of demons. Followers receive occasional gifts, and should use these gifts as" EOL "much as possible. Offerings of any type of item are also appreciated."; break; case GOD_ELYVILON: description = "Elyvilon the Healer is worshipped by the healers (among others), who gain" EOL "their healing powers by long worship and devotion. Although Elyvilon prefers" EOL "a creed of pacifism, those who crusade against evil are not excluded. Elyvilon" EOL "appreciates the offering of weapons. "; break; case GOD_LUGONU: description = "Lugonu the Unformed revels in the chaos of the Abyss. Followers are sent out" EOL "to cause bloodshed and disorder in the world, and must do so unflaggingly to" EOL "earn Lugonu's favour."; break; case GOD_BEOGH: description = "Beogh is a deity worshipped by the cave orcs native to parts of the dungeon." EOL "Only proper orcs may devote their service to Beogh, proving their devotion " EOL "with kills and remnants. Pious orcs may gain the priestly power of smiting. " EOL "Also, there are rumours that the orcs still look out for their Messiah. "; break; default: description = "God of Program Bugs is a weird and dangerous God and his presence should" EOL "be reported to dev-team."; } cprintf("%s", description); //end of printing description // title only shown for our own god if (you.religion == which_god) { //mv: print title based on piety cprintf( EOL EOL "Title - " ); textcolor(colour); // mv: if your piety is high enough you get title // based on your god if (you.piety > 160) { cprintf("%s", (which_god == GOD_SHINING_ONE) ? "Champion of Law" : (which_god == GOD_ZIN) ? "Divine Warrior" : (which_god == GOD_ELYVILON) ? "Champion of Light" : (which_god == GOD_OKAWARU) ? "Master of a Thousand Battles" : (which_god == GOD_YREDELEMNUL) ? "Master of Eternal Death" : (which_god == GOD_KIKUBAAQUDGHA) ? "Lord of Darkness" : (which_god == GOD_MAKHLEB) ? "Champion of Chaos" : (which_god == GOD_VEHUMET) ? "Lord of Destruction" : (which_god == GOD_TROG) ? "Great Slayer" : (which_god == GOD_NEMELEX_XOBEH) ? "Great Trickster" : (which_god == GOD_SIF_MUNA) ? "Master of the Arcane" : (which_god == GOD_LUGONU) ? "Agent of Entropy" : (which_god == GOD_BEOGH) ? "Messiah" : (which_god == GOD_XOM) ? "Teddy Bear" : "Bogy the Lord of the Bugs"); // Xom and no god is handled before } else { //mv: most titles are still universal - if any one wants to //he might write specific titles for all gods or rewrite current //ones (I know they are not perfect) //btw. titles are divided according to piety levels on which you get //new abilities.In the main it means - new ability = new title switch (which_god) { case GOD_ZIN: case GOD_SHINING_ONE: case GOD_KIKUBAAQUDGHA: case GOD_YREDELEMNUL: case GOD_VEHUMET: case GOD_OKAWARU: case GOD_MAKHLEB: case GOD_SIF_MUNA: //mv: what about //sinner, believer, apprentice, disciple, adept, scholar, oracle case GOD_TROG: case GOD_NEMELEX_XOBEH: case GOD_ELYVILON: case GOD_LUGONU: cprintf ( (you.piety >= 120) ? "High Priest" : (you.piety >= 100) ? "Elder" : (you.piety >= 75) ? "Priest" : (you.piety >= 50) ? "Deacon" : (you.piety >= 30) ? "Novice" : (you.piety > 5) ? "Believer" : "Sinner" ); break; case GOD_BEOGH: cprintf ( (you.piety >= 120) ? "Saint" : (you.piety >= 100) ? "High Priest" : (you.piety >= 75) ? "Missionary" : (you.piety >= 50) ? "Priest" : (you.piety >= 30) ? "Disciple" : (you.piety > 5) ? "Believer" : "Sinner" ); break; case GOD_XOM: cprintf("Toy"); break; default: cprintf ("Bug"); } } } // end of print title // mv: now let's print favor as Brent suggested // I know these messages aren't perfect so if you can // think up something better, do it textcolor(LIGHTGRAY); cprintf(EOL EOL "Favour - "); textcolor(colour); //mv: player is praying at altar without appropriate religion //it means player isn't checking his own religion and so we only //display favour and will go out if (you.religion != which_god) { textcolor (colour); cprintf( (you.penance[which_god] >= 50) ? "%s's wrath is upon you!" : (you.penance[which_god] >= 20) ? "%s is annoyed with you." : (you.penance[which_god] >= 5) ? "%s well remembers your sins." : (you.penance[which_god] > 0) ? "%s is ready to forgive your sins." : (you.worshipped[which_god]) ? "%s is ambivalent towards you." : "%s is neutral towards you.", god_name(which_god) ); } else { cprintf(describe_favour(which_god).c_str()); //mv: following code shows abilities given from god (if any) textcolor(LIGHTGRAY); cprintf(EOL EOL "Granted powers: (Cost)" EOL); textcolor(colour); // mv: these gods protects you during your prayer (not mentioning XOM) // chance for doing so is (random2(you.piety) >= 30) // Note that it's not depending on penance. // Btw. I'm not sure how to explain such divine protection // because god isn't really protecting player - he only sometimes // saves his life (probably it shouldn't be displayed at all). // What about this ? bool have_any = false; if ((which_god == GOD_ZIN || which_god == GOD_SHINING_ONE || which_god == GOD_ELYVILON || which_god == GOD_YREDELEMNUL) && you.piety >= 30) { have_any = true; cprintf( "%s %s watches over you during prayer." EOL, god_name(which_god), (you.piety >= 150) ? "carefully": // > 4/5 (you.piety >= 90) ? "often" : // > 2/3 "sometimes"); // less than 2:3 if (which_god == GOD_ZIN) cprintf("Praying to %s will provide sustenance if starving." EOL, god_name(which_god)); } if (which_god == GOD_BEOGH && you.piety >= 30) { have_any = true; cprintf( "%s supports the use of orcish gear." EOL, god_name(which_god)); } // mv: No abilities (except divine protection) under penance if (!player_under_penance()) { for ( int i = 0; i < MAX_GOD_ABILITIES; ++i ) if ( you.piety >= piety_breakpoint(i) ) if (print_god_abil_desc(which_god, i)) have_any = true; } if ( !have_any ) cprintf( "None." EOL ); } getch(); // wait until keypressed } //mv: That's all folks.