From e5c35dd08e149f985c77be908cfc3e9c69f2d13e Mon Sep 17 00:00:00 2001 From: Stefan O'Rear Date: Sat, 24 Oct 2009 22:12:10 -0700 Subject: Roll demonspawn mutations at the start of the game. All demonspawn mutations are now stored in the player data, and are determined at the same time. This makes a lot of things a lot simpler. On the other hand, it means that the influence of skills and gods on demonspawn mutations is now broken. --- crawl-ref/source/acr.cc | 1 - crawl-ref/source/command.cc | 1 - crawl-ref/source/debug.cc | 33 ++------ crawl-ref/source/mutation.cc | 174 ++++++++++++++++++------------------------- crawl-ref/source/mutation.h | 2 +- crawl-ref/source/newgame.cc | 4 + crawl-ref/source/player.cc | 13 ++-- crawl-ref/source/player.h | 3 + crawl-ref/source/tags.cc | 13 ++++ crawl-ref/source/tags.h | 3 +- 10 files changed, 107 insertions(+), 140 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 59294d07f9..d2177f662c 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -514,7 +514,6 @@ static void _do_wizard_command(int wiz_command, bool silent_fail) case 'Z': wizard_cast_spec_spell_name(); break; case '(': wizard_create_feature_number(); break; case ')': wizard_create_feature_name(); break; - case '[': demonspawn(); break; case ':': wizard_list_branches(); break; case '{': wizard_map_level(); break; case '@': wizard_set_stats(); break; diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index d6ec426f20..d66b8c1726 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -2378,7 +2378,6 @@ int list_wizard_commands(bool do_redraw_screen) "Ctrl-L : change experience level\n" "$ : get 1000 gold\n" "] : get a mutation\n" - "[ : get a demonspawn mutation\n" "^ : gain piety\n" "_ : gain religion\n" "@ : set Str Int Dex\n" diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index f1097def10..4aa9b6f07e 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -278,7 +278,6 @@ void wizard_change_species( void ) // Change permanent mutations, but preserve non-permanent ones. unsigned char prev_muts[NUM_MUTATIONS]; - you.attribute[ATTR_NUM_DEMONIC_POWERS] = 0; for (i = 0; i < NUM_MUTATIONS; ++i) { if (you.demon_pow[i] > 0) @@ -326,33 +325,17 @@ void wizard_change_species( void ) case SP_DEMONSPAWN: { - int powers = 0; - - if (you.experience_level < 4) - powers = 0; - else if (you.experience_level < 9) - powers = 1; - else if (you.experience_level < 14) - powers = 2; - else if (you.experience_level < 19) - powers = 3; - else if (you.experience_level < 24) - powers = 4; - else if (you.experience_level == 27) - powers = 5; + roll_demonspawn_mutations(); + for (i = 2; i <= you.experience_level; ++i) + { + mutation_type m = you.demon_trait[i-2]; - int levels[] = {4, 9, 14, 19, 27}; - int real_level = you.experience_level; + if (m == NUM_MUTATIONS) + continue; - for (i = 0; i < powers; ++i) - { - // The types of demonspawn mutations you get depends on your - // experience level at the time of gaining it. - you.experience_level = levels[i]; - demonspawn(); + ++you.mutation[m]; + ++you.demon_pow[m]; } - you.experience_level = real_level; - break; } diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc index d1fa19613f..d792aab732 100644 --- a/crawl-ref/source/mutation.cc +++ b/crawl-ref/source/mutation.cc @@ -2644,17 +2644,13 @@ std::string mutation_name(mutation_type mut, int level, bool colour) return (result); } -// Use an attribute counter for how many demonic mutations a demonspawn has. -void demonspawn() +static mutation_type _demonspawn(FixedVector& muts, int& powers, + int level) { mutation_type whichm = NUM_MUTATIONS; int counter = 0; - const int covered = _body_covered(); - - you.attribute[ATTR_NUM_DEMONIC_POWERS]++; - - mpr("Your demonic ancestry asserts itself...", MSGCH_INTRINSIC_GAIN); + powers++; // A demonspawn logically has six mutation slots, like [cold res, // negative res, teleport, black scales, mapping, repulsion field]. @@ -2674,14 +2670,14 @@ void demonspawn() { whichm = static_cast(i); - if (! you.demon_pow[whichm]) + if (! muts[whichm]) { continue; } ++muts_seen; - if (you.demon_pow[whichm] < mutation_defs[whichm].levels) + if (muts[whichm] < mutation_defs[whichm].levels) { ++increasable_muts_seen; @@ -2719,28 +2715,9 @@ void demonspawn() { const mutation_def& mdef = mutation_defs[mut_to_increase]; - ASSERT(you.demon_pow[mut_to_increase] < mdef.levels); - - if (you.mutation[mut_to_increase] == mdef.levels) - { - // The player has our mutation as a temporary thing. Make - // it permanent. I want to put something like NetHack's "Your - // quickness feels more natural" here, but there doesn't seem - // to be a good way to do that. - mpr(mdef.gain[you.demon_pow[mut_to_increase]], MSGCH_MUTATION); - ++you.demon_pow[mut_to_increase]; - } - else - { - // None of the current demonspawn mutations is capable of - // failing. Be very careful if others are added; for instance, - // talons can fail to mutate if the player already has hooves. - // You'll need to add a case for clearing mutations in - // _handle_conflicting_mutations above. - ASSERT(perma_mutate(mut_to_increase, 1)); - } + ASSERT(muts[mut_to_increase] < mdef.levels); - return; + return mut_to_increase; } // Otherwise we're adding a brand new mutation @@ -2750,22 +2727,20 @@ void demonspawn() // if it's having trouble with the high level list. do { - if (you.experience_level >= 10) + if (level >= 10) { - if (you.skills[SK_CONJURATIONS] < 5) + if (1) { // good conjurers don't get bolt of draining whichm = MUT_SMITE; } - if (you.skills[SK_CONJURATIONS] < 10 && one_chance_in(4)) + if (one_chance_in(4)) { // good conjurers don't get hellfire whichm = MUT_HURL_HELLFIRE; } // Makhlebites have the summonings invocation - if ((you.religion != GOD_MAKHLEB || - you.piety < piety_breakpoint(3)) && - you.skills[SK_SUMMONINGS] < 5 && one_chance_in(3)) + if (one_chance_in(3)) { // good summoners don't get summon demon whichm = MUT_SUMMON_DEMONS; } @@ -2795,7 +2770,7 @@ void demonspawn() whichm = MUT_SHOCK_RESISTANCE; } - if (!you.mutation[MUT_CALL_TORMENT] && one_chance_in(15)) + if (!muts[MUT_CALL_TORMENT] && one_chance_in(15)) { whichm = MUT_TORMENT_RESISTANCE; } @@ -2805,89 +2780,56 @@ void demonspawn() whichm = MUT_NEGATIVE_ENERGY_RESISTANCE; } - if (!you.mutation[MUT_TORMENT_RESISTANCE] && one_chance_in(20)) + if (!muts[MUT_TORMENT_RESISTANCE] && one_chance_in(20)) { whichm = MUT_CALL_TORMENT; } - if (you.skills[SK_SUMMONINGS] < 5 && you.skills[SK_NECROMANCY] < 5 - && one_chance_in(12)) + if (one_chance_in(12)) { whichm = MUT_CONTROL_DEMONS; } - if (you.religion != GOD_MAKHLEB && one_chance_in(11)) + if (one_chance_in(11)) { whichm = MUT_DEATH_STRENGTH; } - // Theoretically, you could use this with Trog (for rods and - // some misc. items), but in general it's going to be much more - // useful for someone capable of casting spells. - if (you.religion != GOD_TROG - && you.religion != GOD_SIF_MUNA && one_chance_in(11)) + if (one_chance_in(11)) { whichm = MUT_CHANNEL_HELL; } - // Yredelemnulites have the raise dead invocation - if (you.religion != GOD_YREDELEMNUL - && you.skills[SK_SUMMONINGS] < 3 - && you.skills[SK_NECROMANCY] < 3 && one_chance_in(10)) + if (one_chance_in(10)) { whichm = MUT_RAISE_DEAD; } - if (you.skills[SK_UNARMED_COMBAT] > 5) + if (one_chance_in(25)) { - // Drain Life only works if you're unarmed, so only - // give it if unarmed is your best attacking skill. - skill_type wpn_skill = best_skill(SK_SHORT_BLADES, SK_STAVES); - if ((you.skills[SK_UNARMED_COMBAT] > you.skills[wpn_skill]) - && one_chance_in(14)) - { - whichm = MUT_DRAIN_LIFE; - } + whichm = MUT_DRAIN_LIFE; } } // check here so we can see if we need to extend our options - if (whichm != NUM_MUTATIONS && you.mutation[whichm] != 0) + if (whichm != NUM_MUTATIONS && muts[whichm] != 0) whichm = NUM_MUTATIONS; - if (you.experience_level < 10 + if (level < 10 || (counter > 0 && whichm == NUM_MUTATIONS)) { - if ((!you.mutation[MUT_THROW_FROST] // only one of these - && !you.mutation[MUT_THROW_FLAMES] - && !you.mutation[MUT_BREATHE_FLAMES]) - && (!you.skills[SK_CONJURATIONS] // conjurers seldomly - || one_chance_in(5)) - // Makhlebites seldom - && (you.religion != GOD_MAKHLEB || one_chance_in(4)) - && (!you.skills[SK_ICE_MAGIC] // already ice & fire? - || !you.skills[SK_FIRE_MAGIC])) + if (!muts[MUT_THROW_FROST] // only one of these + && !muts[MUT_THROW_FLAMES] + && !muts[MUT_BREATHE_FLAMES]) { - // try to give the flavour the character doesn't have - - // neither - if (!you.skills[SK_FIRE_MAGIC] && !you.skills[SK_ICE_MAGIC]) - whichm = (coinflip() ? MUT_THROW_FLAMES : MUT_THROW_FROST); - else if (!you.skills[SK_FIRE_MAGIC]) - whichm = MUT_THROW_FLAMES; - else if (!you.skills[SK_ICE_MAGIC]) - whichm = MUT_THROW_FROST; - // both - else - whichm = (coinflip() ? MUT_THROW_FLAMES : MUT_THROW_FROST); + whichm = (coinflip() ? MUT_THROW_FLAMES : MUT_THROW_FROST); } // summoners and Makhlebites don't get summon imp - if (!you.skills[SK_SUMMONINGS] && you.religion != GOD_MAKHLEB - && one_chance_in(3)) + if (one_chance_in(3)) { - whichm = (you.experience_level < 10) ? MUT_SUMMON_MINOR_DEMONS - : MUT_SUMMON_DEMONS; + whichm = (level < 10) ? MUT_SUMMON_MINOR_DEMONS + : MUT_SUMMON_DEMONS; } if (one_chance_in(4)) @@ -2910,7 +2852,7 @@ void demonspawn() whichm = MUT_ACUTE_VISION; } - if (!you.skills[SK_POISON_MAGIC] && one_chance_in(7)) + if (one_chance_in(7)) { whichm = MUT_SPIT_POISON; } @@ -2925,22 +2867,21 @@ void demonspawn() whichm = MUT_TELEPORT_CONTROL; } - if (!you.mutation[MUT_THROW_FROST] // not with these - && !you.mutation[MUT_THROW_FLAMES] - && !you.mutation[MUT_BREATHE_FLAMES] - && !you.skills[SK_FIRE_MAGIC] // or with fire already + if (!muts[MUT_THROW_FROST] // not with these + && !muts[MUT_THROW_FLAMES] + && !muts[MUT_BREATHE_FLAMES] && one_chance_in(5)) { whichm = MUT_BREATHE_FLAMES; } - if (!you.skills[SK_TRANSLOCATIONS] && one_chance_in(12)) + if (one_chance_in(12)) { - whichm = (you.experience_level < 10) ? MUT_BLINK - : MUT_TELEPORT_AT_WILL; + whichm = (level < 10) ? MUT_BLINK + : MUT_TELEPORT_AT_WILL; } - if (covered < 3 && one_chance_in( 1 + covered * 5 )) + if (1) { if (one_chance_in(10)) { @@ -2979,26 +2920,53 @@ void demonspawn() whichm = MUT_REPULSION_FIELD; } - if (one_chance_in( (you.experience_level < 10) ? 5 : 20 )) + if (one_chance_in( (level < 10) ? 5 : 20 )) { whichm = MUT_HORNS; } } - if (whichm != NUM_MUTATIONS && you.mutation[whichm] != 0) + if (whichm != NUM_MUTATIONS && muts[whichm] != 0) whichm = NUM_MUTATIONS; counter++; } while (whichm == NUM_MUTATIONS && counter < 5000); - if (whichm == NUM_MUTATIONS || !perma_mutate( whichm, 1 )) + if (whichm == NUM_MUTATIONS) { - // Unlikely but remotely possible; I know this is a cop-out. - modify_stat(STAT_STRENGTH, 1, true, "demonspawn mutation"); - modify_stat(STAT_INTELLIGENCE, 1, true, "demonspawn mutation"); - modify_stat(STAT_DEXTERITY, 1, true, "demonspawn mutation"); - mpr("You feel much better now.", MSGCH_INTRINSIC_GAIN); + return MUT_STRONG; + } + + return whichm; +} + +void roll_demonspawn_mutations() +{ + FixedVector muts; + int npowers = 0; + + muts.init(0); + you.demon_trait.init(NUM_MUTATIONS); + + for (int level = 2; level <= 27; ++level) + { + // We want 17 (6*3 - 1) random attemps to raise or add a + // mutation in the 26 level ups. The following check is + // equivalent to taking a string of 17 1s and 9 0s and + // shuffling it. + + if (x_chance_in_y(17 - npowers, 28 - level)) + { + mutation_type newmut = _demonspawn(muts, npowers, level); + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Demonspawn will gain %s at level %d", + get_mutation_def(newmut).wizname, level); +#endif + you.demon_trait[level-2] = newmut; + muts[newmut]++; + } } } diff --git a/crawl-ref/source/mutation.h b/crawl-ref/source/mutation.h index 12323215f1..75309bbcdd 100644 --- a/crawl-ref/source/mutation.h +++ b/crawl-ref/source/mutation.h @@ -53,7 +53,7 @@ std::string mutation_name(mutation_type which_mutat, int level = -1, bool give_bad_mutation(bool failMsg = true, bool force_mutation = false, bool non_fatal = false); -void demonspawn(); +void roll_demonspawn_mutations(); bool perma_mutate(mutation_type which_mut, int how_much); int how_mutated(bool all = false, bool levels = false); diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 50f46dcd31..2c8357438a 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -48,6 +48,7 @@ #include "macro.h" #include "makeitem.h" #include "menu.h" +#include "mutation.h" #include "misc.h" #include "player.h" #include "religion.h" @@ -1011,6 +1012,9 @@ game_start: _give_species_bonus_hp(); _give_species_bonus_mp(); + if (you.species == SP_DEMONSPAWN) + roll_demonspawn_mutations(); + // XXX: These need to be set above using functions!!! {dlb} you.max_dex = you.dex; you.max_strength = you.strength; diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 00bce8440b..a22749f530 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -3458,15 +3458,10 @@ void level_change(bool skip_attribute_increase) break; case SP_DEMONSPAWN: - // We want 17 (6*3 - 1) random attemps to raise or add a - // mutation in the 26 level ups. The following check is - // equivalent to taking a string of 17 1s and 9 0s and - // shuffling it. - - if (x_chance_in_y(17 - you.attribute[ATTR_NUM_DEMONIC_POWERS], - 28 - you.experience_level)) + if (you.demon_trait[you.experience_level - 2] != NUM_MUTATIONS) { - demonspawn(); + mpr("Your demonic ancestry asserts itself...", MSGCH_INTRINSIC_GAIN); + perma_mutate(you.demon_trait[you.experience_level - 2], 1); } if (!(you.experience_level % 4)) @@ -5946,6 +5941,8 @@ void player::init() mutation.init(0); demon_pow.init(0); + demon_trait.init(NUM_MUTATIONS); + had_book.init(false); unique_items.init(UNIQ_NOT_EXISTS); diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index 4e830ad3d6..e8250fc3ac 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -222,6 +222,9 @@ public: FixedVector mutation; FixedVector demon_pow; + // demon_trait[i] is the mutation increased at the i'th + // levellup, or NUM_MUTATIONS + FixedVector demon_trait; unsigned char magic_contamination; FixedVector had_book; diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 23b42b61da..91fe0c0643 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -944,6 +944,12 @@ static void tag_construct_you(writer &th) marshallByte(th, you.demon_pow[j]); } + marshallByte(th, 26); + for (j = 0; j < 26; j++) + { + marshallShort(th, you.demon_trait[j]); + } + // how many penances? marshallByte(th, MAX_NUM_GODS); for (i = 0; i < MAX_NUM_GODS; i++) @@ -1387,6 +1393,13 @@ static void tag_read_you(reader &th, char minorVersion) you.demon_pow[j] = unmarshallByte(th); } + if (minorVersion >= TAG_MINOR_DSTRAITS) + { + count_c = unmarshallByte(th); + for (j = 0; j < count_c; ++j) + you.demon_trait[j] = static_cast(unmarshallShort(th)); + } + // how many penances? count_c = unmarshallByte(th); for (i = 0; i < count_c; i++) diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index 5b23eda941..4f0fcf4116 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -56,7 +56,8 @@ enum tag_minor_version TAG_MINOR_ROTTING = 6, // Added monster-specific rotting resistance. TAG_MINOR_TRANS = 7, // Keep track of cancellable transformations. TAG_MINOR_GITREV = 8, // Removed SVN revision and added Git revision. - TAG_MINOR_VERSION = 8 // Current version. (Keep equal to max.) + TAG_MINOR_DSTRAITS = 9, // Pre-calculate demonspawn mutations + TAG_MINOR_VERSION = 9 // Current version. (Keep equal to max.) }; -- cgit v1.2.3-54-g00ecf