diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/debug.cc | 6 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 13 | ||||
-rw-r--r-- | crawl-ref/source/makefile.obj | 1 | ||||
-rw-r--r-- | crawl-ref/source/mgrow.cc | 206 | ||||
-rw-r--r-- | crawl-ref/source/mgrow.h | 37 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 50 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 2 |
9 files changed, 297 insertions, 29 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 7b2c61cd97..6902c614b0 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -1416,8 +1416,10 @@ void stethoscope(int mwh) // print stats and other info mprf(MSGCH_DIAGNOSTICS, - "HD=%d HP=%d/%d AC=%d EV=%d MR=%d SP=%d energy=%d num=%d flags=%04lx", - menv[i].hit_dice, + "HD=%d (%lu) HP=%d/%d AC=%d EV=%d MR=%d SP=%d " + "energy=%d num=%d flags=%04lx", + menv[i].hit_dice, + menv[i].experience, menv[i].hit_points, menv[i].max_hit_points, menv[i].ac, menv[i].ev, mons_resist_magic( &menv[i] ), diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 6edf258b14..e6097dbb07 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -961,12 +961,13 @@ public: mon_attitude_type attitude; beh_type behaviour; unsigned int foe; - char ench_countdown; + char ench_countdown; mon_enchant_list enchantments; unsigned long flags; // bitfield of boolean flags - unsigned int number; // #heads (hydra), etc. - int colour; + unsigned long experience; + unsigned int number; // #heads (hydra), etc. + int colour; int foe_memory; // how long to 'remember' foe x,y // once they go out of sight @@ -979,6 +980,8 @@ public: // AI_SEE_MONSTER public: + void init_experience(); + bool has_action_energy() const; void check_redraw(const coord_def &oldpos) const; void apply_location_effects(); @@ -999,6 +1002,7 @@ public: bool lose_ench_levels(const mon_enchant &e, int lev); void scale_hp(int num, int den); + void gain_exp(int xp); void add_enchantment_effect(const mon_enchant &me, bool quiet = false); void remove_enchantment_effect(const mon_enchant &me, bool quiet = false); @@ -1154,7 +1158,8 @@ private: void init_with(const monsters &mons); void swap_slots(mon_inv_type a, mon_inv_type b); bool need_message(int &near) const; - + bool level_up(); + bool level_up_change(); bool pickup(item_def &item, int slot, int near, bool force_merge = false); void equip_weapon(item_def &item, int near); void equip_armour(item_def &item, int near); diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index 170eb8b367..89784d01fd 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -44,6 +44,7 @@ mapmark.o \ maps.o \ menu.o \ message.o \ +mgrow.o \ misc.o \ monplace.o \ mon-pick.o \ 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; +} diff --git a/crawl-ref/source/mgrow.h b/crawl-ref/source/mgrow.h new file mode 100644 index 0000000000..ff558265d1 --- /dev/null +++ b/crawl-ref/source/mgrow.h @@ -0,0 +1,37 @@ +#ifndef __MGROW_H__ +#define __MGROW_H__ + +#include "AppHdr.h" +#include "FixVec.h" + +// Monster level-up data. + +struct monster_level_up +{ + monster_type before, after; + int chance; // Chance in 1000 of the monster growing up, + // defaults to 1000. + + bool adjust_hp; // If hp post growing up is less than minimum, adjust it. + + monster_level_up(monster_type _before, monster_type _after, + int _chance = 1000, bool _adjust = true) + : before(_before), after(_after), chance(_chance), adjust_hp(_adjust) + { + } +}; + +const int MAX_MONS_HD = 27; +class mons_experience_levels +{ +public: + mons_experience_levels(); + unsigned operator [] (int xl) const + { + return mexp[xl]; + } +private: + FixedVector<unsigned, MAX_MONS_HD + 1> mexp; +}; + +#endif diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 3ada5a9d14..2e6d55ce3a 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -1305,11 +1305,14 @@ void mons_load_spells( monsters *mon, mon_spellbook_type book ) mon->load_spells(book); } -// generate a shiny new and unscarred monster void define_monster(int index) { - monsters &mons = menv[index]; + define_monster(menv[index]); +} +// generate a shiny new and unscarred monster +void define_monster(monsters &mons) +{ int temp_rand = 0; // probability determination {dlb} int mcls = mons.type; int hd, hp, hp_max, ac, ev, speed; @@ -2316,7 +2319,7 @@ monsters::monsters() ac(0), ev(0), speed(0), speed_increment(0), x(0), y(0), target_x(0), target_y(0), inv(), spells(), attitude(ATT_HOSTILE), behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L), - number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD), + experience(0), number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD), ghost(), seen_context("") { } @@ -2354,6 +2357,7 @@ void monsters::init_with(const monsters &mon) foe = mon.foe; enchantments = mon.enchantments; flags = mon.flags; + experience = mon.experience; number = mon.number; colour = mon.colour; foe_memory = mon.foe_memory; diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 031f976bbe..988d13499b 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -522,6 +522,7 @@ void mons_load_spells( monsters *mon, mon_spellbook_type book ); * called from: dungeon - fight * *********************************************************************** */ void define_monster(int mid); +void define_monster(monsters &mons); // last updated 4jan2001 (gdl) /* *********************************************************************** diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index fdf88457fc..aee12608a2 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -375,17 +375,35 @@ static void check_kill_milestone(const monsters *mons, } #endif // DGL_MILESTONES +static void give_monster_experience( int killer_index, int experience, + bool victim_was_born_friendly ) +{ + if (killer_index < 0 || killer_index >= MAX_MONSTERS) + return; + monsters *mons = &menv[killer_index]; + if (!mons->alive()) + return; + + if (mons_friendly(mons) != victim_was_born_friendly) + mons->gain_exp(experience); +} + static void give_adjusted_experience(monsters *monster, killer_type killer, - bool pet_kill, unsigned int *exp_gain, + bool pet_kill, int killer_index, + unsigned int *exp_gain, unsigned int *avail_gain) { - if (testbits(monster->flags, MF_CREATED_FRIENDLY)) + const int experience = exper_value(monster); + const bool created_friendly = testbits(monster->flags, MF_CREATED_FRIENDLY); + if (created_friendly) ; // No experience if monster was created friendly else if (YOU_KILL(killer)) - gain_exp( exper_value( monster ), exp_gain, avail_gain ); + gain_exp( experience, exp_gain, avail_gain ); else if (pet_kill) - gain_exp( exper_value( monster ) / 2 + 1, - exp_gain, avail_gain ); + gain_exp( experience / 2 + 1, exp_gain, avail_gain ); + + if (MON_KILL(killer)) + give_monster_experience( killer_index, experience, created_friendly ); } static bool is_pet_kill(killer_type killer, int i) @@ -580,12 +598,12 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) did_god_conduct(DID_KILL_DEMON, monster->hit_dice); - //jmf: Trog hates wizards + // jmf: Trog hates wizards if (mons_is_magic_user(monster)) did_god_conduct(DID_KILL_WIZARD, monster->hit_dice); - //Beogh hates priests + // Beogh hates priests of other gods. if (mons_class_flag(monster->type, M_PRIEST)) did_god_conduct(DID_KILL_PRIEST, monster->hit_dice); @@ -825,7 +843,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) KC_OTHER; unsigned int exp_gain = 0, avail_gain = 0; - give_adjusted_experience(monster, killer, pet_kill, + give_adjusted_experience(monster, killer, pet_kill, i, &exp_gain, &avail_gain); PlaceInfo& curr_PlaceInfo = you.get_place_info(); @@ -954,23 +972,15 @@ static bool jelly_divide(monsters * parent) if (parent->hit_points > parent->max_hit_points) parent->hit_points = parent->max_hit_points; + parent->init_experience(); + parent->experience = parent->experience * 3 / 5 + 1; + // create child {dlb}: // this is terribly partial and really requires // more thought as to generation ... {dlb} - child->type = parent->type; - child->hit_dice = parent->hit_dice; - child->hit_points = parent->hit_points; + *child = *parent; child->max_hit_points = child->hit_points; - child->ac = parent->ac; - child->ev = parent->ev; - child->speed = parent->speed; child->speed_increment = 70 + random2(5); - child->behaviour = parent->behaviour; /* Look at this! */ - child->foe = parent->foe; - child->attitude = parent->attitude; - child->colour = parent->colour; - child->enchantments = parent->enchantments; - child->ench_countdown = parent->ench_countdown; child->x = parent->x + jex; child->y = parent->y + jey; diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 8aeabbf1c1..f00181319f 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1641,6 +1641,7 @@ static void marshall_monster(tagHeader &th, const monsters &m) marshallByte(th, m.target_x); marshallByte(th, m.target_y); marshallLong(th, m.flags); + marshallLong(th, m.experience); marshallShort(th, m.enchantments.size()); for (mon_enchant_list::const_iterator i = m.enchantments.begin(); @@ -1804,6 +1805,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m) m.target_x = unmarshallByte(th); m.target_y = unmarshallByte(th); m.flags = unmarshallLong(th); + m.experience = static_cast<unsigned long>(unmarshallLong(th)); m.enchantments.clear(); const int nenchs = unmarshallShort(th); |