Enchantment degree is converted into duration up-front. The average enchantment duration should be nearly the same as before, but we guarantee minimum durations on enchantments. Enchantment duration variance is much less, needs testing to see whether this makes enchantments and summoning too strong.
Enchantments that rely on degree (like poison, sticky flame) still use it.
Durations are now based on individual movement ticks, not turns (10 ticks = 1 normal player turn).
Breaks saves, abjuration doesn't work (will fix).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1828 c06c8d41-db1a-0410-9941-cceddc491573
5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC
QVVHS5GCDMIMZHADBBTNG2ICTHKALU2MK42PUZWT4H53HIMVSJUQC
G7EESLQ3T7YRTYLAOPPKXVZ5BNA4TKN4X3VNZEAL3SMGHXDQG6IQC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
35KOQQV4ZBNNIAXGKPOYHOWTN7RBQY7HRZTVMR3WAS4GOYFBM6PQC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
DH3YTI6VVI727SQXO4CXSDCSBG2UN3UAWLFULBGRLBVH22ACRXIAC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
B62ICMDTN5V7R7RBL4JALFVKEMVOOVLRSJASRNYS6CGFWBEEF5JQC
YLZ5G5CR7526RPCDPMBJ6DSADFWVASB4T3DWENT3HUUCD422QITAC
OREY5XZ7FHN4UHDW4E6EQKGZHQUGK26LOGVHLKFN3YJI3B2734BAC
3GSAVTNKEG45AT2U734R5STSRP22WJZL3H6KUFRUWCIA6A4CZE5QC
VYDMJSFXD2E2CWOJEFFVLRBLHDFINBSVL2X6YE6456IQIRGVZIYQC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
CDKRLJIGVWQE2PMHCSLJBLYQEK7JYC4LQM7H2X3O6NMJMCCDRVIAC
FUEEIUKGHHFPIRZCN3N753GONWAZTWQ2ZWR53IBJAAZ6FZUNGOMAC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
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));
return (speed ? (val * 10) / speed : val);
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);
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));
// 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;
}
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);
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;
}
}
// 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);