apply_enchantments(), since a monster could have apply_enchantments() not called for a normal-speed player turn, and then get called twice in a row during the next turn. This fix also makes zero-speed monsters like plants have apply_enchantments() be handled the same way as other monsters, so enchantments are now allways processed in time increments of 10 energy units (cloud processing for zero speed monsters is still handled separately, though).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2456 c06c8d41-db1a-0410-9941-cceddc491573
UIRWVLX5LDNWURTZOG7EFLXE5OOEL4XBPSLSUHUQSKHC4A7WCVLQC
OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC
JPMNAPRVTMOIM62AD56L6MRBGJGNEF6GNLUXDFVOSZG3KU7BUGEQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
T2AYVN57EFJQLFUFLAZDXKDAFDGTDLQIEQWQZNYFWJZBYSTYH4QQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
AOAJ6D3OKSELEYKAT55XCVU5LYJ7SMCZKC6DIEGLLB3TF2LEENWQC
NFOXLH722RGWYY5D63VV6SF2XEJBEOQEFQME6FSA4HZRK3CPLSRQC
VYDMJSFXD2E2CWOJEFFVLRBLHDFINBSVL2X6YE6456IQIRGVZIYQC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
GTXKQTORYHZ7XB2VIH6372UM5GMWAN7IVRXWY5FGBCHFGBV6D6NAC
static bool handle_enchantment(monsters *monster)
{
// Yes, this is the speed we want. This function will be called in
// two circumstances: (1) the monster can move and has enough energy,
// and (2) the monster cannot move (speed == 0) and the monster loop
// is running.
//
// In the first case we in the player's time by keeping track of
// how much energy the monster has expended since the last time
// apply_enchantments() was called, and calling it each time that
// it equals or exceeds the monsters speed. For example, a bat
// gets 30 energy points for every 10 the player gets, and each
// time it spends 30 energy points apply_enchantments() is called.
//
// In the second case, we're hacking things so that plants can suffer
// from sticky flame. The rate of call in this case is once every
// player action... so the time_taken by the player is the ratio to
// the absolute time frame.
//
// -- bwr
if (monster->speed == 0)
monster->apply_enchantments();
else
{
while (monster->ench_countdown <= 0)
{
monster->apply_enchantments();
monster->ench_countdown += monster->speed;
}
}
return (!monster->alive());
} // end handle_enchantment()
#if DEBUG
if (monster->speed_increment == old_energy)
mprf(MSGCH_DIAGNOSTICS,
"Monster '%s' has same energy as last iteration.",
monster->name(DESC_PLAIN).c_str(), true);
else
mprf(MSGCH_DIAGNOSTICS,
"Monster '%s' has MORE energy than last iteration.",
monster->name(DESC_PLAIN).c_str(), true);
#endif
monster->speed_increment = old_energy - 10;
monster->ench_countdown -= 10;
mon->speed_increment -= entry->energy_usage.swim;
{
if (old_energy != INT_MAX)
{
int energy_spent = old_energy - monster->speed_increment;
monster->ench_countdown -= energy_spent;
}
}
old_energy = monster->speed_increment;
mon->speed_increment -= entry->energy_usage.move;
if (handle_enchantment( monster ))
return;
// Apply monster enchantments once for every normal-speed
// player turn.
monster->ench_countdown -= you.time_taken;
if (you.duration[DUR_SLOW] > 0)
monster->ench_countdown -= you.time_taken;
while (monster->ench_countdown < 0)
{
monster->ench_countdown += 10;
monster->apply_enchantments();
// Don't return if the monster died, since we have to deal
// with giant spores and ball lightning exploding at the
// end of the function.
if (!monster->alive())
break;
if (handle_enchantment(monster))
break;
handle_ench_countdown(monster, old_energy);
if (monster->speed_increment >= old_energy)
{
#if DEBUG
if (monster->speed_increment == old_energy)
mprf(MSGCH_DIAGNOSTICS, "'%s' has same energy as last loop",
monster->name(DESC_PLAIN, true).c_str());
else
mprf(MSGCH_DIAGNOSTICS, "'%s' has MORE energy than last loop",
monster->name(DESC_PLAIN, true).c_str());
#endif
monster->speed_increment = old_energy - 10;
old_energy = monster->speed_increment;
continue;
}
old_energy = monster->speed_increment;
if (monster->type == MONS_GIANT_SPORE
|| monster->type == MONS_BALL_LIGHTNING)
{
// detach monster from the grid first, so it
// doesn't get hit by its own explosion (GDL)
mgrd[monster->x][monster->y] = NON_MONSTER;
// detach monster from the grid first, so it
// doesn't get hit by its own explosion (GDL)
mgrd[monster->x][monster->y] = NON_MONSTER;
monsterentry *entry = get_monster_data(mon->type);
dungeon_feature_type feat = grd[mon->x][mon->y];
if (feat >= DNGN_LAVA && feat <= DNGN_SHALLOW_WATER
&& !mon->airborne())
{
mon->speed_increment -= entry->energy_usage.swim;
}
else
mon->speed_increment -= entry->energy_usage.move;
swim_or_move_energy(mon);
monsterentry *entry = get_monster_data(monster->type);
dungeon_feature_type feat = grd[monster->x][monster->y];
if (feat >= DNGN_LAVA && feat <= DNGN_SHALLOW_WATER
&& !monster->airborne())
{
monster->speed_increment -= entry->energy_usage.swim;
}
else
monster->speed_increment -= entry->energy_usage.move;
swim_or_move_energy(monster);