diff options
-rw-r--r-- | crawl-ref/source/dat/database/godspeak.txt | 3 | ||||
-rw-r--r-- | crawl-ref/source/mutation.cc | 157 | ||||
-rw-r--r-- | crawl-ref/source/mutation.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/ouch.cc | 23 | ||||
-rw-r--r-- | crawl-ref/source/xom.cc | 120 |
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) |