summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/abl-show.cc
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-07-20 21:18:13 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-07-20 21:18:13 +0000
commita28741dd2b29142210f64325cb2cb87c806d3409 (patch)
tree611f028941af67538525e535cb3c4f30cb058bf4 /crawl-ref/source/abl-show.cc
parentc917efe2ecd38f449619d7b25160c8053b81e108 (diff)
downloadcrawl-ref-a28741dd2b29142210f64325cb2cb87c806d3409.tar.gz
crawl-ref-a28741dd2b29142210f64325cb2cb87c806d3409.zip
Fix 2822832: temporary brands not being removed when thrown with LRET_FUMBLED
plus: thrown weapon permabrand being removed when DUR_WEAPON_BRAND is active plus: double messaging of "You are now empty-handed." Fix 2810517: Added a pre-ability requirements check that handles Lugonu's enter/exit abyss, berserking, recite, breath attacks and some more. If the requirements aren't met, the check fails before the success check, thus no turn is wasted. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10360 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/abl-show.cc')
-rw-r--r--crawl-ref/source/abl-show.cc315
1 files changed, 186 insertions, 129 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 88fd7e5641..aa6d1604eb 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -963,6 +963,182 @@ bool activate_ability()
return _activate_talent(talents[selected]);
}
+// Check prerequisites for a number of abilities.
+// Abort any attempt if these cannot be met, without losing the turn.
+// TODO: Many more cases need to be added!
+static bool _check_ability_possible(const ability_def& abil,
+ bool hungerCheck = true)
+{
+ // Don't insta-starve the player.
+ // (Happens at 100, losing consciousness possible from 500 downward.)
+ if (hungerCheck && you.species != SP_VAMPIRE)
+ {
+ const int expected_hunger = you.hunger - abil.food_cost * 2;
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS,
+ "hunger: %d, max. food_cost: %d, expected hunger: %d",
+ you.hunger, abil.food_cost * 2, expected_hunger);
+#endif
+ // Safety margin for natural hunger, mutations etc.
+ if (expected_hunger <= 150)
+ {
+ mpr("You're too hungry.");
+ return (false);
+ }
+ }
+
+ switch (abil.ability)
+ {
+ case ABIL_ZIN_RECITE:
+ {
+ const int result = check_recital_audience();
+ if (result < 0)
+ {
+ mpr("There's no appreciative audience!");
+ return (false);
+ }
+ else if (result < 1)
+ {
+ mpr("There's no-one here to preach to!");
+ return (false);
+ }
+ return (true);
+ }
+ case ABIL_ZIN_CURE_ALL_MUTATIONS:
+ return (how_mutated());
+
+ case ABIL_ZIN_SANCTUARY:
+ if (env.sanctuary_time)
+ {
+ mpr("There's already a sanctuary in place on this level.");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_ELYVILON_PURIFICATION:
+ if (!you.disease && !you.rotting && !you.duration[DUR_POISONING]
+ && !you.duration[DUR_CONF] && !you.duration[DUR_SLOW]
+ && !you.duration[DUR_PARALYSIS] && !you.duration[DUR_PETRIFIED])
+ {
+ mpr("Nothing ails you!");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_ELYVILON_RESTORATION:
+ case ABIL_MUMMY_RESTORATION:
+ if (you.strength == you.max_strength
+ && you.intel == you.max_intel
+ && you.dex == you.max_dex
+ && (abil.ability == ABIL_MUMMY_RESTORATION || !player_rotted()))
+ {
+ mprf("You don't need to restore your stats%s!",
+ abil.ability == ABIL_ELYVILON_RESTORATION ? " or hit points"
+ : "");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_LUGONU_ABYSS_EXIT:
+ if (you.level_type != LEVEL_ABYSS)
+ {
+ mpr("You aren't in the Abyss!");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_LUGONU_CORRUPT:
+ return (!is_level_incorruptible());
+
+ case ABIL_LUGONU_ABYSS_ENTER:
+ if (you.level_type == LEVEL_ABYSS)
+ {
+ mpr("You're already here!");
+ return (false);
+ }
+ else if (you.level_type == LEVEL_PANDEMONIUM)
+ {
+ mpr("That doesn't work from Pandemonium.");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_SIF_MUNA_FORGET_SPELL:
+ if (you.spell_no == 0)
+ {
+ mpr("You don't know any spells.");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_SPIT_POISON:
+ case ABIL_BREATHE_FIRE:
+ case ABIL_BREATHE_FROST:
+ case ABIL_BREATHE_POISON:
+ case ABIL_BREATHE_LIGHTNING:
+ case ABIL_BREATHE_POWER:
+ case ABIL_BREATHE_STICKY_FLAME:
+ case ABIL_BREATHE_STEAM:
+ if (you.duration[DUR_BREATH_WEAPON])
+ {
+ canned_msg(MSG_CANNOT_DO_YET);
+ return (false);
+ }
+ return (true);
+
+ case ABIL_EVOKE_BERSERK:
+ case ABIL_TROG_BERSERK:
+ if (you.hunger_state < HS_SATIATED)
+ {
+ mpr("You're too hungry to berserk.");
+ return (false);
+ }
+ return (you.can_go_berserk(true) && berserk_check_wielded_weapon());
+
+ case ABIL_MAPPING:
+ if (player_mutation_level(MUT_MAPPING) < 3
+ && (you.level_type == LEVEL_PANDEMONIUM
+ || !player_in_mappable_area()))
+ {
+ mpr("You feel momentarily disoriented.");
+ return (false);
+ }
+ return (true);
+
+ case ABIL_FLY_II:
+ if (you.duration[DUR_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);
+ }
+ return (true);
+
+ case ABIL_TORMENT:
+ if (you.is_undead)
+ {
+ mpr("The unliving cannot use this ability.");
+ return (false);
+ }
+ return (true);
+
+ 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);
+ }
+ return (true);
+
+ default:
+ return (true);
+ }
+}
+
static bool _activate_talent(const talent& tal)
{
// Doing these would outright kill the player due to stat drain.
@@ -1029,40 +1205,13 @@ static bool _activate_talent(const talent& tal)
return (false);
}
- if (!enough_hp( abil.hp_cost, false ))
+ if (!enough_hp(abil.hp_cost, false))
{
crawl_state.zero_turns_taken();
return (false);
}
- if (tal.which == ABIL_ZIN_SANCTUARY && env.sanctuary_time)
- {
- mpr("There's already a sanctuary in place on this level.");
- crawl_state.zero_turns_taken();
- return (false);
- }
-
- // Don't insta-starve the player.
- // (Happens at 100, losing consciousness possible from 500 downward.)
- if (hungerCheck && you.species != SP_VAMPIRE)
- {
- const int expected_hunger = you.hunger - abil.food_cost * 2;
-#ifdef DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS,
- "hunger: %d, max. food_cost: %d, expected hunger: %d",
- you.hunger, abil.food_cost * 2, expected_hunger);
-#endif
- // Safety margin for natural hunger, mutations etc.
- if (expected_hunger <= 150)
- {
- mpr("You're too hungry.");
- crawl_state.zero_turns_taken();
- return (false);
- }
- }
-
- if ((tal.which == ABIL_EVOKE_BERSERK || tal.which == ABIL_TROG_BERSERK)
- && !berserk_check_wielded_weapon())
+ if (!_check_ability_possible(abil, hungerCheck))
{
crawl_state.zero_turns_taken();
return (false);
@@ -1159,12 +1308,6 @@ static bool _do_ability(const ability_def& abil)
case ABIL_SPIT_POISON: // Naga + spit poison mutation
{
- if (you.duration[DUR_BREATH_WEAPON])
- {
- canned_msg(MSG_CANNOT_DO_YET);
- return (false);
- }
-
const int pow = you.experience_level
+ player_mutation_level(MUT_SPIT_POISON) * 5
+ (you.species == SP_NAGA) * 10;
@@ -1184,15 +1327,6 @@ static bool _do_ability(const ability_def& abil)
}
case ABIL_EVOKE_MAPPING: // Randarts
case ABIL_MAPPING: // Sense surroundings mutation
- if (abil.ability == ABIL_MAPPING
- && player_mutation_level(MUT_MAPPING) < 3
- && (you.level_type == LEVEL_PANDEMONIUM
- || !player_in_mappable_area()))
- {
- mpr("You feel momentarily disoriented.");
- return (false);
- }
-
power = (abil.ability == ABIL_EVOKE_MAPPING) ?
you.skills[SK_EVOCATIONS] : you.experience_level;
@@ -1229,17 +1363,9 @@ static bool _do_ability(const ability_def& abil)
case ABIL_BREATHE_POWER:
case ABIL_BREATHE_STICKY_FLAME:
case ABIL_BREATHE_STEAM:
- if (you.duration[DUR_BREATH_WEAPON] && abil.ability != ABIL_SPIT_ACID)
- {
- canned_msg(MSG_CANNOT_DO_YET);
+ beam.range = _calc_breath_ability_range(abil.ability);
+ if (!spell_direction(abild, beam))
return (false);
- }
- else
- {
- beam.range = _calc_breath_ability_range(abil.ability);
- if (!spell_direction(abild, beam))
- return (false);
- }
switch (abil.ability)
{
@@ -1336,20 +1462,8 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_EVOKE_BERSERK: // amulet of rage, randarts
- // FIXME: This is not the best way to do stuff, because
- // you have a chance of failing the evocation test, in
- // which case you'll lose MP, etc.
- // We should add a pre-failure-test check in general.
- if (you.hunger_state < HS_SATIATED)
- {
- mpr("You're too hungry to berserk.");
- return (false);
- }
- else if (!you.can_go_berserk(true))
- return (false);
-
- // only exercise if berserk succeeds
- // because of the test above, this should always happen,
+ // Only exercise if berserk succeeds.
+ // Because of the test above, this should always happen,
// but I'm leaving it in - haranp
if (go_berserk(true))
exercise(SK_EVOCATIONS, 1);
@@ -1365,18 +1479,7 @@ static bool _do_ability(const ability_def& abil)
// Fly (Draconians, or anything else with wings).
case ABIL_FLY_II:
- if (you.duration[DUR_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);
+ cast_fly(you.experience_level * 2);
break;
// DEMONIC POWERS:
@@ -1395,12 +1498,6 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_TORMENT:
- if (you.is_undead)
- {
- mpr("The unliving cannot use this ability.");
- return (false);
- }
-
torment(TORMENT_GENERIC, you.pos());
break;
@@ -1448,12 +1545,6 @@ static bool _do_ability(const ability_def& abil)
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), true );
exercise(SK_EVOCATIONS, 1);
@@ -1487,17 +1578,6 @@ static bool _do_ability(const ability_def& abil)
case ABIL_ZIN_RECITE:
{
- int result = check_recital_audience();
- if (result < 0)
- {
- mpr("There's no appreciative audience!");
- return (false);
- }
- else if (result < 1)
- {
- mpr("There's no-one here to preach to!");
- return (false);
- }
// up to (60 + 40)/2 = 50
const int pow = (2*skill_bump(SK_INVOCATIONS) + you.piety / 5) / 2;
start_delay(DELAY_RECITE, 3, pow, you.hp);
@@ -1707,12 +1787,6 @@ static bool _do_ability(const ability_def& abil)
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;
@@ -1729,7 +1803,8 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_SIF_MUNA_FORGET_SPELL:
- cast_selective_amnesia(true);
+ if (!cast_selective_amnesia(true))
+ return (false);
break;
case ABIL_ELYVILON_DESTROY_WEAPONS:
@@ -1787,12 +1862,6 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_LUGONU_ABYSS_EXIT:
- if (you.level_type != LEVEL_ABYSS)
- {
- mpr("You aren't in the Abyss!");
- return (false); // Don't incur costs.
- }
-
banished(DNGN_EXIT_ABYSS);
exercise(SK_INVOCATIONS, 8 + random2(10));
break;
@@ -1830,17 +1899,6 @@ static bool _do_ability(const ability_def& abil)
case ABIL_LUGONU_ABYSS_ENTER:
{
- if (you.level_type == LEVEL_ABYSS)
- {
- mpr("You're already here.");
- return (false);
- }
- else if (you.level_type == LEVEL_PANDEMONIUM)
- {
- mpr("That doesn't work from Pandemonium.");
- return (false);
- }
-
// Move permanent hp/mp loss from leaving to entering the Abyss. (jpeg)
const int maxloss = std::max(2, div_rand_round(you.hp_max, 30));
// Lose permanent HP
@@ -1927,7 +1985,6 @@ static bool _do_ability(const ability_def& abil)
break;
}
case ABIL_FEAWN_SUNLIGHT:
-
if (!sunlight())
return (false);
@@ -1942,7 +1999,7 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_FEAWN_RAIN:
- rain(you.pos() );
+ rain(you.pos());
exercise(SK_INVOCATIONS, 2 + random2(3));
break;