summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mgrow.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-26 08:33:37 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-26 08:33:37 +0000
commit66f022fd710eeb3d62cdd6094e80ca231d3a1263 (patch)
tree6a7e15131a30fd7a51d91c29a04aac611674eae7 /crawl-ref/source/mgrow.cc
parent57f4a1b1382e1c4204cd0991eb3f574420184b83 (diff)
downloadcrawl-ref-66f022fd710eeb3d62cdd6094e80ca231d3a1263.tar.gz
crawl-ref-66f022fd710eeb3d62cdd6094e80ca231d3a1263.zip
Monsters can gain experience and level-up. Breaks saves.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2584 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/mgrow.cc')
-rw-r--r--crawl-ref/source/mgrow.cc206
1 files changed, 206 insertions, 0 deletions
diff --git a/crawl-ref/source/mgrow.cc b/crawl-ref/source/mgrow.cc
new file mode 100644
index 0000000000..a620132677
--- /dev/null
+++ b/crawl-ref/source/mgrow.cc
@@ -0,0 +1,206 @@
+/*
+ * File: mgrow.cc
+ * Summary: Monster level-up code.
+ *
+ * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-10-25T09:49:39.320031Z $
+ */
+
+#include "AppHdr.h"
+#include "enum.h"
+#include "mgrow.h"
+#include "mon-util.h"
+#include "monstuff.h"
+#include "stuff.h"
+
+// Base experience required by a monster to reach HD 1.
+const int monster_xp_base = 8;
+// Experience multiplier to determine the experience needed to gain levels.
+const int monster_xp_multiplier = 120;
+const mons_experience_levels mexplevs;
+
+// Monster growing-up sequences. You can specify a chance to indicate that
+// the monster only has a chance of changing type, otherwise the monster
+// will grow up when it reaches the HD of the target form.
+//
+// No special cases are in place: make sure source and target forms are similar.
+// If the target form requires special handling of some sort, add the handling
+// to level_up_change().
+//
+static const monster_level_up mon_grow[] =
+{
+ monster_level_up(MONS_ORC, MONS_ORC_WARRIOR),
+ monster_level_up(MONS_ORC_WARRIOR, MONS_ORC_KNIGHT),
+ monster_level_up(MONS_ORC_KNIGHT, MONS_ORC_WARLORD),
+ monster_level_up(MONS_ORC_PRIEST, MONS_ORC_HIGH_PRIEST),
+ monster_level_up(MONS_ORC_WIZARD, MONS_ORC_SORCERER),
+
+ monster_level_up(MONS_KOBOLD, MONS_BIG_KOBOLD),
+
+ monster_level_up(MONS_UGLY_THING, MONS_VERY_UGLY_THING),
+
+ monster_level_up(MONS_ANT_LARVA, MONS_GIANT_ANT),
+
+ monster_level_up(MONS_KILLER_BEE_LARVA, MONS_KILLER_BEE),
+
+ monster_level_up(MONS_CENTAUR, MONS_CENTAUR_WARRIOR),
+ monster_level_up(MONS_YAKTAUR, MONS_YAKTAUR_CAPTAIN),
+
+ monster_level_up(MONS_NAGA, MONS_NAGA_WARRIOR),
+ monster_level_up(MONS_NAGA_MAGE, MONS_GREATER_NAGA),
+
+ monster_level_up(MONS_DEEP_ELF_SOLDIER, MONS_DEEP_ELF_FIGHTER),
+ monster_level_up(MONS_DEEP_ELF_FIGHTER, MONS_DEEP_ELF_KNIGHT),
+
+ // deep elf magi can become either conjurers or summoners.
+ monster_level_up(MONS_DEEP_ELF_MAGE, MONS_DEEP_ELF_SUMMONER, 500),
+ monster_level_up(MONS_DEEP_ELF_MAGE, MONS_DEEP_ELF_CONJURER),
+ monster_level_up(MONS_DEEP_ELF_PRIEST, MONS_DEEP_ELF_HIGH_PRIEST),
+};
+
+mons_experience_levels::mons_experience_levels()
+{
+ int experience = monster_xp_base;
+ for (int i = 1; i <= MAX_MONS_HD; ++i)
+ {
+ mexp[i] = experience;
+
+ int delta =
+ (monster_xp_base + experience) * 2 * monster_xp_multiplier
+ / 500;
+ delta =
+ std::min(
+ std::max(delta, monster_xp_base * monster_xp_multiplier / 100),
+ 3000);
+ experience += delta;
+ }
+}
+
+static const monster_level_up *monster_level_up_target(
+ monster_type type, int hit_dice)
+{
+ for (unsigned i = 0; i < ARRAYSIZE(mon_grow); ++i)
+ {
+ const monster_level_up &mlup(mon_grow[i]);
+ if (mlup.before == type)
+ {
+ const monsterentry *me = get_monster_data(mlup.after);
+ if (static_cast<int>(me->hpdice[0]) == hit_dice
+ && random2(1000) < mlup.chance)
+ {
+ return (&mlup);
+ }
+ }
+ }
+ return (NULL);
+}
+
+bool monsters::level_up_change()
+{
+ if (const monster_level_up *lup =
+ monster_level_up_target(static_cast<monster_type>(type), hit_dice))
+ {
+ const monsterentry *orig = get_monster_data(type);
+ // Ta-da!
+ type = lup->after;
+
+ // Initialise a dummy monster to save work.
+ monsters dummy;
+ dummy.type = type;
+ define_monster(dummy);
+
+ colour = dummy.colour;
+ speed = dummy.speed;
+ spells = dummy.spells;
+ fix_speed();
+
+ const monsterentry *m = get_monster_data(type);
+ ac += m->AC - orig->AC;
+ ev += m->ev - orig->ev;
+
+ if (lup->adjust_hp)
+ {
+ const int minhp = dummy.max_hit_points;
+ if (max_hit_points < minhp)
+ {
+ hit_points += minhp - max_hit_points;
+ max_hit_points = minhp;
+ hit_points = std::min(hit_points, max_hit_points);
+ }
+ }
+ return (true);
+ }
+ return (false);
+}
+
+bool monsters::level_up()
+{
+ if (hit_dice >= MAX_MONS_HD)
+ return (false);
+
+ ++hit_dice;
+
+ // A little maxhp boost.
+ if (max_hit_points < 1000)
+ {
+ int hpboost = hit_dice > 3? max_hit_points / 8 : max_hit_points / 4;
+ if (hpboost < 2)
+ hpboost = 2;
+ if (hpboost > 20)
+ hpboost = 20;
+
+ max_hit_points += hpboost;
+ hit_points += hpboost;
+ hit_points = std::min(hit_points, max_hit_points);
+ }
+
+ level_up_change();
+
+ return (true);
+}
+
+void monsters::init_experience()
+{
+ if (experience || !alive())
+ return;
+ hit_dice = std::max(hit_dice, 1);
+ experience = mexplevs[std::min(hit_dice, MAX_MONS_HD)];
+}
+
+void monsters::gain_exp(int exp)
+{
+ if (!alive())
+ return;
+
+ init_experience();
+ if (hit_dice >= MAX_MONS_HD)
+ return;
+
+ // Only natural monsters can level-up.
+ if (holiness() != MH_NATURAL)
+ return;
+
+ // Avoid wrap-around.
+ if (experience + exp < experience)
+ return;
+
+ experience += exp;
+
+ const monsters mcopy(*this);
+ int levels_gained = 0;
+ // Monsters can gain a maximum of two levels from one kill.
+ while (hit_dice < MAX_MONS_HD
+ && experience >= mexplevs[hit_dice + 1]
+ && level_up()
+ && ++levels_gained < 2);
+
+ if (levels_gained)
+ {
+ if (mons_intel(type) >= I_NORMAL)
+ simple_monster_message(&mcopy, " looks more experienced.");
+ else
+ simple_monster_message(&mcopy, " looks stronger.");
+ }
+
+ if (hit_dice < MAX_MONS_HD && experience >= mexplevs[hit_dice + 1])
+ experience = (mexplevs[hit_dice] + mexplevs[hit_dice + 1]) / 2;
+}