summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/dat/database/godspeak.txt3
-rw-r--r--crawl-ref/source/mutation.cc157
-rw-r--r--crawl-ref/source/mutation.h5
-rw-r--r--crawl-ref/source/ouch.cc23
-rw-r--r--crawl-ref/source/xom.cc120
5 files changed, 257 insertions, 51 deletions
diff --git a/crawl-ref/source/dat/database/godspeak.txt b/crawl-ref/source/dat/database/godspeak.txt
index 8c029bfaee..da3291a6ca 100644
--- a/crawl-ref/source/dat/database/godspeak.txt
+++ b/crawl-ref/source/dat/database/godspeak.txt
@@ -351,6 +351,9 @@ You hear Xom's avuncular chuckle.
Xom accidental homicide
"Oops, I didn't mean to do *that*!"
+%%%%
+Xom resurrection
+
Xom brings you back to life.
%%%%
############################################
diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc
index 214b5414c6..ee902d24c2 100644
--- a/crawl-ref/source/mutation.cc
+++ b/crawl-ref/source/mutation.cc
@@ -1613,7 +1613,113 @@ static int calc_mutation_amusement_value(mutation_type which_mutation)
return (amusement);
}
-static bool accept_mutation(mutation_type mutat, bool ignore_rarity = false)
+static bool _is_deadly(mutation_type mutat, bool delete_mut)
+{
+ if (delete_mut)
+ {
+ // First handle non-stat related problems.
+ if ( mutat == MUT_HEAT_RESISTANCE && grd(you.pos()) == DNGN_LAVA
+ && player_res_fire() == 1 && !you.airborne() )
+ {
+ // Don't let player instantly fry to a crisp in lava.
+ return (true);
+ }
+
+ // Swap things around to the same effect, but as if we were gaining
+ // a mutation, or return early if deleting the mutation is never
+ // a problem.
+ switch(mutat)
+ {
+ case MUT_GREY2_SCALES:
+ case MUT_METALLIC_SCALES:
+ case MUT_YELLOW_SCALES:
+ case MUT_RED2_SCALES:
+ case MUT_WEAK:
+ case MUT_DOPEY:
+ case MUT_CLUMSY:
+ return (false);
+
+ case MUT_STRONG_STIFF:
+ mutat = MUT_FLEXIBLE_WEAK;
+ break;
+
+ case MUT_FLEXIBLE_WEAK:
+ mutat = MUT_STRONG_STIFF;
+ break;
+
+ case MUT_STRONG:
+ mutat = MUT_WEAK;
+ break;
+
+ case MUT_CLEVER:
+ mutat = MUT_DOPEY;
+ break;
+
+ case MUT_AGILE:
+ mutat = MUT_CLUMSY;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ unsigned char cur_level = you.mutation[mutat];
+
+ char *stat_ptr = &you.dex; // Default for the scales.
+ char amnt = 1;
+ char mod = 0;
+
+ switch(mutat)
+ {
+ case MUT_GREY2_SCALES:
+ if (cur_level == 0 || cur_level == 2)
+ amnt = 1;
+ else
+ amnt = 0;
+ break;
+
+ case MUT_METALLIC_SCALES:
+ if (cur_level == 0)
+ amnt = 2;
+ else
+ amnt = 1;
+ break;
+
+ case MUT_YELLOW_SCALES:
+ case MUT_RED2_SCALES:
+ if (cur_level == 0)
+ amnt = 0;
+ else
+ amnt = 1;
+ break;
+
+ case MUT_FLEXIBLE_WEAK:
+ case MUT_WEAK:
+ stat_ptr = &you.strength;
+ // Take might into account so we don't lower base strength below
+ // one.
+ if (you.duration[DUR_MIGHT])
+ mod = -5;
+ break;
+
+ case MUT_DOPEY:
+ stat_ptr = &you.intel;
+
+ case MUT_STRONG_STIFF:
+ case MUT_CLUMSY:
+ stat_ptr = &you.dex;
+ break;
+
+ default:
+ return (false);
+ }
+
+ return (amnt >= (*stat_ptr + mod));
+}
+
+static bool accept_mutation(mutation_type mutat, bool ignore_rarity = false,
+ bool non_fatal = false, bool delete_mut = false)
{
if (mutat == RANDOM_MUTATION
|| mutation_defs[mutat].mutation == RANDOM_MUTATION)
@@ -1621,9 +1727,17 @@ static bool accept_mutation(mutation_type mutat, bool ignore_rarity = false)
return (false);
}
+ if (delete_mut)
+ {
+ return (!non_fatal || !_is_deadly(mutat, delete_mut));
+ }
+
if (you.mutation[mutat] >= mutation_defs[mutat].levels)
return (false);
+ if (non_fatal && _is_deadly(mutat, delete_mut))
+ return (false);
+
if (ignore_rarity)
return (true);
@@ -1633,7 +1747,7 @@ static bool accept_mutation(mutation_type mutat, bool ignore_rarity = false)
return (x_chance_in_y(rarity, 10));
}
-static mutation_type get_random_xom_mutation()
+static mutation_type get_random_xom_mutation(bool non_fatal = false)
{
mutation_type mutat = NUM_MUTATIONS;
do
@@ -1657,13 +1771,14 @@ static mutation_type get_random_xom_mutation()
}
}
}
- while (!accept_mutation(mutat));
+ while (!accept_mutation(mutat, false, non_fatal));
return (mutat);
}
static mutation_type get_random_mutation(bool prefer_good,
- int preferred_multiplier)
+ int preferred_multiplier,
+ bool non_fatal = false)
{
int cweight = 0;
mutation_type chosen = NUM_MUTATIONS;
@@ -1673,7 +1788,7 @@ static mutation_type get_random_mutation(bool prefer_good,
continue;
const mutation_type curr = static_cast<mutation_type>(i);
- if (!accept_mutation(curr, true))
+ if (!accept_mutation(curr, true, non_fatal))
continue;
const bool weighted = mutation_defs[i].bad != prefer_good;
@@ -1689,10 +1804,20 @@ static mutation_type get_random_mutation(bool prefer_good,
return (chosen);
}
+static bool _is_random(mutation_type which_mutation)
+{
+ return (which_mutation == RANDOM_MUTATION
+ || which_mutation == RANDOM_XOM_MUTATION
+ || which_mutation == RANDOM_GOOD_MUTATION
+ || which_mutation == RANDOM_BAD_MUTATION);
+}
+
bool mutate(mutation_type which_mutation, bool failMsg,
- bool force_mutation, bool god_gift,
- bool stat_gain_potion, bool demonspawn)
+ bool force_mutation, bool god_gift, bool stat_gain_potion,
+ bool demonspawn, bool non_fatal)
{
+ ASSERT(!non_fatal || _is_random(which_mutation));
+
if (demonspawn)
force_mutation = true;
@@ -1788,7 +1913,8 @@ bool mutate(mutation_type which_mutation, bool failMsg,
if (!one_chance_in(3) && !god_gift && !force_mutation)
return (false);
else
- return (delete_mutation(RANDOM_MUTATION));
+ return (delete_mutation(RANDOM_MUTATION, failMsg,
+ force_mutation, non_fatal));
}
}
@@ -1800,21 +1926,23 @@ bool mutate(mutation_type which_mutation, bool failMsg,
if (one_chance_in(1000))
return (false);
}
- while (!accept_mutation(mutat));
+ while (!accept_mutation(mutat, false, non_fatal));
}
else if (which_mutation == RANDOM_XOM_MUTATION)
{
- if ((mutat = get_random_xom_mutation()) == NUM_MUTATIONS)
+ if ((mutat = get_random_xom_mutation(non_fatal)) == NUM_MUTATIONS)
return (false);
}
else if (which_mutation == RANDOM_GOOD_MUTATION)
{
- if ((mutat = get_random_mutation(true, 500)) == NUM_MUTATIONS)
+ mutat = get_random_mutation(true, 500, non_fatal);
+ if (mutat == NUM_MUTATIONS)
return (false);
}
else if (which_mutation == RANDOM_BAD_MUTATION)
{
- if ((mutat = get_random_mutation(false, 500)) == NUM_MUTATIONS)
+ mutat = get_random_mutation(false, 500, non_fatal);
+ if (mutat == NUM_MUTATIONS)
return (false);
}
@@ -2219,8 +2347,10 @@ bool mutate(mutation_type which_mutation, bool failMsg,
}
bool delete_mutation(mutation_type which_mutation, bool failMsg,
- bool force_mutation)
+ bool force_mutation, bool non_fatal)
{
+ ASSERT(!non_fatal || _is_random(which_mutation));
+
mutation_type mutat = which_mutation;
if (!force_mutation)
@@ -2251,6 +2381,7 @@ bool delete_mutation(mutation_type which_mutation, bool failMsg,
&& mutat != MUT_AGILE)
&& (mutat != MUT_WEAK && mutat != MUT_DOPEY
&& mutat != MUT_CLUMSY))
+ || !accept_mutation(mutat, true, non_fatal, true)
|| random2(10) >= mutation_defs[mutat].rarity
|| you.demon_pow[mutat] >= you.mutation[mutat]
|| (which_mutation == RANDOM_GOOD_MUTATION
diff --git a/crawl-ref/source/mutation.h b/crawl-ref/source/mutation.h
index b49e2c2110..fb28c16378 100644
--- a/crawl-ref/source/mutation.h
+++ b/crawl-ref/source/mutation.h
@@ -34,7 +34,8 @@ void fixup_mutations();
* *********************************************************************** */
bool mutate(mutation_type which_mutation, bool failMsg = true,
bool force_mutation = false, bool god_gift = false,
- bool stat_gain_potion = false, bool demonspawn = false);
+ bool stat_gain_potion = false, bool demonspawn = false,
+ bool non_fatal = false);
// last updated 12may2000 {dlb}
/* ***********************************************************************
@@ -52,7 +53,7 @@ formatted_string describe_mutations();
* called from: decks - it_use2 - mutation - spells
* *********************************************************************** */
bool delete_mutation(mutation_type which_mutation, bool failMsg = true,
- bool force_mutation = false);
+ bool force_mutation = false, bool non_fatal = false);
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index be12b7db79..2779920550 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -896,20 +896,31 @@ void ouch(int dam, int death_source, kill_method_type death_type,
} // else hp <= 0
}
+ // Is the player being killed by a direct act of Xom?
if (crawl_state.is_god_acting()
&& crawl_state.which_god_acting() == GOD_XOM
&& crawl_state.other_gods_acting().size() == 0)
{
- if (aux == NULL || strstr(aux, "Xom") == NULL)
- death_type = KILLED_BY_XOM;
-
- // Xom should only cause death if the player is under penance or
+ // Xom should only kill his worhsippers if they're under penance or
// Xom is bored.
- if (!you.penance[GOD_XOM]
- && !(you.religion == GOD_XOM && you.gift_timeout == 0))
+ if (you.religion == GOD_XOM && !you.penance[GOD_XOM]
+ && you.gift_timeout > 0)
{
return;
}
+
+ // Also don't kill wizards testing Xom acts.
+ if (crawl_state.prev_cmd == CMD_WIZARD)
+ return;
+
+ // Ensure some minimal informfullness about Xom's involvment.
+ if (aux == NULL)
+ {
+ if (death_type != KILLED_BY_XOM)
+ aux = "Xom";
+ }
+ else if(strstr(aux, "Xom") == NULL)
+ death_type = KILLED_BY_XOM;
}
// Construct scorefile entry.
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 834aef0fec..28d0f3dbcc 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -1002,8 +1002,11 @@ static bool _xom_is_good(int sever)
for (int i = random2(4); i >= 0; --i)
{
- if (mutate(RANDOM_GOOD_MUTATION, failMsg, false, true))
+ if (mutate(RANDOM_GOOD_MUTATION, failMsg, false, true, false,
+ false, true))
+ {
done = true;
+ }
else
failMsg = false;
}
@@ -1051,9 +1054,6 @@ static bool _xom_is_good(int sever)
{
if (you.hp <= random2(201))
you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 1;
- else
- // Make sure we don't directly kill the player.
- you.hp += 90;
god_speaks(GOD_XOM, "The area is suffused with divine lightning!");
@@ -1077,11 +1077,10 @@ static bool _xom_is_good(int sever)
mpr("Your divine protection wanes.");
you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0;
}
- else
- {
- you.hp -= 90;
- you.hp = std::max(1, you.hp);
- }
+
+ // Don't accidentally kill the player when doing a good
+ // act.
+ you.hp = std::max(1, you.hp);
done = true;
}
@@ -1229,8 +1228,11 @@ static bool _xom_is_bad(int sever)
for (int i = random2(4); i >= 0; --i)
{
- if (mutate(RANDOM_XOM_MUTATION, failMsg, false, true))
+ if (mutate(RANDOM_XOM_MUTATION, failMsg, false, true,
+ false, false, !nasty))
+ {
done = true;
+ }
else
failMsg = false;
}
@@ -1412,12 +1414,16 @@ void xom_acts(bool niceness, int sever)
}
}
- int orig_hp = you.hp;
- int orig_str = you.strength;
- int orig_dex = you.dex;
- int orig_int = you.intel;
+ const dungeon_feature_type orig_feat = grd(you.pos());
- FixedVector<unsigned char, NUM_MUTATIONS> orig_mutation = you.mutation;
+ const int orig_hp = you.hp;
+
+ char* stat_ptrs[3] = {&you.strength, &you.intel, &you.dex};
+ const char orig_stats[3] = {*(stat_ptrs[0]), *(stat_ptrs[1]),
+ *(stat_ptrs[2])};
+
+ const FixedVector<unsigned char, NUM_MUTATIONS> orig_mutation
+ = you.mutation;
if (niceness && !one_chance_in(5))
{
@@ -1432,41 +1438,95 @@ void xom_acts(bool niceness, int sever)
;
}
+ bool already_oopsed = false;
if (you.hp <= 0 || you.strength <= 0 || you.dex <= 0 || you.intel <= 0)
{
// ouch() returned early because the player died from the Xom effect
// even though neither is the player under penance nor is Xom bored.
mpr("You die...");
god_speaks(GOD_XOM, _get_xom_speech("accidental homicide").c_str());
+ god_speaks(GOD_XOM, _get_xom_speech("resurrection").c_str());
+
+ already_oopsed = true;
+
+ if (you.hp <= 0)
+ you.hp = orig_hp;
+
+ mutation_type dex_muts[5] = {MUT_GREY2_SCALES, MUT_METALLIC_SCALES,
+ MUT_YELLOW_SCALES, MUT_RED2_SCALES,
+ MUT_STRONG_STIFF};
- int changes = 0;
- for (int i = 0; i < NUM_MUTATIONS; i++)
+ for (int i = 0; i < 5; i++)
{
- if (orig_mutation[i] != you.mutation[i])
- changes++;
+ mutation_type bad = dex_muts[i];
+
+ while (you.dex <= 0 && you.mutation[bad] > orig_mutation[bad])
+ delete_mutation(bad, true, true);
+ }
+ while(you.dex <= 0
+ && you.mutation[MUT_FLEXIBLE_WEAK] <
+ orig_mutation[MUT_FLEXIBLE_WEAK])
+ {
+ mutate(MUT_FLEXIBLE_WEAK, true, true, true);
}
- if (changes > 0)
+ while (you.strength <= 0
+ && you.mutation[MUT_FLEXIBLE_WEAK] >
+ orig_mutation[MUT_FLEXIBLE_WEAK])
{
- std::string str = "Xom undoes your latest mutation";
- if (changes > 1)
- str += "s";
- str += ".";
- god_speaks(GOD_XOM, str.c_str());
+ delete_mutation(MUT_FLEXIBLE_WEAK, true, true);
+ }
+ while (you.strength <= 0
+ && you.mutation[MUT_STRONG_STIFF] <
+ orig_mutation[MUT_STRONG_STIFF])
+ {
+ mutate(MUT_STRONG_STIFF, true, true, true);
}
- you.mutation = orig_mutation;
+ mutation_type bad_muts[3] = { MUT_WEAK, MUT_DOPEY, MUT_CLUMSY };
+ mutation_type good_muts[3] = { MUT_STRONG, MUT_CLEVER, MUT_AGILE };
- you.hp = orig_hp;
- you.strength = orig_str;
- you.dex = orig_dex;
- you.intel = orig_int;
+ for (int i = 0; i < 3; i++)
+ {
+ while (*(stat_ptrs[i]) <= 0)
+ {
+ mutation_type good = good_muts[i];
+ mutation_type bad = bad_muts[i];
+ if (you.mutation[bad] > orig_mutation[bad]
+ || you.mutation[good] < orig_mutation[good])
+ {
+ mutate(good, true, true, true);
+ }
+ else
+ {
+ *(stat_ptrs[i]) = orig_stats[i];
+ break;
+ }
+ }
+ }
you.max_strength = std::max(you.max_strength, you.strength);
you.max_intel = std::max(you.max_intel, you.intel);
you.max_dex = std::max(you.max_dex, you.dex);
}
+ // Or maybe Xom accidentally tossed you in deep water or lava.
+ dungeon_feature_type feat = grd(you.pos());
+ if (feat != orig_feat && !you.airborne()
+ && (feat == DNGN_DEEP_WATER && !you.swimming()
+ || feat == DNGN_LAVA && player_res_fire() <= 0))
+ {
+ if (!already_oopsed)
+ {
+ mpr("You die...");
+ god_speaks(GOD_XOM,
+ _get_xom_speech("accidental homicide").c_str());
+ god_speaks(GOD_XOM, _get_xom_speech("resurrection").c_str());
+ }
+
+ you.teleport(true);
+ }
+
// Drawing the Xom card from Nemelex's decks of oddities or punishment.
if (crawl_state.is_god_acting()
&& crawl_state.which_god_acting() != GOD_XOM)