summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-21 22:35:35 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-21 22:35:35 +0000
commitf9617e163d657219b8e3930f703060e291d05984 (patch)
tree133c9956096f64bb19d5518dd28e791f2380ebfc /crawl-ref/source
parent0480b2a904133ba40129d2effa33f7d638bb95d0 (diff)
downloadcrawl-ref-f9617e163d657219b8e3930f703060e291d05984.tar.gz
crawl-ref-f9617e163d657219b8e3930f703060e291d05984.zip
Improved handling of Xom accidentally killing the player.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7900 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc3
-rw-r--r--crawl-ref/source/dat/database/godspeak.txt4
-rw-r--r--crawl-ref/source/externs.h6
-rw-r--r--crawl-ref/source/ouch.cc12
-rw-r--r--crawl-ref/source/player.cc14
-rw-r--r--crawl-ref/source/xom.cc277
6 files changed, 212 insertions, 104 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index e87e5ab535..02e6422eb7 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -1453,6 +1453,9 @@ static void _input()
religion_turn_start();
check_beholders();
+ // Currently only set if Xom accidentally kills the player.
+ you.reset_escaped_death();
+
if (crawl_state.is_replaying_keys() && crawl_state.is_repeating_cmd()
&& kbhit())
{
diff --git a/crawl-ref/source/dat/database/godspeak.txt b/crawl-ref/source/dat/database/godspeak.txt
index da3291a6ca..b9118d3a4c 100644
--- a/crawl-ref/source/dat/database/godspeak.txt
+++ b/crawl-ref/source/dat/database/godspeak.txt
@@ -352,6 +352,10 @@ Xom accidental homicide
"Oops, I didn't mean to do *that*!"
%%%%
+Xom weird death
+
+"How'd *that* happen? Weird."
+%%%%
Xom resurrection
Xom brings you back to life.
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index a25248dc0d..5ffddad96c 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -950,6 +950,9 @@ public:
PlaceInfo global_info;
player_quiver* m_quiver;
+ int escaped_death_cause;
+ std::string escaped_death_aux;
+
protected:
FixedVector<PlaceInfo, NUM_BRANCHES> branch_info;
FixedVector<PlaceInfo, NUM_LEVEL_AREA_TYPES - 1> non_branch_info;
@@ -1134,6 +1137,9 @@ public:
bool dungeon_only = false) const;
bool do_shaft();
+
+ bool did_escape_death() const;
+ void reset_escaped_death();
};
extern player you;
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 2bdda4bf10..ffe58014e5 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -911,7 +911,10 @@ void ouch(int dam, int death_source, kill_method_type death_type,
&& crawl_state.which_god_acting() == GOD_XOM
&& crawl_state.other_gods_acting().size() == 0)
{
- // Xom should only kill his worhsippers if they're under penance or
+ you.escaped_death_cause = death_type;
+ you.escaped_death_aux = aux == NULL ? "" : aux;
+
+ // Xom should only kill his worshippers if they're under penance or
// Xom is bored.
if (you.religion == GOD_XOM && !you.penance[GOD_XOM]
&& you.gift_timeout > 0)
@@ -920,11 +923,14 @@ void ouch(int dam, int death_source, kill_method_type death_type,
}
// Also don't kill wizards testing Xom acts.
- if (crawl_state.prev_cmd == CMD_WIZARD)
+ if (crawl_state.prev_cmd == CMD_WIZARD && you.religion != GOD_XOM)
return;
+ // Okay, you *didn't* escape death.
+ you.reset_escaped_death();
+
// Ensure some minimal informfullness about Xom's involvment.
- if (aux == NULL)
+ if (aux == NULL || strlen(aux) == 0)
{
if (death_type != KILLED_BY_XOM)
aux = "Xom";
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 1a47d3c4b1..a083d68541 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -5810,6 +5810,9 @@ void player::init()
if (m_quiver)
delete m_quiver;
m_quiver = new player_quiver;
+
+ // Currently only set if Xom accidentally kills the player.
+ reset_escaped_death();
}
player_save_info player_save_info::operator=(const player& rhs)
@@ -7291,3 +7294,14 @@ bool player::do_shaft()
return (true);
}
+
+bool player::did_escape_death() const
+{
+ return (escaped_death_cause != NUM_KILLBY);
+}
+
+void player::reset_escaped_death()
+{
+ escaped_death_cause = NUM_KILLBY;
+ escaped_death_aux = "";
+}
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 4902fb2217..81987e104c 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -706,13 +706,28 @@ static monster_type _xom_random_demon(int sever, bool use_greater_demons = true)
return (demon);
}
+static bool _feat_is_deadly(dungeon_feature_type feat)
+{
+ if (you.airborne())
+ return (false);
+
+ return (feat == DNGN_LAVA || feat == DNGN_DEEP_WATER && !you.can_swim());
+}
+
+static bool _player_is_dead()
+{
+ return (you.hp <= 0 || you.strength <= 0 || you.dex <= 0 || you.intel <= 0
+ || _feat_is_deadly(grd(you.pos()))
+ || you.did_escape_death());
+}
+
// The nicer stuff. Note: these things are not necessarily nice.
static bool _xom_is_good(int sever, int tension)
{
bool done = false;
// Did Xom (already) kill the player?
- if (you.hp <= 0)
+ if (_player_is_dead())
return (true);
god_acting gdact(GOD_XOM);
@@ -1083,9 +1098,13 @@ static bool _xom_is_good(int sever, int tension)
you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION] = 0;
}
- // Don't accidentally kill the player when doing a good
- // act.
- you.hp = std::max(1, you.hp);
+ // Don't accidentally kill the player when doing a good act.
+ if (you.escaped_death_cause == KILLED_BY_WILD_MAGIC
+ && you.escaped_death_aux == "Xom's lightning strike")
+ {
+ you.hp = 1;
+ you.reset_escaped_death();
+ }
done = true;
}
@@ -1116,7 +1135,7 @@ static bool _xom_is_bad(int sever, int tension)
while (!done)
{
// Did Xom kill the player?
- if (you.hp <= 0)
+ if (_player_is_dead())
return (true);
if (x_chance_in_y(3, sever))
@@ -1404,6 +1423,133 @@ static bool _xom_is_bad(int sever, int tension)
return (done);
}
+static char* _stat_ptrs[3] = {&you.strength, &you.intel, &you.dex};
+
+static void _handle_accidental_death(const int orig_hp,
+ const char orig_stats[],
+ const FixedVector<unsigned char, NUM_MUTATIONS> &orig_mutation)
+{
+ // Did ouch() return early because the player died from the Xom effect
+ // even though neither is the player under penance nor is Xom bored?
+
+ if (!you.did_escape_death()
+ && you.escaped_death_aux.empty()
+ && !_player_is_dead())
+ {
+ // Player is fine.
+ return;
+ }
+
+ std::string speech_type = "accidental homicide";
+
+ const dungeon_feature_type feat = grd(you.pos());
+
+ switch(you.escaped_death_cause)
+ {
+ case NUM_KILLBY:
+ case KILLED_BY_LEAVING:
+ case KILLED_BY_WINNING:
+ case KILLED_BY_QUITTING:
+ speech_type = "weird death";
+ break;
+
+ case KILLED_BY_LAVA:
+ case KILLED_BY_WATER:
+ if (!_feat_is_deadly(feat))
+ speech_type = "weird death";
+ break;
+
+ case KILLED_BY_STUPIDITY:
+ if (you.intel > 0)
+ speech_type = "weird death";
+ break;
+
+ case KILLED_BY_WEAKNESS:
+ if (you.strength > 0)
+ speech_type = "weird death";
+ break;
+
+ case KILLED_BY_CLUMSINESS:
+ if (you.dex > 0)
+ speech_type = "weird death";
+ break;
+
+ default:
+ if (_feat_is_deadly(feat))
+ speech_type = "weird death";
+ if (you.strength <= 0 || you.intel <= 0 || you.dex <= 0)
+ speech_type = "weird death";
+ break;
+ }
+
+ mpr("You die...");
+ god_speaks(GOD_XOM, _get_xom_speech(speech_type).c_str());
+ god_speaks(GOD_XOM, _get_xom_speech("resurrection").c_str());
+
+ if (you.hp <= 0)
+ you.hp = std::min(orig_hp, you.hp_max);
+
+ mutation_type dex_muts[5] = {MUT_GREY2_SCALES, MUT_METALLIC_SCALES,
+ MUT_YELLOW_SCALES, MUT_RED2_SCALES,
+ MUT_STRONG_STIFF};
+
+ for (int i = 0; i < 5; ++i)
+ {
+ 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);
+ }
+
+ while (you.strength <= 0
+ && you.mutation[MUT_FLEXIBLE_WEAK] >
+ orig_mutation[MUT_FLEXIBLE_WEAK])
+ {
+ 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);
+ }
+
+ mutation_type bad_muts[3] = { MUT_WEAK, MUT_DOPEY, MUT_CLUMSY };
+ mutation_type good_muts[3] = { MUT_STRONG, MUT_CLEVER, MUT_AGILE };
+
+ 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);
+
+ if (_feat_is_deadly(feat))
+ you.teleport(true);
+}
+
void xom_acts(bool niceness, int sever)
{
#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
@@ -1411,6 +1557,25 @@ void xom_acts(bool niceness, int sever)
niceness, sever, you.piety, you.gift_timeout);
#endif
+#ifdef WIZARD
+ if (_player_is_dead())
+ {
+ // Should only happen if the player used wizard mode to escape from
+ // death via stat loss, or used wizard mode to escape death from
+ // deep water or lava.
+ ASSERT(you.wizard && !you.did_escape_death());
+ if (_feat_is_deadly(grd(you.pos())))
+ mpr("Player is standing in deadly terrain, skipping Xom act.",
+ MSGCH_DIAGNOSTICS);
+ else
+ mpr("Player is already dead, skipping Xom act.",
+ MSGCH_DIAGNOSTICS);
+ return;
+ }
+#else
+ ASSERT(!_player_is_dead());
+#endif
+
entry_cause_type old_entry_cause = you.entry_cause;
sever = std::max(1, sever);
@@ -1441,13 +1606,9 @@ void xom_acts(bool niceness, int sever)
mprf(MSGCH_DIAGNOSTICS, "xom tension: %d", tension);
#endif
- const dungeon_feature_type orig_feat = grd(you.pos());
-
- 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 int orig_hp = you.hp;
+ const char orig_stats[3] = {*(_stat_ptrs[0]), *(_stat_ptrs[1]),
+ *(_stat_ptrs[2])};
const FixedVector<unsigned char, NUM_MUTATIONS> orig_mutation
= you.mutation;
@@ -1465,94 +1626,7 @@ 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};
-
- for (int i = 0; i < 5; ++i)
- {
- 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);
- }
-
- while (you.strength <= 0
- && you.mutation[MUT_FLEXIBLE_WEAK] >
- orig_mutation[MUT_FLEXIBLE_WEAK])
- {
- 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);
- }
-
- mutation_type bad_muts[3] = { MUT_WEAK, MUT_DOPEY, MUT_CLUMSY };
- mutation_type good_muts[3] = { MUT_STRONG, MUT_CLEVER, MUT_AGILE };
-
- 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);
- }
+ _handle_accidental_death(orig_hp, orig_stats, orig_mutation);
// Drawing the Xom card from Nemelex's decks of oddities or punishment.
if (crawl_state.is_god_acting()
@@ -1565,7 +1639,8 @@ void xom_acts(bool niceness, int sever)
}
}
- if (you.religion == GOD_XOM && one_chance_in(2)) {
+ if (you.religion == GOD_XOM && coinflip())
+ {
you.piety = MAX_PIETY - you.piety;
char buf[8192];