diff options
Diffstat (limited to 'stone_soup/crawl-ref/source/abl-show.cc')
-rw-r--r-- | stone_soup/crawl-ref/source/abl-show.cc | 2164 |
1 files changed, 0 insertions, 2164 deletions
diff --git a/stone_soup/crawl-ref/source/abl-show.cc b/stone_soup/crawl-ref/source/abl-show.cc deleted file mode 100644 index ae7c89fa59..0000000000 --- a/stone_soup/crawl-ref/source/abl-show.cc +++ /dev/null @@ -1,2164 +0,0 @@ -/* - * File: abl-show.cc - * Summary: Functions related to special abilities. - * Written by: Linley Henzell - * - * Modified for Crawl Reference by $Author$ on $Date$ - * - * Change History (most recent first): - * - * <6> 19mar2000 jmf added elvish Glamour - * <5> 11/06/99 cdl reduced power of minor destruction - * - * <4> 9/25/99 cdl linuxlib -> liblinux - * - * <3> 5/20/99 BWR Now use scan_randarts to - * check for flags, rather than - * only checking the weapon. - * - * <2> 5/20/99 BWR Extended screen line support - * - * <1> -/--/-- LRH Created - */ - -#include "AppHdr.h" -#include "abl-show.h" - -#include <string.h> -#include <stdio.h> -#include <ctype.h> - -#ifdef DOS -#include <conio.h> -#endif - -#include "externs.h" - -#include "beam.h" -#include "effects.h" -#include "food.h" -#include "it_use2.h" -#include "macro.h" -#include "message.h" -#include "misc.h" -#include "monplace.h" -#include "player.h" -#include "religion.h" -#include "skills.h" -#include "skills2.h" -#include "spl-cast.h" -#include "spl-util.h" -#include "spells1.h" -#include "spells2.h" -#include "spells3.h" -#include "spells4.h" -#include "stuff.h" -#include "transfor.h" -#include "view.h" - - -#ifdef UNIX -#include "libunix.h" -#endif - -// this all needs to be split into data/util/show files -// and the struct mechanism here needs to be rewritten (again) -// along with the display routine to piece the strings -// together dynamically ... I'm getting to it now {dlb} - -// it makes more sense to think of them as an array -// of structs than two arrays that share common index -// values -- well, doesn't it? {dlb} -struct talent -{ - int which; - int fail; - bool is_invocation; -}; - -static FixedVector< talent, 52 > Curr_abil; - -static bool insert_ability( int which_ability ); - -// The description screen was way out of date with the actual costs. -// This table puts all the information in one place... -- bwr -// -// The four numerical fields are: MP, HP, food, and piety. -// Note: food_cost = val + random2avg( val, 2 ) -// piety_cost = val + random2( (val + 1) / 2 + 1 ); -static const struct ability_def Ability_List[] = -{ - // NON_ABILITY should always come first - { ABIL_NON_ABILITY, "No ability", 0, 0, 0, 0, ABFLAG_NONE }, - { ABIL_SPIT_POISON, "Spit Poison", 0, 0, 40, 0, ABFLAG_BREATH }, - { ABIL_GLAMOUR, "Glamour", 5, 0, 40, 0, ABFLAG_DELAY }, - - { ABIL_MAPPING, "Sense Surroundings", 0, 0, 30, 0, ABFLAG_NONE }, - { ABIL_TELEPORTATION, "Teleportation", 3, 0, 200, 0, ABFLAG_NONE }, - { ABIL_BLINK, "Blink", 1, 0, 50, 0, ABFLAG_NONE }, - - { ABIL_BREATHE_FIRE, "Breathe Fire", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_FROST, "Breathe Frost", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_POISON, "Breathe Poison Gas", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_LIGHTNING, "Breathe Lightning", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_POWER, "Breathe Power", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_STICKY_FLAME, "Breathe Sticky Flame", 0, 0, 125, 0, ABFLAG_BREATH }, - { ABIL_BREATHE_STEAM, "Breathe Steam", 0, 0, 75, 0, ABFLAG_BREATH }, - - // Handled with breath weapons, but doesn't cause a breathing delay - { ABIL_SPIT_ACID, "Spit Acid", 0, 0, 125, 0, ABFLAG_NONE }, - - { ABIL_FLY, "Fly", 3, 0, 100, 0, ABFLAG_NONE }, - { ABIL_SUMMON_MINOR_DEMON, "Summon Minor Demon", 3, 3, 75, 0, ABFLAG_NONE }, - { ABIL_SUMMON_DEMONS, "Summon Demons", 5, 5, 150, 0, ABFLAG_NONE }, - { ABIL_HELLFIRE, "Hellfire", 8, 8, 200, 0, ABFLAG_NONE }, - { ABIL_TORMENT, "Torment", 9, 0, 250, 0, ABFLAG_PAIN }, - { ABIL_RAISE_DEAD, "Raise Dead", 5, 5, 150, 0, ABFLAG_NONE }, - { ABIL_CONTROL_DEMON, "Control Demon", 4, 4, 100, 0, ABFLAG_NONE }, - { ABIL_TO_PANDEMONIUM, "Gate Yourself to Pandemonium", 7, 0, 200, 0, ABFLAG_NONE }, - { ABIL_CHANNELING, "Channeling", 1, 0, 30, 0, ABFLAG_NONE }, - { ABIL_THROW_FLAME, "Throw Flame", 1, 1, 50, 0, ABFLAG_NONE }, - { ABIL_THROW_FROST, "Throw Frost", 1, 1, 50, 0, ABFLAG_NONE }, - { ABIL_BOLT_OF_DRAINING, "Bolt of Draining", 4, 4, 100, 0, ABFLAG_NONE }, - - // FLY_II used to have ABFLAG_EXHAUSTION, but that's somewhat meaningless - // as exhaustion's only (and designed) effect is preventing Berserk. -- bwr - { ABIL_FLY_II, "Fly", 0, 0, 25, 0, ABFLAG_NONE }, - { ABIL_DELAYED_FIREBALL, "Release Delayed Fireball", 0, 0, 0, 0, ABFLAG_INSTANT }, - { ABIL_MUMMY_RESTORATION, "Restoration", 1, 0, 0, 0, ABFLAG_PERMANENT_MP }, - - // EVOKE abilities use Evocations and come from items: - // Mapping, Teleportation, and Blink can also come from mutations - // so we have to distinguish them (see above). The off items - // below are labeled EVOKE because they only work now if the - // player has an item with the evocable power (not just because - // you used a wand, potion, or miscast effect). I didn't see - // any reason to label them as "Evoke" in the text, they don't - // use or train Evocations (the others do). -- bwr - { ABIL_EVOKE_MAPPING, "Evoke Sense Surroundings", 0, 0, 30, 0, ABFLAG_NONE }, - { ABIL_EVOKE_TELEPORTATION, "Evoke Teleportation", 3, 0, 200, 0, ABFLAG_NONE }, - { ABIL_EVOKE_BLINK, "Evoke Blink", 1, 0, 50, 0, ABFLAG_NONE }, - - { ABIL_EVOKE_BERSERK, "Evoke Berserk Rage", 0, 0, 0, 0, ABFLAG_NONE }, - - { ABIL_EVOKE_TURN_INVISIBLE, "Evoke Invisibility", 2, 0, 250, 0, ABFLAG_NONE }, - { ABIL_EVOKE_TURN_VISIBLE, "Turn Visible", 0, 0, 0, 0, ABFLAG_NONE }, - { ABIL_EVOKE_LEVITATE, "Evoke Levitation", 1, 0, 100, 0, ABFLAG_NONE }, - { ABIL_EVOKE_STOP_LEVITATING, "Stop Levitating", 0, 0, 0, 0, ABFLAG_NONE }, - - { ABIL_END_TRANSFORMATION, "End Transformation", 0, 0, 0, 0, ABFLAG_NONE }, - - // INVOCATIONS: - // Zin - { ABIL_ZIN_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE }, - { ABIL_ZIN_HEALING, "Minor Healing", 2, 0, 50, 1, ABFLAG_NONE }, - { ABIL_ZIN_PESTILENCE, "Pestilence", 3, 0, 100, 2, ABFLAG_NONE }, - { ABIL_ZIN_HOLY_WORD, "Holy Word", 6, 0, 150, 3, ABFLAG_NONE }, - { ABIL_ZIN_SUMMON_GUARDIAN, "Summon Guardian", 7, 0, 150, 4, ABFLAG_NONE }, - - // The Shining One - { ABIL_TSO_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE }, - { ABIL_TSO_SMITING, "Smiting", 3, 0, 50, 2, ABFLAG_NONE }, - { ABIL_TSO_ANNIHILATE_UNDEAD, "Annihilate Undead", 3, 0, 50, 2, ABFLAG_NONE }, - { ABIL_TSO_CLEANSING_FLAME, "Cleansing Flame", 5, 0, 100, 2, ABFLAG_NONE }, - { ABIL_TSO_SUMMON_DAEVA, "Summon Daeva", 8, 0, 150, 4, ABFLAG_NONE }, - - // Kikubaaqudgha - { ABIL_KIKU_RECALL_UNDEAD_SLAVES, "Recall Undead Slaves", 2, 0, 50, 0, ABFLAG_NONE }, - { ABIL_KIKU_ENSLAVE_UNDEAD, "Enslave Undead", 4, 0, 150, 3, ABFLAG_NONE }, - { ABIL_KIKU_INVOKE_DEATH, "Invoke Death", 4, 0, 250, 3, ABFLAG_NONE }, - - // Yredelemnul - { ABIL_YRED_ANIMATE_CORPSE, "Animate Corpse", 1, 0, 50, 0, ABFLAG_NONE }, - { ABIL_YRED_RECALL_UNDEAD, "Recall Undead Slaves", 2, 0, 50, 0, ABFLAG_NONE }, - { ABIL_YRED_ANIMATE_DEAD, "Animate Dead", 3, 0, 100, 1, ABFLAG_NONE }, - { ABIL_YRED_DRAIN_LIFE, "Drain Life", 6, 0, 200, 2, ABFLAG_NONE }, - { ABIL_YRED_CONTROL_UNDEAD, "Control Undead", 5, 0, 150, 2, ABFLAG_NONE }, - - // Vehumet - { ABIL_VEHUMET_CHANNEL_ENERGY, "Channel Energy", 0, 0, 50, 0, ABFLAG_NONE }, - - // Okawaru - { ABIL_OKAWARU_MIGHT, "Might", 2, 0, 50, 1, ABFLAG_NONE }, - { ABIL_OKAWARU_HEALING, "Healing", 2, 0, 75, 1, ABFLAG_NONE }, - { ABIL_OKAWARU_HASTE, "Haste", 5, 0, 100, 3, ABFLAG_NONE }, - - // Makhleb - { ABIL_MAKHLEB_MINOR_DESTRUCTION, "Minor Destruction", 1, 0, 20, 0, ABFLAG_NONE }, - { ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB, "Lesser Servant of Makhleb", 2, 0, 50, 1, ABFLAG_NONE }, - { ABIL_MAKHLEB_MAJOR_DESTRUCTION, "Major Destruction", 4, 0, 100, 2, ABFLAG_NONE }, - { ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB, "Greater Servant of Makhleb", 6, 0, 100, 3, ABFLAG_NONE }, - - // Sif Muna - { ABIL_SIF_MUNA_FORGET_SPELL, "Forget Spell", 5, 0, 0, 8, ABFLAG_NONE }, - - // Trog - { ABIL_TROG_BERSERK, "Berserk", 0, 0, 200, 0, ABFLAG_NONE }, - { ABIL_TROG_MIGHT, "Might", 0, 0, 200, 1, ABFLAG_NONE }, - { ABIL_TROG_HASTE_SELF, "Haste Self", 0, 0, 250, 3, ABFLAG_NONE }, - - // Elyvilon - { ABIL_ELYVILON_LESSER_HEALING, "Lesser Healing", 1, 0, 100, 0, ABFLAG_NONE }, - { ABIL_ELYVILON_PURIFICATION, "Purification", 2, 0, 150, 1, ABFLAG_NONE }, - { ABIL_ELYVILON_HEALING, "Healing", 2, 0, 250, 2, ABFLAG_NONE }, - { ABIL_ELYVILON_RESTORATION, "Restoration", 3, 0, 400, 3, ABFLAG_NONE }, - { ABIL_ELYVILON_GREATER_HEALING, "Greater Healing", 6, 0, 600, 4, ABFLAG_NONE }, - - // These six are unused "evil" god abilities: - { ABIL_CHARM_SNAKE, "Charm Snake", 6, 0, 200, 5, ABFLAG_NONE }, - { ABIL_TRAN_SERPENT_OF_HELL, "Turn into Demonic Serpent", 16, 0, 600, 8, ABFLAG_NONE }, - { ABIL_BREATHE_HELLFIRE, "Breathe Hellfire", 0, 8, 200, 0, ABFLAG_BREATH }, - - { ABIL_ROTTING, "Rotting", 4, 4, 0, 2, ABFLAG_NONE }, - { ABIL_TORMENT_II, "Call Torment", 9, 0, 0, 3, ABFLAG_PAIN }, - - { ABIL_RENOUNCE_RELIGION, "Renounce Religion", 0, 0, 0, 0, ABFLAG_NONE }, -}; - - -const struct ability_def & get_ability_def( int abil ) -/****************************************************/ -{ - for (unsigned int i = 0; i < sizeof( Ability_List ); i++) - { - if (Ability_List[i].ability == abil) - return (Ability_List[i]); - } - - return (Ability_List[0]); -} - - -const char * get_ability_name_by_index( char index ) -/**************************************************/ -{ - const struct ability_def &abil = get_ability_def( Curr_abil[index].which ); - - return (abil.name); -} - - -const std::string make_cost_description( const struct ability_def &abil ) -/***********************************************************************/ -{ - char tmp_buff[80]; // avoiding string steams for portability - std::string ret = ""; - - if (abil.mp_cost) - { - snprintf( tmp_buff, sizeof(tmp_buff), "%d%s MP", - abil.mp_cost, - (abil.flags & ABFLAG_PERMANENT_MP) ? " Permanent" : "" ); - - ret += tmp_buff; - } - - if (abil.hp_cost) - { - if (ret.length()) - ret += ", "; - - snprintf( tmp_buff, sizeof(tmp_buff), "%d%s HP", - abil.hp_cost, - (abil.flags & ABFLAG_PERMANENT_HP) ? " Permanent" : "" ); - - ret += tmp_buff; - } - - if (abil.food_cost) - { - if (ret.length()) - ret += ", "; - - ret += "Food"; // randomized and amount hidden from player - } - - if (abil.piety_cost) - { - if (ret.length()) - ret += ", "; - - ret += "Piety"; // randomized and amount hidden from player - } - - if (abil.flags & ABFLAG_BREATH) - { - if (ret.length()) - ret += ", "; - - ret += "Breath"; - } - - if (abil.flags & ABFLAG_DELAY) - { - if (ret.length()) - ret += ", "; - - ret += "Delay"; - } - - if (abil.flags & ABFLAG_PAIN) - { - if (ret.length()) - ret += ", "; - - ret += "Pain"; - } - - if (abil.flags & ABFLAG_EXHAUSTION) - { - if (ret.length()) - ret += ", "; - - ret += "Exhaustion"; - } - - if (abil.flags & ABFLAG_INSTANT) - { - if (ret.length()) - ret += ", "; - - ret += "Instant"; // not really a cost, more of a bonus -bwr - } - - // If we haven't output anything so far, then the effect has no cost - if (!ret.length()) - ret += "None"; - - return (ret); -} - -std::vector<const char *> get_ability_names() -{ - std::vector<const char *> abils; - if (generate_abilities()) - { - for (int i = 0; i < 52; ++i) - { - if (Curr_abil[i].which != ABIL_NON_ABILITY) - abils.push_back( get_ability_name_by_index(i) ); - } - } - return (abils); -} - -/* - Activates a menu which gives player access to all of their non-spell - special abilities - Eg naga's spit poison, or the Invocations you get - from worshipping. Generated dynamically - the function checks to see which - abilities you have every time. - */ -bool activate_ability(void) -/*************************/ -{ - unsigned char keyin = 0; - unsigned char spc, spc2; - - int power; - struct dist abild; - struct bolt beam; - struct dist spd; - - unsigned char abil_used; - - // early returns prior to generation of ability list {dlb}: - if (you.conf) - { - mpr("You're too confused!"); - return (false); - } - - if (you.berserker) - { - canned_msg(MSG_TOO_BERSERK); - return (false); - } - - // populate the array of structs {dlb}: - if (!generate_abilities()) - { - mpr("Sorry, you're not good enough to have a special ability."); - return (false); - } - - bool need_redraw = false; - bool need_prompt = true; - bool need_getch = true; - - for (;;) - { - if (need_redraw) - { - mesclr( true ); - redraw_screen(); - } - - if (need_prompt) - mpr( "Use which ability? (? or * to list)", MSGCH_PROMPT ); - - if (need_getch) - keyin = get_ch(); - - need_redraw = false; - need_prompt = true; - need_getch = true; - - if (isalpha( keyin )) - { - break; - } - else if (keyin == '?' || keyin == '*') - { - keyin = show_abilities(); - - need_getch = false; - need_redraw = true; - need_prompt = true; - } - else if (keyin == ESCAPE || keyin == ' ' - || keyin == '\r' || keyin == '\n') - { - canned_msg( MSG_OK ); - return (false); - } - } - - spc = (int) keyin; - - if (!isalpha( spc )) - { - mpr("You can't do that."); - return (false); - } - - spc2 = letter_to_index(spc); - - if (Curr_abil[spc2].which == -1) - { - mpr("You can't do that."); - return (false); - } - - abil_used = spc2; - - // some abilities don't need a hunger check - bool hungerCheck = true; - switch (Curr_abil[abil_used].which) - { - case ABIL_RENOUNCE_RELIGION: - case ABIL_EVOKE_STOP_LEVITATING: - case ABIL_EVOKE_TURN_VISIBLE: - case ABIL_END_TRANSFORMATION: - case ABIL_DELAYED_FIREBALL: - case ABIL_MUMMY_RESTORATION: - hungerCheck = false; - break; - default: - break; - } - - if (hungerCheck && you.hunger_state < HS_HUNGRY) - { - mpr("You're too hungry."); - return (false); - } - - // no turning back now... {dlb} - const struct ability_def abil = get_ability_def(Curr_abil[abil_used].which); - - // currently only delayed fireball is instantaneous -- bwr - you.turn_is_over = ((abil.flags & ABFLAG_INSTANT) ? 0 : 1); - - if (random2avg(100, 3) < Curr_abil[abil_used].fail) - { - mpr("You fail to use your ability."); - return (false); - } - - if (!enough_mp( abil.mp_cost, false )) - return (false); - - if (!enough_hp( abil.hp_cost, false )) - return (false); - - // Note: the costs will not be applied until after this switch - // statement... it's assumed that only failures have returned! -- bwr - switch (abil.ability) - { - case ABIL_MUMMY_RESTORATION: - mpr( "You infuse your body with magical energy." ); - restore_stat( STAT_ALL, false ); - unrot_hp( 100 ); - break; - - case ABIL_DELAYED_FIREBALL: - // Note: power level of ball calculated at release -- bwr - fireball( calc_spell_power( SPELL_DELAYED_FIREBALL, true ) ); - - // only one allowed since this is instantaneous -- bwr - you.attribute[ ATTR_DELAYED_FIREBALL ] = 0; - break; - - case ABIL_GLAMOUR: - if (you.duration[DUR_GLAMOUR]) - { - canned_msg(MSG_CANNOT_DO_YET); - return (false); - } - - mpr("You use your Elvish wiles."); - - cast_glamour( 10 + random2(you.experience_level) - + random2(you.experience_level) ); - - you.duration[DUR_GLAMOUR] = 20 + random2avg(13, 3); - break; - - case ABIL_SPIT_POISON: // Naga + spit poison mutation - if (you.duration[DUR_BREATH_WEAPON]) - { - canned_msg(MSG_CANNOT_DO_YET); - return (false); - } - else if (spell_direction(abild, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - else - { - mpr("You spit poison."); - - zapping( ZAP_SPIT_POISON, - you.experience_level - + you.mutation[MUT_SPIT_POISON] * 5 - + (you.species == SP_NAGA) * 10, - beam ); - - you.duration[DUR_BREATH_WEAPON] = 3 + random2(5); - } - break; - - case ABIL_EVOKE_MAPPING: // randarts - mpr("You sense your surroundings."); - - magic_mapping( 3 + roll_dice( 2, you.skills[SK_EVOCATIONS] ), - 40 + roll_dice( 2, you.skills[SK_EVOCATIONS] ) ); - - exercise( SK_EVOCATIONS, 1 ); - break; - - case ABIL_MAPPING: // Gnome + sense surrounds mut - mpr("You sense your surroundings."); - - magic_mapping( 3 + roll_dice( 2, you.experience_level ) - + you.mutation[MUT_MAPPING] * 10, - 40 + roll_dice( 2, you.experience_level ) ); - break; - - case ABIL_EVOKE_TELEPORTATION: // ring of teleportation - case ABIL_TELEPORTATION: // teleport mut - if (you.mutation[MUT_TELEPORT_AT_WILL] == 3) - you_teleport2( true, true ); // instant and to new area of Abyss - else - you_teleport(); - - if (abil.ability == ABIL_EVOKE_TELEPORTATION) - exercise( SK_EVOCATIONS, 1 ); - break; - - case ABIL_BREATHE_FIRE: - case ABIL_BREATHE_FROST: - case ABIL_BREATHE_POISON: - case ABIL_BREATHE_LIGHTNING: - case ABIL_SPIT_ACID: - case ABIL_BREATHE_POWER: - case ABIL_BREATHE_STICKY_FLAME: - case ABIL_BREATHE_STEAM: - if (you.duration[DUR_BREATH_WEAPON] - && Curr_abil[abil_used].which != ABIL_SPIT_ACID) - { - canned_msg(MSG_CANNOT_DO_YET); - return (false); - } - else if (spell_direction( abild, beam ) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - switch (Curr_abil[abil_used].which) - { - case ABIL_BREATHE_FIRE: - power = you.experience_level; - power += you.mutation[MUT_BREATHE_FLAMES] * 4; - - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON) - power += 12; - - // don't check for hell serpents - they get hell fire, - // never regular fire (GDL) - - snprintf( info, INFO_SIZE, "You breathe fire%c", (power < 15)?'.':'!'); - mpr(info); - - zapping( ZAP_BREATHE_FIRE, power, beam); - break; - - case ABIL_BREATHE_FROST: - mpr("You exhale a wave of freezing cold."); - zapping(ZAP_BREATHE_FROST, you.experience_level, beam); - break; - - case ABIL_BREATHE_POISON: - mpr("You exhale a blast of poison gas."); - zapping(ZAP_BREATHE_POISON, you.experience_level, beam); - break; - - case ABIL_BREATHE_LIGHTNING: - mpr("You spit a bolt of lightning."); - zapping(ZAP_LIGHTNING, (you.experience_level * 2), beam); - break; - - case ABIL_SPIT_ACID: - mpr("You spit acid."); - zapping(ZAP_BREATHE_ACID, you.experience_level, beam); - break; - - case ABIL_BREATHE_POWER: - mpr("You spit a bolt of incandescent energy."); - zapping(ZAP_BREATHE_POWER, you.experience_level, beam); - break; - - case ABIL_BREATHE_STICKY_FLAME: - mpr("You spit a glob of burning liquid."); - zapping(ZAP_STICKY_FLAME, you.experience_level, beam); - break; - - case ABIL_BREATHE_STEAM: - mpr("You exhale a blast of scalding steam."); - zapping(ZAP_BREATHE_STEAM, you.experience_level, beam); - break; - - } - - if (Curr_abil[abil_used].which != ABIL_SPIT_ACID) - { - you.duration[DUR_BREATH_WEAPON] = 3 + random2(5) - + random2(30 - you.experience_level); - } - - if (Curr_abil[abil_used].which == ABIL_BREATHE_STEAM) - { - you.duration[DUR_BREATH_WEAPON] /= 2; - } - break; - - case ABIL_EVOKE_BLINK: // randarts - case ABIL_BLINK: // mutation - random_blink(true); - - if (abil.ability == ABIL_EVOKE_BLINK) - exercise( SK_EVOCATIONS, 1 ); - break; - - case ABIL_EVOKE_BERSERK: // amulet of rage, randarts - if (you.hunger_state < HS_SATIATED) - { - mpr("You're too hungry to berserk."); - return (false); - } - - go_berserk(true); - exercise( SK_EVOCATIONS, 1 ); - break; - - // fly (kenku) -- eventually becomes permanent (see acr.cc) - case ABIL_FLY: - cast_fly( you.experience_level * 4 ); - - if (you.experience_level > 14) - { - mpr("You feel very comfortable in the air."); - you.levitation = 100; - you.duration[DUR_CONTROLLED_FLIGHT] = 100; - } - break; - - case ABIL_FLY_II: // Fly (Draconians, or anything else with wings) - if (you.exhausted) - { - mpr("You're too exhausted to fly."); - return (false); - } - else if (you.burden_state != BS_UNENCUMBERED) - { - mpr("You're carrying too much weight to fly."); - return (false); - } - else - { - cast_fly( you.experience_level * 2 ); - // you.attribute[ATTR_EXPENSIVE_FLIGHT] = 1; // unused - } - break; - - // DEMONIC POWERS: - case ABIL_SUMMON_MINOR_DEMON: - summon_ice_beast_etc( you.experience_level * 4, - summon_any_demon(DEMON_LESSER) ); - break; - - case ABIL_SUMMON_DEMONS: - summon_ice_beast_etc( you.experience_level * 4, - summon_any_demon(DEMON_COMMON) ); - break; - - case ABIL_HELLFIRE: - your_spells(SPELL_HELLFIRE, 20 + you.experience_level, false); - break; - - case ABIL_TORMENT: - if (you.is_undead) - { - mpr("The unliving cannot use this ability."); - return (false); - } - - torment(you.x_pos, you.y_pos); - break; - - case ABIL_RAISE_DEAD: - your_spells(SPELL_ANIMATE_DEAD, you.experience_level * 5, false); - break; - - case ABIL_CONTROL_DEMON: - if (spell_direction(abild, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping(ZAP_CONTROL_DEMON, you.experience_level * 5, beam); - break; - - case ABIL_TO_PANDEMONIUM: - if (you.level_type == LEVEL_PANDEMONIUM) - { - mpr("You're already here."); - return (false); - } - - banished(DNGN_ENTER_PANDEMONIUM); - break; - - case ABIL_CHANNELING: - mpr("You channel some magical energy."); - inc_mp(1 + random2(5), false); - break; - - case ABIL_THROW_FLAME: - case ABIL_THROW_FROST: - if (spell_direction(abild, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping( (Curr_abil[abil_used].which == ABIL_THROW_FLAME ? ZAP_FLAME - : ZAP_FROST), - you.experience_level * 3, - beam ); - break; - - case ABIL_BOLT_OF_DRAINING: - if (spell_direction(abild, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping(ZAP_NEGATIVE_ENERGY, you.experience_level * 6, beam); - break; - - case ABIL_EVOKE_TURN_INVISIBLE: // ring, randarts, darkness items - if (you.hunger_state < HS_SATIATED) - { - mpr("You're too hungry to turn invisible."); - return (false); - } - - potion_effect( POT_INVISIBILITY, 2 * you.skills[SK_EVOCATIONS] + 5 ); - contaminate_player( 1 + random2(3) ); - exercise( SK_EVOCATIONS, 1 ); - break; - - case ABIL_EVOKE_TURN_VISIBLE: - mpr("You feel less transparent."); - you.invis = 1; - break; - - case ABIL_EVOKE_LEVITATE: // ring, boots, randarts - potion_effect( POT_LEVITATION, 2 * you.skills[SK_EVOCATIONS] + 30 ); - exercise( SK_EVOCATIONS, 1 ); - break; - - case ABIL_EVOKE_STOP_LEVITATING: - mpr("You feel heavy."); - you.levitation = 1; - break; - - case ABIL_END_TRANSFORMATION: - mpr("You feel almost normal."); - you.duration[DUR_TRANSFORMATION] = 2; - break; - - // INVOCATIONS: - case ABIL_ZIN_REPEL_UNDEAD: - case ABIL_TSO_REPEL_UNDEAD: - turn_undead(you.piety); - - if (!you.duration[DUR_REPEL_UNDEAD]) - mpr( "You feel a holy aura protecting you." ); - - you.duration[DUR_REPEL_UNDEAD] += 8 - + roll_dice(2, 2 * you.skills[SK_INVOCATIONS]); - - if (you.duration[ DUR_REPEL_UNDEAD ] > 50) - you.duration[ DUR_REPEL_UNDEAD ] = 50; - - exercise(SK_INVOCATIONS, 1); - break; - - case ABIL_ZIN_HEALING: - if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) )) - break; - - exercise(SK_INVOCATIONS, 1 + random2(3)); - break; - - case ABIL_ZIN_PESTILENCE: - mpr( "You call forth a swarm of pestilential beasts!" ); - - if (!summon_swarm( you.skills[SK_INVOCATIONS] * 8, false, true )) - mpr( "Nothing seems to have answered your call." ); - - exercise( SK_INVOCATIONS, 2 + random2(4) ); - break; - - case ABIL_ZIN_HOLY_WORD: - holy_word( you.skills[SK_INVOCATIONS] * 8 ); - exercise(SK_INVOCATIONS, 3 + random2(5)); - break; - - case ABIL_ZIN_SUMMON_GUARDIAN: - summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_ANGEL); - exercise(SK_INVOCATIONS, 8 + random2(10)); - break; - - case ABIL_TSO_SMITING: - cast_smiting( you.skills[SK_INVOCATIONS] * 6 ); - exercise( SK_INVOCATIONS, (coinflip()? 3 : 2) ); - break; - - case ABIL_TSO_ANNIHILATE_UNDEAD: - if (spell_direction(spd, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping(ZAP_DISPEL_UNDEAD, you.skills[SK_INVOCATIONS] * 6, beam); - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_TSO_CLEANSING_FLAME: - if (spell_direction(spd, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping(ZAP_CLEANSING_FLAME, 20 + you.skills[SK_INVOCATIONS] * 6, beam); - exercise(SK_INVOCATIONS, 3 + random2(6)); - break; - - case ABIL_TSO_SUMMON_DAEVA: - summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_DAEVA); - exercise(SK_INVOCATIONS, 8 + random2(10)); - break; - - case ABIL_KIKU_RECALL_UNDEAD_SLAVES: - recall(1); - exercise(SK_INVOCATIONS, 1); - break; - - case ABIL_KIKU_ENSLAVE_UNDEAD: - if (spell_direction(spd, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - zapping( ZAP_ENSLAVE_UNDEAD, you.skills[SK_INVOCATIONS] * 8, beam ); - exercise(SK_INVOCATIONS, 5 + random2(5)); - break; - - case ABIL_KIKU_INVOKE_DEATH: - summon_ice_beast_etc( - 20 + you.skills[SK_INVOCATIONS] * 3, MONS_REAPER, true); - exercise(SK_INVOCATIONS, 10 + random2(14)); - break; - - case ABIL_YRED_ANIMATE_CORPSE: - mpr("You call on the dead to walk for you..."); - - animate_a_corpse( you.x_pos, you.y_pos, BEH_FRIENDLY, - you.pet_target, CORPSE_BODY ); - - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_YRED_RECALL_UNDEAD: - recall(1); - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_YRED_ANIMATE_DEAD: - mpr("You call on the dead to walk for you..."); - - animate_dead( 1 + you.skills[SK_INVOCATIONS], BEH_FRIENDLY, - you.pet_target, 1 ); - - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_YRED_DRAIN_LIFE: - drain_life( you.skills[SK_INVOCATIONS] ); - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_YRED_CONTROL_UNDEAD: - mass_enchantment( ENCH_CHARM, you.skills[SK_INVOCATIONS] * 8, MHITYOU ); - exercise(SK_INVOCATIONS, 3 + random2(4)); - break; - - case ABIL_VEHUMET_CHANNEL_ENERGY: - mpr("You channel some magical energy."); - - inc_mp(1 + random2(you.skills[SK_INVOCATIONS] / 4 + 2), false); - exercise(SK_INVOCATIONS, 1 + random2(3)); - break; - - case ABIL_OKAWARU_MIGHT: - potion_effect( POT_MIGHT, you.skills[SK_INVOCATIONS] * 8 ); - exercise(SK_INVOCATIONS, 1 + random2(3)); - break; - - case ABIL_OKAWARU_HEALING: - if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) )) - break; - - exercise(SK_INVOCATIONS, 2 + random2(5)); - break; - - case ABIL_OKAWARU_HASTE: - potion_effect( POT_SPEED, you.skills[SK_INVOCATIONS] * 8 ); - exercise(SK_INVOCATIONS, 3 + random2(7)); - break; - - case ABIL_MAKHLEB_MINOR_DESTRUCTION: - if (spell_direction(spd, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - power = you.skills[SK_INVOCATIONS] - + random2( 1 + you.skills[SK_INVOCATIONS] ) - + random2( 1 + you.skills[SK_INVOCATIONS] ); - - switch (random2(5)) - { - case 0: zapping( ZAP_FLAME, power, beam ); break; - case 1: zapping( ZAP_PAIN, power, beam ); break; - case 2: zapping( ZAP_STONE_ARROW, power, beam ); break; - case 3: zapping( ZAP_ELECTRICITY, power, beam ); break; - case 4: zapping( ZAP_BREATHE_ACID, power / 2, beam ); break; - } - - exercise(SK_INVOCATIONS, 1); - break; - - case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB: - summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3, - MONS_NEQOXEC + random2(5) ); - - exercise(SK_INVOCATIONS, 2 + random2(3)); - break; - - case ABIL_MAKHLEB_MAJOR_DESTRUCTION: - if (spell_direction(spd, beam) == -1) - { - canned_msg(MSG_OK); - return (false); - } - - power = you.skills[SK_INVOCATIONS] * 3 - + random2( 1 + you.skills[SK_INVOCATIONS] ) - + random2( 1 + you.skills[SK_INVOCATIONS] ); - - switch (random2(8)) - { - case 0: zapping( ZAP_FIRE, power, beam ); break; - case 1: zapping( ZAP_FIREBALL, power, beam ); break; - case 2: zapping( ZAP_LIGHTNING, power, beam ); break; - case 3: zapping( ZAP_NEGATIVE_ENERGY, power, beam ); break; - case 4: zapping( ZAP_STICKY_FLAME, power, beam ); break; - case 5: zapping( ZAP_IRON_BOLT, power, beam ); break; - case 6: zapping( ZAP_ORB_OF_ELECTRICITY, power, beam ); break; - - case 7: - you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1; - mpr("Makhleb hurls a blast of lightning!"); - - // make a divine lightning bolt... - beam.beam_source = NON_MONSTER; - beam.type = SYM_BURST; - beam.damage = dice_def( 3, 30 ); - beam.flavour = BEAM_ELECTRICITY; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - strcpy(beam.beam_name, "blast of lightning"); - beam.colour = LIGHTCYAN; - beam.thrower = KILL_YOU; - beam.aux_source = "Makhleb's lightning strike"; - beam.ex_size = 1 + you.skills[SK_INVOCATIONS] / 8; - beam.is_tracer = false; - - // ... and fire! - explosion(beam); - - // protection down - mpr("Your divine protection wanes."); - you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0; - break; - } - - exercise(SK_INVOCATIONS, 3 + random2(5)); - break; - - case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB: - summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3, - MONS_EXECUTIONER + random2(5) ); - - exercise(SK_INVOCATIONS, 6 + random2(6)); - break; - - case ABIL_TROG_BERSERK: - // Trog abilities don't use or train invocations. - if (you.hunger_state < HS_SATIATED) - { - mpr("You're too hungry to berserk."); - return (false); - } - - go_berserk(true); - break; - - case ABIL_TROG_MIGHT: - // Trog abilities don't use or train invocations. - potion_effect( POT_MIGHT, 150 ); - break; - - case ABIL_TROG_HASTE_SELF: - // Trog abilities don't use or train invocations. - potion_effect( POT_SPEED, 150 ); - break; - - case ABIL_SIF_MUNA_FORGET_SPELL: - cast_selective_amnesia(true); - break; - - case ABIL_ELYVILON_LESSER_HEALING: - if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) )) - break; - - exercise( SK_INVOCATIONS, 1 ); - break; - - case ABIL_ELYVILON_PURIFICATION: - purification(); - exercise( SK_INVOCATIONS, 2 + random2(3) ); - break; - - case ABIL_ELYVILON_HEALING: - if (!cast_healing( 10 + (you.skills[SK_INVOCATIONS] / 3) )) - break; - - exercise( SK_INVOCATIONS, 3 + random2(5) ); - break; - - case ABIL_ELYVILON_RESTORATION: - restore_stat( STAT_ALL, false ); - unrot_hp( 100 ); - - exercise( SK_INVOCATIONS, 4 + random2(6) ); - break; - - case ABIL_ELYVILON_GREATER_HEALING: - if (!cast_healing( 20 + you.skills[SK_INVOCATIONS] * 2 )) - break; - - exercise( SK_INVOCATIONS, 6 + random2(10) ); - break; - - //jmf: intended as invocations from evil god(s): - case ABIL_CHARM_SNAKE: - cast_snake_charm( you.experience_level * 2 - + you.skills[SK_INVOCATIONS] * 3 ); - - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_TRAN_SERPENT_OF_HELL: - transform(10 + (you.experience_level * 2) + - (you.skills[SK_INVOCATIONS] * 3), TRAN_SERPENT_OF_HELL); - - exercise(SK_INVOCATIONS, 6 + random2(9)); - break; - - case ABIL_BREATHE_HELLFIRE: - if (you.duration[DUR_BREATH_WEAPON]) - { - canned_msg(MSG_CANNOT_DO_YET); - return (false); - } - - your_spells( SPELL_HELLFIRE, 20 + you.experience_level, false ); - - you.duration[DUR_BREATH_WEAPON] += - 3 + random2(5) + random2(30 - you.experience_level); - break; - - case ABIL_ROTTING: - cast_rotting(you.experience_level * 2 + you.skills[SK_INVOCATIONS] * 3); - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_TORMENT_II: - if (you.is_undead) - { - mpr("The unliving cannot use this ability."); - return (false); - } - - torment(you.x_pos, you.y_pos); - exercise(SK_INVOCATIONS, 2 + random2(4)); - break; - - case ABIL_RENOUNCE_RELIGION: - if (yesno("Really renounce your faith, foregoing its fabulous benefits?") - && yesno( "Are you sure you won't change your mind later?" )) - { - excommunication(); - } - else - { - canned_msg(MSG_OK); - } - break; - - default: - mpr("Sorry, you can't do that."); - break; - } - - // All failures should have returned by this point, so we'll - // apply the costs -- its not too neat, but it works for now. -- bwr - const int food_cost = abil.food_cost + random2avg(abil.food_cost, 2); - const int piety_cost = abil.piety_cost + random2((abil.piety_cost + 1) / 2 + 1); - -#if DEBUG_DIAGNOSTICS - snprintf( info, INFO_SIZE, "Cost: mp=%d; hp=%d; food=%d; piety=%d", - abil.mp_cost, abil.hp_cost, food_cost, piety_cost ); - - mpr( info, MSGCH_DIAGNOSTICS ); -#endif - - if (abil.mp_cost) - { - dec_mp( abil.mp_cost ); - if (abil.flags & ABFLAG_PERMANENT_MP) - rot_mp(1); - } - - if (abil.hp_cost) - { - dec_hp( abil.hp_cost, false ); - if (abil.flags & ABFLAG_PERMANENT_HP) - rot_hp(1); - } - - if (food_cost) - make_hungry( food_cost, false ); - - if (piety_cost) - lose_piety( piety_cost ); - - return (true); -} // end activate_ability() - - -// Lists any abilities the player may possess -char show_abilities( void ) -/*************************/ -{ - int loopy = 0; - char lines = 0; - unsigned char anything = 0; - char ki; - bool can_invoke = false; - - const int num_lines = get_number_of_lines(); - - for (loopy = 0; loopy < 52; loopy++) - { - if (Curr_abil[loopy].is_invocation) - { - can_invoke = true; - break; - } - } - - -#ifdef DOS_TERM - char buffer[4800]; - - gettext(1, 1, 80, 25, buffer); - window(1, 1, 80, 25); -#endif - - clrscr(); - cprintf(" Ability Cost Success"); - lines++; - - for (int do_invoke = 0; do_invoke < (can_invoke ? 2 : 1); do_invoke++) - { - if (do_invoke) - { - anything++; - textcolor(BLUE); - cprintf(EOL " Invocations - "); - textcolor(LIGHTGREY); - lines++; - } - - for (loopy = 0; loopy < 52; loopy++) - { - if (lines > num_lines - 2) - { - gotoxy(1, num_lines); - cprintf("-more-"); - - ki = getch(); - - if (ki == ESCAPE) - { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (ESCAPE); - } - - if (ki >= 'A' && ki <= 'z') - { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (ki); - } - - if (ki == 0) - ki = getch(); - - lines = 0; - clrscr(); - gotoxy(1, 1); - anything = 0; - } - - if (Curr_abil[loopy].which != ABIL_NON_ABILITY - && (do_invoke == Curr_abil[loopy].is_invocation)) - { - anything++; - - if (lines > 0) - cprintf(EOL); - - lines++; - - const struct ability_def abil = get_ability_def( Curr_abil[loopy].which ); - - cprintf( " %c - %s", index_to_letter(loopy), abil.name ); - - // Output costs: - gotoxy( 35, wherey() ); - - std::string cost_str = make_cost_description( abil ); - - if (cost_str.length() > 24) - cost_str = cost_str.substr( 0, 24 ); - - cprintf( cost_str.c_str() ); - - gotoxy(60, wherey()); - - int spell_f = Curr_abil[loopy].fail; - - cprintf( (spell_f >= 100) ? "Useless" : - (spell_f > 90) ? "Terrible" : - (spell_f > 80) ? "Cruddy" : - (spell_f > 70) ? "Bad" : - (spell_f > 60) ? "Very Poor" : - (spell_f > 50) ? "Poor" : - (spell_f > 40) ? "Fair" : - (spell_f > 30) ? "Good" : - (spell_f > 20) ? "Very Good" : - (spell_f > 10) ? "Great" : - (spell_f > 0) ? "Excellent" : - "Perfect" ); - - gotoxy(70, wherey()); - } // end if conditional - } // end "for loopy" - } - - if (anything > 0) - { - ki = getch(); - - if (ki >= 'A' && ki <= 'z') - { -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - return (ki); - } - - if (ki == 0) - ki = getch(); - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - - return (ki); - } - -#ifdef DOS_TERM - puttext(1, 1, 80, 25, buffer); -#endif - - ki = getch(); - - return (ki); -} // end show_abilities() - - -bool generate_abilities( void ) -/*****************************/ -{ - int loopy; - int ability = -1; // used with draconian checks {dlb} - - // fill array of structs with "empty" values {dlb}: - for (loopy = 0; loopy < 52; loopy++) - { - Curr_abil[loopy].which = ABIL_NON_ABILITY; - Curr_abil[loopy].fail = 100; - Curr_abil[loopy].is_invocation = false; - } - - // first we do the racial abilities: - - // Mummies get the ability to restore HPs and stats, but it - // costs permanent MP (and those can never be recovered). -- bwr - if (you.species == SP_MUMMY && you.experience_level >= 13) - { - insert_ability( ABIL_MUMMY_RESTORATION ); - } - - // checking for species-related abilities and mutagenic counterparts {dlb}: - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_NONE - && ((you.species == SP_GREY_ELF && you.experience_level >= 5) - || (you.species == SP_HIGH_ELF && you.experience_level >= 15))) - { - insert_ability( ABIL_GLAMOUR ); - } - - if (you.species == SP_NAGA) - { - if (you.mutation[MUT_BREATHE_POISON]) - insert_ability( ABIL_BREATHE_POISON ); - else - insert_ability( ABIL_SPIT_POISON ); - } - else if (you.mutation[MUT_SPIT_POISON]) - { - insert_ability( ABIL_SPIT_POISON ); - } - - if (player_genus(GENPC_DRACONIAN)) - { - if (you.experience_level >= 7) - { - ability = ( - (you.species == SP_GREEN_DRACONIAN) ? ABIL_BREATHE_POISON : - (you.species == SP_RED_DRACONIAN) ? ABIL_BREATHE_FIRE : - (you.species == SP_WHITE_DRACONIAN) ? ABIL_BREATHE_FROST : - (you.species == SP_GOLDEN_DRACONIAN) ? ABIL_SPIT_ACID : - (you.species == SP_BLACK_DRACONIAN) ? ABIL_BREATHE_LIGHTNING : - (you.species == SP_PURPLE_DRACONIAN) ? ABIL_BREATHE_POWER : - (you.species == SP_PALE_DRACONIAN) ? ABIL_BREATHE_STEAM : - (you.species == SP_MOTTLED_DRACONIAN)? ABIL_BREATHE_STICKY_FLAME: - -1); - - if (ability != -1) - insert_ability( ability ); - } - } - - //jmf: alternately put check elsewhere - if ((you.level_type == LEVEL_DUNGEON - && (you.species == SP_GNOME || you.mutation[MUT_MAPPING])) - || (you.level_type == LEVEL_PANDEMONIUM - && you.mutation[MUT_MAPPING] == 3)) - { - insert_ability( ABIL_MAPPING ); - } - - if (!you.duration[DUR_CONTROLLED_FLIGHT] && !player_is_levitating()) - { - // kenku can fly, but only from the ground - // (until levitation 15, when it becomes permanent until revoked) - //jmf: "upgrade" for draconians -- expensive flight - if (you.species == SP_KENKU && you.experience_level >= 5) - insert_ability( ABIL_FLY ); - else if (player_genus(GENPC_DRACONIAN) && you.mutation[MUT_BIG_WINGS]) - insert_ability( ABIL_FLY_II ); - } - - // demonic powers {dlb}: - if (you.mutation[MUT_SUMMON_MINOR_DEMONS]) - insert_ability( ABIL_SUMMON_MINOR_DEMON ); - - if (you.mutation[MUT_SUMMON_DEMONS]) - insert_ability( ABIL_SUMMON_DEMONS ); - - if (you.mutation[MUT_HURL_HELLFIRE]) - insert_ability( ABIL_HELLFIRE ); - - if (you.mutation[MUT_CALL_TORMENT]) - insert_ability( ABIL_TORMENT ); - - if (you.mutation[MUT_RAISE_DEAD]) - insert_ability( ABIL_RAISE_DEAD ); - - if (you.mutation[MUT_CONTROL_DEMONS]) - insert_ability( ABIL_CONTROL_DEMON ); - - if (you.mutation[MUT_PANDEMONIUM]) - insert_ability( ABIL_TO_PANDEMONIUM ); - - if (you.mutation[MUT_CHANNEL_HELL]) - insert_ability( ABIL_CHANNELING ); - - if (you.mutation[MUT_THROW_FLAMES]) - insert_ability( ABIL_THROW_FLAME ); - - if (you.mutation[MUT_THROW_FROST]) - insert_ability( ABIL_THROW_FROST ); - - if (you.mutation[MUT_SMITE]) - insert_ability( ABIL_BOLT_OF_DRAINING ); - - if (you.duration[DUR_TRANSFORMATION]) - insert_ability( ABIL_END_TRANSFORMATION ); - - if (you.mutation[MUT_BLINK]) - insert_ability( ABIL_BLINK ); - - if (you.mutation[MUT_TELEPORT_AT_WILL]) - insert_ability( ABIL_TELEPORTATION ); - - // gods take abilities away until penance completed -- bwr - if (!player_under_penance() && !silenced( you.x_pos, you.y_pos )) - { - switch (you.religion) - { - case GOD_ZIN: - if (you.piety >= 30) - insert_ability( ABIL_ZIN_REPEL_UNDEAD ); - if (you.piety >= 50) - insert_ability( ABIL_ZIN_HEALING ); - if (you.piety >= 75) - insert_ability( ABIL_ZIN_PESTILENCE ); - if (you.piety >= 100) - insert_ability( ABIL_ZIN_HOLY_WORD ); - if (you.piety >= 120) - insert_ability( ABIL_ZIN_SUMMON_GUARDIAN ); - break; - - case GOD_SHINING_ONE: - if (you.piety >= 30) - insert_ability( ABIL_TSO_REPEL_UNDEAD ); - if (you.piety >= 50) - insert_ability( ABIL_TSO_SMITING ); - if (you.piety >= 75) - insert_ability( ABIL_TSO_ANNIHILATE_UNDEAD ); - if (you.piety >= 100) - insert_ability( ABIL_TSO_CLEANSING_FLAME ); - if (you.piety >= 120) - insert_ability( ABIL_TSO_SUMMON_DAEVA ); - break; - - case GOD_YREDELEMNUL: - if (you.piety >= 30) - insert_ability( ABIL_YRED_ANIMATE_CORPSE ); - if (you.piety >= 50) - insert_ability( ABIL_YRED_RECALL_UNDEAD ); - if (you.piety >= 75) - insert_ability( ABIL_YRED_ANIMATE_DEAD ); - if (you.piety >= 100) - insert_ability( ABIL_YRED_DRAIN_LIFE ); - if (you.piety >= 120) - insert_ability( ABIL_YRED_CONTROL_UNDEAD ); - break; - - case GOD_ELYVILON: - if (you.piety >= 30) - insert_ability( ABIL_ELYVILON_LESSER_HEALING ); - if (you.piety >= 50) - insert_ability( ABIL_ELYVILON_PURIFICATION ); - if (you.piety >= 75) - insert_ability( ABIL_ELYVILON_HEALING ); - if (you.piety >= 100) - insert_ability( ABIL_ELYVILON_RESTORATION ); - if (you.piety >= 120) - insert_ability( ABIL_ELYVILON_GREATER_HEALING ); - break; - - case GOD_MAKHLEB: - if (you.piety >= 50) - insert_ability( ABIL_MAKHLEB_MINOR_DESTRUCTION ); - if (you.piety >= 75) - insert_ability( ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB ); - if (you.piety >= 100) - insert_ability( ABIL_MAKHLEB_MAJOR_DESTRUCTION ); - if (you.piety >= 120) - insert_ability( ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB ); - break; - - case GOD_KIKUBAAQUDGHA: - if (you.piety >= 30) - insert_ability( ABIL_KIKU_RECALL_UNDEAD_SLAVES ); - if (you.piety >= 75) - insert_ability( ABIL_KIKU_ENSLAVE_UNDEAD ); - if (you.piety >= 120) - insert_ability( ABIL_KIKU_INVOKE_DEATH ); - break; - - case GOD_OKAWARU: - if (you.piety >= 30) - insert_ability( ABIL_OKAWARU_MIGHT ); - if (you.piety >= 50) - insert_ability( ABIL_OKAWARU_HEALING ); - if (you.piety >= 120) - insert_ability( ABIL_OKAWARU_HASTE ); - break; - - case GOD_TROG: - if (you.piety >= 30) - insert_ability( ABIL_TROG_BERSERK ); - if (you.piety >= 50) - insert_ability( ABIL_TROG_MIGHT ); - if (you.piety >= 100) - insert_ability( ABIL_TROG_HASTE_SELF ); - break; - - case GOD_SIF_MUNA: - if (you.piety >= 50) - insert_ability( ABIL_SIF_MUNA_FORGET_SPELL ); - break; - - case GOD_VEHUMET: - if (you.piety >= 100) - insert_ability( ABIL_VEHUMET_CHANNEL_ENERGY ); - break; - - default: - break; - } - } - - // and finally, the ability to opt-out of your faith {dlb}: - if (you.religion != GOD_NO_GOD && !silenced( you.x_pos, you.y_pos )) - insert_ability( ABIL_RENOUNCE_RELIGION ); - - //jmf: check for breath weapons -- they're exclusive of each other I hope! - // better make better ones first. - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_SERPENT_OF_HELL) - { - insert_ability( ABIL_BREATHE_HELLFIRE ); - } - else if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON - || you.mutation[MUT_BREATHE_FLAMES]) - { - insert_ability( ABIL_BREATHE_FIRE ); - } - - // checking for unreleased delayed fireball - if (you.attribute[ ATTR_DELAYED_FIREBALL ]) - { - insert_ability( ABIL_DELAYED_FIREBALL ); - } - - // evocations from items: - if (scan_randarts(RAP_BLINK)) - insert_ability( ABIL_EVOKE_BLINK ); - - if (wearing_amulet(AMU_RAGE) || scan_randarts(RAP_BERSERK)) - insert_ability( ABIL_EVOKE_BERSERK ); - - if (scan_randarts( RAP_MAPPING )) - insert_ability( ABIL_EVOKE_MAPPING ); - - if (player_equip( EQ_RINGS, RING_INVISIBILITY ) - || player_equip_ego_type( EQ_ALL_ARMOUR, SPARM_DARKNESS ) - || scan_randarts( RAP_INVISIBLE )) - { - // Now you can only turn invisibility off if you have an - // activatable item. Wands and potions allow will have - // to time out. -- bwr - if (you.invis) - insert_ability( ABIL_EVOKE_TURN_VISIBLE ); - else - insert_ability( ABIL_EVOKE_TURN_INVISIBLE ); - } - - //jmf: "upgrade" for draconians -- expensive flight - // note: this ability only applies to this counter - if (player_equip( EQ_RINGS, RING_LEVITATION ) - || player_equip_ego_type( EQ_BOOTS, SPARM_LEVITATION ) - || scan_randarts( RAP_LEVITATE )) - { - // Now you can only turn levitation off if you have an - // activatable item. Potions and miscast effects will - // have to time out (this makes the miscast effect actually - // a bit annoying). -- bwr - if (you.levitation) - insert_ability( ABIL_EVOKE_STOP_LEVITATING ); - else - insert_ability( ABIL_EVOKE_LEVITATE ); - } - - if (player_equip( EQ_RINGS, RING_TELEPORTATION ) - || scan_randarts( RAP_CAN_TELEPORT )) - { - insert_ability( ABIL_EVOKE_TELEPORTATION ); - } - - // this is a shameless kludge for the time being {dlb}: - // still shameless. -- bwr - for (loopy = 0; loopy < 52; loopy++) - { - if (Curr_abil[loopy].which != ABIL_NON_ABILITY) - return (true); - } - - return (false); -} // end generate_abilities() - -// Note: we're trying for a behaviour where the player gets -// to keep their assigned invocation slots if they get excommunicated -// and then rejoin (but if they spend time with another god we consider -// the old invocation slots void and erase them). We also try to -// protect any bindings the character might have made into the -// traditional invocation slots (A-E and X). -- bwr -void set_god_ability_helper( int abil, char letter ) -/**************************************************/ -{ - int i; - const int index = letter_to_index( letter ); - - for (i = 0; i < 52; i++) - { - if (you.ability_letter_table[i] == abil) - break; - } - - if (i == 52) // ability is not already assigned - { - // if slot is unoccupied, move in - if (you.ability_letter_table[index] == ABIL_NON_ABILITY) - you.ability_letter_table[index] = abil; - } -} - -void set_god_ability_slots( void ) -/********************************/ -{ - ASSERT( you.religion != GOD_NO_GOD ); - - int i; - - set_god_ability_helper( ABIL_RENOUNCE_RELIGION, 'X' ); - - int num_abil = 0; - int abil_start = ABIL_NON_ABILITY; - - switch (you.religion) - { - case GOD_ZIN: - abil_start = ABIL_ZIN_REPEL_UNDEAD; - num_abil = 5; - break; - - case GOD_SHINING_ONE: - abil_start = ABIL_TSO_REPEL_UNDEAD; - num_abil = 5; - break; - - case GOD_KIKUBAAQUDGHA: - abil_start = ABIL_KIKU_RECALL_UNDEAD_SLAVES; - num_abil = 3; - break; - - case GOD_YREDELEMNUL: - abil_start = ABIL_YRED_ANIMATE_CORPSE; - num_abil = 5; - break; - - case GOD_VEHUMET: - abil_start = ABIL_VEHUMET_CHANNEL_ENERGY; - num_abil = 1; - break; - - case GOD_OKAWARU: - abil_start = ABIL_OKAWARU_MIGHT; - num_abil = 3; - break; - - case GOD_MAKHLEB: - abil_start = ABIL_MAKHLEB_MINOR_DESTRUCTION; - num_abil = 4; - break; - - case GOD_SIF_MUNA: - abil_start = ABIL_SIF_MUNA_FORGET_SPELL; - num_abil = 1; - break; - - case GOD_TROG: - abil_start = ABIL_TROG_BERSERK; - num_abil = 3; - break; - - case GOD_ELYVILON: - abil_start = ABIL_ELYVILON_LESSER_HEALING; - num_abil = 5; - break; - - case GOD_NEMELEX_XOBEH: - case GOD_XOM: - default: - break; - } - - // clear out other god invocations: - for (i = 0; i < 52; i++) - { - const int abil = you.ability_letter_table[i]; - - if ((abil >= ABIL_ZIN_REPEL_UNDEAD // is a god ability - && abil <= ABIL_ELYVILON_GREATER_HEALING) - && (num_abil == 0 // current god does have abilities - || abil < abil_start // not one of current god's abilities - || abil >= abil_start + num_abil)) - { - you.ability_letter_table[i] = ABIL_NON_ABILITY; - } - } - - // finally, add in current god's invocaions in traditional slots: - if (num_abil) - { - for (i = 0; i < num_abil; i++) - { - set_god_ability_helper( abil_start + i, - (Options.lowercase_invocations ? 'a' : 'A') + i ); - } - } -} - - -// returns index to Curr_abil, -1 on failure -static int find_ability_slot( int which_ability ) -/***********************************************/ -{ - int slot; - for (slot = 0; slot < 52; slot++) - { - if (you.ability_letter_table[slot] == which_ability) - break; - } - - // no requested slot, find new one and make it prefered. - if (slot == 52) - { - // skip over a-e if player prefers them for invocations - for (slot = (Options.lowercase_invocations ? 5 : 0); slot < 52; slot++) - { - if (you.ability_letter_table[slot] == ABIL_NON_ABILITY) - break; - } - - // if we skipped over a-e to reserve them, try them now - if (Options.lowercase_invocations && slot == 52) - { - for (slot = 5; slot >= 0; slot--) - { - if (you.ability_letter_table[slot] == ABIL_NON_ABILITY) - break; - } - } - - // All letters are assigned, check Curr_abil and try to steal a letter - if (slot == 52) - { - // backwards, to protect the low lettered slots from replacement - for (slot = 51; slot >= 0; slot--) - { - if (Curr_abil[slot].which == ABIL_NON_ABILITY) - break; - } - - // no slots at all == no hope of adding - if (slot < 0) - return (-1); - } - - // this ability now takes over this slot - you.ability_letter_table[slot] = which_ability; - } - - return (slot); -} - -static bool insert_ability( int which_ability ) -/**********************************************/ -{ - ASSERT( which_ability != ABIL_NON_ABILITY ); - - int failure = 0; - bool perfect = false; // is perfect - bool invoc = false; - - // Look through the table to see if there's a preference, else - // find a new empty slot for this ability. -- bwr - const int slot = find_ability_slot( which_ability ); - if (slot == -1) - return (false); - - Curr_abil[slot].which = which_ability; - - switch (which_ability) - { - // begin spell abilities - case ABIL_DELAYED_FIREBALL: - case ABIL_MUMMY_RESTORATION: - perfect = true; - failure = 0; - break; - - // begin species abilities - some are mutagenic, too {dlb} - case ABIL_GLAMOUR: - failure = 50 - (you.experience_level * 2); - break; - - case ABIL_SPIT_POISON: - failure = ((you.species == SP_NAGA) ? 20 : 40) - - 10 * you.mutation[MUT_SPIT_POISON] - - you.experience_level; - break; - - case ABIL_EVOKE_MAPPING: - failure = 30 - you.skills[SK_EVOCATIONS]; - break; - - case ABIL_MAPPING: - failure = ((you.species == SP_GNOME) ? 20 : 40) - - 10 * you.mutation[MUT_MAPPING] - - you.experience_level; - break; - - case ABIL_BREATHE_FIRE: - failure = ((you.species == SP_RED_DRACONIAN) ? 30 : 50) - - 10 * you.mutation[MUT_BREATHE_FLAMES] - - you.experience_level; - - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON) - failure -= 20; - break; - - case ABIL_BREATHE_FROST: - case ABIL_BREATHE_POISON: - case ABIL_SPIT_ACID: - case ABIL_BREATHE_LIGHTNING: - case ABIL_BREATHE_POWER: - case ABIL_BREATHE_STICKY_FLAME: - failure = 30 - you.experience_level; - - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON) - failure -= 20; - break; - - case ABIL_BREATHE_STEAM: - failure = 20 - you.experience_level; - - if (you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON) - failure -= 20; - break; - - case ABIL_FLY: // this is for kenku {dlb} - failure = 45 - (3 * you.experience_level); - break; - - case ABIL_FLY_II: // this is for draconians {dlb} - failure = 45 - (you.experience_level + you.strength); - break; - // end species abilties (some mutagenic) - - // begin demonic powers {dlb} - case ABIL_THROW_FLAME: - case ABIL_THROW_FROST: - failure = 10 - you.experience_level; - break; - - case ABIL_SUMMON_MINOR_DEMON: - failure = 27 - you.experience_level; - break; - - case ABIL_CHANNELING: - case ABIL_BOLT_OF_DRAINING: - failure = 30 - you.experience_level; - break; - - case ABIL_CONTROL_DEMON: - failure = 35 - you.experience_level; - break; - - case ABIL_SUMMON_DEMONS: - failure = 40 - you.experience_level; - break; - - case ABIL_TO_PANDEMONIUM: - failure = 57 - (you.experience_level * 2); - break; - - case ABIL_HELLFIRE: - case ABIL_RAISE_DEAD: - failure = 50 - you.experience_level; - break; - - case ABIL_TORMENT: - failure = 60 - you.experience_level; - break; - - case ABIL_BLINK: - failure = 30 - (10 * you.mutation[MUT_BLINK]) - you.experience_level; - break; - - case ABIL_TELEPORTATION: - failure = ((you.mutation[MUT_TELEPORT_AT_WILL] > 1) ? 30 : 50) - - you.experience_level; - break; - // end demonic powers {dlb} - - // begin transformation abilities {dlb} - case ABIL_END_TRANSFORMATION: - perfect = true; - failure = 0; - break; - - case ABIL_BREATHE_HELLFIRE: - failure = 32 - you.experience_level; - break; - // end transformation abilities {dlb} - // - // begin item abilities - some possibly mutagenic {dlb} - case ABIL_EVOKE_TURN_INVISIBLE: - case ABIL_EVOKE_TELEPORTATION: - failure = 60 - 2 * you.skills[SK_EVOCATIONS]; - break; - - case ABIL_EVOKE_TURN_VISIBLE: - case ABIL_EVOKE_STOP_LEVITATING: - perfect = true; - failure = 0; - break; - - case ABIL_EVOKE_LEVITATE: - case ABIL_EVOKE_BLINK: - failure = 40 - 2 * you.skills[SK_EVOCATIONS]; - break; - - case ABIL_EVOKE_BERSERK: - failure = 50 - 2 * you.skills[SK_EVOCATIONS]; - - if (you.species == SP_TROLL) - failure -= 30; - else if (player_genus(GENPC_DWARVEN) || you.species == SP_HILL_ORC - || you.species == SP_OGRE) - { - failure -= 10; - } - break; - // end item abilities - some possibly mutagenic {dlb} - - // begin invocations {dlb} - case ABIL_ELYVILON_PURIFICATION: - invoc = true; - failure = 20 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_ZIN_REPEL_UNDEAD: - case ABIL_TSO_REPEL_UNDEAD: - case ABIL_KIKU_RECALL_UNDEAD_SLAVES: - case ABIL_OKAWARU_MIGHT: - case ABIL_ELYVILON_LESSER_HEALING: - invoc = true; - failure = 30 - (you.piety / 20) - (6 * you.skills[SK_INVOCATIONS]); - break; - - // These three are Trog abilities... Invocations means nothing -- bwr - case ABIL_TROG_BERSERK: // piety >= 30 - invoc = true; - failure = 30 - you.piety; // starts at 0% - break; - - case ABIL_TROG_MIGHT: // piety >= 50 - invoc = true; - failure = 80 - you.piety; // starts at 30% - break; - - case ABIL_TROG_HASTE_SELF: // piety >= 100 - invoc = true; - failure = 160 - you.piety; // starts at 60% - break; - - case ABIL_YRED_ANIMATE_CORPSE: - invoc = true; - failure = 40 - (you.piety / 20) - (3 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_ZIN_HEALING: - case ABIL_TSO_SMITING: - case ABIL_OKAWARU_HEALING: - case ABIL_MAKHLEB_MINOR_DESTRUCTION: - case ABIL_SIF_MUNA_FORGET_SPELL: - case ABIL_KIKU_ENSLAVE_UNDEAD: - case ABIL_YRED_ANIMATE_DEAD: - case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB: - case ABIL_ELYVILON_HEALING: - invoc = true; - failure = 40 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_VEHUMET_CHANNEL_ENERGY: - invoc = true; - failure = 40 - you.intel - you.skills[SK_INVOCATIONS]; - break; - - case ABIL_YRED_RECALL_UNDEAD: - invoc = true; - failure = 50 - (you.piety / 20) - (you.skills[SK_INVOCATIONS] * 4); - break; - - case ABIL_ZIN_PESTILENCE: - case ABIL_TSO_ANNIHILATE_UNDEAD: - invoc = true; - failure = 60 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_MAKHLEB_MAJOR_DESTRUCTION: - case ABIL_YRED_DRAIN_LIFE: - invoc = true; - failure = 60 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4); - break; - - case ABIL_ZIN_HOLY_WORD: - case ABIL_TSO_CLEANSING_FLAME: - case ABIL_ELYVILON_RESTORATION: - case ABIL_YRED_CONTROL_UNDEAD: - case ABIL_OKAWARU_HASTE: - case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB: - invoc = true; - failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4); - break; - - case ABIL_ZIN_SUMMON_GUARDIAN: - case ABIL_TSO_SUMMON_DAEVA: - case ABIL_KIKU_INVOKE_DEATH: - case ABIL_ELYVILON_GREATER_HEALING: - invoc = true; - failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4); - break; - - //jmf: following for to-be-created gods - case ABIL_CHARM_SNAKE: - invoc = true; - failure = 40 - (you.piety / 20) - (3 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_TRAN_SERPENT_OF_HELL: - invoc = true; - failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4); - break; - - case ABIL_ROTTING: - invoc = true; - failure = 60 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]); - break; - - case ABIL_TORMENT_II: - invoc = true; - failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4); - break; - - case ABIL_RENOUNCE_RELIGION: - invoc = true; - perfect = true; - failure = 0; - break; - - // end invocations {dlb} - default: - failure = -1; - break; - } - - // Perfect abilities are things like "renounce religion", which - // shouldn't have a failure rate ever. -- bwr - if (failure <= 0 && !perfect) - failure = 1; - - if (failure > 100) - failure = 100; - - Curr_abil[slot].fail = failure; - Curr_abil[slot].is_invocation = invoc; - - return (true); -} // end insert_ability() |