git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2584 c06c8d41-db1a-0410-9941-cceddc491573
5UC5TI7B6NWGIGN74QRBZKDBYUMHLM2ZO5ATXEZ6TZOGOLF3JX5QC
OONYLF4DAPLIYLBNNRW74IVT5BBTWI4XHQBXSNSPVRX3FTKJBTRAC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
C5VA63WAQRWPENIMXRPUPZLZJMC77PL2B3A77HYFWDCZU5QDG7VQC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
WZNB427K3EUNV3FMVXLQTM4UIHER4FIKQXWLUUXRNQC3OQ33VQYAC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
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);
}
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;
#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
/*
* 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;
}