/* File: borg3.c */ /* Purpose: Object and Spell routines for the Borg -BEN- */ #include "angband.h" #ifdef ALLOW_BORG #include "borg1.h" #include "borg3.h" /* * This file helps the Borg analyze "objects" and "shops", and to * deal with objects and spells. */ /* * Some variables */ auto_item *auto_items; /* Current "inventory" */ auto_shop *auto_shops; /* Current "shops" */ /* * Safety arrays for simulating possible worlds */ auto_item *safe_items; /* Safety "inventory" */ auto_item *safe_home; /* Safety "home stuff" */ auto_shop *safe_shops; /* Safety "shops" */ /* * Spell info */ auto_magic auto_magics[9][9]; /* Spell info, by book/what */ /* * Hack -- help analyze the magic * * The comments yield the "name" of the spell or prayer. * * Also, the leading letter in the comment indicates how we use the * spell or prayer, if at all, using "A" for "attack", "D" for "call * light" and "detection", "E" for "escape", "H" for healing, "O" for * "object manipulation", and "F" for "terrain feature manipulation", * plus "!" for entries that can soon be handled. */ static byte auto_magic_method[2][9][9] = { /*** Spells ***/ { { /* Magic for Beginners (sval 0) */ BORG_MAGIC_AIM /* A "Magic Missile" */, BORG_MAGIC_EXT /* "Detect Monsters" */, BORG_MAGIC_NOP /* E "Phase Door" */, BORG_MAGIC_NOP /* D "Light Area" */, BORG_MAGIC_NOP /* "Treasure Detection" */, BORG_MAGIC_NOP /* H "Cure Light Wounds" */, BORG_MAGIC_NOP /* "Object Detection" */, BORG_MAGIC_NOP /* D "Find Hidden Traps/Doors" */, BORG_MAGIC_AIM /* A "Stinking Cloud" */ }, { /* Conjurings and Tricks (sval 1) */ BORG_MAGIC_AIM /* "Confusion" */, BORG_MAGIC_AIM /* A "Lightning Bolt" */, BORG_MAGIC_NOP /* F "Trap/Door Destruction" */, BORG_MAGIC_AIM /* "Sleep I" */, BORG_MAGIC_NOP /* H "Cure Poison" */, BORG_MAGIC_NOP /* E "Teleport Self" */, BORG_MAGIC_AIM /* A "Spear of Light" */, BORG_MAGIC_AIM /* A "Frost Bolt" */, BORG_MAGIC_AIM /* F "Turn Stone to Mud" */ }, { /* Incantations and Illusions (sval 2) */ BORG_MAGIC_NOP /* H "Satisfy Hunger" */, BORG_MAGIC_OBJ /* O "Recharge Item I" */, BORG_MAGIC_NOP /* "Sleep II" */, BORG_MAGIC_AIM /* "Polymorph Other" */, BORG_MAGIC_OBJ /* O "Identify" */, BORG_MAGIC_NOP /* "Sleep III" */, BORG_MAGIC_AIM /* A "Fire Bolt" */, BORG_MAGIC_AIM /* "Slow Monster" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Sorcery and Evocations (sval 3) */ BORG_MAGIC_AIM /* A "Frost Ball" */, BORG_MAGIC_OBJ /* O "Recharge Item II" */, BORG_MAGIC_AIM /* "Teleport Other" */, BORG_MAGIC_NOP /* "Haste Self" */, BORG_MAGIC_AIM /* A "Fire Ball" */, BORG_MAGIC_NOP /* "Word of Destruction" */, BORG_MAGIC_WHO /* "Genocide" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Resistance of Scarabtarices (sval 4) */ BORG_MAGIC_NOP /* "Resist Fire" */, BORG_MAGIC_NOP /* "Resist Cold" */, BORG_MAGIC_NOP /* "Resist Acid" */, BORG_MAGIC_NOP /* "Resist Poison" */, BORG_MAGIC_NOP /* "Resistance" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Mordenkainen's Escapes (sval 5) */ BORG_MAGIC_NOP /* "Door Creation" */, BORG_MAGIC_NOP /* "Stair Creation" */, BORG_MAGIC_NOP /* "Teleport Level" */, BORG_MAGIC_NOP /* "Earthquake" */, BORG_MAGIC_NOP /* E "Word of Recall" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Kelek's Grimoire of Power (sval 6) */ BORG_MAGIC_EXT /* "Detect Evil" */, BORG_MAGIC_NOP /* "Detect Enchantment" */, BORG_MAGIC_OBJ /* O "Recharge Item III" */, BORG_MAGIC_WHO /* "Genocide" */, BORG_MAGIC_NOP /* "Mass Genocide" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Tenser's transformations... (sval 7) */ BORG_MAGIC_NOP /* ! "Heroism" */, BORG_MAGIC_NOP /* "Shield" */, BORG_MAGIC_NOP /* ! "Berserker" */, BORG_MAGIC_NOP /* "Essence of Speed" */, BORG_MAGIC_NOP /* "Globe of Invulnerability" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Raal's Tome of Destruction (sval 8) */ BORG_MAGIC_AIM /* A "Acid Bolt" */, BORG_MAGIC_AIM /* A "Cloud Kill" */, BORG_MAGIC_AIM /* A "Acid Ball" */, BORG_MAGIC_AIM /* A "Ice Storm" */, BORG_MAGIC_AIM /* A "Meteor Swarm" */, BORG_MAGIC_AIM /* A "Mana Storm" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ } }, /*** Prayers ***/ { { /* Beginners Handbook (sval 0) */ BORG_MAGIC_EXT /* "Detect Evil" */, BORG_MAGIC_NOP /* "Cure Light Wounds" */, BORG_MAGIC_NOP /* "Bless" */, BORG_MAGIC_NOP /* H "Remove Fear" */, BORG_MAGIC_NOP /* D "Call Light" */, BORG_MAGIC_NOP /* D "Find Traps" */, BORG_MAGIC_NOP /* D "Detect Doors/Stairs" */, BORG_MAGIC_NOP /* "Slow Poison" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Words of Wisdom (sval 1) */ BORG_MAGIC_AIM /* "Confuse Creature" */, BORG_MAGIC_NOP /* E "Portal" */, BORG_MAGIC_NOP /* H "Cure Serious Wounds" */, BORG_MAGIC_NOP /* "Chant" */, BORG_MAGIC_NOP /* "Sanctuary" */, BORG_MAGIC_NOP /* H "Satisfy Hunger" */, BORG_MAGIC_NOP /* "Remove Curse" */, BORG_MAGIC_NOP /* "Resist Heat and Cold" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Chants and Blessings (sval 2) */ BORG_MAGIC_NOP /* H "Neutralize Poison" */, BORG_MAGIC_AIM /* A "Orb of Draining" */, BORG_MAGIC_NOP /* H "Cure Critical Wounds" */, BORG_MAGIC_EXT /* "Sense Invisible" */, BORG_MAGIC_NOP /* "Protection from Evil" */, BORG_MAGIC_NOP /* "Earthquake" */, BORG_MAGIC_NOP /* D "Sense Surroundings" */, BORG_MAGIC_NOP /* H "Cure Mortal Wounds" */, BORG_MAGIC_NOP /* "Turn Undead" */ }, { /* Exorcism and Dispelling (sval 3) */ BORG_MAGIC_NOP /* "Prayer" */, BORG_MAGIC_NOP /* ! "Dispel Undead" */, BORG_MAGIC_NOP /* H "Heal" */, BORG_MAGIC_NOP /* ! "Dispel Evil" */, BORG_MAGIC_NOP /* "Glyph of Warding" */, BORG_MAGIC_NOP /* ! "Holy Word" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Ethereal openings (sval 4) */ BORG_MAGIC_NOP /* E "Blink" */, BORG_MAGIC_NOP /* E "Teleport" */, BORG_MAGIC_AIM /* "Teleport Away" */, BORG_MAGIC_NOP /* "Teleport Level" */, BORG_MAGIC_NOP /* E "Word of Recall" */, BORG_MAGIC_NOP /* "Alter Reality" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Godly Insights... (sval 5) */ BORG_MAGIC_EXT /* "Detect Monsters" */, BORG_MAGIC_EXT /* D "Detection" */, BORG_MAGIC_OBJ /* O "Perception" */, BORG_MAGIC_NOP /* "Probing" */, BORG_MAGIC_NOP /* D "Clairvoyance" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Purifications and Healing (sval 6) */ BORG_MAGIC_NOP /* H "Cure Serious Wounds" */, BORG_MAGIC_NOP /* H "Cure Mortal Wounds" */, BORG_MAGIC_NOP /* H "Healing" */, BORG_MAGIC_NOP /* ! "Restoration" */, BORG_MAGIC_NOP /* ! "Remembrance" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Holy Infusions (sval 7) */ BORG_MAGIC_NOP /* F "Unbarring Ways" */, BORG_MAGIC_OBJ /* O "Recharging" */, BORG_MAGIC_NOP /* "Dispel Curse" */, BORG_MAGIC_OBJ /* O "Enchant Weapon" */, BORG_MAGIC_OBJ /* O "Enchant Armour" */, BORG_MAGIC_NOP /* "Elemental Brand" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ }, { /* Wrath of God (sval 8) */ BORG_MAGIC_NOP /* ! "Dispel Undead" */, BORG_MAGIC_NOP /* ! "Dispel Evil" */, BORG_MAGIC_NOP /* "Banishment" */, BORG_MAGIC_NOP /* "Word of Destruction" */, BORG_MAGIC_AIM /* "Annihilation" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */, BORG_MAGIC_ICK /* "(blank)" */ } } }; /* * Hack -- help analyze the magic * * The comments yield the "name" of the spell or prayer. * * Also, the leading letter in the comment indicates how we use the * spell or prayer, if at all, using "A" for "attack", "D" for "call * light" and "detection", "E" for "escape", "H" for healing, "O" for * "object manipulation", "F" for "terrain feature manipulation", * "X" for "never use this", and "!" for "soon to be handled". * * The value indicates how much we want to know the spell/prayer. A * rating of zero indicates that the spell/prayer is useless, and should * never be learned or used. A rating from 1 to 49 indicates that the * spell/prayer is worth some experience to use once, so we should study * (and use) it when we get bored in town. A rating from 50 to 99 means * that the spell/prayer should be learned as soon as possible (and used * when bored). Note that spells/prayers which are "bizarre", such as * "genocide" and "mass genocide" have a rating of zero. * * XXX XXX XXX Verify ratings. */ static byte auto_magic_rating[2][9][9] = { /*** Spells ***/ { { /* Magic for Beginners (sval 0) */ 85 /* A "Magic Missile" */, 5 /* "Detect Monsters" */, 75 /* E "Phase Door" */, 65 /* D "Light Area" */, 5 /* "Treasure Detection" */, 55 /* H "Cure Light Wounds" */, 5 /* "Object Detection" */, 95 /* D "Find Hidden Traps/Doors" */, 85 /* A "Stinking Cloud" */ }, { /* Conjurings and Tricks (sval 1) */ 5 /* "Confusion" */, 85 /* A "Lightning Bolt" */, 55 /* F "Trap/Door Destruction" */, 5 /* "Sleep I" */, 65 /* H "Cure Poison" */, 95 /* E "Teleport Self" */, 55 /* A "Spear of Light" */, 85 /* A "Frost Bolt" */, 75 /* F "Turn Stone to Mud" */ }, { /* Incantations and Illusions (sval 2) */ 95 /* H "Satisfy Hunger" */, 55 /* O "Recharge Item I" */, 5 /* "Sleep II" */, 5 /* "Polymorph Other" */, 96 /* O "Identify" */, 5 /* "Sleep III" */, 85 /* A "Fire Bolt" */, 5 /* "Slow Monster" */, 0 /* "(blank)" */ }, { /* Sorcery and Evocations (sval 3) */ 85 /* A "Frost Ball" */, 75 /* O "Recharge Item II" */, 5 /* "Teleport Other" */, 75 /* "Haste Self" */, 85 /* A "Fire Ball" */, 0 /* X "Word of Destruction" */, 5 /* "Genocide" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Resistance of Scarabtarices (sval 4) */ 70 /* "Resist Fire" */, 65 /* "Resist Cold" */, 60 /* "Resist Acid" */, 70 /* "Resist Poison" */, 75 /* "Resistance" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Mordenkainen's Escapes (sval 5) */ 5 /* "Door Creation" */, 5 /* "Stair Creation" */, 5 /* "Teleport Level" */, 0 /* X "Earthquake" */, 75 /* E "Word of Recall" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Kelek's Grimoire of Power (sval 6) */ 5 /* "Detect Evil" */, 5 /* "Detect Enchantment" */, 75 /* O "Recharge Item III" */, 0 /* "Genocide" */, 0 /* "Mass Genocide" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Tenser's transformations... (sval 7) */ 55 /* H "Heroism" */, 75 /* "Shield" */, 55 /* H "Berserker" */, 75 /* "Essence of Speed" */, 75 /* "Globe of Invulnerability" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Raal's Tome of Destruction (sval 8) */ 85 /* A "Acid Bolt" */, 85 /* A "Cloud Kill" */, 85 /* A "Acid Ball" */, 85 /* A "Ice Storm" */, 85 /* A "Meteor Swarm" */, 85 /* A "Mana Storm" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ } }, /*** Prayers ***/ { { /* Beginners Handbook (sval 0) */ 5 /* "Detect Evil" */, 55 /* H "Cure Light Wounds" */, 5 /* "Bless" */, 35 /* H "Remove Fear" */, 35 /* D "Call Light" */, 75 /* D "Find Traps" */, 75 /* D "Detect Doors/Stairs" */, 5 /* "Slow Poison" */, 0 /* "(blank)" */ }, { /* Words of Wisdom (sval 1) */ 5 /* "Confuse Creature" */, 95 /* E "Portal" */, 5 /* H "Cure Serious Wounds" */, 5 /* "Chant" */, 5 /* "Sanctuary" */, 95 /* H "Satisfy Hunger" */, 5 /* "Remove Curse" */, 5 /* "Resist Heat and Cold" */, 0 /* "(blank)" */ }, { /* Chants and Blessings (sval 2) */ 65 /* H "Neutralize Poison" */, 90 /* A "Orb of Draining" */, 55 /* H "Cure Critical Wounds" */, 5 /* "Sense Invisible" */, 5 /* "Protection from Evil" */, 0 /* X "Earthquake" */, 65 /* D "Sense Surroundings" */, 55 /* H "Cure Mortal Wounds" */, 5 /* "Turn Undead" */ }, { /* Exorcism and Dispelling (sval 3) */ 5 /* "Prayer" */, 5 /* ! "Dispel Undead" */, 55 /* H "Heal" */, 5 /* ! "Dispel Evil" */, 5 /* "Glyph of Warding" */, 5 /* ! "Holy Word" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Ethereal openings (sval 4) */ 65 /* E "Blink" */, 65 /* E "Teleport" */, 5 /* "Teleport Away" */, 5 /* "Teleport Level" */, 75 /* E "Word of Recall" */, 5 /* "Alter Reality" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Godly Insights... (sval 5) */ 5 /* "Detect Monsters" */, 65 /* D "Detection" */, 75 /* O "Perception" */, 5 /* "Probing" */, 65 /* D "Clairvoyance" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Purifications and Healing (sval 6) */ 55 /* H "Cure Serious Wounds" */, 55 /* H "Cure Mortal Wounds" */, 55 /* H "Healing" */, 5 /* ! "Restoration" */, 5 /* ! "Remembrance" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Holy Infusions (sval 7) */ 50 /* F "Unbarring Ways" */, 50 /* O "Recharging" */, 5 /* "Dispel Curse" */, 50 /* O "Enchant Weapon" */, 50 /* O "Enchant Armour" */, 5 /* "Elemental Brand" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ }, { /* Wrath of God (sval 8) */ 5 /* ! "Dispel Undead" */, 5 /* ! "Dispel Evil" */, 5 /* "Banishment" */, 0 /* X "Word of Destruction" */, 5 /* "Annihilation" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */, 0 /* "(blank)" */ } } }; /* * Constant "item description parsers" (singles) */ static int auto_single_size; /* Number of "singles" */ static s16b *auto_single_what; /* Kind indexes for "singles" */ static cptr *auto_single_text; /* Textual prefixes for "singles" */ /* * Constant "item description parsers" (plurals) */ static int auto_plural_size; /* Number of "plurals" */ static s16b *auto_plural_what; /* Kind index for "plurals" */ static cptr *auto_plural_text; /* Textual prefixes for "plurals" */ /* * Constant "item description parsers" (suffixes) */ static int auto_artego_size; /* Number of "artegos" */ static s16b *auto_artego_what; /* Indexes for "artegos" */ static cptr *auto_artego_text; /* Textual prefixes for "artegos" */ /* * Return the slot that items of the given type are wielded into * * Note that "rings" are now automatically wielded into the left hand * * Returns "-1" if the item cannot (or should not) be wielded */ int borg_wield_slot(auto_item *item) { /* Slot for equipment */ switch (item->tval) { case TV_SWORD: case TV_POLEARM: case TV_HAFTED: case TV_DIGGING: { return (INVEN_WIELD); } case TV_BOW: { return (INVEN_BOW); } case TV_RING: { return (INVEN_LEFT); } case TV_AMULET: { return (INVEN_NECK); } case TV_LITE: { return (INVEN_LITE); } case TV_DRAG_ARMOR: case TV_HARD_ARMOR: case TV_SOFT_ARMOR: { return (INVEN_BODY); } case TV_CLOAK: { return (INVEN_OUTER); } case TV_SHIELD: { return (INVEN_ARM); } case TV_CROWN: case TV_HELM: { return (INVEN_HEAD); } case TV_GLOVES: { return (INVEN_HANDS); } case TV_BOOTS: { return (INVEN_FEET); } } /* No slot available */ return (-1); } /* * Get the *ID information * * This function pulls the information from the screen if it is not passed * a *real* item. It is only passed in *real* items if the borg is allowed * to 'cheat' for inventory. * This function returns TRUE if space needs to be pressed */ bool borg_object_star_id_aux(auto_item *borg_item, object_type *real_item) { u32b f1, f2, f3; /* If a real item pointer is passed in then we are cheating to get */ /* the data directly from the real item */ if (real_item) { object_flags(real_item, &f1, &f2, &f3); } else { int i; byte t_a; char buf[71]; for (i = 2; i < 22; i++) { if (!(0 == borg_what_text(15, i, 65, &t_a, buf))) { /* bummer, problem reading from screen */ borg_oops("cannot read from screen"); return FALSE; } /* Gives Stat Bonus */ if (prefix(buf, "It affects your strength.")) { f1 &= TR1_STR; continue; } if (prefix(buf, "It affects your intelligence.")) { f1 &= TR1_INT; continue; } if (prefix(buf, "It affects your wisdom.")) { f1 &= TR1_WIS; continue; } if (prefix(buf, "It affects your dexterity.")) { f1 &= TR1_DEX; continue; } if (prefix(buf, "It affects your constitution.")) { f1 &= TR1_CON; continue; } if (prefix(buf, "It affects your charisma.")) { f1 &= TR1_CHR; continue; } /* Gives stealth Bonus */ if (prefix(buf, "It affects your stealth.")) { f1 &= TR1_STEALTH; continue; } /* Gives searching Bonus */ if (prefix(buf, "It affects your searching.")) { f1 &= TR1_SEARCH; continue; } /* Gives Infravision Bonus */ if (prefix(buf, "It affects your infravision.")) { f1 &= TR1_INFRA; continue; } /* Gives digging Bonus */ if (prefix(buf, "It affects your ability to tunnel.")) { f1 &= TR1_TUNNEL; continue; } /* Gives Speed Bonus (Wee!) */ if (prefix(buf, "It affects your speed.")) { f1 &= TR1_SPEED; continue; } /* Gives Extra Blows */ if (prefix(buf, "It affects your attack speed.")) { f1 &= TR1_BLOWS; continue; } /* Various Brands */ if (prefix(buf, "It does extra damage from acid.")) { f1 &= TR1_BRAND_ACID; continue; } if (prefix(buf, "It does extra damage from electricity.")) { f1 &= TR1_BRAND_ELEC; continue; } if (prefix(buf, "It does extra damage from fire.")) { f1 &= TR1_BRAND_FIRE; continue; } if (prefix(buf, "It does extra damage from frost.")) { f1 &= TR1_BRAND_COLD; continue; } /* This is Grond. */ if (prefix(buf, "It can cause earthquakes.")) { f1 &= TR1_IMPACT; continue; } /* *SLAY* Dragon */ if (prefix(buf, "It is a great bane of dragons.")) { f1 &= TR1_KILL_DRAGON; continue; } /* Various Slays */ if (prefix(buf, "It is especially deadly against dragons.")) { f1 &= TR1_SLAY_DRAGON; continue; } if (prefix(buf, "It is especially deadly against orcs.")) { f1 &= TR1_SLAY_ORC; continue; } if (prefix(buf, "It is especially deadly against trolls.")) { f1 &= TR1_SLAY_TROLL; continue; } if (prefix(buf, "It is especially deadly against giants.")) { f1 &= TR1_SLAY_GIANT; continue; } if (prefix(buf, "It strikes at demons with holy wrath.")) { f1 &= TR1_SLAY_DEMON; continue; } if (prefix(buf, "It strikes at undead with holy wrath.")) { f1 &= TR1_SLAY_UNDEAD; continue; } if (prefix(buf, "It fights against evil with holy fury.")) { f1 &= TR1_SLAY_EVIL; continue; } if (prefix(buf, "It is especially deadly against natural creatures.")) { f1 &= TR1_SLAY_ANIMAL; continue; } /* Various Sustains */ if (prefix(buf, "It sustains your strength.")) { f2 &= TR2_SUST_STR; continue; } if (prefix(buf, "It sustains your intelligence.")) { f2 &= TR2_SUST_INT; continue; } if (prefix(buf, "It sustains your wisdom.")) { f2 &= TR2_SUST_WIS; continue; } if (prefix(buf, "It sustains your dexterity.")) { f2 &= TR2_SUST_DEX; continue; } if (prefix(buf, "It sustains your constitution.")) { f2 &= TR2_SUST_CON; continue; } if (prefix(buf, "It sustains your charisma.")) { f2 &= TR2_SUST_CHR; continue; } /* Various immunities */ if (prefix(buf, "It provides immunity to acid.")) { f2 &= TR2_IM_ACID; continue; } if (prefix(buf, "It provides immunity to electricity.")) { f2 &= TR2_IM_ELEC; continue; } if (prefix(buf, "It provides immunity to fire.")) { f2 &= TR2_IM_FIRE; continue; } if (prefix(buf, "It provides immunity to cold.")) { f2 &= TR2_IM_COLD; continue; } /* Free Action */ if (prefix(buf, "It provides immunity to paralysis.")) { f2 &= TR2_FREE_ACT; continue; } /* Hold Life */ if (prefix(buf, "It provides resistance to life draining.")) { f2 &= TR2_HOLD_LIFE; continue; } /* Resists */ if (prefix(buf, "It provides resistance to acid.")) { f2 &= TR2_RES_ACID; continue; } if (prefix(buf, "It provides resistance to electricity.")) { f2 &= TR2_RES_ELEC; continue; } if (prefix(buf, "It provides resistance to fire.")) { f2 &= TR2_RES_FIRE; continue; } if (prefix(buf, "It provides resistance to cold.")) { f2 &= TR2_RES_COLD; continue; } if (prefix(buf, "It provides resistance to poison.")) { f2 &= TR2_RES_POIS; continue; } if (prefix(buf, "It provides resistance to light.")) { f2 &= TR2_RES_LITE; continue; } if (prefix(buf, "It provides resistance to dark.")) { f2 &= TR2_RES_DARK; continue; } if (prefix(buf, "It provides resistance to blindness.")) { f2 &= TR2_RES_BLIND; continue; } if (prefix(buf, "It provides resistance to confusion.")) { f2 &= TR2_RES_CONF; continue; } if (prefix(buf, "It provides resistance to sound.")) { f2 &= TR2_RES_SOUND; continue; } if (prefix(buf, "It provides resistance to shards.")) { f2 &= TR2_RES_SHARDS; continue; } if (prefix(buf, "It provides resistance to nether.")) { f2 &= TR2_RES_NETHER; continue; } if (prefix(buf, "It provides resistance to nexus.")) { f2 &= TR2_RES_NEXUS; continue; } if (prefix(buf, "It provides resistance to chaos.")) { f2 &= TR2_RES_CHAOS; continue; } if (prefix(buf, "It provides resistance to disenchantment.")) { f2 &= TR2_RES_DISEN; continue; } /* Feather Fall */ if (prefix(buf, "It induces feather falling.")) { f3 &= TR3_FEATHER; continue; } /* It Glows! */ if (prefix(buf, "It provides permanent light.")) { f3 &= TR3_LITE; continue; } /* See Invisible */ if (prefix(buf, "It allows you to see invisible monsters.")) { f3 &= TR3_SEE_INVIS; continue; } /* ESP */ if (prefix(buf, "It gives telepathic powers.")) { f3 &= TR3_TELEPATHY; continue; } /* Slow Digestion */ if (prefix(buf, "It slows your metabolism.")) { f3 &= TR3_SLOW_DIGEST; continue; } /* Regenerate */ if (prefix(buf, "It speeds your regenerative powers.")) { f3 &= TR3_REGEN; continue; } /* Extra Mult for Missle Weapons */ if (prefix(buf, "It fires missiles with extra might.")) { f3 &= TR3_XTRA_MIGHT; continue; } /* Extra Shots */ if (prefix(buf, "It fires missiles excessively fast.")) { f3 &= TR3_XTRA_SHOTS; continue; } /* The One Ring! */ if (prefix(buf, "It drains experience.")) { f3 &= TR3_DRAIN_EXP; continue; } /* Teleports (cursed) */ if (prefix(buf, "It induces random teleportation.")) { f3 &= TR3_TELEPORT; continue; } /* Aggravate */ if (prefix(buf, "It aggravates nearby creatures.")) { f3 &= TR3_AGGRAVATE; continue; } /* Can be used by priests */ if (prefix(buf, "It has been blessed by the gods.")) { f3 &= TR3_BLESSED; continue; } /* Perma-curse */ if (prefix(buf, "It is permanently cursed.")) { f3 &= TR3_PERMA_CURSE; continue; } /* Regualar old curse */ if (prefix(buf, "It is cursed.")) { f3 &= TR3_CURSED; continue; } /* Item imunity */ if (prefix(buf, "It cannot be harmed by acid.")) { f3 &= TR3_IGNORE_ACID; continue; } if (prefix(buf, "It cannot be harmed by electricity.")) { f3 &= TR3_IGNORE_ELEC; continue; } if (prefix(buf, "It cannot be harmed by fire.")) { f3 &= TR3_IGNORE_FIRE; continue; } if (prefix(buf, "It cannot be harmed by cold.")) { f3 &= TR3_IGNORE_COLD; continue; } /* press space to go to next screen. */ if (prefix(buf, "-- more --")) { return (TRUE); } } } borg_item->flags1 = f1; borg_item->flags2 = f2; borg_item->flags3 = f3; borg_item->needs_I = FALSE; return (FALSE); } /* * Look for an item that needs to be analysed because it has been *ID*d * * This will go through inventory and look for items that were just*ID*'d * and examine them for their bonuses. */ bool borg_object_star_id( void ) { int i; /* look in inventory and equiptment for something to *id* */ for (i = 0; i < INVEN_TOTAL; i++) { if (auto_items[i].needs_I) { if ((auto_cheat_equip && i >= INVEN_WIELD ) || auto_cheat_inven && i < INVEN_WIELD ) { /* cheat to get the information. */ borg_object_star_id_aux( &auto_items[i], &inventory[i]); } else { byte t_a; char buf[10]; /* Check to see if we are looking at the 'I' screen. */ if (!(0 == borg_what_text(0, 0, 9, &t_a, buf) && buf[0] == 'E' & buf[1] == 'x' & buf[2] == 'a' & buf[3] == 'm' & buf[4] == 'i' & buf[5] == 'n' & buf[6] == 'i' & buf[7] == 'n' & buf[8] == 'g') ) { borg_keypress('I'); if (i < INVEN_WIELD) { borg_keypress(I2A(i)); } else { borg_keypress('/'); borg_keypress(I2A(i - INVEN_WIELD)); } return (TRUE); } /* Look at the screen to get the information */ if (borg_object_star_id_aux( &auto_items[i], 0 )) { borg_keypress(' '); return (TRUE); } /* Get rid of the *ID* screen */ borg_keypress(' '); borg_keypress(' '); borg_keypress(' '); return (TRUE); } } } return (FALSE); } /* * Determine the "base price" of a known item (see below) * * This function is adapted from "object_value_known()". * * This routine is called only by "borg_item_analyze()", which * uses this function to guess at the "value" of an item, if it * was to be sold to a store, with perfect "charisma" modifiers. */ static s32b borg_object_value_known(auto_item *item) { s32b value; object_kind *k_ptr = &k_info[item->kind]; /* Worthless items */ if (!k_ptr->cost) return (0L); /* Extract the base value */ value = k_ptr->cost; /* Hack -- use artifact base costs */ if (item->name1) { artifact_type *a_ptr = &a_info[item->name1]; /* Worthless artifacts */ if (!a_ptr->cost) return (0L); /* Hack -- use the artifact cost */ value = a_ptr->cost; } /* Hack -- add in ego-item bonus cost */ if (item->name2) { ego_item_type *e_ptr = &e_info[item->name2]; /* Worthless ego-items */ if (!e_ptr->cost) return (0L); /* Hack -- reward the ego-item cost */ value += e_ptr->cost; } /* Analyze pval bonus */ switch (item->tval) { /* Wands/Staffs */ case TV_WAND: case TV_STAFF: { /* Pay extra for charges */ value += ((value / 20) * item->pval); break; } /* Wearable items */ case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_BOW: case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: case TV_LITE: case TV_AMULET: case TV_RING: { /* Hack -- Negative "pval" is always bad */ if (item->pval < 0) return (0L); /* No pval */ if (!item->pval) break; /* Give credit for stat bonuses */ if (item->flags1 & TR1_STR) value += (item->pval * 200L); if (item->flags1 & TR1_INT) value += (item->pval * 200L); if (item->flags1 & TR1_WIS) value += (item->pval * 200L); if (item->flags1 & TR1_DEX) value += (item->pval * 200L); if (item->flags1 & TR1_CON) value += (item->pval * 200L); if (item->flags1 & TR1_CHR) value += (item->pval * 200L); /* Give credit for stealth and searching */ if (item->flags1 & TR1_STEALTH) value += (item->pval * 100L); if (item->flags1 & TR1_SEARCH) value += (item->pval * 100L); /* Give credit for infra-vision and tunneling */ if (item->flags1 & TR1_INFRA) value += (item->pval * 50L); if (item->flags1 & TR1_TUNNEL) value += (item->pval * 50L); /* Give credit for extra attacks */ if (item->flags1 & TR1_BLOWS) value += (item->pval * 2000L); /* Give credit for speed bonus */ if (item->flags1 & TR1_SPEED) value += (item->pval * 30000L); break; } } /* Analyze the item */ switch (item->tval) { /* Rings/Amulets */ case TV_RING: case TV_AMULET: { /* Hack -- negative bonuses are bad */ if (item->to_a < 0) return (0L); if (item->to_h < 0) return (0L); if (item->to_d < 0) return (0L); /* Give credit for bonuses */ value += ((item->to_h + item->to_d + item->to_a) * 100L); break; } /* Armor */ case TV_BOOTS: case TV_GLOVES: case TV_CLOAK: case TV_CROWN: case TV_HELM: case TV_SHIELD: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: { /* Hack -- negative armor bonus */ if (item->to_a < 0) return (0L); /* Give credit for bonuses */ value += ((item->to_h + item->to_d + item->to_a) * 100L); break; } /* Bows/Weapons */ case TV_BOW: case TV_DIGGING: case TV_HAFTED: case TV_SWORD: case TV_POLEARM: { /* Hack -- negative hit/damage bonuses */ if (item->to_h + item->to_d < 0) return (0L); /* Factor in the bonuses */ value += ((item->to_h + item->to_d + item->to_a) * 100L); /* Hack -- Factor in extra damage dice */ if ((item->dd > k_ptr->dd) && (item->ds == k_ptr->ds)) { value += (item->dd - k_ptr->dd) * item->ds * 200L; } break; } /* Ammo */ case TV_SHOT: case TV_ARROW: case TV_BOLT: { /* Hack -- negative hit/damage bonuses */ if (item->to_h + item->to_d < 0) return (0L); /* Factor in the bonuses */ value += ((item->to_h + item->to_d) * 5L); /* Hack -- Factor in extra damage dice */ if ((item->dd > k_ptr->dd) && (item->ds == k_ptr->ds)) { value += (item->dd - k_ptr->dd) * item->ds * 5L; } break; } } /* Return the value */ return (value); } /* * Analyze an item given a description and (optional) cost * * From the description, extract the item identity, and the various * bonuses, plus the "aware" and "known" flags (in an encoded state). * * Note the use of a "prefix binary search" on the arrays of object * base names, and on the arrays of artifact/ego-item special names. * * A "prefix binary search" starts out just like a normal binary search, * in that it searches a sorted array of entries for a specific entry, * using a simple "less than or equal to" comparison. When it finds * an entry, however, instead of simply checking for "equality" of the * entry to the key, it must check whether the key is a "prefix" of the * entry. And if any entry can be a prefix of another entry, then it * must check whether the key is a "prefix" of any of the entries which * precede the "found" entry. Technically, it only has to check the * preceding N entries, where N is the maximum distance between any two * entries sharing a "prefix" relation, but note that only in the case * of "failure" will the search need to check more than a few entries, * even if it scans all the way to the start of the list. * * We use the object kind to guess at the object weight and flags, and * then we use the artifact/ego-item information to update our guesses. * * We also guess at the value of the item, as given by "object_value()". * * Note that we will fail if the "description" was "partial", that is, * if it was "broken" by the display functions for any reason. This * should only be an issue in "stores", which "chop" the description * to a length of about 60 characters, which may be "messy". Luckily, * objects in stores never have important inscriptions, and we should * correctly handle objects with "bizarre" inscriptions, or even with * "broken" inscriptions, so we should be okay. */ void borg_item_analyze(auto_item *item, cptr desc) { int i, m, n; int d1 = 0; int d2 = 0; int ac = 0; int th = 0; int td = 0; int ta = 0; bool done = FALSE; char *scan; char *tail; char temp[128]; /* Wipe the item */ WIPE(item, auto_item); /* Save the item description */ strcpy(item->desc, desc); /* Advance to the "inscription" or end of string */ for (scan = item->desc; *scan && (*scan != c1); scan++) /* loop */; /* Save a pointer to the inscription */ item->note = scan; /* Empty item */ if (!desc[0]) return; /* Assume singular */ item->iqty = 1; /* Notice prefix "a " */ if ((desc[0] == 'a') && (desc[1] == ' ')) { /* Skip "a " */ desc += 2; } /* Notice prefix "a " */ else if ((desc[0] == 'a') && (desc[1] == 'n') && (desc[2] == ' ')) { /* Skip "an " */ desc += 3; } /* Notice prefix "The " */ else if ((desc[0] == 'T') && (desc[1] == 'h') && (desc[2] == 'e') && (desc[3] == ' ')) { /* Skip "The " */ desc += 4; } /* Notice "numerical" prefixes */ else if (isdigit(desc[0])) { cptr s; /* Find the first space */ for (s = desc; *s && (*s != ' '); s++) /* loop */; /* Paranoia -- Catch sillyness */ if (*s != ' ') return; /* Extract a quantity */ item->iqty = atoi(desc); /* Skip the quantity and space */ desc = s + 1; } /* Paranoia */ if (!desc[0]) return; /* Obtain a copy of the description */ strcpy(temp, desc); /* Advance to the "inscription" or end of string */ for (scan = temp; *scan && (*scan != c1); scan++) /* loop */; /* Nuke the space before the inscription */ if ((scan[0] == c1) && (scan[-1] == ' ')) *--scan = '\0'; /* Note that "scan" points at the "tail" of "temp" */ /* Hack -- non-aware, singular, flavored items */ if (item->iqty == 1) { if (prefix(temp, "Scroll titled ")) item->tval = TV_SCROLL; else if (streq(scan-7, " Potion")) item->tval = TV_POTION; else if (streq(scan-6, " Staff")) item->tval = TV_STAFF; else if (streq(scan-5, " Wand")) item->tval = TV_WAND; else if (streq(scan-4, " Rod")) item->tval = TV_ROD; else if (streq(scan-5, " Ring")) item->tval = TV_RING; else if (streq(scan-7, " Amulet")) item->tval = TV_AMULET; else if (streq(scan-9, " Mushroom")) item->tval = TV_FOOD; } /* Hack -- non-aware, plural, flavored items */ else { if (prefix(temp, "Scrolls titled ")) item->tval = TV_SCROLL; else if (streq(scan-8, " Potions")) item->tval = TV_POTION; else if (streq(scan-7, " Staffs")) item->tval = TV_STAFF; else if (streq(scan-6, " Wands")) item->tval = TV_WAND; else if (streq(scan-5, " Rods")) item->tval = TV_ROD; else if (streq(scan-6, " Rings")) item->tval = TV_RING; else if (streq(scan-8, " Amulets")) item->tval = TV_AMULET; else if (streq(scan-10, " Mushrooms")) item->tval = TV_FOOD; } /* Accept non-aware flavored objects */ if (item->tval) { /* Guess at weight and cost */ switch (item->tval) { case TV_FOOD: { item->weight = 1; item->value = 5L; break; } case TV_POTION: { item->weight = 4; item->value = 20L; break; } case TV_SCROLL: { item->weight = 5; item->value = 20L; break; } case TV_STAFF: { item->weight = 50; item->value = 70L; break; } case TV_WAND: { item->weight = 10; item->value = 50L; break; } case TV_ROD: { item->weight = 15; item->value = 90L; break; } case TV_RING: { item->weight = 2; item->value = 45L; break; } case TV_AMULET: { item->weight = 3; item->value = 45L; break; } } /* Done */ return; } /* Start at the beginning */ tail = temp; /* Check singular items */ if (item->iqty == 1) { /* Start the search */ m = 0; n = auto_single_size; /* Simple binary search */ while (m < n - 1) { /* Pick a "middle" entry */ i = (m + n) / 2; /* Search to the right (or here) */ if (strcmp(auto_single_text[i], tail) <= 0) { m = i; } /* Search to the left */ else { n = i; } } /* Check prefixes XXX */ for (i = m; i >= 0; i--) { /* Verify prefix */ if (prefix(tail, auto_single_text[i])) { /* Save the item kind */ item->kind = auto_single_what[i]; /* Skip past the base name */ tail += strlen(auto_single_text[i]); /* Done */ break; } } } /* Check plural items */ else { /* Start the search */ m = 0; n = auto_plural_size; /* Simple binary search */ while (m < n - 1) { /* Pick a "middle" entry */ i = (m + n) / 2; /* Search to the right (or here) */ if (strcmp(auto_plural_text[i], tail) <= 0) { m = i; } /* Search to the left */ else { n = i; } } /* Check prefixes XXX */ for (i = m; i >= 0; i--) { /* Verify prefix */ if (prefix(tail, auto_plural_text[i])) { /* Save the item kind */ item->kind = auto_plural_what[i]; /* Skip past the base name */ tail += strlen(auto_plural_text[i]); /* Done */ break; } } } /* Oops */ if (!item->kind) { borg_oops("bizarre object"); return; } /* Extract some info */ item->tval = k_info[item->kind].tval; item->sval = k_info[item->kind].sval; /* Guess at the weight */ item->weight = k_info[item->kind].weight; /* Extract the base flags */ item->flags1 = k_info[item->kind].flags1; item->flags2 = k_info[item->kind].flags2; item->flags3 = k_info[item->kind].flags3; /* Analyze "bonuses" */ switch (item->tval) { /* Basic items */ case TV_MAGIC_BOOK: case TV_PRAYER_BOOK: case TV_FLASK: case TV_FOOD: case TV_POTION: case TV_SCROLL: case TV_SPIKE: case TV_SKELETON: case TV_BOTTLE: case TV_JUNK: { /* Always "able" */ item->able = TRUE; break; } /* Chests */ case TV_CHEST: { /* XXX XXX XXX */ /* Require the prefix and suffix */ if (!prefix(tail, " (")) break; if (!suffix(tail, ")")) break; /* Assume "able" */ item->able = TRUE; /* Hack -- assume "trapped" */ item->pval = 63; /* Hack -- extract "empty" */ if (streq(tail, " (empty)")) item->pval = 0; break; } /* Wands/Staffs -- charges */ case TV_WAND: case TV_STAFF: { /* assume 1 charge unless empty. This will allow use of */ /* staffs of teleport to get away when hit with a forget spell. */ item->pval = 1; if (streq(item->note, "{empty}")) item->pval = 0; /* Require the prefix and suffix */ if (!prefix(tail, " (")) break; /* --(-- */ if (!suffix(tail, " charge)") && !suffix(tail, " charges)")) break; /* Extract the "charges" */ item->pval = atoi(tail+2); /* Assume "able" */ item->able = TRUE; break; } /* Rods -- charging */ case TV_ROD: { /* Always "able" */ item->able = TRUE; /* Mega-Hack -- fake "charges" */ item->pval = 1; /* Mega-Hack -- "charging" means no "charges" */ if (streq(tail, " (charging)")) item->pval = 0; break; } /* Wearable items */ case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_BOW: case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR: case TV_LITE: case TV_AMULET: case TV_RING: { /* Hack -- handle "easy know" */ if (k_info[item->kind].flags3 & TR3_EASY_KNOW) { /* Always known */ item->able = TRUE; } /* No suffix */ if (tail[0] != ' ') break; /* Start the search */ m = 0; n = auto_artego_size; /* Binary search */ while (m < n - 1) { /* Pick a "middle" entry */ i = (m + n) / 2; /* Search to the right (or here) */ if (strcmp(auto_artego_text[i], tail) <= 0) { m = i; } /* Search to the left */ else { n = i; } } /* Check prefixes XXX */ for (i = m; i >= 0; i--) { /* Verify prefix */ if (prefix(tail, auto_artego_text[i])) { /* Paranoia */ item->able = TRUE; /* Save the artifact name */ if (auto_artego_what[i] < 256) { item->name1 = auto_artego_what[i]; } /* Save the ego-item name */ else { item->name2 = auto_artego_what[i] - 256; } /* Skip the artifact/ego-item name */ tail += strlen(auto_artego_text[i]); /* Done */ break; } } /* Hack -- grab "charging" suffix */ if (suffix(tail, " (charging)")) { /* Remove the suffix */ tail[strlen(tail)-11] = '\0'; /* Remember it */ item->timeout = 999; } /* Hack -- handle Lite's */ if (item->tval == TV_LITE) { /* Hack -- Artifact Lite's */ if (item->name1) { /* Assume "able" */ item->able = TRUE; /* Hack -- huge fuel */ item->pval = 29999; break; } /* Require the prefix and suffix */ if (!prefix(tail, " (with ")) break; if (!suffix(tail, " of light)")) break; /* Extract "turns of lite" */ item->pval = atoi(tail+7); /* Assume "able" */ item->able = TRUE; break; } /* Hack -- Skip spaces */ while (tail[0] == ' ') tail++; /* No suffix */ if (!tail[0]) break; /* Parse "weapon-style" damage strings */ if ((tail[0] == p1) && ((item->tval == TV_HAFTED) || (item->tval == TV_POLEARM) || (item->tval == TV_SWORD) || (item->tval == TV_DIGGING) || (item->tval == TV_BOLT) || (item->tval == TV_ARROW) || (item->tval == TV_SHOT))) { /* First extract the damage string */ for (scan = tail; *scan != p2; scan++) /* loop */; scan++; /* Hack -- Notice "end of string" */ if (scan[0] != ' ') done = TRUE; /* Terminate the string and advance */ *scan++ = '\0'; /* Parse the damage string, or stop XXX */ if (sscanf(tail, "(%dd%d)", &d1, &d2) != 2) break; /* Save the values */ item->dd = d1; item->ds = d2; /* No extra information means not identified */ if (done) break; /* Skip the "damage" info */ tail = scan; } /* Parse the "damage" string for bows */ else if ((tail[0] == p1) && (item->tval == TV_BOW)) { /* First extract the damage string */ for (scan = tail; *scan != p2; scan++) /* loop */; scan++; /* Hack -- Notice "end of string" */ if (scan[0] != ' ') done = TRUE; /* Terminate the string and advance */ *scan++ = '\0'; /* Parse the multiplier string, or stop */ if (sscanf(tail, "(x%d)", &d1) != 1) break; /* No extra information means not identified */ if (done) break; /* Skip the "damage" info */ tail = scan; } /* Parse the "bonus" string */ if (tail[0] == p1) { /* Extract the extra info */ for (scan = tail; *scan != p2; scan++) /* loop */; scan++; /* Hack -- Notice "end of string" */ if (scan[0] != ' ') done = TRUE; /* Terminate the damage, advance */ *scan++ = '\0'; /* Parse standard "bonuses" */ if (sscanf(tail, "(%d,%d)", &th, &td) == 2) { item->to_h = th; item->to_d = td; item->able = TRUE; } /* XXX XXX Hack -- assume non-final bonuses are "to_hit" */ else if (!done && sscanf(tail, "(%d)", &th) == 1) { item->to_h = th; item->able = TRUE; } /* XXX XXX Hack -- assume final bonuses are "pval" codes */ else if (done) { item->pval = atoi(tail + 1); item->able = TRUE; } /* Oops */ else { break; } /* Nothing left */ if (done) break; /* Skip the "damage bonus" info */ tail = scan; } /* Parse the "bonus" string */ if (tail[0] == b1) { /* Extract the extra info */ for (scan = tail; *scan != b2; scan++) /* loop */; scan++; /* Hack -- Notice "end of string" */ if (scan[0] != ' ') done = TRUE; /* Terminate the armor string, advance */ *scan++ = '\0'; /* Parse the armor, and bonus */ if (sscanf(tail, "[%d,%d]", &ac, &ta) == 2) { item->ac = ac; item->to_a = ta; item->able = TRUE; } /* Negative armor bonus */ else if (sscanf(tail, "[-%d]", &ta) == 1) { item->to_a = -ta; item->able = TRUE; } /* Positive armor bonus */ else if (sscanf(tail, "[+%d]", &ta) == 1) { item->to_a = ta; item->able = TRUE; } /* Just base armor */ else if (sscanf(tail, "[%d]", &ac) == 1) { item->ac = ac; } /* Oops */ else { break; } /* Nothing left */ if (done) break; /* Skip the "armor" data */ tail = scan; } /* Parse the final "pval" string, if any */ if (tail[0] == p1) { /* Assume identified */ item->able = TRUE; /* Hack -- Grab it */ item->pval = atoi(tail + 1); } break; } } /* Hack -- repair rings of damage */ if ((item->tval == TV_RING) && (item->sval == SV_RING_DAMAGE)) { /* Bonus to dam, not pval */ item->to_d = item->pval; item->pval = 0; } /* Hack -- repair rings of accuracy */ if ((item->tval == TV_RING) && (item->sval == SV_RING_ACCURACY)) { /* Bonus to hit, not pval */ item->to_h = item->pval; item->pval = 0; } /* XXX XXX XXX Repair various "ego-items" */ /* Hack -- examine artifacts */ if (item->name1) { /* XXX XXX Hack -- fix "weird" artifacts */ if ((item->tval != a_info[item->name1].tval) || (item->sval != a_info[item->name1].sval)) { /* Save the kind */ item->kind = lookup_kind(item->tval, item->sval); /* Save the tval/sval */ item->tval = k_info[item->kind].tval; item->sval = k_info[item->kind].sval; } /* Extract the weight */ item->weight = a_info[item->name1].weight; /* Extract the artifact flags */ item->flags1 = a_info[item->name1].flags1; item->flags2 = a_info[item->name1].flags2; item->flags3 = a_info[item->name1].flags3; } /* Hack -- examine ego-items */ if (item->name2) { /* XXX Extract the weight */ /* Extract the ego-item flags */ item->flags1 |= e_info[item->name2].flags1; item->flags2 |= e_info[item->name2].flags2; item->flags3 |= e_info[item->name2].flags3; } /* Known items */ if (item->able) { /* Process various fields */ item->value = borg_object_value_known(item); } /* Aware items */ else { /* Aware items can assume template cost */ item->value = k_info[item->kind].cost; } /* Parse various "inscriptions" */ if (item->note[0]) { /* Special "discount" */ if (streq(item->note, "{on sale}")) item->discount = 50; /* Standard "discounts" */ else if (streq(item->note, "{25% off}")) item->discount = 25; else if (streq(item->note, "{50% off}")) item->discount = 50; else if (streq(item->note, "{75% off}")) item->discount = 75; else if (streq(item->note, "{90% off}")) item->discount = 90; /* Cursed indicators */ else if (streq(item->note, "{cursed}")) item->value = 0L; else if (streq(item->note, "{broken}")) item->value = 0L; else if (streq(item->note, "{terrible}")) item->value = 0L; else if (streq(item->note, "{worthless}")) item->value = 0L; /* Ignore certain feelings */ /* "{average}" */ /* "{blessed}" */ /* "{good}" */ /* "{excellent}" */ /* "{special}" */ /* Ignore special inscriptions */ /* "{empty}", "{tried}" */ } /* Apply "discount" if any */ if (item->discount) item->value -= item->value * item->discount / 100; /* Assume not fully Identified. */ item->needs_I = item->fully_identified = FALSE; } /* * Send a command to inscribe item number "i" with the inscription "str". */ void borg_send_inscribe(int i, cptr str) { cptr s; /* Label it */ borg_keypress(c1); /* Choose from inventory */ if (i < INVEN_WIELD) { /* Choose the item */ borg_keypress(I2A(i)); } /* Choose from equipment */ else { /* Go to equipment (if necessary) */ if (auto_items[0].iqty) borg_keypress('/'); /* Choose the item */ borg_keypress(I2A(i - INVEN_WIELD)); } /* Send the label */ for (s = str; *s; s++) borg_keypress(*s); /* End the inscription */ borg_keypress('\n'); } /* * Find the slot of an item with the given tval/sval, if available. * Given multiple choices, choose the item with the largest "pval". * Given multiple choices, choose the smallest available pile. */ int borg_slot(int tval, int sval) { int i, n = -1; /* Scan the pack */ for (i = 0; i < INVEN_PACK; i++) { auto_item *item = &auto_items[i]; /* Skip empty items */ if (!item->iqty) continue; /* Skip un-aware items */ if (!item->kind) continue; /* Require correct tval */ if (item->tval != tval) continue; /* Require correct sval */ if (item->sval != sval) continue; /* Prefer largest "pval" */ if ((n >= 0) && (item->pval < auto_items[n].pval)) continue; /* Prefer smallest pile */ if ((n >= 0) && (item->iqty > auto_items[n].iqty)) continue; /* Save this item */ n = i; } /* Done */ return (n); } /* * Hack -- refuel a torch */ bool borg_refuel_torch(void) { int i; /* Look for a torch */ i = borg_slot(TV_LITE, SV_LITE_TORCH); /* None available */ if (i < 0) return (FALSE); /* Log the message */ borg_note(format("# Refueling with %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('F'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- refuel a lantern */ bool borg_refuel_lantern(void) { int i; /* Look for a torch */ i = borg_slot(TV_FLASK, 0); /* None available */ if (i < 0) return (FALSE); /* Log the message */ borg_note(format("# Refueling with %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('F'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to eat the given food (by sval) */ bool borg_eat_food(int sval) { int i; /* Look for that food */ i = borg_slot(TV_FOOD, sval); /* None available */ if (i < 0) return (FALSE); /* Log the message */ borg_note(format("# Eating %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('E'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to quaff the given potion (by sval) */ bool borg_quaff_potion(int sval) { int i; /* Look for that potion */ i = borg_slot(TV_POTION, sval); /* None available */ if (i < 0) return (FALSE); /* Log the message */ borg_note(format("# Quaffing %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('q'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to read the given scroll (by sval) */ bool borg_read_scroll(int sval) { int i; /* Blind or Confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* Look for that scroll */ i = borg_slot(TV_SCROLL, sval); /* None available */ if (i < 0) return (FALSE); /* Log the message */ borg_note(format("# Reading %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('r'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to zap the given (charged) rod (by sval) */ bool borg_zap_rod(int sval) { int i; /* Look for that rod */ i = borg_slot(TV_ROD, sval); /* None available */ if (i < 0) return (FALSE); /* Hack -- Still charging */ if (!auto_items[i].pval) return (FALSE); /* Log the message */ borg_note(format("# Zapping %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('z'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to aim the given (charged) wand (by sval) */ bool borg_aim_wand(int sval) { int i; /* Look for that wand */ i = borg_slot(TV_WAND, sval); /* None available */ if (i < 0) return (FALSE); /* No charges */ if (!auto_items[i].pval) return (FALSE); /* Log the message */ borg_note(format("# Aiming %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('a'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to use the given (charged) staff (by sval) */ bool borg_use_staff(int sval) { int i; /* Look for that staff */ i = borg_slot(TV_STAFF, sval); /* None available */ if (i < 0) return (FALSE); /* No charges */ if (!auto_items[i].pval) return (FALSE); /* Log the message */ borg_note(format("# Using %s.", auto_items[i].desc)); /* Perform the action */ borg_keypress('u'); borg_keypress(I2A(i)); /* Success */ return (TRUE); } /* * Hack -- attempt to use the given artifact (by index) */ bool borg_activate_artifact(int name1) { int i; /* Check the equipment */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { auto_item *item = &auto_items[i]; /* Skip incorrect artifacts */ if (item->name1 != name1) continue; /* Check charge */ if (item->timeout) continue; /* Log the message */ borg_note(format("# Activating %s.", item->desc)); /* Perform the action */ borg_keypress('A'); borg_keypress(I2A(i - INVEN_WIELD)); /* Success */ return (TRUE); } /* Oops */ return (FALSE); } /* * Determine if borg can cast a given spell (when fully rested) */ bool borg_spell_legal(int book, int what) { auto_magic *as = &auto_magics[book][what]; /* The borg must be able to "cast" spells */ if (mb_ptr->spell_book != TV_MAGIC_BOOK) return (FALSE); /* The book must be possessed */ if (amt_book[book] <= 0) return (FALSE); /* The spell must be "known" */ if (as->status < BORG_MAGIC_TEST) return (FALSE); /* The spell must be affordable (when rested) */ if (as->power > auto_msp) return (FALSE); /* Success */ return (TRUE); } /* * Determine if borg can cast a given spell (right now) */ bool borg_spell_okay(int book, int what) { auto_magic *as = &auto_magics[book][what]; /* Require ability (when rested) */ if (!borg_spell_legal(book, what)) return (FALSE); /* Hack -- blind/confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* The spell must be affordable (now) */ if (as->power > auto_csp) return (FALSE); /* Success */ return (TRUE); } /* * fail rate on a spell */ static int borg_spell_fail_rate(int book, int what) { int chance, minfail; auto_magic *as = &auto_magics[book][what]; /* Access the spell */ chance = as->sfail; /* Reduce failure rate by "effective" level adjustment */ chance -= 3 * (auto_level - as->level); /* Reduce failure rate by INT/WIS adjustment */ chance -= 3 * (adj_mag_stat[my_stat_ind[A_INT]] - 1); /* Not enough mana to cast */ /* Do not bother with this check because it will be taken care of seperatly. if (as->power > auto_csp) { chance += 5 * (as->power - auto_csp); } */ /* Extract the minimum failure rate */ minfail = adj_mag_fail[my_stat_ind[A_INT]]; /* Non mage characters never get too good */ if (auto_class != CLASS_MAGE) { if (minfail < 5) minfail = 5; } /* Minimum failure rate */ if (chance < minfail) chance = minfail; /* Stunning makes spells harder */ if (do_heavy_stun) chance += 25; if (do_stun) chance += 15; /* Always a 5 percent chance of working */ if (chance > 95) chance = 95; /* Return the chance */ return (chance); } /* * same as borg_spell_okay with a fail % check */ bool borg_spell_okay_fail(int book, int what, int allow_fail ) { if (borg_spell_fail_rate(book, what) > allow_fail) return FALSE; return borg_spell_okay( book, what ); } /* * Same as borg_spell with a fail % check */ bool borg_spell_fail(int book, int what, int allow_fail) { if (borg_spell_fail_rate(book, what) > allow_fail) return FALSE; return borg_spell( book, what ); } /* * Same as borg_spell_legal with a fail % check */ bool borg_spell_legal_fail(int book, int what, int allow_fail) { if (borg_spell_fail_rate(book, what) > allow_fail) return FALSE; return borg_spell_legal( book, what ); } /* * Attempt to cast a spell */ bool borg_spell(int book, int what) { int i; auto_magic *as = &auto_magics[book][what]; /* Require ability (right now) */ if (!borg_spell_okay(book, what)) return (FALSE); /* Look for the book */ i = auto_book[book]; /* Paranoia */ if (i < 0) return (FALSE); /* Debugging Info */ borg_note(format("# Casting %s (%d,%d).", as->name, book, what)); /* Cast a spell */ borg_keypress('m'); borg_keypress(I2A(i)); borg_keypress(I2A(what)); /* Success */ return (TRUE); } /* * Determine if borg can pray a given prayer (when fully rested) */ bool borg_prayer_legal(int book, int what) { auto_magic *as = &auto_magics[book][what]; /* The borg must be able to "pray" prayers */ if (mb_ptr->spell_book != TV_PRAYER_BOOK) return (FALSE); /* Look for the book */ if (amt_book[book] <= 0) return (FALSE); /* The prayer must be "known" */ if (as->status < BORG_MAGIC_TEST) return (FALSE); /* The prayer must be affordable (when fully rested) */ if (as->power > auto_msp) return (FALSE); /* Success */ return (TRUE); } /* * Determine if borg can pray a given prayer (right now) */ bool borg_prayer_okay(int book, int what) { auto_magic *as = &auto_magics[book][what]; /* Require ability (when rested) */ if (!borg_prayer_legal(book, what)) return (FALSE); /* Hack -- blind/confused */ if (do_blind || do_confused) return (FALSE); /* XXX XXX XXX Dark */ /* The prayer must be affordable (right now) */ if (as->power > auto_csp) return (FALSE); /* Success */ return (TRUE); } static int borg_prayer_fail_rate(int book, int what) { int chance, minfail; auto_magic *as = &auto_magics[book][what]; /* Access the spell */ chance = as->sfail; /* Reduce failure rate by "effective" level adjustment */ chance -= 3 * (auto_level - as->level); /* Reduce failure rate by INT/WIS adjustment */ chance -= 3 * (adj_mag_stat[my_stat_ind[A_WIS]] - 1); /* Not enough mana to cast */ /* Do not bother with this check because it will be taken care of seperatly. if (as->power > auto_csp) { chance += 5 * (as->power - auto_csp); } */ /* Extract the minimum failure rate */ minfail = adj_mag_fail[my_stat_ind[A_WIS]]; /* Non priest characters never get too good */ if (auto_class != CLASS_PRIEST) { if (minfail < 5) minfail = 5; } /* Hack -- Priest prayer penalty for "edged" weapons -DGK */ if (auto_class == CLASS_PRIEST) { auto_item *item; item = &auto_items[INVEN_WIELD]; /* Penalize non-blessed edged weapons */ if (((item->tval == TV_SWORD) || (item->tval == TV_POLEARM)) && (!(item->flags3 & TR3_BLESSED))) { chance += 25; } } /* Minimum failure rate */ if (chance < minfail) chance = minfail; /* Stunning makes spells harder */ if (do_heavy_stun) chance += 25; if (do_stun) chance += 15; /* Always a 5 percent chance of working */ if (chance > 95) chance = 95; /* Return the chance */ return (chance); } /* * same as borg_prayer_okay with a fail % check */ bool borg_prayer_okay_fail(int book, int what, int allow_fail ) { if (borg_prayer_fail_rate(book, what) > allow_fail) return FALSE; return borg_prayer_okay( book, what ); } /* * Same as borg_prayer with a fail % check */ bool borg_prayer_fail(int book, int what, int allow_fail) { if (borg_prayer_fail_rate(book, what) > allow_fail) return FALSE; return borg_prayer( book, what ); } /* * Same as borg_prayer_legal with a fail % check */ bool borg_prayer_legal_fail(int book, int what, int allow_fail) { if (borg_prayer_fail_rate(book, what) > allow_fail) return FALSE; return borg_prayer_legal( book, what ); } /* * Attempt to pray a prayer */ bool borg_prayer(int book, int what) { int i; auto_magic *as = &auto_magics[book][what]; /* Require ability (right now) */ if (!borg_prayer_okay(book, what)) return (FALSE); /* Look for the book */ i = auto_book[book]; /* Paranoia */ if (i < 0) return (FALSE); /* Debugging Info */ borg_note(format("# Praying %s (%d,%d).", as->name, book, what)); /* Pray a prayer */ borg_keypress('p'); borg_keypress(I2A(i)); borg_keypress(I2A(what)); /* Success */ return (TRUE); } /* * Cheat the "equip" screen */ void borg_cheat_equip(void) { int i; char buf[256]; /* Extract the equipment */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { /* Default to "nothing" */ buf[0] = '\0'; /* Describe a real item */ if (inventory[i].k_idx) { /* Describe it */ object_desc(buf, &inventory[i], TRUE, 3); } /* Ignore "unchanged" items */ /* !FIX do I still need this? I forget... AJG */ if (auto_items[i].needs_I) { if (streq(buf, auto_items[i].desc)) continue; } /* Analyze the item (no price) */ borg_item_analyze(&auto_items[i], buf); /* get the fully id stuff */ #ifdef ID_MENTAL if (inventory[i].ident & ID_MENTAL) { auto_items[i].fully_identified = TRUE; auto_items[i].needs_I = TRUE; auto_do_star_id = TRUE; } #endif } } /* * Cheat the "inven" screen */ void borg_cheat_inven(void) { int i; char buf[256]; /* Extract the current weight */ auto_cur_wgt = total_weight; /* Extract the inventory */ for (i = 0; i < INVEN_PACK; i++) { /* Default to "nothing" */ buf[0] = '\0'; /* Describe a real item */ if (inventory[i].k_idx) { /* Describe it */ object_desc(buf, &inventory[i], TRUE, 3); } /* Ignore "unchanged" items */ if (streq(buf, auto_items[i].desc)) continue; /* inventory changed so goals must change. */ goal_shop = goal_ware = goal_item = -1; /* Analyze the item (no price) */ borg_item_analyze(&auto_items[i], buf); /* get the fully id stuff */ #ifdef ID_MENTAL if (inventory[i].ident & ID_MENTAL) { auto_items[i].fully_identified = TRUE; auto_items[i].needs_I = TRUE; auto_do_star_id = TRUE; } #endif /* Note changed inventory */ auto_do_crush_junk = TRUE; auto_do_crush_hole = TRUE; auto_do_crush_slow = TRUE; } } /* * Parse the "equip" screen */ void borg_parse_equip(void) { int i; int row, col; bool done = FALSE; byte t_a; char buf[160]; /* Find the column */ for (col = 0; col < 55; col++) { /* Look for first prefix */ if ((0 == borg_what_text(col, 1, 3, &t_a, buf)) && (buf[0] == I2A(0)) && (buf[1] == p2) && (buf[2] == ' ')) { break; } } /* Extract the inventory */ for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) { /* Access the row */ row = i - INVEN_WIELD; /* Attempt to get some text */ if (!done && (0 == borg_what_text(col, row+1, 3, &t_a, buf)) && (buf[0] == I2A(row)) && (buf[1] == p2) && (buf[2] == ' ') && (0 == borg_what_text(col+3, row+1, -80, &t_a, buf)) && (buf[0] && (buf[0] != ' '))) { int k; /* Strip trailing spaces */ for (k = strlen(buf); (k > 0) && (buf[k-1] == ' '); k--) /* loop */; buf[k] = '\0'; } /* Default to "nothing" */ else { buf[0] = '\0'; done = TRUE; } /* Notice empty slots */ if (streq(buf, "(nothing)")) strcpy(buf, ""); /* Ignore "unchanged" items */ if (streq(buf, auto_items[i].desc)) continue; /* Analyze the item (no price) */ borg_item_analyze(&auto_items[i], buf); /* get the fully *id* stuff */ #ifdef ID_MENTAL if (inventory[i].ident & ID_MENTAL) { auto_items[i].fully_identified = TRUE; auto_items[i].needs_I = TRUE; auto_do_star_id = TRUE; } #endif } } /* * Parse the "inven" screen */ void borg_parse_inven(void) { int i; int row, col; int w1a, w1b; bool done = FALSE; byte t_a; char buf[160]; /* XXX XXX XXX */ /* Hack -- Parse the current total weight */ if ((0 == borg_what_text(0, 0, -80, &t_a, buf)) && (sscanf(buf, "Inventory (carrying %d.%d pounds)", &w1a, &w1b) == 2)) { /* Save the current weight */ auto_cur_wgt = w1a * 10 + w1b; } /* Find the column */ for (col = 0; col < 55; col++) { /* Look for first prefix */ if ((0 == borg_what_text(col, 1, 3, &t_a, buf)) && (buf[0] == I2A(0)) && (buf[1] == p2) && (buf[2] == ' ')) { break; } } /* Extract the inventory */ for (i = 0; i < INVEN_PACK; i++) { /* Access the row */ row = i; /* Attempt to get some text */ if (!done && (0 == borg_what_text(col, row+1, 3, &t_a, buf)) && (buf[0] == I2A(row)) && (buf[1] == p2) && (buf[2] == ' ') && (0 == borg_what_text(col+3, row+1, -80, &t_a, buf)) && (buf[0] && (buf[0] != ' '))) { int k; /* Strip trailing spaces */ for (k = strlen(buf); (k > 0) && (buf[k-1] == ' '); k--) /* loop */; buf[k] = '\0'; } /* Default to "nothing" */ else { buf[0] = '\0'; done = TRUE; } /* Notice empty slots */ if (streq(buf, "(nothing)")) strcpy(buf, ""); /* Ignore "unchanged" items */ if (streq(buf, auto_items[i].desc)) continue; /* Analyze the item (no price) */ borg_item_analyze(&auto_items[i], buf); /* get the fully id stuff */ #ifdef ID_MENTAL if (inventory[i].ident & ID_MENTAL) { auto_items[i].fully_identified = TRUE; auto_items[i].needs_I = TRUE; auto_do_star_id = TRUE; } #endif /* Note changed inventory */ auto_do_crush_junk = TRUE; auto_do_crush_hole = TRUE; auto_do_crush_slow = TRUE; } } /* * Hack -- Cheat the "spell" info (given the book) * * Hack -- note the use of the "cheat" field for efficiency */ void borg_cheat_spell(int book) { int j, what; /* Can we use spells/prayers? */ if (!mb_ptr->spell_book) return; /* Process the spells */ for (what = 0; what < 9; what++) { /* Access the spell */ auto_magic *as = &auto_magics[book][what]; /* Skip illegible spells */ if (as->status == BORG_MAGIC_ICKY) continue; /* Access the index */ j = as->cheat; /* Note "forgotten" spells */ if ((j < 32) ? ((spell_forgotten1 & (1L << j))) : ((spell_forgotten2 & (1L << (j - 32))))) { /* Forgotten */ as->status = BORG_MAGIC_LOST; } /* Note "difficult" spells */ else if (auto_level < as->level) { /* Unknown */ as->status = BORG_MAGIC_HIGH; } /* Note "unknown" spells */ else if (!((j < 32) ? (spell_learned1 & (1L << j)) : (spell_learned2 & (1L << (j - 32))))) { /* Unknown */ as->status = BORG_MAGIC_OKAY; } /* Note "untried" spells */ else if (!((j < 32) ? (spell_worked1 & (1L << j)) : (spell_worked2 & (1L << (j - 32))))) { /* Untried */ as->status = BORG_MAGIC_TEST; } /* Note "known" spells */ else { /* Known */ as->status = BORG_MAGIC_KNOW; } } } /* * Hack -- Parse the "spell" info (given the book) */ void borg_parse_spell(int book) { int what; byte t_a; char buf[160]; /* Can we use spells/prayers? */ if (!mb_ptr->spell_book) return; /* Process the spells */ for (what = 0; what < 9; what++) { int row = ROW_SPELL + 1 + what; int col = COL_SPELL; /* Access the spell */ auto_magic *as = &auto_magics[book][what]; /* Skip illegible spells */ if (as->status == BORG_MAGIC_ICKY) continue; #if 0 /* Format: "spell-name...................." at col 20+5 */ if (0 != borg_what_text(col-30, row, -30, &t_a, buf)) continue; #endif /* Format: "Lv Mana Freq Comment" at col 20+35 */ if (0 != borg_what_text(col, row, -20, &t_a, buf)) continue; /* Note "forgotten" spells */ if (prefix(buf + 13, "forgott")) { /* Forgotten */ as->status = BORG_MAGIC_LOST; } /* Note "difficult" spells */ else if (auto_level < as->level) { /* Unknown */ as->status = BORG_MAGIC_HIGH; } /* Note "unknown" spells */ else if (prefix(buf + 13, "unknown")) { /* Unknown */ as->status = BORG_MAGIC_OKAY; } /* Note "untried" spells */ else if (prefix(buf + 13, "untried")) { /* Untried */ as->status = BORG_MAGIC_TEST; } /* Note "known" spells */ else { /* Known */ as->status = BORG_MAGIC_KNOW; } } } /* * Prepare a book */ static void prepare_book_info(int book) { int i, what; int spell[64], num = 0; /* Reset each spell entry */ for (what = 0; what < 9; what++) { auto_magic *as = &auto_magics[book][what]; /* Assume no name */ as->name = NULL; /* Assume illegible */ as->status = BORG_MAGIC_ICKY; /* Assume illegible */ as->method = BORG_MAGIC_ICK; /* Impossible values */ as->level = 99; as->power = 99; /* Impossible value */ as->cheat = 99; } /* Can we use spells/prayers? */ if (!mb_ptr->spell_book) return; /* Extract spells */ for (i = 0; i < 64; i++) { /* Check for this spell */ if ((i < 32) ? (spell_flags[mb_ptr->spell_type][book][0] & (1L << i)) : (spell_flags[mb_ptr->spell_type][book][1] & (1L << (i - 32)))) { /* Collect this spell */ spell[num++] = i; } } /* Process each existing spell */ for (what = 0; what < num; what++) { auto_magic *as = &auto_magics[book][what]; magic_type *s_ptr = &mb_ptr->info[spell[what]]; /* Skip "illegible" spells */ if (s_ptr->slevel == 99) continue; /* Save the spell name */ as->name = spell_names[mb_ptr->spell_type][spell[what]]; /* Save the spell index */ as->cheat = spell[what]; /* Hack -- assume excessive level */ as->status = BORG_MAGIC_HIGH; /* Access the correct "method" */ as->method = auto_magic_method[mb_ptr->spell_type][book][what]; /* Access the correct "rating" */ as->rating = auto_magic_rating[mb_ptr->spell_type][book][what]; /* Extract the level and power */ as->level = s_ptr->slevel; as->power = s_ptr->smana; /* extract fail rate. */ as->sfail = s_ptr->sfail; } } /* * Hack -- prepare some stuff based on the player race and class */ void prepare_race_class_info(void) { int book; /* Initialize the various spell arrays by book */ for (book = 0; book < 9; book++) prepare_book_info(book); } /* * Sorting hook -- comp function -- see below * * We use "u" to point to an array of strings, and "v" to point to * an array of indexes, and we sort them together by the strings. */ static bool ang_sort_comp_hook(vptr u, vptr v, int a, int b) { cptr *text = (cptr*)(u); s16b *what = (s16b*)(v); int cmp; /* Compare the two strings */ cmp = (strcmp(text[a], text[b])); /* Strictly less */ if (cmp < 0) return (TRUE); /* Strictly more */ if (cmp > 0) return (FALSE); /* Enforce "stable" sort */ return (what[a] <= what[b]); } /* * Sorting hook -- swap function -- see below * * We use "u" to point to an array of strings, and "v" to point to * an array of indexes, and we sort them together by the strings. */ static void ang_sort_swap_hook(vptr u, vptr v, int a, int b) { cptr *text = (cptr*)(u); s16b *what = (s16b*)(v); cptr texttmp; s16b whattmp; /* Swap "text" */ texttmp = text[a]; text[a] = text[b]; text[b] = texttmp; /* Swap "what" */ whattmp = what[a]; what[a] = what[b]; what[b] = whattmp; } /* * Initialize this file * * Note that the Borg will never find Grond/Morgoth, but we * prepare the item parsers for them anyway. Actually, the * Borg might get lucky and find some of the special artifacts, * so it is always best to prepare for a situation if it does * not cost any effort. * * Note that all six artifact "Rings" will parse as "kind 506" * (the first artifact ring) and both artifact "Amulets" will * parse as "kind 503" (the first of the two artifact amulets), * but as long as we use the "name1" field (and not the "kind" * or "sval" fields) we should be okay. * * We sort the two arrays of items names in reverse order, so that * we will catch "mace of disruption" before "mace", "Scythe of * Slicing" before "Scythe", and for "Ring of XXX" before "Ring". * * Note that we do not have to parse "plural artifacts" (!) * * Hack -- This entire routine is a giant hack, but it works */ void borg_init_3(void) { int i, k, n; int size; s16b what[512]; cptr text[512]; char buf[256]; /*** Item/Ware arrays ***/ /* Make the inventory array */ C_MAKE(auto_items, INVEN_TOTAL, auto_item); /* Make the stores in the town */ C_MAKE(auto_shops, 8, auto_shop); /*** Item/Ware arrays (simulation) ***/ /* Make the "safe" inventory array */ C_MAKE(safe_items, INVEN_TOTAL, auto_item); C_MAKE(safe_home, STORE_INVEN_MAX, auto_item); /* Make the "safe" stores in the town */ C_MAKE(safe_shops, 8, auto_shop); /*** Plural Object Templates ***/ /* Start with no objects */ size = 0; /* Analyze some "item kinds" */ for (k = 1; k < MAX_K_IDX; k++) { object_type hack; /* Get the kind */ object_kind *k_ptr = &k_info[k]; /* Skip "empty" items */ if (!k_ptr->name) continue; /* Skip "gold" objects */ if (k_ptr->tval == TV_GOLD) continue; /* Skip "artifacts" */ if (k_ptr->flags3 & TR3_INSTA_ART) continue; /* Hack -- make an item */ /* invcopy(&hack, k); This has gone - Tim */ object_prep(&hack, k); /* Describe a "plural" object */ hack.number = 2; object_desc_store(buf, &hack, FALSE, 0); /* Save an entry */ text[size] = string_make(buf); what[size] = k; size++; } /* Set the sort hooks */ ang_sort_comp = ang_sort_comp_hook; ang_sort_swap = ang_sort_swap_hook; /* Sort */ ang_sort(text, what, size); /* Save the size */ auto_plural_size = size; /* Allocate the "item parsing arrays" (plurals) */ C_MAKE(auto_plural_text, auto_plural_size, cptr); C_MAKE(auto_plural_what, auto_plural_size, s16b); /* Save the entries */ for (i = 0; i < size; i++) auto_plural_text[i] = text[i]; for (i = 0; i < size; i++) auto_plural_what[i] = what[i]; /*** Singular Object Templates ***/ /* Start with no objects */ size = 0; /* Analyze some "item kinds" */ for (k = 1; k < MAX_K_IDX; k++) { object_type hack; /* Get the kind */ object_kind *k_ptr = &k_info[k]; /* Skip "empty" items */ if (!k_ptr->name) continue; /* Skip "dungeon terrain" objects */ if (k_ptr->tval == TV_GOLD) continue; /* Skip "artifacts" */ if (k_ptr->flags3 & TR3_INSTA_ART) continue; /* Hack -- make an item */ /* invcopy(&hack, k); this has changed - Tim*/ object_prep(&hack, k); /* Describe a "singular" object */ hack.number = 1; object_desc_store(buf, &hack, FALSE, 0); /* Save an entry */ text[size] = string_make(buf); what[size] = k; size++; } /* Analyze the "INSTA_ART" items */ for (i = 1; i < MAX_A_IDX; i++) { object_type hack; artifact_type *a_ptr = &a_info[i]; cptr name = (a_name + a_ptr->name); /* Skip "empty" items */ if (!a_ptr->name) continue; /* Skip non INSTA_ART things */ if (!(a_ptr->flags3 & TR3_INSTA_ART)) continue; /* Extract the "kind" */ k = lookup_kind(a_ptr->tval, a_ptr->sval); /* Hack -- make an item */ /* invcopy(&hack, k); this has changed - Tim */ object_prep(&hack, k); /* Save the index */ hack.name1 = i; /* Describe a "singular" object */ hack.number = 1; object_desc_store(buf, &hack, FALSE, 0); /* Extract the "suffix" length */ n = strlen(name) + 1; /* Remove the "suffix" */ buf[strlen(buf) - n] = '\0'; /* Save an entry */ text[size] = string_make(buf); what[size] = k; size++; } /* Set the sort hooks */ ang_sort_comp = ang_sort_comp_hook; ang_sort_swap = ang_sort_swap_hook; /* Sort */ ang_sort(text, what, size); /* Save the size */ auto_single_size = size; /* Allocate the "item parsing arrays" (plurals) */ C_MAKE(auto_single_text, auto_single_size, cptr); C_MAKE(auto_single_what, auto_single_size, s16b); /* Save the entries */ for (i = 0; i < size; i++) auto_single_text[i] = text[i]; for (i = 0; i < size; i++) auto_single_what[i] = what[i]; /*** Artifact and Ego-Item Parsers ***/ /* No entries yet */ size = 0; /* Collect the "artifact names" */ for (k = 1; k < MAX_A_IDX; k++) { artifact_type *a_ptr = &a_info[k]; /* Skip non-items */ if (!a_ptr->name) continue; /* Extract a string */ sprintf(buf, " %s", (a_name + a_ptr->name)); /* Save an entry */ text[size] = string_make(buf); what[size] = k; size++; } /* Collect the "ego-item names" */ for (k = 1; k < MAX_E_IDX; k++) { ego_item_type *e_ptr = &e_info[k]; /* Skip non-items */ if (!e_ptr->name) continue; /* Extract a string */ sprintf(buf, " %s", (e_name + e_ptr->name)); /* Save an entry */ text[size] = string_make(buf); what[size] = k + 256; size++; } /* Set the sort hooks */ ang_sort_comp = ang_sort_comp_hook; ang_sort_swap = ang_sort_swap_hook; /* Sort */ ang_sort(text, what, size); /* Save the size */ auto_artego_size = size; /* Allocate the "item parsing arrays" (plurals) */ C_MAKE(auto_artego_text, auto_artego_size, cptr); C_MAKE(auto_artego_what, auto_artego_size, s16b); /* Save the entries */ for (i = 0; i < size; i++) auto_artego_text[i] = text[i]; for (i = 0; i < size; i++) auto_artego_what[i] = what[i]; } #else #ifdef MACINTOSH static int HACK = 0; #endif #endif