summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-05-11 14:14:10 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-05-11 14:14:10 +0000
commit18dac1924da21380570eb193e6a363e0c813c9de (patch)
treedd9659e0a9a5b3127d4736aa3ca6b411ce9f2d90
parentf95c27c96c4fa900e334d269619503410b5d1f78 (diff)
downloadcrawl-ref-18dac1924da21380570eb193e6a363e0c813c9de.tar.gz
crawl-ref-18dac1924da21380570eb193e6a363e0c813c9de.zip
Merged trunk fixes back to 0.2:
- Moth of wrath rage attack. - Pulsating lump mutation attack. - Combat messages for out-of-view monsters fighting monsters in LOS. - Waypoint deletion. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup-0.2@1449 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/enum.h3
-rw-r--r--crawl-ref/source/externs.h10
-rw-r--r--crawl-ref/source/fight.cc400
-rw-r--r--crawl-ref/source/fight.h14
-rw-r--r--crawl-ref/source/misc.cc28
-rw-r--r--crawl-ref/source/mon-data.h2
-rw-r--r--crawl-ref/source/mon-util.cc31
-rw-r--r--crawl-ref/source/mon-util.h2
-rw-r--r--crawl-ref/source/monstuff.cc2
-rw-r--r--crawl-ref/source/player.cc47
-rw-r--r--crawl-ref/source/travel.cc59
-rw-r--r--crawl-ref/source/travel.h14
12 files changed, 418 insertions, 194 deletions
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index af55054702..abe1b0a990 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2293,7 +2293,8 @@ enum mon_attack_flavour
AF_ROT,
AF_VAMPIRIC,
AF_KLOWN,
- AF_DISTORT
+ AF_DISTORT,
+ AF_RAGE
};
enum mon_attitude_type
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 004cc278c4..facb80e54f 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -142,7 +142,10 @@ public:
// (statues have only indirect attacks).
virtual bool cannot_fight() const = 0;
virtual void attacking(actor *other) = 0;
+ virtual bool can_go_berserk() const = 0;
+ virtual bool is_icy() const = 0;
virtual void go_berserk(bool intentional) = 0;
+ virtual void mutate() = 0;
virtual void hurt(const actor *attacker, int amount) = 0;
virtual void heal(int amount, bool max_too = false) = 0;
virtual void banish(const std::string &who = "") = 0;
@@ -711,6 +714,7 @@ public:
bool can_swim() const;
bool is_levitating() const;
bool cannot_speak() const;
+ bool is_icy() const;
kill_category kill_alignment() const;
@@ -746,7 +750,10 @@ public:
bool cannot_fight() const;
void attacking(actor *other);
+ bool can_go_berserk() const;
+ bool can_go_berserk(bool verbose) const;
void go_berserk(bool intentional);
+ void mutate();
void banish(const std::string &who = "");
void blink();
void teleport(bool right_now = false, bool abyss_shift = false);
@@ -963,7 +970,9 @@ public:
int skill(skill_type skill, bool skill_bump = false) const;
void attacking(actor *other);
+ bool can_go_berserk() const;
void go_berserk(bool intentional);
+ void mutate();
void banish(const std::string &who = "");
void expose_to_element(beam_type element, int strength = 0);
bool visible() const;
@@ -979,6 +988,7 @@ public:
int levitates() const;
+ bool is_icy() const;
bool paralysed() const;
bool confused() const;
bool asleep() const;
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 91ab96e859..b96b779941 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -260,101 +260,6 @@ int calc_heavy_armour_penalty( bool random_factor )
return heavy_armour;
}
-// Returns true if a head got lopped off.
-static bool chop_hydra_head( const actor *attacker,
- actor *def,
- int damage_done,
- int dam_type,
- int wpn_brand )
-{
- monsters *defender = dynamic_cast<monsters*>(def);
-
- const bool defender_visible = mons_near(defender);
-
- // Monster attackers have only a 25% chance of making the
- // chop-check to prevent runaway head inflation.
- if (attacker->atype() == ACT_MONSTER && !one_chance_in(4))
- return (false);
-
- if ((dam_type == DVORP_SLICING || dam_type == DVORP_CHOPPING
- || dam_type == DVORP_CLAWING)
- && damage_done > 0
- && (damage_done >= 4 || wpn_brand == SPWPN_VORPAL || coinflip()))
- {
- defender->number--;
-
- const char *verb = NULL;
-
- if (dam_type == DVORP_CLAWING)
- {
- static const char *claw_verbs[] = { "rip", "tear", "claw" };
- verb =
- claw_verbs[
- random2( sizeof(claw_verbs) / sizeof(*claw_verbs) ) ];
- }
- else
- {
- static const char *slice_verbs[] =
- {
- "slice", "lop", "chop", "hack"
- };
- verb =
- slice_verbs[
- random2( sizeof(slice_verbs) / sizeof(*slice_verbs) ) ];
- }
-
- if (defender->number < 1)
- {
- if (defender_visible)
- mprf( "%s %s %s's last head off!",
- attacker->name(DESC_CAP_THE).c_str(),
- attacker->conj_verb(verb).c_str(),
- defender->name(DESC_NOCAP_THE).c_str() );
-
- defender->hurt(attacker, defender->hit_points);
- }
- else
- {
- if (defender_visible)
- mprf( "%s %s one of %s's heads off!",
- attacker->name(DESC_CAP_THE).c_str(),
- attacker->conj_verb(verb).c_str(),
- defender->name(DESC_NOCAP_THE).c_str() );
-
- if (wpn_brand == SPWPN_FLAMING)
- {
- if (defender_visible)
- mpr( "The flame cauterises the wound!" );
- }
- else if (defender->number < 19)
- {
- simple_monster_message( defender, " grows two more!" );
- defender->number += 2;
- heal_monster( defender, 8 + random2(8), true );
- }
- }
-
- return (true);
- }
-
- return (false);
-}
-
-static bool actor_decapitates_hydra(actor *attacker, actor *defender,
- int damage_done, int damage_type = -1)
-{
- if (defender->id() == MONS_HYDRA)
- {
- const int dam_type =
- damage_type != -1? damage_type : attacker->damage_type();
- const int wpn_brand = attacker->damage_brand();
-
- return chop_hydra_head(attacker, defender, damage_done,
- dam_type, wpn_brand);
- }
- return (false);
-}
-
static bool player_fights_well_unarmed(int heavy_armour_penalty)
{
return (you.burden_state == BS_UNENCUMBERED
@@ -433,6 +338,63 @@ void melee_attack::init_attack()
needs_message = attacker_visible || defender_visible;
}
+std::string melee_attack::actor_name(const actor *a,
+ description_level_type desc,
+ bool actor_visible)
+{
+ return (actor_visible? a->name(desc) : anon_name(desc));
+}
+
+std::string melee_attack::pronoun(const actor *a,
+ pronoun_type pron,
+ bool actor_visible)
+{
+ return (actor_visible? a->pronoun(pron) : anon_pronoun(pron));
+}
+
+std::string melee_attack::anon_pronoun(pronoun_type pron)
+{
+ switch (pron)
+ {
+ default:
+ case PRONOUN_CAP: return "It";
+ case PRONOUN_NOCAP: return "it";
+ case PRONOUN_CAP_POSSESSIVE: return "Its";
+ case PRONOUN_NOCAP_POSSESSIVE: return "its";
+ case PRONOUN_REFLEXIVE: return "itself";
+ }
+}
+
+std::string melee_attack::anon_name(description_level_type desc)
+{
+ switch (desc)
+ {
+ case DESC_CAP_THE:
+ case DESC_CAP_A:
+ return ("It");
+ case DESC_CAP_YOUR:
+ return ("Its");
+ case DESC_NOCAP_YOUR:
+ case DESC_NOCAP_ITS:
+ return ("its");
+ case DESC_NOCAP_THE:
+ case DESC_NOCAP_A:
+ case DESC_PLAIN:
+ default:
+ return ("it");
+ }
+}
+
+std::string melee_attack::atk_name(description_level_type desc) const
+{
+ return actor_name(attacker, desc, attacker_visible);
+}
+
+std::string melee_attack::def_name(description_level_type desc) const
+{
+ return actor_name(defender, desc, defender_visible);
+}
+
bool melee_attack::is_water_attack(const actor *attk,
const actor *defn) const
{
@@ -1368,7 +1330,7 @@ bool melee_attack::player_monattk_hit_effects(bool mondied)
// These effects apply only to monsters that are still alive:
- if (actor_decapitates_hydra(attacker, defender, damage_done))
+ if (decapitate_hydra(damage_done))
return (true);
// These two (staff damage and damage brand) are mutually exclusive!
@@ -1431,9 +1393,9 @@ void melee_attack::calc_elemental_brand_damage(
{
special_damage_message = make_stringf(
"%s %s %s%s",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb(verb).c_str(),
- defender->name(DESC_NOCAP_THE).c_str(),
+ def_name(DESC_NOCAP_THE).c_str(),
special_attack_punctuation().c_str());
}
}
@@ -1473,9 +1435,9 @@ void melee_attack::drain_monster()
special_damage_message =
make_stringf(
"%s %s %s!",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb("drain").c_str(),
- defender->name(DESC_NOCAP_THE).c_str());
+ def_name(DESC_NOCAP_THE).c_str());
if (one_chance_in(5))
def->hit_dice--;
@@ -1503,10 +1465,11 @@ bool melee_attack::distortion_affects_defender()
if (one_chance_in(5))
{
emit_nodmg_hit_message();
- special_damage_message =
- make_stringf("%s %s in the translocular energy.",
- defender->name(DESC_CAP_THE).c_str(),
- defender->conj_verb("bask").c_str());
+ if (defender_visible)
+ special_damage_message =
+ make_stringf("%s %s in the translocular energy.",
+ def_name(DESC_CAP_THE).c_str(),
+ defender->conj_verb("bask").c_str());
defender->heal(1 + random2avg(7, 2), true); // heh heh
}
@@ -1515,21 +1478,23 @@ bool melee_attack::distortion_affects_defender()
if (one_chance_in(3))
{
- special_damage_message =
- make_stringf(
- "Space bends around %s.",
- defender->name(DESC_NOCAP_THE).c_str());
+ if (defender_visible)
+ special_damage_message =
+ make_stringf(
+ "Space bends around %s.",
+ def_name(DESC_NOCAP_THE).c_str());
special_damage += 1 + random2avg(7, 2);
return (false);
}
if (one_chance_in(3))
{
- special_damage_message =
- make_stringf(
- "Space warps horribly around %s!",
- defender->name(DESC_NOCAP_THE).c_str());
-
+ if (defender_visible)
+ special_damage_message =
+ make_stringf(
+ "Space warps horribly around %s!",
+ def_name(DESC_NOCAP_THE).c_str());
+
special_damage += 3 + random2avg(24, 2);
return (false);
}
@@ -1573,7 +1538,7 @@ bool melee_attack::apply_damage_brand()
{
case SPWPN_FLAMING:
res = fire_res_apply_cerebov_downgrade( defender->res_fire() );
- calc_elemental_brand_damage(res, "burn");
+ calc_elemental_brand_damage(res, defender->is_icy()? "melt" : "burn");
defender->expose_to_element(BEAM_FIRE);
break;
@@ -1596,12 +1561,12 @@ bool melee_attack::apply_damage_brand()
default:
break;
}
- if (special_damage)
+ if (special_damage && defender_visible)
{
special_damage_message =
make_stringf(
"%s %s%s",
- defender->name(DESC_CAP_THE).c_str(),
+ def_name(DESC_CAP_THE).c_str(),
defender->conj_verb("convulse").c_str(),
special_attack_punctuation().c_str());
}
@@ -1626,12 +1591,13 @@ bool melee_attack::apply_damage_brand()
if (defender->mons_species() == MONS_ORC)
{
special_damage = 1 + random2(damage_done);
- special_damage_message =
- make_stringf(
- "%s %s%s",
- defender->name(DESC_CAP_THE).c_str(),
- defender->conj_verb("convulse").c_str(),
- special_attack_punctuation().c_str());
+ if (defender_visible)
+ special_damage_message =
+ make_stringf(
+ "%s %s%s",
+ defender->name(DESC_CAP_THE).c_str(),
+ defender->conj_verb("convulse").c_str(),
+ special_attack_punctuation().c_str());
}
break;
@@ -1710,12 +1676,13 @@ bool melee_attack::apply_damage_brand()
case SPWPN_DISRUPTION:
if (defender->holiness() == MH_UNDEAD && !one_chance_in(3))
{
- special_damage_message =
- defender->atype() == ACT_MONSTER?
- make_stringf("%s %s.",
- defender->name(DESC_CAP_THE).c_str(),
- defender->conj_verb("shudder").c_str())
- : ("You are blasted by holy energy!");
+ if (defender_visible)
+ special_damage_message =
+ defender->atype() == ACT_MONSTER?
+ make_stringf("%s %s.",
+ defender->name(DESC_CAP_THE).c_str(),
+ defender->conj_verb("shudder").c_str())
+ : ("You are blasted by holy energy!");
special_damage += random2avg((1 + (damage_done * 3)), 3);
}
@@ -1725,10 +1692,11 @@ bool melee_attack::apply_damage_brand()
if (defender->res_negative_energy() <= 0
&& random2(8) <= attacker->skill(SK_NECROMANCY))
{
- special_damage_message =
- make_stringf("%s %s in agony.",
- defender->name(DESC_CAP_THE).c_str(),
- defender->conj_verb("writhe").c_str());
+ if (defender_visible)
+ special_damage_message =
+ make_stringf("%s %s in agony.",
+ defender->name(DESC_CAP_THE).c_str(),
+ defender->conj_verb("writhe").c_str());
special_damage += random2( 1 + attacker->skill(SK_NECROMANCY) );
}
attacker->god_conduct(DID_NECROMANCY, 4);
@@ -1764,6 +1732,93 @@ bool melee_attack::apply_damage_brand()
return (false);
}
+// Returns true if a head got lopped off.
+bool melee_attack::chop_hydra_head( int dam,
+ int dam_type,
+ int wpn_brand )
+{
+ // Monster attackers have only a 25% chance of making the
+ // chop-check to prevent runaway head inflation.
+ if (attacker->atype() == ACT_MONSTER && !one_chance_in(4))
+ return (false);
+
+ if ((dam_type == DVORP_SLICING || dam_type == DVORP_CHOPPING
+ || dam_type == DVORP_CLAWING)
+ && dam > 0
+ && (dam >= 4 || wpn_brand == SPWPN_VORPAL || coinflip()))
+ {
+ def->number--;
+
+ const char *verb = NULL;
+
+ if (dam_type == DVORP_CLAWING)
+ {
+ static const char *claw_verbs[] = { "rip", "tear", "claw" };
+ verb =
+ claw_verbs[
+ random2( sizeof(claw_verbs) / sizeof(*claw_verbs) ) ];
+ }
+ else
+ {
+ static const char *slice_verbs[] =
+ {
+ "slice", "lop", "chop", "hack"
+ };
+ verb =
+ slice_verbs[
+ random2( sizeof(slice_verbs) / sizeof(*slice_verbs) ) ];
+ }
+
+ if (def->number < 1)
+ {
+ if (defender_visible)
+ mprf( "%s %s %s's last head off!",
+ atk_name(DESC_CAP_THE).c_str(),
+ attacker->conj_verb(verb).c_str(),
+ def_name(DESC_NOCAP_THE).c_str() );
+
+ defender->hurt(attacker, def->hit_points);
+ }
+ else
+ {
+ if (defender_visible)
+ mprf( "%s %s one of %s's heads off!",
+ atk_name(DESC_CAP_THE).c_str(),
+ attacker->conj_verb(verb).c_str(),
+ def_name(DESC_NOCAP_THE).c_str() );
+
+ if (wpn_brand == SPWPN_FLAMING)
+ {
+ if (defender_visible)
+ mpr( "The flame cauterises the wound!" );
+ }
+ else if (def->number < 19)
+ {
+ simple_monster_message( def, " grows two more!" );
+ def->number += 2;
+ heal_monster( def, 8 + random2(8), true );
+ }
+ }
+
+ return (true);
+ }
+
+ return (false);
+}
+
+bool melee_attack::decapitate_hydra(int dam, int damage_type)
+{
+ if (defender->id() == MONS_HYDRA)
+ {
+ const int dam_type =
+ damage_type != -1? damage_type : attacker->damage_type();
+ const int wpn_brand = attacker->damage_brand();
+
+ return chop_hydra_head(dam, dam_type, wpn_brand);
+ }
+ return (false);
+}
+
void melee_attack::player_sustain_passive_damage()
{
if (mons_class_flag(defender->id(), M_ACID_SPLASH))
@@ -2405,9 +2460,10 @@ bool melee_attack::mons_attack_warded_off()
if (needs_message)
{
mprf("%s tries to attack %s, but is repelled by %s holy aura.",
- atk->name(DESC_CAP_THE).c_str(),
- defender->name(DESC_NOCAP_THE).c_str(),
- defender->pronoun(PRONOUN_NOCAP_POSSESSIVE).c_str());
+ atk_name(DESC_CAP_THE).c_str(),
+ def_name(DESC_NOCAP_THE).c_str(),
+ pronoun(defender, PRONOUN_NOCAP_POSSESSIVE,
+ defender_visible).c_str());
}
return (true);
}
@@ -2421,8 +2477,8 @@ bool melee_attack::mons_attack_warded_off()
if (needs_message)
{
mprf("%s tries to attack %s, but flinches away.",
- atk->name(DESC_CAP_THE).c_str(),
- defender->name(DESC_NOCAP_THE).c_str());
+ atk_name(DESC_CAP_THE).c_str(),
+ def_name(DESC_NOCAP_THE).c_str());
}
return (true);
}
@@ -2453,9 +2509,9 @@ bool melee_attack::attack_shield_blocked(bool verbose)
if (needs_message && verbose)
mprf("%s %s %s attack.",
- defender->name(DESC_CAP_THE).c_str(),
+ def_name(DESC_CAP_THE).c_str(),
defender->conj_verb("block").c_str(),
- attacker->name(DESC_NOCAP_ITS).c_str());
+ atk_name(DESC_NOCAP_YOUR).c_str());
defender->shield_block_succeeded();
@@ -2565,9 +2621,9 @@ std::string melee_attack::mons_weapon_desc()
std::string melee_attack::mons_defender_name()
{
if (attacker == defender)
- return attacker->pronoun(PRONOUN_REFLEXIVE);
+ return pronoun(attacker, PRONOUN_REFLEXIVE, attacker_visible);
else
- return defender->name(DESC_NOCAP_THE);
+ return def_name(DESC_NOCAP_THE);
}
void melee_attack::mons_announce_hit(const mon_attack_def &attk)
@@ -2578,7 +2634,7 @@ void melee_attack::mons_announce_hit(const mon_attack_def &attk)
if (needs_message)
mprf("%s %s %s%s%s%s",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb( mons_attack_verb(attk) ).c_str(),
mons_defender_name().c_str(),
debug_damage_number().c_str(),
@@ -2590,7 +2646,7 @@ void melee_attack::mons_announce_dud_hit(const mon_attack_def &attk)
{
if (needs_message)
mprf("%s %s %s but doesn't do any damage.",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb( mons_attack_verb(attk) ).c_str(),
mons_defender_name().c_str());
}
@@ -2638,14 +2694,15 @@ void melee_attack::mons_do_poison(const mon_attack_def &attk)
if (defender->atype() == ACT_PLAYER
&& (attk.type == AT_BITE || attk.type == AT_STING))
{
- mprf("%s %s was poisonous!",
- attacker->name(DESC_CAP_YOUR).c_str(),
- mons_attack_verb(attk).c_str());
+ if (attacker_visible)
+ mprf("%s %s was poisonous!",
+ attacker->name(DESC_CAP_YOUR).c_str(),
+ mons_attack_verb(attk).c_str());
}
else
mprf("%s poisons %s!",
- attacker->name(DESC_CAP_THE).c_str(),
- defender->name(DESC_NOCAP_THE).c_str());
+ atk_name(DESC_CAP_THE).c_str(),
+ def_name(DESC_NOCAP_THE).c_str());
}
int amount = 1;
@@ -2682,7 +2739,7 @@ void melee_attack::wasp_paralyse_defender()
void melee_attack::splash_monster_with_acid(int strength)
{
special_damage += roll_dice(2, 4);
- if (needs_message)
+ if (defender_visible)
mprf("%s is splashed with acid.", defender->name(DESC_CAP_THE).c_str());
}
@@ -2706,6 +2763,11 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
{
default:
break;
+
+ case AF_MUTATE:
+ if (one_chance_in(4))
+ defender->mutate();
+ break;
case AF_POISON:
case AF_POISON_NASTY:
@@ -2742,7 +2804,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
atk->hit_dice + random2(atk->hit_dice));
if (needs_message && special_damage)
mprf("%s %s engulfed in flames%s",
- defender->name(DESC_CAP_THE).c_str(),
+ def_name(DESC_CAP_THE).c_str(),
defender->conj_verb("are").c_str(),
special_attack_punctuation().c_str());
@@ -2755,9 +2817,9 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
atk->hit_dice + random2( 2 * atk->hit_dice ));
if (needs_message && special_damage)
mprf("%s %s %s!",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb("freeze").c_str(),
- defender->name(DESC_NOCAP_THE).c_str());
+ def_name(DESC_NOCAP_THE).c_str());
break;
case AF_ELEC:
@@ -2771,9 +2833,9 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if (needs_message && special_damage)
mprf("%s %s %s%s",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb("shock").c_str(),
- defender->name(DESC_NOCAP_THE).c_str(),
+ def_name(DESC_NOCAP_THE).c_str(),
special_attack_punctuation().c_str());
#ifdef DEBUG_DIAGNOSTICS
@@ -2792,9 +2854,9 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if (needs_message)
{
mprf("%s %s strength from %s injuries!",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb("draw").c_str(),
- defender->name(DESC_NOCAP_ITS).c_str());
+ def_name(DESC_NOCAP_YOUR).c_str());
}
// 4.1.2 actually drains max hp; we're being nicer and just doing
@@ -2835,8 +2897,9 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_BLINK:
if (one_chance_in(3))
{
- mprf("%s %s!", attacker->name(DESC_CAP_THE).c_str(),
- attacker->conj_verb("blink").c_str());
+ if (attacker_visible)
+ mprf("%s %s!", attacker->name(DESC_CAP_THE).c_str(),
+ attacker->conj_verb("blink").c_str());
attacker->blink();
}
break;
@@ -2850,7 +2913,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if (--atk->hit_dice <= 0)
atk->hit_points = -1;
- if (needs_message)
+ if (defender_visible)
mprf("%s %s engulfed in a cloud of spores!",
defender->name(DESC_CAP_THE).c_str(),
defender->conj_verb("are").c_str());
@@ -2890,6 +2953,19 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_DISTORT:
distortion_affects_defender();
break;
+
+ case AF_RAGE:
+ if (!one_chance_in(3) || !defender->can_go_berserk())
+ break;
+
+ if (needs_message)
+ mprf("%s %s %s!",
+ atk_name(DESC_CAP_THE).c_str(),
+ attacker->conj_verb("infuriate").c_str(),
+ def_name(DESC_NOCAP_THE).c_str());
+
+ defender->go_berserk(false);
+ break;
}
}
@@ -2954,7 +3030,7 @@ void melee_attack::mons_perform_attack_rounds()
if (needs_message)
mprf("%s misses %s.",
- attacker->name(DESC_CAP_THE).c_str(),
+ atk_name(DESC_CAP_THE).c_str(),
mons_defender_name().c_str());
}
}
@@ -2967,8 +3043,8 @@ void melee_attack::mons_perform_attack_rounds()
mons_announce_hit(attk);
check_defender_train_armour();
- if (actor_decapitates_hydra(attacker, defender, damage_done,
- attacker->damage_type(attack_number)))
+ if (decapitate_hydra(damage_done,
+ attacker->damage_type(attack_number)))
continue;
special_damage = 0;
diff --git a/crawl-ref/source/fight.h b/crawl-ref/source/fight.h
index 48eb893dc1..f10d5391d6 100644
--- a/crawl-ref/source/fight.h
+++ b/crawl-ref/source/fight.h
@@ -124,6 +124,13 @@ public:
int calc_to_hit(bool random = true);
+ static std::string anon_name(description_level_type desc);
+ static std::string actor_name(const actor *a, description_level_type desc,
+ bool actor_visible);
+ static std::string pronoun(const actor *a, pronoun_type ptyp,
+ bool actor_visible);
+ static std::string anon_pronoun(pronoun_type ptyp);
+
private:
void init_attack();
bool is_water_attack(const actor *, const actor *) const;
@@ -137,6 +144,9 @@ private:
std::string special_attack_punctuation();
std::string attack_strength_punctuation();
+ std::string atk_name(description_level_type desc) const;
+ std::string def_name(description_level_type desc) const;
+
bool attack_shield_blocked(bool verbose);
bool apply_damage_brand();
void calc_elemental_brand_damage(int res, const char *verb);
@@ -149,6 +159,10 @@ private:
void check_defender_train_dodging();
void splash_defender_with_acid(int strength);
void splash_monster_with_acid(int strength);
+ bool decapitate_hydra(int damage_done, int damage_type = -1);
+ bool chop_hydra_head( int damage_done,
+ int dam_type,
+ int wpn_brand );
// Returns true if the defender is banished.
bool distortion_affects_defender();
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 1369f7ed76..a8a070ee2a 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1678,32 +1678,12 @@ void weird_colours(unsigned char coll, char wc[30])
bool go_berserk(bool intentional)
{
- 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 here
- return false;
- }
-
- if (you.is_undead)
- {
- if (intentional)
- mpr("You cannot raise a blood rage in your lifeless body.");
- // or else you won't notice -- no message here
- return false;
- }
-
+ if (!you.can_go_berserk(intentional))
+ return (false);
+
if (Options.tutorial_left)
Options.tut_berserk_counter++;
+
mpr("A red film seems to cover your vision as you go berserk!");
mpr("You feel yourself moving faster!");
mpr("You feel mighty!");
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index bf3d0b56a9..8b5c963210 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -3894,7 +3894,7 @@
M_FLIES,
MR_NO_FLAGS,
0, 10, MONS_MOTH_OF_WRATH, MONS_MOTH_OF_WRATH, MH_NATURAL, -3,
- { {AT_BITE, AF_PLAIN, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_BITE, AF_RAGE, 25}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
{ 9, 3, 5, 0 },
0, 10, 12, 7, MST_NO_SPELLS, CE_CLEAN, Z_SMALL, S_SHOUT, I_NORMAL,
MONUSE_NOTHING, SIZE_MEDIUM
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 8001357055..a0ba09cfc6 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -377,6 +377,18 @@ bool mons_is_stationary(const monsters *mons)
return (mons_class_is_stationary(mons->type));
}
+bool mons_is_icy(const monsters *mons)
+{
+ return (mons_is_icy(mons->type));
+}
+
+bool mons_is_icy(int mtype)
+{
+ return (mtype == MONS_ICE_BEAST
+ || mtype == MONS_SIMULACRUM_SMALL
+ || mtype == MONS_SIMULACRUM_LARGE);
+}
+
bool invalid_monster(const monsters *mons)
{
return (!mons || mons->type == -1);
@@ -2626,6 +2638,12 @@ void monsters::attacking(actor * /* other */)
{
}
+bool monsters::can_go_berserk() const
+{
+ // Stub
+ return (false);
+}
+
void monsters::go_berserk(bool /* intentional */)
{
}
@@ -3712,6 +3730,19 @@ void monsters::check_speed()
}
}
+void monsters::mutate()
+{
+ if (holiness() != MH_NATURAL)
+ return;
+
+ monster_polymorph(this, RANDOM_MONSTER, 100);
+}
+
+bool monsters::is_icy() const
+{
+ return (mons_is_icy(type));
+}
+
/////////////////////////////////////////////////////////////////////////
// mon_enchant
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 1317bf983a..9f2a2f4a47 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -411,6 +411,8 @@ bool mons_was_seen(const monsters *m);
bool mons_is_known_mimic(const monsters *m);
bool mons_is_evil( const monsters *mon );
bool mons_is_unholy( const monsters *mon );
+bool mons_is_icy( const monsters *mon );
+bool mons_is_icy( int mcls );
bool mons_has_lifeforce( const monsters *mon );
monster_type mons_genus( int mc );
monster_type mons_species( int mc );
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index a14d593a2e..b05018f745 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -1003,7 +1003,7 @@ static bool valid_morph( struct monsters *monster, int new_mclass )
// note that power is (as of yet) unused within this function -
// may be worthy of consideration of later implementation, though,
// so I'll still let the parameter exist for the time being {dlb}
-bool monster_polymorph( struct monsters *monster, int targetc, int power )
+bool monster_polymorph( monsters *monster, int targetc, int power )
{
char str_polymon[INFO_SIZE] = ""; // cannot use info[] here {dlb}
bool player_messaged = false;
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index e3aee03759..eb2c4767a4 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -4935,6 +4935,40 @@ void player::go_berserk(bool intentional)
::go_berserk(intentional);
}
+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 here
+ return (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 here
+ return (false);
+ }
+
+ return (true);
+}
+
void player::god_conduct(int thing_done, int level)
{
::did_god_conduct(thing_done, level);
@@ -5220,3 +5254,16 @@ void player::sicken(int amount)
disease = (tmp > 210) ? 210 : tmp;
learned_something_new(TUT_YOU_SICK);
}
+
+void player::mutate()
+{
+ if (one_chance_in(5))
+ ::mutate(100);
+ else
+ give_bad_mutation();
+}
+
+bool player::is_icy() const
+{
+ return (attribute[ATTR_TRANSFORMATION] == TRAN_ICE_BEAST);
+}
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index dfdb0ab4fd..082ad2c784 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -3027,6 +3027,44 @@ void TravelCache::update_waypoints() const
}
}
+void TravelCache::delete_waypoint()
+{
+ if (!get_waypoint_count())
+ return;
+
+ while (get_waypoint_count())
+ {
+ mesclr();
+ mpr("Existing waypoints:");
+ list_waypoints();
+ mpr("Delete which waypoint? (* - delete all, Esc - exit) ",
+ MSGCH_PROMPT);
+
+ int key = getch();
+ if (key >= '0' && key <= '9')
+ {
+ key -= '0';
+ if (waypoints[key].is_valid())
+ {
+ waypoints[key].reset();
+ continue;
+ }
+ }
+ else if (key == '*')
+ {
+ for (int i = 0; i < TRAVEL_WAYPOINT_COUNT; ++i)
+ waypoints[i].reset();
+ break;
+ }
+
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ mesclr();
+ mpr("All waypoints deleted. Have a nice day!");
+}
+
void TravelCache::add_waypoint(int x, int y)
{
if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS
@@ -3037,16 +3075,27 @@ void TravelCache::add_waypoint(int x, int y)
}
mesclr();
- if (get_waypoint_count())
+
+ const bool waypoints_exist = get_waypoint_count();
+ if (waypoints_exist)
{
- mpr("Existing waypoints");
+ mpr("Existing waypoints:");
list_waypoints();
}
- mpr("Assign waypoint to what number? (0-9) ", MSGCH_PROMPT);
- int keyin = get_ch();
+ mprf(MSGCH_PROMPT, "Assign waypoint to what number? (0-9%s) ",
+ waypoints_exist? ", D - delete waypoint" : "");
- if (keyin < '0' || keyin > '9') return;
+ int keyin = tolower(get_ch());
+
+ if (waypoints_exist && keyin == 'd')
+ {
+ delete_waypoint();
+ return;
+ }
+
+ if (keyin < '0' || keyin > '9')
+ return;
int waynum = keyin - '0';
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index d60311b07c..eb8f1abd13 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -162,6 +162,13 @@ public:
unsigned short packed_place() const;
std::string describe(bool long_name = false, bool with_number = true) const;
+ void reset()
+ {
+ branch = 0;
+ depth = -1;
+ level_type = LEVEL_DUNGEON;
+ }
+
bool is_valid() const
{
return (branch != -1 && depth != -1) || level_type != LEVEL_DUNGEON;
@@ -234,6 +241,12 @@ struct level_pos
return id.depth > -1 && pos.x != -1 && pos.y != -1;
}
+ void reset()
+ {
+ id.reset();
+ pos = coord_def(-1, -1);
+ }
+
void save(FILE *) const;
void load(FILE *);
};
@@ -404,6 +417,7 @@ public:
void set_level_excludes();
void add_waypoint(int x = -1, int y = -1);
+ void delete_waypoint();
unsigned char is_waypoint(const level_pos &lp) const;
void list_waypoints() const;
void travel_to_waypoint(int number);