diff options
Diffstat (limited to 'stone_soup/crawl-ref/source/spl-book.cc')
-rw-r--r-- | stone_soup/crawl-ref/source/spl-book.cc | 1597 |
1 files changed, 1597 insertions, 0 deletions
diff --git a/stone_soup/crawl-ref/source/spl-book.cc b/stone_soup/crawl-ref/source/spl-book.cc new file mode 100644 index 0000000000..302afdab4c --- /dev/null +++ b/stone_soup/crawl-ref/source/spl-book.cc @@ -0,0 +1,1597 @@ +/* + * File: spl-book.cc + * Summary: Spellbook/Staff contents array and management functions + * Written by: Josh Fishman + * + * Change History (most recent first): + * + * 24jun2000 jmf Changes to many books; addition of Assassinations; + * alteration of type-printout to match new bitfield. + * <1> 19mar2000 jmf Created by taking stuff from dungeon.cc, spells0.cc, + * spells.cc, shopping.cc + */ + +#include "AppHdr.h" +#include "spl-book.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifdef DOS +#include <conio.h> +#endif + +#include "externs.h" + +#include "debug.h" +#include "delay.h" +#include "food.h" +#include "invent.h" +#include "itemname.h" +#include "itemprop.h" +#include "items.h" +#include "it_use3.h" +#include "player.h" +#include "religion.h" +#include "spl-cast.h" +#include "spl-util.h" +#include "stuff.h" + +static int spellbook_template_array[NUMBER_SPELLBOOKS][SPELLBOOK_SIZE] = +{ + // 0 - Minor Magic I + {0, + SPELL_MAGIC_DART, + SPELL_SUMMON_SMALL_MAMMAL, + SPELL_THROW_FLAME, + SPELL_BLINK, + SPELL_SLOW, + SPELL_MEPHITIC_CLOUD, + SPELL_CONJURE_FLAME, + SPELL_NO_SPELL, + }, + // 1 - Minor Magic II + {0, + SPELL_MAGIC_DART, + SPELL_THROW_FROST, + SPELL_BLINK, + SPELL_STICKS_TO_SNAKES, + SPELL_SLOW, + SPELL_MEPHITIC_CLOUD, + SPELL_OZOCUBUS_ARMOUR, + SPELL_NO_SPELL, + }, + // 2 - Minor Magic III + {0, + SPELL_MAGIC_DART, + SPELL_SUMMON_SMALL_MAMMAL, + SPELL_BLINK, + SPELL_REPEL_MISSILES, + SPELL_SLOW, + SPELL_SUMMON_LARGE_MAMMAL, + SPELL_MEPHITIC_CLOUD, + SPELL_NO_SPELL, + }, + // 3 - Book of Conjurations I - Fire and Earth + {0, + SPELL_MAGIC_DART, + SPELL_THROW_FLAME, + SPELL_STONE_ARROW, + SPELL_CONJURE_FLAME, + SPELL_BOLT_OF_MAGMA, + SPELL_FIREBALL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 4 - Book of Conjurations II - Air and Ice + {0, + SPELL_MAGIC_DART, + SPELL_THROW_FROST, + SPELL_MEPHITIC_CLOUD, + SPELL_DISCHARGE, + SPELL_BOLT_OF_COLD, + SPELL_FREEZING_CLOUD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 5 - Book of Flames + {0, + SPELL_FLAME_TONGUE, + SPELL_THROW_FLAME, + SPELL_CONJURE_FLAME, + SPELL_STICKY_FLAME, + SPELL_BOLT_OF_FIRE, + SPELL_FIREBALL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 6 - Book of Frost + {0, + SPELL_FREEZE, + SPELL_THROW_FROST, + SPELL_OZOCUBUS_ARMOUR, + SPELL_ICE_BOLT, + SPELL_SUMMON_ICE_BEAST, + SPELL_FREEZING_CLOUD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 7 - Book of Summonings + {0, + SPELL_ABJURATION_I, + SPELL_RECALL, + SPELL_SUMMON_LARGE_MAMMAL, + SPELL_SHADOW_CREATURES, + SPELL_SUMMON_WRAITHS, + SPELL_SUMMON_HORRIBLE_THINGS, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 8 - Book of Fire + {0, + SPELL_EVAPORATE, + SPELL_FIRE_BRAND, + SPELL_SUMMON_ELEMENTAL, + SPELL_BOLT_OF_MAGMA, + SPELL_DELAYED_FIREBALL, + SPELL_IGNITE_POISON, + SPELL_RING_OF_FLAMES, + SPELL_NO_SPELL, + }, + // 9 - Book of Ice + {0, + SPELL_FREEZING_AURA, + SPELL_SLEEP, + SPELL_CONDENSATION_SHIELD, + SPELL_BOLT_OF_COLD, + SPELL_OZOCUBUS_REFRIGERATION, + SPELL_SIMULACRUM, + SPELL_MASS_SLEEP, + SPELL_NO_SPELL, + }, + + // 10 - Book of Surveyances + {0, + SPELL_DETECT_SECRET_DOORS, + SPELL_DETECT_TRAPS, + SPELL_DETECT_ITEMS, + SPELL_MAGIC_MAPPING, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL + }, + // 11 - Book of Spatial Translocations + {0, + SPELL_APPORTATION, + SPELL_BLINK, + SPELL_RECALL, + SPELL_TELEPORT_OTHER, + SPELL_TELEPORT_SELF, + SPELL_CONTROL_TELEPORT, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 12 - Book of Enchantments (fourth one) + {0, + SPELL_LEVITATION, + SPELL_SELECTIVE_AMNESIA, + SPELL_REMOVE_CURSE, + SPELL_CAUSE_FEAR, + SPELL_EXTENSION, + SPELL_DEFLECT_MISSILES, + SPELL_HASTE, + SPELL_NO_SPELL, + }, + // 13 - Young Poisoner's Handbook + {0, + SPELL_STING, + SPELL_CURE_POISON_II, + SPELL_MEPHITIC_CLOUD, + SPELL_POISON_WEAPON, + SPELL_VENOM_BOLT, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 14 - Book of the Tempests + {0, + SPELL_DISCHARGE, + SPELL_LIGHTNING_BOLT, + SPELL_FIREBALL, + SPELL_SHATTER, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 15 - Book of Death + {0, + SPELL_CORPSE_ROT, + SPELL_BONE_SHARDS, + SPELL_LETHAL_INFUSION, + SPELL_AGONY, + SPELL_BOLT_OF_DRAINING, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 16 - Book of Hinderance + {0, + SPELL_CONFUSING_TOUCH, + SPELL_SLOW, + SPELL_CONFUSE, + SPELL_PARALYZE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 17 - Book of Changes + {0, + SPELL_FULSOME_DISTILLATION, + SPELL_STICKS_TO_SNAKES, + SPELL_EVAPORATE, + SPELL_SPIDER_FORM, + SPELL_ICE_FORM, + SPELL_DIG, + SPELL_BLADE_HANDS, + SPELL_NO_SPELL, + }, + // 18 - Book of Transfigurations + {0, + SPELL_SANDBLAST, + SPELL_POLYMORPH_OTHER, + SPELL_STATUE_FORM, + SPELL_ALTER_SELF, + SPELL_DRAGON_FORM, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 19 - Book of Practical Magic + {0, + SPELL_PROJECTED_NOISE, + SPELL_SELECTIVE_AMNESIA, + SPELL_DETECT_CURSE, + SPELL_DIG, + SPELL_REMOVE_CURSE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 20 - Book of War Chants + {0, + SPELL_FIRE_BRAND, + SPELL_FREEZING_AURA, + SPELL_REPEL_MISSILES, + SPELL_BERSERKER_RAGE, + SPELL_REGENERATION, + SPELL_HASTE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 21 - Book of Clouds + {0, + SPELL_EVAPORATE, + SPELL_MEPHITIC_CLOUD, + SPELL_CONJURE_FLAME, + SPELL_POISONOUS_CLOUD, + SPELL_FREEZING_CLOUD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 22 - Book of Healing + {0, + SPELL_CURE_POISON_I, + SPELL_LESSER_HEALING, + SPELL_GREATER_HEALING, + SPELL_PURIFICATION, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 23 - Book of Necromancy + {0, + SPELL_PAIN, + SPELL_ANIMATE_SKELETON, + SPELL_VAMPIRIC_DRAINING, + SPELL_REGENERATION, + SPELL_DISPEL_UNDEAD, + SPELL_ANIMATE_DEAD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 24 - Necronomicon -- Kikubaaqudgha special + {0, + SPELL_SYMBOL_OF_TORMENT, + SPELL_CONTROL_UNDEAD, + SPELL_SUMMON_WRAITHS, + SPELL_DEATHS_DOOR, + SPELL_NECROMUTATION, + SPELL_DEATH_CHANNEL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 25 - Book of Callings + {0, + SPELL_SUMMON_SMALL_MAMMAL, + SPELL_STICKS_TO_SNAKES, + SPELL_CALL_IMP, + SPELL_SUMMON_ELEMENTAL, + SPELL_SUMMON_SCORPIONS, + SPELL_SUMMON_ICE_BEAST, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 26 - Book of Charms + {0, + SPELL_BACKLIGHT, + SPELL_REPEL_MISSILES, + SPELL_SLEEP, + SPELL_CONFUSE, + SPELL_ENSLAVEMENT, + SPELL_SILENCE, + SPELL_INVISIBILITY, + SPELL_NO_SPELL, + }, + // 27 - Book of Demonology -- Vehumet special + {0, + SPELL_ABJURATION_I, + SPELL_RECALL, + SPELL_CALL_IMP, + SPELL_SUMMON_DEMON, + SPELL_DEMONIC_HORDE, + SPELL_SUMMON_GREATER_DEMON, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 28 - Book of Air + {0, + SPELL_SHOCK, + SPELL_SWIFTNESS, + SPELL_REPEL_MISSILES, + SPELL_LEVITATION, + SPELL_MEPHITIC_CLOUD, + SPELL_DISCHARGE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // Removing Air Walk... it's currently broken in a number or ways: + // - the AC/EV bonus probably means very little to any character + // capable of casting a level nine spell + // - the penalty of dropping inventory is a bit harsh considering + // the above + // - the fire/ice susceptibility doesn't work... the AC/EV bonus + // cancel it out (so you'd hardly be wary of them since they + // can't really do any damage). + // - there is no need for another invulnerability spell (which is + // what this spell is trying to be), one is more than enough... + // let people use necromancy. + // - there is no need for another air spell... air spells are + // already very common (ie. this level nine spell occured in + // two books!) + + // 29 - Book of the Sky + {0, + SPELL_SUMMON_ELEMENTAL, + SPELL_INSULATION, + SPELL_AIRSTRIKE, + SPELL_FLY, + SPELL_SILENCE, + SPELL_DEFLECT_MISSILES, + SPELL_LIGHTNING_BOLT, + SPELL_CONJURE_BALL_LIGHTNING, + }, + + // 30 - Book of Divinations + {0, + SPELL_DETECT_SECRET_DOORS, + SPELL_DETECT_CREATURES, + SPELL_DETECT_ITEMS, + SPELL_DETECT_CURSE, + SPELL_SEE_INVISIBLE, + SPELL_FORESCRY, + SPELL_IDENTIFY, + SPELL_NO_SPELL, + }, + // 31 - Book of the Warp + {0, + SPELL_BANISHMENT, + SPELL_WARP_BRAND, + SPELL_DISPERSAL, + SPELL_PORTAL, + SPELL_CONTROLLED_BLINK, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 32 - Book of Envenomations + {0, + SPELL_SPIDER_FORM, + SPELL_POISON_AMMUNITION, + SPELL_SUMMON_SCORPIONS, + SPELL_RESIST_POISON, + SPELL_OLGREBS_TOXIC_RADIANCE, + SPELL_POISONOUS_CLOUD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 33 - Book of Annihilations -- Vehumet special + {0, + SPELL_ISKENDERUNS_MYSTIC_BLAST, + SPELL_POISON_ARROW, + SPELL_CHAIN_LIGHTNING, + SPELL_LEHUDIBS_CRYSTAL_SPEAR, + SPELL_ICE_STORM, + SPELL_FIRE_STORM, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 34 - Book of Unlife + {0, + SPELL_SUBLIMATION_OF_BLOOD, + SPELL_ANIMATE_DEAD, + SPELL_TWISTED_RESURRECTION, + SPELL_BORGNJORS_REVIVIFICATION, + SPELL_SIMULACRUM, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 35 - Tome of Destruction + {0, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 36 - Book of Control + {0, + SPELL_ENSLAVEMENT, + SPELL_TAME_BEASTS, + SPELL_MASS_CONFUSION, + SPELL_CONTROL_UNDEAD, + SPELL_CONTROL_TELEPORT, + SPELL_MASS_SLEEP, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 37 - Book of Mutations //jmf: now Morphology + {0, + SPELL_FRAGMENTATION, + SPELL_POLYMORPH_OTHER, + SPELL_ALTER_SELF, + SPELL_CIGOTUVIS_DEGENERATION, + // SPELL_IGNITE_POISON, // moved to Fire which was a bit slim -- bwr + SPELL_SHATTER, + // SPELL_AIR_WALK, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 38 - Book of Tukima + {0, + SPELL_SURE_BLADE, + SPELL_TUKIMAS_VORPAL_BLADE, + SPELL_TUKIMAS_DANCE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 39 - Book of Geomancy + {0, + SPELL_SANDBLAST, + SPELL_STONESKIN, + SPELL_PASSWALL, + SPELL_STONE_ARROW, + SPELL_SUMMON_ELEMENTAL, + SPELL_FRAGMENTATION, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 40 - Book of Earth + {0, + // SPELL_MAXWELLS_SILVER_HAMMER, + SPELL_MAGIC_MAPPING, + SPELL_DIG, + SPELL_STATUE_FORM, + SPELL_BOLT_OF_IRON, + SPELL_TOMB_OF_DOROKLOHE, + SPELL_SHATTER, + SPELL_NO_SPELL, + }, + // 41 - manuals of all kinds + {0, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 42 - Book of Wizardry + {0, + SPELL_DETECT_CREATURES, + SPELL_SUMMON_ELEMENTAL, + SPELL_MAGIC_MAPPING, + SPELL_TELEPORT_SELF, + SPELL_FIREBALL, + SPELL_IDENTIFY, + SPELL_HASTE, + SPELL_NO_SPELL, + }, + // 43 - Book of Power + {0, + SPELL_ANIMATE_DEAD, + SPELL_TELEPORT_OTHER, + SPELL_VENOM_BOLT, + SPELL_BOLT_OF_IRON, + SPELL_INVISIBILITY, + SPELL_MASS_CONFUSION, + SPELL_POISONOUS_CLOUD, + SPELL_NO_SPELL, + }, + // 44 - Book of Cantrips //jmf: added 04jan2000 + {0, + SPELL_CONFUSING_TOUCH, + SPELL_ANIMATE_SKELETON, + SPELL_SUMMON_SMALL_MAMMAL, + SPELL_DETECT_SECRET_DOORS, + SPELL_APPORTATION, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 45 - Book of Party Tricks //jmf: added 04jan2000 + {0, + SPELL_SUMMON_BUTTERFLIES, + SPELL_APPORTATION, + SPELL_PROJECTED_NOISE, + SPELL_BLINK, + SPELL_LEVITATION, + SPELL_INTOXICATE, + SPELL_NO_SPELL, //jmf: SPELL_ERINGYAS_SURPRISING_BOUQUET, when finished + SPELL_NO_SPELL, + }, + + // 46 - Book of Beasts //jmf: added 19mar2000 + {0, + SPELL_SUMMON_SMALL_MAMMAL, + SPELL_STICKS_TO_SNAKES, + SPELL_DETECT_CREATURES, + SPELL_SUMMON_LARGE_MAMMAL, + SPELL_TAME_BEASTS, + SPELL_DRAGON_FORM, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 47 - Book of Stalking //jmf: 24jun2000 + {0, + SPELL_STING, + SPELL_SURE_BLADE, + SPELL_PROJECTED_NOISE, + SPELL_MEPHITIC_CLOUD, + SPELL_POISON_WEAPON, + SPELL_PARALYZE, + SPELL_INVISIBILITY, + SPELL_NO_SPELL, + }, + + // 48 -- unused + {0, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 49 - unused + {0, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + + // 50 - Staff of Smiting //jmf: totally obsolete --- no longer looks here. + {0, + SPELL_SMITING, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 51 - Staff of Summoning + {0, + SPELL_ABJURATION_I, + SPELL_RECALL, + SPELL_SUMMON_ELEMENTAL, + SPELL_SWARM, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 52 - Staff of Destruction + {0, + SPELL_THROW_FLAME, + SPELL_BOLT_OF_FIRE, + SPELL_FIREBALL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 53 - Staff of Destruction + {0, + SPELL_THROW_FROST, + SPELL_ICE_BOLT, + SPELL_FREEZING_CLOUD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 54 - Staff of Destruction + {0, + SPELL_BOLT_OF_IRON, + SPELL_FIREBALL, + SPELL_LIGHTNING_BOLT, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 55 - Staff of Destruction + {0, + SPELL_BOLT_OF_INACCURACY, + SPELL_BOLT_OF_MAGMA, + SPELL_BOLT_OF_COLD, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 56 - Staff of Warding + {0, + SPELL_ABJURATION_I, + SPELL_CONDENSATION_SHIELD, + SPELL_CAUSE_FEAR, + SPELL_DEFLECT_MISSILES, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 57 - Staff of Exploration + {0, + SPELL_DETECT_SECRET_DOORS, + SPELL_DETECT_TRAPS, + SPELL_DETECT_ITEMS, + SPELL_MAGIC_MAPPING, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 58 - Staff of Demonology + {0, + SPELL_ABJURATION_I, + SPELL_RECALL, + SPELL_CALL_IMP, + SPELL_SUMMON_DEMON, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, + // 59 - Staff of Striking -- unused like Smiting + {0, + SPELL_STRIKING, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + }, +}; + +static void spellbook_template( int sbook_type, + FixedVector < int, SPELLBOOK_SIZE > &sbtemplate_pass ) +{ + ASSERT( sbook_type >= 0 ); + ASSERT( sbook_type < NUMBER_SPELLBOOKS ); + + // no point doing anything if tome of destruction or a manual + if (sbook_type == BOOK_DESTRUCTION || sbook_type == BOOK_MANUAL) + return; + + for (int i = 0; i < SPELLBOOK_SIZE; i++) //jmf: was i = 1 + { + sbtemplate_pass[i] = spellbook_template_array[sbook_type][i]; + } +} // end spellbook_template() + +int which_spell_in_book(int sbook_type, int spl) +{ + FixedVector < int, SPELLBOOK_SIZE > wsib_pass; // was 10 {dlb} + + spellbook_template(sbook_type, wsib_pass); + + return (wsib_pass[ spl + 1 ]); +} // end which_spell_in_book() + +// If fs is not NULL, updates will be to the formatted_string instead of +// the display. +unsigned char spellbook_contents( item_def &book, int action, + formatted_string *fs ) +{ + FixedVector<int, SPELLBOOK_SIZE> spell_types; // was 10 {dlb} + int spelcount = 0; + int i, j; + bool update_screen = !fs; + + const int spell_levels = player_spell_levels(); + + // special case for staves + const int type = (book.base_type == OBJ_STAVES) ? book.sub_type + 40 + : book.sub_type; + + bool spell_skills = false; + + for (i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++) + { + if (you.skills[i]) + { + spell_skills = true; + break; + } + } + + set_ident_flags( book, ISFLAG_KNOW_TYPE ); + + spellbook_template( type, spell_types ); + + formatted_string out; + out.textcolor(LIGHTGREY); + + char str_pass[ ITEMNAME_SIZE ]; + item_name( book, DESC_CAP_THE, str_pass ); + out.cprintf( str_pass ); + + out.cprintf( EOL EOL " Spells Type Level" EOL ); + + for (j = 1; j < SPELLBOOK_SIZE; j++) + { + if (spell_types[j] == SPELL_NO_SPELL) + continue; + + out.cprintf(" "); + + bool knowsSpell = false; + for (i = 0; i < 25 && !knowsSpell; i++) + { + knowsSpell = (you.spells[i] == spell_types[j]); + } + + const int level_diff = spell_difficulty( spell_types[j] ); + const int levels_req = spell_levels_required( spell_types[j] ); + + int colour = DARKGREY; + if (action == RBOOK_USE_STAFF) + { + if (you.experience_level >= level_diff + && you.magic_points >= level_diff) + { + colour = LIGHTGREY; + } + } + else + { + if (knowsSpell) + colour = LIGHTGREY; + else if (you.experience_level >= level_diff + && spell_levels >= levels_req + && spell_skills) + { + colour = LIGHTBLUE; + } + } + + out.textcolor( colour ); + + // Old: + // textcolor(knowsSpell ? DARKGREY : LIGHTGREY); + // was: ? LIGHTGREY : LIGHTBLUE + + char strng[2]; + + strng[0] = index_to_letter(spelcount); + strng[1] = '\0'; + + out.cprintf(strng); + out.cprintf(" - "); + + out.cprintf( spell_title(spell_types[j]) ); + out.gotoxy( 35, -1 ); + + + if (action == RBOOK_USE_STAFF) + out.cprintf( "Evocations" ); + else + { + bool already = false; + + for (i = 0; i <= SPTYP_LAST_EXPONENT; i++) + { + if (spell_typematch( spell_types[j], 1 << i )) + { + if (already) + out.cprintf( "/" ); + + out.cprintf( spelltype_name( 1 << i ) ); + already = true; + } + } + } + + out.gotoxy( 65, -1 ); + + char sval[3]; + + itoa( level_diff, sval, 10 ); + out.cprintf( sval ); + out.cprintf( EOL ); + spelcount++; + } + + out.textcolor(LIGHTGREY); + out.cprintf(EOL); + + switch (action) + { + case RBOOK_USE_STAFF: + out.cprintf( "Select a spell to cast." EOL ); + break; + + case RBOOK_MEMORISE: + out.cprintf( "Select a spell to memorise (%d level%s available)." EOL, + spell_levels, (spell_levels == 1) ? "" : "s" ); + break; + + case RBOOK_READ_SPELL: + out.cprintf( "Select a spell to read its description." EOL ); + break; + + default: + break; + } + + if (fs) + *fs = out; + + unsigned char keyn = 0; + if (update_screen) + { +#ifdef DOS_TERM + char buffer[4800]; + gettext(1, 1, 80, 25, buffer); + window(1, 1, 80, 25); +#endif + clrscr(); + + out.display(); + + keyn = getch(); + if (keyn == 0) + getch(); + +#ifdef DOS_TERM + puttext(1, 1, 80, 25, buffer); + window(1, 18, 80, 25); +#endif + } + + return (keyn); // try to figure out that for which this is used {dlb} +} + +//jmf: was in shopping.cc +char book_rarity(unsigned char which_book) +{ + switch (which_book) + { + case BOOK_MINOR_MAGIC_I: + case BOOK_MINOR_MAGIC_II: + case BOOK_MINOR_MAGIC_III: + case BOOK_SURVEYANCES: + case BOOK_HINDERANCE: + case BOOK_CANTRIPS: //jmf: added 04jan2000 + return 1; + + case BOOK_CHANGES: + case BOOK_CHARMS: + return 2; + + case BOOK_CONJURATIONS_I: + case BOOK_CONJURATIONS_II: + case BOOK_PRACTICAL_MAGIC: + case BOOK_NECROMANCY: + case BOOK_CALLINGS: + case BOOK_WIZARDRY: + return 3; + + case BOOK_FLAMES: + case BOOK_FROST: + case BOOK_AIR: + case BOOK_GEOMANCY: + return 4; + + case BOOK_YOUNG_POISONERS: + case BOOK_STALKING: //jmf: added 24jun2000 + case BOOK_WAR_CHANTS: + return 5; + + case BOOK_CLOUDS: + case BOOK_POWER: + return 6; + + case BOOK_ENCHANTMENTS: + case BOOK_PARTY_TRICKS: //jmf: added 04jan2000 + return 7; + + case BOOK_TRANSFIGURATIONS: + case BOOK_DIVINATIONS: + return 8; + + case BOOK_FIRE: + case BOOK_ICE: + case BOOK_SKY: + case BOOK_EARTH: + case BOOK_UNLIFE: + case BOOK_CONTROL: + case BOOK_SPATIAL_TRANSLOCATIONS: + return 10; + + case BOOK_TEMPESTS: + case BOOK_DEATH: + return 11; + + case BOOK_MUTATIONS: + case BOOK_BEASTS: //jmf: added 23mar2000 + return 12; + + case BOOK_ENVENOMATIONS: + case BOOK_WARP: + return 15; + + case BOOK_TUKIMA: + return 16; + + case BOOK_SUMMONINGS: + return 18; + + case BOOK_ANNIHILATIONS: // Vehumet special + case BOOK_DEMONOLOGY: // Vehumet special + case BOOK_NECRONOMICON: // Kikubaaqudgha special + case BOOK_MANUAL: + return 20; + + case BOOK_DESTRUCTION: + return 30; + + case BOOK_HEALING: + return 100; + + default: + return 1; + } +} // end book_rarity() + +bool is_valid_spell_in_book( unsigned int splbook, int spell ) +{ + FixedVector< int, SPELLBOOK_SIZE > spells; + + spellbook_template( you.inv[ splbook ].sub_type, spells ); + + if (spells[ spell ] != SPELL_NO_SPELL) + return true; + + return false; +} // end is_valid_spell_in_book() + +static bool which_spellbook( int &book, int &spell ) +{ + const int avail_levels = player_spell_levels(); + + // Knowing delayed fireball will allow Fireball to be learned for free -bwr + if (avail_levels < 1 && !player_has_spell(SPELL_DELAYED_FIREBALL)) + { + mpr("You can't memorise any more spells yet."); + return (false); + } + else if (inv_count() < 1) + { + canned_msg(MSG_NOTHING_CARRIED); + return (false); + } + + snprintf( info, INFO_SIZE, "You can memorise %d more level%s of spells.", + avail_levels, (avail_levels > 1) ? "s" : "" ); + + mpr( info ); + + book = prompt_invent_item( "Memorise from which spellbook?", OBJ_BOOKS ); + if (book == PROMPT_ABORT) + { + canned_msg( MSG_OK ); + return (false); + } + + if (you.inv[book].base_type != OBJ_BOOKS + || you.inv[book].sub_type == BOOK_MANUAL) + { + mpr("That isn't a spellbook!"); + return (false); + } + + if (you.inv[book].sub_type == BOOK_DESTRUCTION) + { + tome_of_power( book ); + return (false); + } + + spell = read_book( you.inv[book], RBOOK_MEMORISE ); + clrscr(); + + return (true); +} // end which_spellbook() + +// Returns false if the player cannot read/memorize from the book, +// and true otherwise. -- bwr +static bool player_can_read_spellbook( const item_def &book ) +{ + if (book.base_type != OBJ_BOOKS) + return (true); + + if ((book.sub_type == BOOK_ANNIHILATIONS + && you.religion != GOD_VEHUMET + && (you.skills[SK_CONJURATIONS] < 10 + || you.skills[SK_SPELLCASTING] < 10)) + || (book.sub_type == BOOK_DEMONOLOGY + && you.religion != GOD_VEHUMET + && (you.skills[SK_SUMMONINGS] < 10 + || you.skills[SK_SPELLCASTING] < 10)) + || (book.sub_type == BOOK_NECRONOMICON + && you.religion != GOD_KIKUBAAQUDGHA + && (you.skills[SK_NECROMANCY] < 10 + || you.skills[SK_SPELLCASTING] < 10))) + { + return (false); + } + + return (true); +} + +unsigned char read_book( item_def &book, int action ) +{ + unsigned char key2 = 0; + + if (book.base_type == OBJ_BOOKS && !player_can_read_spellbook( book )) + { + mpr( "This book is beyond your current level of understanding." ); + more(); + return (0); + } + + // remember that this function is called from staff spells as well: + key2 = spellbook_contents( book, action ); + + if (book.base_type == OBJ_BOOKS) + { + you.had_book[ book.sub_type ] = 1; + + if ( book.sub_type == BOOK_MINOR_MAGIC_I + || book.sub_type == BOOK_MINOR_MAGIC_II + || book.sub_type == BOOK_MINOR_MAGIC_III) + { + you.had_book[BOOK_MINOR_MAGIC_I] = 1; + you.had_book[BOOK_MINOR_MAGIC_II] = 1; + you.had_book[BOOK_MINOR_MAGIC_III] = 1; + } + else if (book.sub_type == BOOK_CONJURATIONS_I + || book.sub_type == BOOK_CONJURATIONS_II) + { + you.had_book[BOOK_CONJURATIONS_I] = 1; + you.had_book[BOOK_CONJURATIONS_II] = 1; + } + } + + redraw_screen(); + + /* Put special book effects in another function which can be called from + memorise as well */ + + // reading spell descriptions doesn't take time: + if (action != RBOOK_READ_SPELL) + you.turn_is_over = 1; + + set_ident_flags( book, ISFLAG_KNOW_TYPE ); + + return (key2); +} // end read_book() + +// recoded to answer whether an UNDEAD_STATE is +// barred from a particular spell passed to the +// function - note that the function can be expanded +// to prevent memorisation of certain spells by +// the living by setting up an US_ALIVE case returning +// a value of false for a set of spells ... might be +// an idea worth further consideration - 12mar2000 {dlb} +bool undead_cannot_memorise(unsigned char spell, unsigned char being) +{ + switch (being) + { + case US_HUNGRY_DEAD: + switch (spell) + { + //case SPELL_REGENERATION: + case SPELL_BORGNJORS_REVIVIFICATION: + case SPELL_CURE_POISON_II: + case SPELL_DEATHS_DOOR: + case SPELL_NECROMUTATION: + case SPELL_RESIST_POISON: + case SPELL_SYMBOL_OF_TORMENT: + case SPELL_TAME_BEASTS: + case SPELL_BERSERKER_RAGE: + return true; + } + break; + + case US_UNDEAD: + switch (spell) + { + case SPELL_AIR_WALK: + case SPELL_ALTER_SELF: + case SPELL_BLADE_HANDS: + case SPELL_BORGNJORS_REVIVIFICATION: + case SPELL_CURE_POISON_II: + case SPELL_DEATHS_DOOR: + case SPELL_DRAGON_FORM: + case SPELL_GLAMOUR: + case SPELL_ICE_FORM: + case SPELL_INTOXICATE: + case SPELL_NECROMUTATION: + case SPELL_PASSWALL: + case SPELL_REGENERATION: + case SPELL_RESIST_POISON: + case SPELL_SPIDER_FORM: + case SPELL_STATUE_FORM: + case SPELL_SUMMON_HORRIBLE_THINGS: + case SPELL_SYMBOL_OF_TORMENT: + case SPELL_TAME_BEASTS: + case SPELL_BERSERKER_RAGE: + return true; + } + break; + } + + return false; +} // end undead_cannot_memorise() + +bool learn_spell(void) +{ + int chance = 0; + int levels_needed = 0; + unsigned char keyin; + int book, spell; + int index; + + int i; + int j = 0; + + for (i = SK_SPELLCASTING; i <= SK_POISON_MAGIC; i++) + { + if (you.skills[i]) + j++; + } + + if (j == 0) + { + mpr("You can't use spell magic! I'm afraid it's scrolls only for now."); + return (false); + } + + if (!which_spellbook( book, spell )) + return (false); + + if (spell < 'A' || (spell > 'Z' && spell < 'a') || spell > 'z') + { + whatt: + redraw_screen(); + mpr("What?"); + return (false); + } + + index = letter_to_index( spell ); + + if (index >= SPELLBOOK_SIZE) + goto whatt; + + if (!is_valid_spell_in_book( book, index )) + goto whatt; + + unsigned int specspell = which_spell_in_book(you.inv[book].sub_type,index); + + if (specspell == SPELL_NO_SPELL) + goto whatt; + + // You can always memorise selective amnesia: + if (you.spell_no == 21 && specspell != SPELL_SELECTIVE_AMNESIA) + { + redraw_screen(); + mpr("Your head is already too full of spells!"); + return (false); + } + + if (you.is_undead && spell_typematch(specspell, SPTYP_HOLY)) + { + redraw_screen(); + mpr("You cannot use this type of magic!"); + return (false); + } + + if (undead_cannot_memorise(specspell, you.is_undead)) + { + redraw_screen(); + mpr("You cannot use this spell."); + return (false); + } + + for (i = 0; i < 25; i++) + { + if (you.spells[i] == specspell) + { + redraw_screen(); + mpr("You already know that spell!"); + you.turn_is_over = 1; + return (false); + } + } + + levels_needed = spell_levels_required( specspell ); + + if (player_spell_levels() < levels_needed) + { + redraw_screen(); + mpr("You can't memorise that many levels of magic yet!"); + you.turn_is_over = 1; + return (false); + } + + if (you.experience_level < spell_difficulty(specspell)) + { + redraw_screen(); + mpr("You're too inexperienced to learn that spell!"); + you.turn_is_over = 1; + return (false); + } + + redraw_screen(); + + chance = spell_fail(specspell); + + strcpy(info, "This spell is "); + + strcat(info, (chance >= 80) ? "very" : + (chance >= 60) ? "quite" : + (chance >= 45) ? "rather" : + (chance >= 30) ? "somewhat" + : "not that"); + + strcat(info, " "); + + int temp_rand = random2(3); + + strcat(info, (temp_rand == 0) ? "difficult" : + (temp_rand == 1) ? "tricky" : + (temp_rand == 2) ? "challenging" + : ""); + + strcat(info, " to "); + + temp_rand = random2(4); + + strcat(info, (temp_rand == 0) ? "memorise" : + (temp_rand == 1) ? "commit to memory" : + (temp_rand == 2) ? "learn" : + (temp_rand == 3) ? "absorb" + : ""); + + strcat(info, "."); + + mpr(info); + + strcpy(info, "Memorise "); + strcat(info, spell_title(specspell)); + strcat(info, "?"); + mpr(info); + + for (;;) + { + keyin = getch(); + + if (keyin == 'n' || keyin == 'N') + { + redraw_screen(); + return (false); + } + + if (keyin == 'y' || keyin == 'Y') + break; + } + + mesclr( true ); + + if (you.mutation[MUT_BLURRY_VISION] > 0 + && random2(4) < you.mutation[MUT_BLURRY_VISION]) + { + mpr("The writing blurs into unreadable gibberish."); + you.turn_is_over = 1; + return (false); + } + + if (random2(40) + random2(40) + random2(40) < chance) + { + redraw_screen(); + mpr("You fail to memorise the spell."); + you.turn_is_over = 1; + + if (you.inv[ book ].sub_type == BOOK_NECRONOMICON) + { + mpr("The pages of the Necronomicon glow with a dark malevolence..."); + miscast_effect( SPTYP_NECROMANCY, 8, random2avg(88, 3), 100, + "reading the Necronomicon" ); + } + else if (you.inv[ book ].sub_type == BOOK_DEMONOLOGY) + { + mpr("This book does not appreciate being disturbed by one of your ineptitude!"); + miscast_effect( SPTYP_SUMMONING, 7, random2avg(88, 3), 100, + "reading the book of Demonology" ); + } + else if (you.inv[ book ].sub_type == BOOK_ANNIHILATIONS) + { + mpr("This book does not appreciate being disturbed by one of your ineptitude!"); + miscast_effect( SPTYP_CONJURATION, 8, random2avg(88, 3), 100, + "reading the book of Annihilations" ); + } + +#if WIZARD + if (!you.wizard) + return (false); + else if (!yesno("Memorize anyway?")) + return (false); +#else + return (false); +#endif + } + + start_delay( DELAY_MEMORISE, spell_difficulty( specspell ), specspell ); + + you.turn_is_over = 1; + redraw_screen(); + + did_god_conduct( DID_SPELL_CASTING, 2 + random2(5) ); + + return (true); +} // end which_spell() + +int count_staff_spells(const item_def &item, bool need_id) +{ + if (item.base_type != OBJ_STAVES) + return (-1); + + if (need_id && !item_ident( item, ISFLAG_KNOW_TYPE )) + return (0); + + const int stype = item.sub_type; + const int type = stype + 40; + if (stype < STAFF_SMITING || stype >= STAFF_AIR) + return (0); + + FixedVector< int, SPELLBOOK_SIZE > spell_list; + spellbook_template( type, spell_list ); + + int num_spells = 0; + for (num_spells = 0; num_spells < SPELLBOOK_SIZE - 1; num_spells++) + { + if (spell_list[ num_spells + 1 ] == SPELL_NO_SPELL) + break; + } + return (num_spells); +} + +int staff_spell( int staff ) +{ + int spell; + unsigned char specspell; + int mana, diff, food, energy; + FixedVector< int, SPELLBOOK_SIZE > spell_list; + + // converting sub_type into book index type + const int type = you.inv[staff].sub_type + 40; + + // Spell staves are mostly for the benefit of non-spellcasters, so we're + // not going to involve INT or Spellcasting skills for power. -- bwr + const int powc = 5 + you.skills[SK_EVOCATIONS] + + roll_dice( 2, you.skills[SK_EVOCATIONS] ); + + const int staff_type = you.inv[staff].sub_type; + if (staff_type < STAFF_SMITING || staff_type >= STAFF_AIR) + { + //mpr("That staff has no spells in it."); + canned_msg(MSG_NOTHING_HAPPENS); + return (0); + } + + if (!item_ident( you.inv[staff], ISFLAG_KNOW_TYPE )) + { + set_ident_flags( you.inv[staff], ISFLAG_KNOW_TYPE ); + you.wield_change = true; + } + + spellbook_template( type, spell_list ); + + unsigned char num_spells; + for (num_spells = 0; num_spells < SPELLBOOK_SIZE - 1; num_spells++) + { + if (spell_list[ num_spells + 1 ] == SPELL_NO_SPELL) + break; + } + + if (num_spells == 0) + { + canned_msg(MSG_NOTHING_HAPPENS); // shouldn't happen + return (0); + } + else if (num_spells == 1) + spell = 'a'; // automatically selected if its the only option + else + { + snprintf( info, INFO_SIZE, + "Evoke which spell from the rod ([a-%c] spell [?*] list)? ", + 'a' + num_spells - 1 ); + + mpr( info, MSGCH_PROMPT ); + spell = get_ch(); + + if (spell == '?' || spell == '*') + spell = read_book( you.inv[staff], RBOOK_USE_STAFF ); + } + + if (spell < 'A' || (spell > 'Z' && spell < 'a') || spell > 'z') + { + goto whattt; + } + + spell = letter_to_index( spell ); + + if (spell >= SPELLBOOK_SIZE) + goto whattt; + + if (!is_valid_spell_in_book( staff, spell )) + goto whattt; + + specspell = which_spell_in_book( type, spell ); + + if (specspell == SPELL_NO_SPELL) + goto whattt; + + mana = spell_mana( specspell ) * ROD_CHARGE_MULT; + diff = spell_difficulty( specspell ); + food = spell_hunger( specspell ); + + if (food && (you.is_undead != US_UNDEAD + && (you.hunger_state < HS_HUNGRY || you.hunger <= food))) + { + mpr("You don't have the energy to cast that spell."); + return (0); + } + + if (staff_type == STAFF_STRIKING) + mana /= ROD_CHARGE_MULT; + + if ((staff_type == STAFF_STRIKING? + you.magic_points < mana + : you.inv[staff].plus < mana) + || you.experience_level < diff) + { +#ifdef DEBUG_DIAGNOSTICS + mprf("Mana needed: %d, Staff plus: %d, Difficulty: %d, XP: %d", + mana, you.inv[staff].plus, diff, you.experience_level); +#endif + if (you.experience_level < diff) + mprf("You need to be at least level %d to use that.", diff); + else + mprf("%s have enough magic points.", + staff_type == STAFF_STRIKING? "You don't" : "The rod doesn't"); + + // confuse_player( 2 + random2(4) ); + you.turn_is_over = 1; + return (0); + } + + // Exercising the spell skills doesn't make very much sense given + // that spell staves are largely intended to supply spells to + // non-spellcasters, and they don't use spell skills to determine + // power in the same way that spellcasting does. -- bwr + // + // exercise_spell(specspell, true, true); + + your_spells(specspell, powc, false); + + + // [dshaligram] + // dec_mp(spell_mana(specspell)); + if (staff_type != STAFF_STRIKING) + you.inv[staff].plus -= mana; + else { + you.magic_points -= mana; + you.redraw_magic_points = true; + } + + energy = player_energy(); + if (energy <= 0 && you.is_undead != US_UNDEAD) + { + food -= 10 * you.skills[SK_EVOCATIONS]; + if (food < diff * 5) + food = diff * 5; + + make_hungry( food, true ); + } + + you.wield_change = true; + + you.turn_is_over = 1; + + return (roll_dice( 1, 1 + spell_difficulty(specspell) / 2 )); + + whattt: + mpr("What?"); + + return (0); +} // end staff_spell() |