summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/debug.cc4
-rw-r--r--crawl-ref/source/direct.cc2
-rw-r--r--crawl-ref/source/externs.h31
-rw-r--r--crawl-ref/source/misc.cc18
-rw-r--r--crawl-ref/source/misc.h2
-rw-r--r--crawl-ref/source/mon-util.cc439
-rw-r--r--crawl-ref/source/monstuff.cc3
-rw-r--r--crawl-ref/source/mstuff2.cc14
-rw-r--r--crawl-ref/source/spells2.cc4
-rw-r--r--crawl-ref/source/spells3.cc2
-rw-r--r--crawl-ref/source/spells4.cc2
-rw-r--r--crawl-ref/source/stuff.h5
-rw-r--r--crawl-ref/source/tags.cc11
13 files changed, 339 insertions, 198 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 061f856073..9bb8a37679 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -979,9 +979,7 @@ void stethoscope(int mwh)
mons_res_negative_energy( &menv[i] ) );
mprf(MSGCH_DIAGNOSTICS, "ench: %s",
- comma_separated_line(menv[i].enchantments.begin(),
- menv[i].enchantments.end(),
- ", ").c_str());
+ menv[i].describe_enchantments().c_str());
if (menv[i].type == MONS_PLAYER_GHOST
|| menv[i].type == MONS_PANDEMONIUM_DEMON)
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index bd0010ae26..214d88d808 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -1659,7 +1659,7 @@ static void describe_cell(int mx, int my)
for (mon_enchant_list::const_iterator e = menv[i].enchantments.begin();
e != menv[i].enchantments.end(); ++e)
{
- describe_mons_enchantment(menv[i], *e, paralysed);
+ describe_mons_enchantment(menv[i], e->second, paralysed);
}
#if DEBUG_DIAGNOSTICS
stethoscope(i);
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 14828a0dd8..db07ab191a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -931,17 +931,18 @@ struct mon_attack_def
class ghost_demon;
class level_id;
-struct mon_enchant
+class mon_enchant
{
+public:
enchant_type ench;
int degree;
+ int duration, maxduration;
kill_category who; // Who set this enchantment?
+public:
mon_enchant(enchant_type e = ENCH_NONE, int deg = 0,
- kill_category whose = KC_OTHER)
- : ench(e), degree(deg), who(whose)
- {
- }
+ kill_category whose = KC_OTHER,
+ int dur = 0);
killer_type killer() const;
int kill_agent() const;
@@ -951,6 +952,8 @@ struct mon_enchant
void merge_killer(kill_category who);
void cap_degree();
+ void set_duration(const monsters *mons, const mon_enchant *exist);
+
bool operator < (const mon_enchant &other) const
{
return (ench < other.ench);
@@ -964,9 +967,14 @@ struct mon_enchant
mon_enchant &operator += (const mon_enchant &other);
mon_enchant operator + (const mon_enchant &other) const;
+
+private:
+ int modded_speed(const monsters *mons, int hdplus) const;
+ int apply_fuzz(int dur, int lo, int hi) const;
+ int calc_duration(const monsters *mons, const mon_enchant *added) const;
};
-typedef std::set<mon_enchant> mon_enchant_list;
+typedef std::map<enchant_type, mon_enchant> mon_enchant_list;
class monsters : public actor
{
@@ -1020,14 +1028,15 @@ public:
bool add_ench(const mon_enchant &);
void update_ench(const mon_enchant &);
bool del_ench(enchant_type ench, bool quiet = false);
+ bool lose_ench_duration(const mon_enchant &e, int levels);
+ bool lose_ench_levels(const mon_enchant &e, int lev);
void scale_hp(int num, int den);
- void lose_ench_levels(const mon_enchant &e, int levels);
void add_enchantment_effect(const mon_enchant &me, bool quiet = false);
void remove_enchantment_effect(const mon_enchant &me, bool quiet = false);
- void apply_enchantments(int speed);
- void apply_enchantment(mon_enchant me, int speed);
+ void apply_enchantments();
+ void apply_enchantment(const mon_enchant &me);
void timeout_enchantments(int levels);
@@ -1153,6 +1162,8 @@ public:
void fix_speed();
void check_speed();
+ std::string describe_enchantments() const;
+
static int base_speed(int mcls);
private:
@@ -1163,6 +1174,8 @@ private:
bool pickup(item_def &item, int slot, int near, bool force_merge = false);
void equip_weapon(const item_def &item, int near);
+ bool decay_enchantment(const mon_enchant &me, bool decay_degree = false);
+
bool drop_item(int eslot, int near);
bool wants_weapon(const item_def &item) const;
bool can_throw_rocks() const;
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 7d492a148b..590a8fcda8 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -2287,3 +2287,21 @@ coord_def pick_adjacent_free_square(int x, int y)
}
return result;
}
+
+// Converts a movement speed to a duration. i.e., answers the
+// question: if the monster is so fast, how much time has it spent in
+// its last movement?
+//
+// If speed is 10 (normal), one movement is a duration of 10.
+// If speed is 1 (very slow), each movement is a duration of 100.
+// If speed is 15 (50% faster than normal), each movement is a duration of
+// 6.6667.
+int speed_to_duration(int speed)
+{
+ if (speed < 1)
+ speed = 10;
+ else if (speed > 100)
+ speed = 100;
+
+ return div_rand_round(100, speed);
+}
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index c95f1bde66..ef6804cfab 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -208,4 +208,6 @@ bool player_in_a_dangerous_place();
coord_def pick_adjacent_free_square(int x, int y);
+int speed_to_duration(int speed);
+
#endif
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 107623a4d2..3f3cddeb0b 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -22,10 +22,11 @@
#include "mon-util.h"
#include "monstuff.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+#include <sstream>
#include "externs.h"
@@ -2892,9 +2893,9 @@ void monsters::go_berserk(bool /* intentional */)
del_ench(ENCH_HASTE);
del_ench(ENCH_FATIGUE);
- const int duration = 20 + random2avg(20, 2);
- add_ench(mon_enchant(ENCH_BERSERK, duration));
- add_ench(mon_enchant(ENCH_HASTE, duration));
+ const int duration = 16 + random2avg(13, 2);
+ add_ench(mon_enchant(ENCH_BERSERK, 0, KC_OTHER, duration * 10));
+ add_ench(mon_enchant(ENCH_HASTE, 0, KC_OTHER, duration * 10));
simple_monster_message( this, " goes berserk!" );
}
@@ -3106,7 +3107,7 @@ void monsters::rot(actor *agent, int rotlevel, int immed_rot)
}
if (rotlevel > 0)
- add_ench( mon_enchant(ENCH_ROT, cap_int(rotlevel, 4),
+ add_ench( mon_enchant(ENCH_ROT, std::min(rotlevel, 4),
agent->kill_alignment()) );
}
@@ -3381,7 +3382,7 @@ mon_enchant monsters::get_ench(enchant_type ench1,
mon_enchant_list::const_iterator i =
enchantments.find(static_cast<enchant_type>(e));
if (i != enchantments.end())
- return (*i);
+ return (i->second);
}
return mon_enchant();
@@ -3391,12 +3392,9 @@ void monsters::update_ench(const mon_enchant &ench)
{
if (ench.ench != ENCH_NONE)
{
- mon_enchant_list::iterator i = enchantments.find(ench);
+ mon_enchant_list::iterator i = enchantments.find(ench.ench);
if (i != enchantments.end())
- {
- enchantments.erase(i);
- enchantments.insert(ench);
- }
+ i->second = ench;
}
}
@@ -3406,20 +3404,25 @@ bool monsters::add_ench(const mon_enchant &ench)
if (ench.ench == ENCH_NONE)
return (false);
- mon_enchant_list::iterator i = enchantments.find(ench);
+ mon_enchant_list::iterator i = enchantments.find(ench.ench);
bool new_enchantment = false;
+ mon_enchant *added = NULL;
if (i == enchantments.end())
{
new_enchantment = true;
- enchantments.insert(ench);
+ added = &(enchantments[ench.ench] = ench);
}
else
{
- mon_enchant new_ench = *i + ench;
- enchantments.erase(i);
- enchantments.insert(new_ench);
+ i->second += ench;
+ added = &i->second;
}
+ // If the duration is not set, we must calculate it (depending on the
+ // enchantment).
+ if (!ench.duration)
+ added->set_duration(this, new_enchantment? NULL : &ench);
+
if (new_enchantment)
add_enchantment_effect(ench);
@@ -3461,10 +3464,9 @@ bool monsters::del_ench(enchant_type ench, bool quiet)
if (i == enchantments.end())
return (false);
- mon_enchant me = *i;
- enchantments.erase(i);
-
- remove_enchantment_effect(me, quiet);
+ const enchant_type et = i->first;
+ remove_enchantment_effect(i->second, quiet);
+ enchantments.erase(et);
return (true);
}
@@ -3573,18 +3575,42 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
}
}
-void monsters::lose_ench_levels(const mon_enchant &e, int levels)
+bool monsters::lose_ench_levels(const mon_enchant &e, int lev)
{
- if (!levels)
- return;
+ if (!lev)
+ return (false);
- mon_enchant me(e);
- me.degree -= levels;
+ if (e.degree <= lev)
+ {
+ del_ench(e.ench);
+ return (true);
+ }
+ else
+ {
+ mon_enchant newe(e);
+ newe.degree -= lev;
+ update_ench(newe);
+ return (false);
+ }
+}
- if (me.degree < 1)
+bool monsters::lose_ench_duration(const mon_enchant &e, int dur)
+{
+ if (!dur)
+ return (false);
+
+ if (e.duration <= dur)
+ {
del_ench(e.ench);
+ return (true);
+ }
else
- update_ench(me);
+ {
+ mon_enchant newe(e);
+ newe.duration -= dur;
+ update_ench(newe);
+ return (false);
+ }
}
//---------------------------------------------------------------
@@ -3622,33 +3648,33 @@ void monsters::timeout_enchantments(int levels)
for (mon_enchant_list::const_iterator i = ec.begin();
i != ec.end(); ++i)
{
- switch (i->ench)
+ switch (i->first)
{
case ENCH_POISON: case ENCH_ROT: case ENCH_BACKLIGHT:
case ENCH_STICKY_FLAME: case ENCH_ABJ: case ENCH_SHORT_LIVED:
case ENCH_SLOW: case ENCH_HASTE: case ENCH_FEAR:
case ENCH_INVIS: case ENCH_CHARM: case ENCH_SLEEP_WARY:
case ENCH_SICK: case ENCH_SLEEPY:
- lose_ench_levels(*i, levels);
+ lose_ench_levels(i->second, levels);
break;
case ENCH_BERSERK:
- del_ench(i->ench);
+ del_ench(i->first);
del_ench(ENCH_HASTE);
break;
case ENCH_FATIGUE:
- del_ench(i->ench);
+ del_ench(i->first);
del_ench(ENCH_SLOW);
break;
case ENCH_TP:
- del_ench(i->ench);
+ del_ench(i->first);
teleport(true);
break;
case ENCH_CONFUSION:
- del_ench(i->ench);
+ del_ench(i->first);
blink();
break;
@@ -3661,31 +3687,81 @@ void monsters::timeout_enchantments(int levels)
}
}
+std::string monsters::describe_enchantments() const
+{
+ std::ostringstream oss;
+ for (mon_enchant_list::const_iterator i = enchantments.begin();
+ i != enchantments.end(); ++i)
+ {
+ if (i != enchantments.begin())
+ oss << ", ";
+ oss << std::string(i->second);
+ }
+ return (oss.str());
+}
+
// used to adjust time durations in handle_enchantment() for monster speed
static inline int mod_speed( int val, int speed )
{
- return (speed ? (val * 10) / speed : val);
+ if (!speed)
+ speed = you.time_taken;
+ const int modded = (speed ? (val * 10) / speed : val);
+ return (modded? modded : 1);
+}
+
+bool monsters::decay_enchantment(const mon_enchant &me, bool decay_degree)
+{
+ const int spd = speed == 0? you.time_taken : speed;
+ const int actdur = speed_to_duration(spd);
+ if (lose_ench_duration(me, actdur))
+ return (true);
+
+ if (!decay_degree)
+ return (false);
+
+ // Decay degree so that higher degrees decay faster than lower
+ // degrees, and a degree of 1 does not decay (it expires when the
+ // duration runs out).
+ const int level = std::max(me.degree, 1);
+ if (level <= 1)
+ return (false);
+
+ const int decay_factor = level * (level + 1) / 2;
+ if (me.duration < me.maxduration * (decay_factor - 1) / decay_factor)
+ {
+ mon_enchant newme = me;
+ --newme.degree;
+ newme.maxduration = newme.duration;
+
+ if (newme.degree <= 0)
+ {
+ del_ench(me.ench);
+ return (true);
+ }
+ else
+ update_ench(newme);
+ }
+ return (false);
}
-void monsters::apply_enchantment(mon_enchant me, int spd)
+void monsters::apply_enchantment(const mon_enchant &me)
{
+ const int spd = speed == 0? you.time_taken : speed;
switch (me.ench)
{
case ENCH_BERSERK:
- lose_ench_levels(me, 1);
- if (me.degree <= 1)
+ if (decay_enchantment(me))
{
simple_monster_message(this, " is no longer berserk.");
del_ench(ENCH_HASTE);
- const int duration = random_range(7, 13);
- add_ench(mon_enchant(ENCH_FATIGUE, duration));
- add_ench(mon_enchant(ENCH_SLOW, duration));
+ const int duration = random_range(70, 130);
+ add_ench(mon_enchant(ENCH_FATIGUE, 0, KC_OTHER, duration));
+ add_ench(mon_enchant(ENCH_SLOW, 0, KC_OTHER, duration));
}
break;
case ENCH_FATIGUE:
- lose_ench_levels(me, 1);
- if (me.degree <= 1)
+ if (decay_enchantment(me))
{
simple_monster_message(this, " looks more energetic.");
del_ench(ENCH_SLOW);
@@ -3693,54 +3769,26 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
break;
case ENCH_SLOW:
- if (me.degree > 0)
- lose_ench_levels(me, 1);
- else if (random2(250) <= mod_speed( hit_dice + 10, spd ))
- del_ench(me.ench);
- break;
-
case ENCH_HASTE:
- if (me.degree > 0)
- lose_ench_levels(me, 1);
- else if (random2(1000) < mod_speed( 25, spd ))
- del_ench(ENCH_HASTE);
- break;
-
case ENCH_FEAR:
- if (random2(150) <= mod_speed( hit_dice + 5, spd ))
- del_ench(ENCH_FEAR);
- break;
-
case ENCH_PARALYSIS:
- if (random2(120) < mod_speed( hit_dice + 5, spd ))
- del_ench(ENCH_PARALYSIS);
+ case ENCH_SICK:
+ case ENCH_BACKLIGHT:
+ case ENCH_ABJ:
+ case ENCH_CHARM:
+ case ENCH_SLEEP_WARY:
+ decay_enchantment(me);
break;
case ENCH_CONFUSION:
- if (random2(120) < mod_speed( hit_dice + 5, spd ))
- {
- // don't delete perma-confusion
- if (!mons_class_flag(type, M_CONFUSED))
- del_ench(ENCH_CONFUSION);
- }
+ if (!mons_class_flag(type, M_CONFUSED))
+ decay_enchantment(me);
break;
case ENCH_INVIS:
- if (random2(1000) < mod_speed( 25, spd ))
- {
- // don't delete perma-invis
- if (!mons_class_flag( type, M_INVIS ))
- del_ench(ENCH_INVIS);
- }
- break;
-
- case ENCH_SICK:
- {
- const int lost = !spd? 1 : div_rand_round(10, spd);
- if (lost > 0)
- lose_ench_levels(me, lost);
+ if (!mons_class_flag( type, M_INVIS ))
+ decay_enchantment(me);
break;
- }
case ENCH_SUBMERGED:
{
@@ -3820,12 +3868,11 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
}
}
- // chance to get over poison (1 in 8, modified for speed)
- if (random2(1000) < mod_speed( 125, spd ))
- lose_ench_levels(me, 1);
+ decay_enchantment(me, true);
break;
}
case ENCH_ROT:
+ {
if (hit_points > 1
&& random2(1000) < mod_speed( 333, spd ))
{
@@ -3834,17 +3881,11 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
--max_hit_points;
}
- if (random2(1000) < mod_speed( me.degree == 1? 250 : 333, spd ))
- lose_ench_levels(me, 1);
-
- break;
-
- case ENCH_BACKLIGHT:
- if (random2(1000) < mod_speed( me.degree == 1? 100 : 200, spd ))
- lose_ench_levels(me, 1);
+ decay_enchantment(me, true);
break;
+ }
- // assumption: mons_res_fire has already been checked
+ // assumption: mons_res_fire has already been checked
case ENCH_STICKY_FLAME:
{
int dam = roll_dice( 2, 4 ) - 1;
@@ -3874,36 +3915,16 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
}
}
- // chance to get over sticky flame (1 in 5, modified for speed)
- if (random2(1000) < mod_speed( 200, spd ))
- lose_ench_levels(me, 1);
+ decay_enchantment(me, true);
break;
}
case ENCH_SHORT_LIVED:
// This should only be used for ball lightning -- bwr
- if (random2(1000) < mod_speed( 200, spd ))
+ if (decay_enchantment(me))
hit_points = -1;
break;
- // 19 is taken by summoning:
- // If these are changed, must also change abjuration
- case ENCH_ABJ:
- {
- const int mspd =
- me.degree == 6? 10 :
- me.degree == 5? 20 : 100;
-
- if (random2(1000) < mod_speed( mspd, spd ))
- lose_ench_levels(me, 1);
- break;
- }
-
- case ENCH_CHARM:
- if (random2(500) <= mod_speed( hit_dice + 10, spd ))
- del_ench(ENCH_CHARM);
- break;
-
case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
// number of actions is fine for shapeshifters
if (type == MONS_GLOWING_SHAPESHIFTER
@@ -3922,44 +3943,8 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
break;
case ENCH_TP:
- if (me.degree <= 1)
- {
- del_ench(ENCH_TP);
+ if (decay_enchantment(me, true))
monster_teleport( this, true );
- }
- else
- {
- int tmp = mod_speed( 1000, spd );
-
- if (tmp < 1000 && random2(1000) < tmp)
- lose_ench_levels(me, 1);
- else if (me.degree - tmp / 1000 >= 1)
- {
- lose_ench_levels(me, tmp / 1000);
- tmp %= 1000;
-
- if (random2(1000) < tmp)
- {
- if (me.degree > 1)
- lose_ench_levels(me, 1);
- else
- {
- del_ench( ENCH_TP );
- monster_teleport( this, true );
- }
- }
- }
- else
- {
- del_ench( ENCH_TP );
- monster_teleport( this, true );
- }
- }
- break;
-
- case ENCH_SLEEP_WARY:
- if (random2(1000) < mod_speed( 50, spd ))
- del_ench(ENCH_SLEEP_WARY);
break;
case ENCH_SLEEPY:
@@ -3971,16 +3956,15 @@ void monsters::apply_enchantment(mon_enchant me, int spd)
}
}
-void monsters::apply_enchantments(int spd)
+void monsters::apply_enchantments()
{
if (enchantments.empty())
return;
const mon_enchant_list ec = enchantments;
- for (mon_enchant_list::const_iterator i = ec.begin();
- i != ec.end(); ++i)
+ for (mon_enchant_list::const_iterator i = ec.begin(); i != ec.end(); ++i)
{
- apply_enchantment(*i, spd);
+ apply_enchantment(i->second);
if (!alive())
break;
}
@@ -4016,7 +4000,7 @@ bool monsters::sicken(int amount)
mprf("%s looks sick.", name(DESC_CAP_THE).c_str());
}
- add_ench(mon_enchant(ENCH_SICK, amount));
+ add_ench(mon_enchant(ENCH_SICK, 0, KC_OTHER, amount * 10));
return (true);
}
@@ -4071,8 +4055,7 @@ void monsters::check_speed()
"Bad speed: %s, spd: %d, spi: %d, hd: %d, ench: %s",
name(DESC_PLAIN).c_str(),
speed, speed_increment, hit_dice,
- comma_separated_line(enchantments.begin(),
- enchantments.end()).c_str());
+ describe_enchantments().c_str());
#endif
fix_speed();
@@ -4200,18 +4183,25 @@ const char *mons_enchantment_name(enchant_type ench)
return (enchant_names[ench]);
}
+mon_enchant::mon_enchant(enchant_type e, int deg, kill_category whose,
+ int dur)
+ : ench(e), degree(deg), duration(dur), maxduration(0), who(whose)
+{
+}
+
mon_enchant::operator std::string () const
{
- return make_stringf("%s (%d%s)",
+ return make_stringf("%s (%d:%d%s)",
mons_enchantment_name(ench),
degree,
+ duration,
kill_category_desc(who));
}
const char *mon_enchant::kill_category_desc(kill_category k) const
{
- return (k == KC_YOU? "you" :
- k == KC_FRIENDLY? "pet" : "");
+ return (k == KC_YOU? " you" :
+ k == KC_FRIENDLY? " pet" : "");
}
void mon_enchant::merge_killer(kill_category k)
@@ -4236,8 +4226,9 @@ mon_enchant &mon_enchant::operator += (const mon_enchant &other)
{
if (ench == other.ench)
{
- degree += other.degree;
+ degree += other.degree;
cap_degree();
+ duration += other.duration;
merge_killer(other.who);
}
return (*this);
@@ -4261,3 +4252,121 @@ int mon_enchant::kill_agent() const
{
return (who == KC_FRIENDLY? ANON_FRIENDLY_MONSTER : 0);
}
+
+int mon_enchant::modded_speed(const monsters *mons, int hdplus) const
+{
+ return (mod_speed(mons->hit_dice + hdplus, mons->speed));
+}
+
+int mon_enchant::apply_fuzz(int dur, int lowfuzz, int highfuzz) const
+{
+ const int lfuzz = lowfuzz * dur / 100,
+ hfuzz = highfuzz * dur / 100;
+ return dur + random2avg(lfuzz + hfuzz + 1, 2) - lfuzz;
+}
+
+int mon_enchant::calc_duration(const monsters *mons,
+ const mon_enchant *added) const
+{
+ int cturn = 0;
+
+ const int newdegree = added? added->degree : degree;
+ const int deg = newdegree? newdegree : 1;
+
+ // Beneficial enchantments (like Haste) should not be throttled by
+ // monster HD!
+ switch (ench)
+ {
+ case ENCH_HASTE:
+ cturn = 1000 / mod_speed(25, mons->speed);
+ break;
+ case ENCH_INVIS:
+ cturn = 1000 / mod_speed(25, mons->speed);
+ break;
+ case ENCH_SLOW:
+ cturn = 250 / (1 + modded_speed(mons, 10));
+ break;
+ case ENCH_FEAR:
+ cturn = 150 / (1 + modded_speed(mons, 5));
+ break;
+ case ENCH_PARALYSIS:
+ case ENCH_CONFUSION:
+ cturn = 120 / modded_speed(mons, 5);
+ break;
+ case ENCH_POISON:
+ cturn = 1000 * deg / mod_speed(125, mons->speed);
+ break;
+ case ENCH_STICKY_FLAME:
+ cturn = 1000 * deg / mod_speed(200, mons->speed);
+ break;
+ case ENCH_ROT:
+ if (deg > 1)
+ cturn = 1000 * (deg - 1) / mod_speed(333, mons->speed);
+ cturn += 1000 / mod_speed(250, mons->speed);
+ break;
+ case ENCH_BACKLIGHT:
+ if (deg > 1)
+ cturn = 1000 * (deg - 1) / mod_speed(200, mons->speed);
+ cturn += 1000 / mod_speed(100, mons->speed);
+ break;
+ case ENCH_SHORT_LIVED:
+ cturn = 1000 / mod_speed(200, mons->speed);
+ break;
+ case ENCH_ABJ:
+ if (deg >= 6)
+ cturn = 1000 / mod_speed(10, mons->speed);
+ if (deg >= 5)
+ cturn += 1000 / mod_speed(20, mons->speed);
+ cturn += 1000 * std::min(4, deg) / mod_speed(100, mons->speed);
+ break;
+ case ENCH_CHARM:
+ cturn = 500 / modded_speed(mons, 10);
+ break;
+ case ENCH_TP:
+ cturn = 1000 * deg / mod_speed(1000, mons->speed);
+ break;
+ case ENCH_SLEEP_WARY:
+ cturn = 1000 / mod_speed(50, mons->speed);
+ break;
+ default:
+ break;
+ }
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Ench for %s: raw turn duration for %s (%d) == %d",
+ mons->name(DESC_PLAIN).c_str(), std::string(*this).c_str(),
+ deg, cturn);
+#endif
+
+ if (cturn < 2)
+ cturn = 2;
+
+ int raw_duration = (cturn * speed_to_duration(mons->speed));
+ raw_duration = apply_fuzz(raw_duration, 60, 40);
+ if (raw_duration < 15)
+ raw_duration = 15;
+
+ return (raw_duration);
+}
+
+// Calculate the effective duration (in terms of normal player time - 10
+// duration units being one normal player action) of this enchantment.
+void mon_enchant::set_duration(const monsters *mons, const mon_enchant *added)
+{
+ if (duration && !added)
+ return;
+
+ if (added && added->duration)
+ duration += added->duration;
+ else
+ duration += calc_duration(mons, added);
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Ench on %s: ench energy for %s: %d",
+ mons->name(DESC_PLAIN).c_str(), std::string(*this).c_str(),
+ duration);
+#endif
+
+ if (duration > maxduration)
+ maxduration = duration;
+}
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 7d43767837..c9d18cd78a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -1926,8 +1926,7 @@ static bool handle_enchantment(monsters *monster)
// 3 times as many calls to this function (ie 8 rounds * 3 calls).
//
// -- bwr
- const int speed = (monster->speed == 0) ? you.time_taken : monster->speed;
- monster->apply_enchantments(speed);
+ monster->apply_enchantments();
return (!monster->alive());
} // end handle_enchantment()
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index bab6d51e8f..63eb013342 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -380,7 +380,7 @@ static void do_high_level_summon(monsters *monster, bool monsterNearby,
if (mons_abjured(monster, monsterNearby))
return;
- const int duration = cap_int(2 + monster->hit_dice / 5, 6);
+ const int duration = std::min(2 + monster->hit_dice / 5, 6);
for (int i = 0; i < nsummons; ++i)
{
const monster_type which_mons = mpicker();
@@ -502,7 +502,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 10 + 1 );
- duration = cap_int(2 + monster->hit_dice / 10, 6);
+ duration = std::min(2 + monster->hit_dice / 10, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_COMMON), duration,
@@ -519,7 +519,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
case SPELL_CALL_IMP: // class 5 demons
sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
- duration = cap_int(2 + monster->hit_dice / 5, 6);
+ duration = std::min(2 + monster->hit_dice / 5, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_LESSER), duration,
@@ -531,7 +531,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
case SPELL_SUMMON_UFETUBUS:
sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 5 + 1 );
- duration = cap_int(2 + monster->hit_dice / 5, 6);
+ duration = std::min(2 + monster->hit_dice / 5, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
@@ -556,7 +556,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 4 + 1 );
- duration = cap_int(2 + monster->hit_dice / 5, 6);
+ duration = std::min(2 + monster->hit_dice / 5, 6);
for (int i = 0; i < sumcount2; ++i)
create_monster(MONS_WANDERING_MUSHROOM, duration,
SAME_ATTITUDE(monster),
@@ -596,7 +596,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
sumcount2 = 1 + random2( monster->hit_dice / 10 + 1 );
- duration = cap_int(2 + monster->hit_dice / 10, 6);
+ duration = std::min(2 + monster->hit_dice / 10, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_GREATER), duration,
@@ -612,7 +612,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast)
sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
- duration = cap_int(2 + monster->hit_dice / 10, 6);
+ duration = std::min(2 + monster->hit_dice / 10, 6);
{
std::vector<int> monsters;
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 981ca972cc..9eeaa49fc4 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -1147,7 +1147,7 @@ int summon_elemental(int pow, int restricted_type,
int targ_x;
int targ_y;
- int numsc = cap_int(2 + (random2(pow) / 5), 6);
+ int numsc = std::min(2 + (random2(pow) / 5), 6);
for (;;)
{
@@ -1371,7 +1371,7 @@ void summon_scorpions(int pow)
void summon_ice_beast_etc(int pow, int ibc, bool divine_gift)
{
- int numsc = cap_int(2 + (random2(pow) / 4), 6);
+ int numsc = std::min(2 + (random2(pow) / 4), 6);
beh_type beha = divine_gift? BEH_GOD_GIFT : BEH_FRIENDLY;
switch (ibc)
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index fff5a799d3..142f0e94d9 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -413,7 +413,7 @@ void simulacrum(int power)
void dancing_weapon(int pow, bool force_hostile)
{
- int numsc = cap_int(2 + (random2(pow) / 5), 6);
+ int numsc = std::min(2 + (random2(pow) / 5), 6);
int i;
int summs = 0;
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index cca3770ac2..97aca63a03 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -667,7 +667,7 @@ void cast_sticks_to_snakes(int pow)
int mon;
int how_many = 0;
int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4;
- int dur = cap_int(3 + random2(pow) / 20, 5);
+ int dur = std::min(3 + random2(pow) / 20, 5);
const int weapon = you.equip[EQ_WEAPON];
if (weapon == -1)
diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h
index f936151b24..f72a5f9730 100644
--- a/crawl-ref/source/stuff.h
+++ b/crawl-ref/source/stuff.h
@@ -108,11 +108,6 @@ inline bool testbits(unsigned long flags, unsigned long test)
return ((flags & test) == test);
}
-inline int cap_int(int val, int cap)
-{
- return (val > cap? cap : val);
-}
-
template <typename Z> inline Z sgn(Z x)
{
return (x < 0? -1 : (x > 0? 1 : 0));
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 8b779c0995..c4d039134f 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1426,6 +1426,8 @@ static void marshall_mon_enchant(tagHeader &th, const mon_enchant &me)
marshallShort(th, me.ench);
marshallShort(th, me.degree);
marshallShort(th, me.who);
+ marshallShort(th, me.duration);
+ marshallShort(th, me.maxduration);
}
static mon_enchant unmarshall_mon_enchant(tagHeader &th)
@@ -1434,6 +1436,8 @@ static mon_enchant unmarshall_mon_enchant(tagHeader &th)
me.ench = static_cast<enchant_type>( unmarshallShort(th) );
me.degree = unmarshallShort(th);
me.who = static_cast<kill_category>( unmarshallShort(th) );
+ me.duration = unmarshallShort(th);
+ me.maxduration = unmarshallShort(th);
return (me);
}
@@ -1455,7 +1459,7 @@ static void marshall_monster(tagHeader &th, const monsters &m)
for (mon_enchant_list::const_iterator i = m.enchantments.begin();
i != m.enchantments.end(); ++i)
{
- marshall_mon_enchant(th, *i);
+ marshall_mon_enchant(th, i->second);
}
marshallShort(th, m.type);
@@ -1612,7 +1616,10 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
m.enchantments.clear();
const int nenchs = unmarshallShort(th);
for (int i = 0; i < nenchs; ++i)
- m.enchantments.insert( unmarshall_mon_enchant(th) );
+ {
+ mon_enchant me = unmarshall_mon_enchant(th);
+ m.enchantments[me.ench] = me;
+ }
m.type = unmarshallShort(th);
m.hit_points = unmarshallShort(th);