From 18dac1924da21380570eb193e6a363e0c813c9de Mon Sep 17 00:00:00 2001 From: dshaligram Date: Fri, 11 May 2007 14:14:10 +0000 Subject: 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 --- crawl-ref/source/enum.h | 3 +- crawl-ref/source/externs.h | 10 ++ crawl-ref/source/fight.cc | 400 +++++++++++++++++++++++++------------------ crawl-ref/source/fight.h | 14 ++ crawl-ref/source/misc.cc | 28 +-- crawl-ref/source/mon-data.h | 2 +- crawl-ref/source/mon-util.cc | 31 ++++ crawl-ref/source/mon-util.h | 2 + crawl-ref/source/monstuff.cc | 2 +- crawl-ref/source/player.cc | 47 +++++ crawl-ref/source/travel.cc | 59 ++++++- crawl-ref/source/travel.h | 14 ++ 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(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); -- cgit v1.2.3-54-g00ecf