Monsters can now go berserk (the rage spell, or by moth of wrath attack).
Rupert is now a crusading-style berserker.
Moths of wrath can now enrage nearby monsters of similar attitude.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1256 c06c8d41-db1a-0410-9941-cceddc491573
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC 442VGKMARB6LTQUEBIB5P447EI34BRJL6JALZKXLWPDHWCM6KKCQC L4PKJZERR7WADKWHY3MR6J6OZFREVPL3CB43I6MLJ2BVKWCUTE7AC CDKRLJIGVWQE2PMHCSLJBLYQEK7JYC4LQM7H2X3O6NMJMCCDRVIAC YLZ5G5CR7526RPCDPMBJ6DSADFWVASB4T3DWENT3HUUCD422QITAC X3RDT655FEYO6XEVPIUAPEPJZAFE55KZBH2AZOLK3NGHINMVIGFQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC RC6L3CIBLJEH4GWRFD7UQNGI6PZT74FRUVOYHSAN2XCC74NZUASQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC Y46M2XO74VYDTBTFFUUCI275UGELTXUXS4GEIBBXCY5USQKJ5O6AC 7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC OREY5XZ7FHN4UHDW4E6EQKGZHQUGK26LOGVHLKFN3YJI3B2734BAC FUEEIUKGHHFPIRZCN3N753GONWAZTWQ2ZWR53IBJAAZ6FZUNGOMAC 74LQ7JXVLAFSHLI7LCBKFX47CNTYSKGUQSXNX5FCIUIGCC2JTR3QC MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC AOAJ6D3OKSELEYKAT55XCVU5LYJ7SMCZKC6DIEGLLB3TF2LEENWQC }bool player::can_go_berserk() const{return can_go_berserk(false);}bool player::can_go_berserk(bool verbose) const{if (you.berserker){if (verbose)mpr("You're already berserk!");// or else you won't notice -- no message here.return (false);}if (you.exhausted){if (verbose)mpr("You're too exhausted to go berserk.");// or else they won't notice -- no message herereturn (false);}if (you.is_undead){if (verbose)mpr("You cannot raise a blood rage in your lifeless body.");// or else you won't notice -- no message herereturn (false);}return (true);
static bool make_monster_angry(const monsters *mon, monsters *targ){if (mon->attitude != targ->attitude)return (false);// targ is guaranteed to have a foe (needs_berserk checks this).// Now targ needs to be closer to *its* foe than mon is (otherwise// mon might be in the way).coord_def victim;if (targ->foe == MHITYOU)victim = you.pos();else if (targ->foe != MHITNOT){const monsters *vmons = &menv[targ->foe];if (!vmons->alive())return (false);victim = vmons->pos();}else{// Should be impossible. needs_berserk should find this case.ASSERT(false);return (false);}// If mon may be blocking targ from its victim, don't try.if (victim.distance_from(targ->pos()) > victim.distance_from(mon->pos()))return (false);const bool need_message = mons_near(mon) && player_monster_visible(mon);if (need_message)mprf("%s goads %s on!", mon->name(DESC_CAP_THE).c_str(),targ->name(DESC_NOCAP_THE).c_str());targ->go_berserk(false);return (true);}bool moth_incite_monsters(const monsters *mon){int goaded = 0;for (int i = 0; i < MAX_MONSTERS; ++i){monsters *targ = &menv[i];if (targ == mon || !targ->alive() || !targ->needs_berserk())continue;if (mon->pos().distance_from(targ->pos()) > 3)continue;// Cannot goad other moths of wrath!if (targ->type == MONS_MOTH_OF_WRATH)continue;if (make_monster_angry(mon, targ) && !one_chance_in(3 * ++goaded))return (true);}return (false);}
case MS_BANISHMENT:case MS_COLD_BOLT:case MS_ICE_BOLT:case MS_SHOCK:case MS_MAGMA:case MS_CONFUSE:case MS_CRYSTAL_SPEAR:case MS_DISINTEGRATE:case MS_ENERGY_BOLT:case MS_FIRE_BOLT:case MS_FIREBALL:case MS_FLAME:case MS_FROST:case MS_HELLFIRE:case MS_IRON_BOLT:case MS_LIGHTNING_BOLT:case MS_MARSH_GAS:case MS_MIASMA:case MS_METAL_SPLINTERS:case MS_MMISSILE:case MS_NEGATIVE_BOLT:case MS_ORB_ENERGY:case MS_PAIN:case MS_PARALYSIS:case MS_POISON_BLAST:case MS_POISON_ARROW:case MS_POISON_SPLASH:case MS_QUICKSILVER_BOLT:case MS_SLOW:case MS_STEAM_BALL:case MS_STICKY_FLAME:case MS_STING:case MS_STONE_ARROW:case MS_TELEPORT_OTHER:case MS_VENOM_BOLT:requires = true;break;// self-niceties and direct effectscase MS_ANIMATE_DEAD:case MS_BLINK:case MS_BRAIN_FEED:case MS_DIG:case MS_FAKE_RAKSHASA_SUMMON:case MS_HASTE:case MS_HEAL:case MS_HELLFIRE_BURST:case MS_INVIS:case MS_LEVEL_SUMMON:case MS_MUTATION:case MS_SMITE:case MS_SUMMON_BEAST:case MS_SUMMON_DEMON_LESSER:case MS_SUMMON_DEMON:case MS_SUMMON_DEMON_GREATER:case MS_SUMMON_UFETUBUS:case MS_TELEPORT:case MS_TORMENT:case MS_SUMMON_SMALL_MAMMALS:case MS_VAMPIRE_SUMMON:case MS_CANTRIP:
case MS_BANISHMENT:case MS_COLD_BOLT:case MS_ICE_BOLT:case MS_SHOCK:case MS_MAGMA:case MS_CONFUSE:case MS_CRYSTAL_SPEAR:case MS_DISINTEGRATE:case MS_ENERGY_BOLT:case MS_FIRE_BOLT:case MS_FIREBALL:case MS_FLAME:case MS_FROST:case MS_HELLFIRE:case MS_IRON_BOLT:case MS_LIGHTNING_BOLT:case MS_MARSH_GAS:case MS_MIASMA:case MS_METAL_SPLINTERS:case MS_MMISSILE:case MS_NEGATIVE_BOLT:case MS_ORB_ENERGY:case MS_PAIN:case MS_PARALYSIS:case MS_POISON_BLAST:case MS_POISON_ARROW:case MS_POISON_SPLASH:case MS_QUICKSILVER_BOLT:case MS_SLOW:case MS_STEAM_BALL:case MS_STICKY_FLAME:case MS_STING:case MS_STONE_ARROW:case MS_TELEPORT_OTHER:case MS_VENOM_BOLT:requires = true;break;
// meaningless, but sure, why not?case MS_NO_SPELL:break;
// self-niceties and direct effectscase MS_ANIMATE_DEAD:case MS_BLINK:case MS_BRAIN_FEED:case MS_DIG:case MS_FAKE_RAKSHASA_SUMMON:case MS_HASTE:case MS_HEAL:case MS_HELLFIRE_BURST:case MS_INVIS:case MS_LEVEL_SUMMON:case MS_MUTATION:case MS_SMITE:case MS_SUMMON_BEAST:case MS_SUMMON_DEMON_LESSER:case MS_SUMMON_DEMON:case MS_SUMMON_DEMON_GREATER:case MS_SUMMON_UFETUBUS:case MS_TELEPORT:case MS_TORMENT:case MS_SUMMON_SMALL_MAMMALS:case MS_VAMPIRE_SUMMON:case MS_CANTRIP:case MS_BERSERK_RAGE:
// self-niceties/summoningscase MS_ANIMATE_DEAD:case MS_BLINK:case MS_DIG:case MS_FAKE_RAKSHASA_SUMMON:case MS_HASTE:case MS_HEAL:case MS_INVIS:case MS_LEVEL_SUMMON:case MS_SUMMON_BEAST:case MS_SUMMON_DEMON_LESSER:case MS_SUMMON_DEMON:case MS_SUMMON_DEMON_GREATER:case MS_SUMMON_UFETUBUS:case MS_TELEPORT:case MS_SUMMON_SMALL_MAMMALS:case MS_VAMPIRE_SUMMON:nasty = false;break;
// self-niceties/summoningscase MS_ANIMATE_DEAD:case MS_BLINK:case MS_DIG:case MS_FAKE_RAKSHASA_SUMMON:case MS_HASTE:case MS_HEAL:case MS_INVIS:case MS_LEVEL_SUMMON:case MS_SUMMON_BEAST:case MS_SUMMON_DEMON_LESSER:case MS_SUMMON_DEMON:case MS_SUMMON_DEMON_GREATER:case MS_SUMMON_UFETUBUS:case MS_TELEPORT:case MS_SUMMON_SMALL_MAMMALS:case MS_VAMPIRE_SUMMON:nasty = false;break;
if (holiness() != MH_NATURAL || has_ench(ENCH_FATIGUE))return;if (has_ench(ENCH_SLOW)){del_ench(ENCH_SLOW);simple_monster_message(this,make_stringf(" shakes off %s lethargy.",name(DESC_NOCAP_YOUR).c_str()).c_str());}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));simple_monster_message( this, " goes berserk!" );
case ENCH_BERSERK:lose_ench_levels(me, 1);if (me.degree <= 1){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));}break;case ENCH_FATIGUE:lose_ench_levels(me, 1);if (me.degree <= 1){simple_monster_message(this, " looks more energetic.");del_ench(ENCH_SLOW);}break;
}}int monsters::foe_distance() const{// early out -- no foe!if (foe == MHITNOT)return (INFINITE_DISTANCE);if (foe == MHITYOU)return grid_distance(x, y, you.x_pos, you.y_pos);// must be a monsterconst monsters *my_foe = &menv[foe];if (my_foe->alive())return grid_distance(x, y, my_foe->x, my_foe->y);return (INFINITE_DISTANCE);}bool monsters::can_go_berserk() const{if (holiness() != MH_NATURAL)return (false);if (has_ench(ENCH_FATIGUE) || has_ench(ENCH_BERSERK))return (false);// If we have no melee attack, going berserk is pointless.const mon_attack_def attk = mons_attack_spec(this, 0);if (attk.type == AT_NONE || attk.damage == 0)return (false);return (true);}bool monsters::needs_berserk(bool check_spells) const{if (!can_go_berserk())return (false);if (has_ench(ENCH_HASTE) || has_ench(ENCH_TP))return (false);if (foe_distance() > 3)return (false);if (check_spells){for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; ++i){const int spell = spells[i];if (spell != MS_NO_SPELL && spell != MS_BERSERK_RAGE)return (false);}
if (you.berserker){if (intentional)mpr("You're already berserk!");// or else you won't notice -- no message here.return false;}if (you.exhausted){if (intentional)mpr("You're too exhausted to go berserk.");// or else they won't notice -- no message herereturn false;}
if (!you.can_go_berserk(intentional))return (false);
bool add_ench(const mon_enchant &);void update_ench(const mon_enchant &);bool del_ench(enchant_type ench, bool quiet = false);
bool add_ench(const mon_enchant &);void update_ench(const mon_enchant &);bool del_ench(enchant_type ench, bool quiet = false);void scale_hp(int num, int den);