summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorStefan O'Rear <stefanor@cox.net>2009-10-24 22:12:10 -0700
committerStefan O'Rear <stefanor@cox.net>2009-10-24 22:38:26 -0700
commite5c35dd08e149f985c77be908cfc3e9c69f2d13e (patch)
tree67adba7b180a1908c7d960e97861740af162f8d3 /crawl-ref/source
parent5bae81aab842d440e045a1fa061a9553589d9616 (diff)
downloadcrawl-ref-e5c35dd08e149f985c77be908cfc3e9c69f2d13e.tar.gz
crawl-ref-e5c35dd08e149f985c77be908cfc3e9c69f2d13e.zip
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.
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc1
-rw-r--r--crawl-ref/source/command.cc1
-rw-r--r--crawl-ref/source/debug.cc33
-rw-r--r--crawl-ref/source/mutation.cc174
-rw-r--r--crawl-ref/source/mutation.h2
-rw-r--r--crawl-ref/source/newgame.cc4
-rw-r--r--crawl-ref/source/player.cc13
-rw-r--r--crawl-ref/source/player.h3
-rw-r--r--crawl-ref/source/tags.cc13
-rw-r--r--crawl-ref/source/tags.h3
10 files changed, 107 insertions, 140 deletions
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)
"<w>Ctrl-L</w> : change experience level\n"
"<w>$</w> : get 1000 gold\n"
"<w>]</w> : get a mutation\n"
- "<w>[</w> : get a demonspawn mutation\n"
"<w>^</w> : gain piety\n"
"<w>_</w> : gain religion\n"
"<w>@</w> : 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<int, NUM_MUTATIONS>& 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<mutation_type>(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<int, NUM_MUTATIONS> 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<unsigned char, NUM_MUTATIONS> mutation;
FixedVector<unsigned char, NUM_MUTATIONS> demon_pow;
+ // demon_trait[i] is the mutation increased at the i'th
+ // levellup, or NUM_MUTATIONS
+ FixedVector<mutation_type, 26> demon_trait;
unsigned char magic_contamination;
FixedVector<bool, NUM_FIXED_BOOKS> 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<mutation_type>(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.)
};