player vs monster. Specifically, hydras get their as many attacks as they have heads vs other monsters, and other monsters can chop off hydra heads (at 25% of the probability that the player has of chopping off heads).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@936 c06c8d41-db1a-0410-9941-cceddc491573
33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC /////////////////////////////////////////////////////////////////////////////// Actor stuff - generic functions that can be called with a monster pointer,// or NULL for the player.std::string pronoun_you(description_level_type desc){return (desc == DESC_CAP_A || desc == DESC_CAP_THE? "You" : "you");}std::string actor_name(const monsters *actor, description_level_type desc){return (actor? ptr_monam(actor, desc) : pronoun_you(desc));}// actor_verb(NULL, "chop") == chop, as in "You chop"// actor_verb(monster, "chop") == chops, as in "The skeletal warrior chops".std::string actor_verb(const monsters *actor, const std::string &verb){// Simplistic - we really should be conjugating the verb// appropriately. We'll special-case as necessary.return (actor? verb + "s" : verb);}int actor_damage_type(const monsters *actor){return (actor? mons_damage_type(actor) : player_damage_type());}int actor_damage_brand(const monsters *actor){return (actor? mons_damage_brand(actor) : player_damage_brand());}
(you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS|| you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON|| you.mutation[MUT_CLAWS]|| you.species == SP_TROLL|| you.species == SP_GHOUL))
you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
}bool mons_wields_two_weapons(const monsters *m){return (m->type == MONS_TWO_HEADED_OGRE || m->type == MONS_ETTIN);}// Does not check whether the monster can dual-wield - that is the// caller's responsibility.int mons_offhand_weapon_index(const monsters *m){return (m->inv[1]);}int mons_weapon_index(const monsters *m){// This randomly picks one of the wielded weapons for monsters that can use// two weapons. Not ideal, but better than nothing. fight.cc does it right,// for various values of right.int weap = m->inv[MSLOT_WEAPON];if (mons_wields_two_weapons(m)){const int offhand = mons_offhand_weapon_index(m);if (offhand != NON_ITEM && (weap == NON_ITEM || coinflip()))weap = offhand;}return (weap);}int mons_base_damage_type(const monsters *m){return (mons_class_flag(m->type, M_CLAWS)? DVORP_CLAWING : DVORP_CRUSHING);}int mons_damage_type(const monsters *m){const int mweap = mons_weapon_index(m);if (mweap == NON_ITEM)return (mons_base_damage_type(m));return (get_vorpal_type(mitm[mweap]));
}// Returns true if a head got lopped off.static bool chop_hydra_head( const monsters *attacker,monsters *defender,int damage_done,int dam_type,int wpn_brand ){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 && !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!",actor_name(attacker, DESC_CAP_THE).c_str(),actor_verb(attacker, verb).c_str(),str_monam(defender, DESC_NOCAP_THE).c_str() );defender->hit_points = -1;}else{if (defender_visible)mprf( "%s %s one of %s's heads off!",actor_name(attacker, DESC_CAP_THE).c_str(),actor_verb(attacker, verb).c_str(),str_monam(defender, 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(monsters *attacker, monsters *defender,int damage_done){if (defender->type == MONS_HYDRA){const int dam_type = actor_damage_type(attacker);const int wpn_brand = actor_damage_brand(attacker);return chop_hydra_head(attacker, defender, damage_done,dam_type, wpn_brand);}return (false);}static bool player_fumbles_attack(){// fumbling in shallow water <early return>:if (player_in_water() && !player_is_swimming()){if (random2(you.dex) < 4 || one_chance_in(5)){mpr("Unstable footing causes you to fumble your attack.");return (true);}}return (false);}
// fumbling in shallow water <early return>:if (player_in_water() && !player_is_swimming()){if (random2(you.dex) < 4 || one_chance_in(5)){mpr("Unstable footing causes you to fumble your attack.");return (false);}}
if (player_fumbles_attack())return (false);
// wet merfolkif (player_is_swimming()// monster not a water creature, but is in water&& monster_floundering(defender)){water_attack = true;}
// Swimmers get bonus against non-swimmers wading in water.water_attack = player_is_swimming() && monster_floundering(defender);
if (defender->type == MONS_JELLY|| defender->type == MONS_BROWN_OOZE|| defender->type == MONS_ACID_BLOB|| defender->type == MONS_ROYAL_JELLY){weapon_acid(5);}
if (defender->type == MONS_JELLY|| defender->type == MONS_BROWN_OOZE|| defender->type == MONS_ACID_BLOB|| defender->type == MONS_ROYAL_JELLY){weapon_acid(5);}
if (defender->type == MONS_HYDRA){const int dam_type = player_damage_type();const int wpn_brand = player_damage_brand();
// If decapitation, extra damage is bypassed.if (actor_decapitates_hydra(NULL, defender, damage_done))goto mons_dies;
if ((dam_type == DVORP_SLICING || dam_type == DVORP_CHOPPING)&& damage_done > 0&& (damage_done >= 4 || wpn_brand == SPWPN_VORPAL || coinflip())){defender->number--;temp_rand = random2(4);const char *const verb = (temp_rand == 0) ? "slice" :(temp_rand == 1) ? "lop" :(temp_rand == 2) ? "chop" : "hack";if (defender->number < 1){snprintf( info, INFO_SIZE, "You %s %s's last head off!",verb, ptr_monam(defender, DESC_NOCAP_THE) );mpr( info );defender->hit_points = -1;}else{snprintf( info, INFO_SIZE, "You %s one of %s's heads off!",verb, ptr_monam(defender, DESC_NOCAP_THE) );mpr( info );if (wpn_brand == SPWPN_FLAMING)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 );}}// if the hydra looses a head:// - it's dead if it has none remaining (HP set to -1)// - flame used to cauterise doesn't do extra damage// - ego weapons do their additional damage to the// hydra's decapitated head, so it's ignored.//// ... and so we skip the special damage.goto mons_dies;}}
static void mons_lose_attack_energy(monsters *attacker, int wpn_speed,int which_attack){// speed adjustment for weapon using monstersif (wpn_speed > 0){// only get one third penalty/bonus for second weapons.if (which_attack > 0)wpn_speed = (20 + wpn_speed) / 3;attacker->speed_increment -= (wpn_speed - 10) / 2;}}
// adjust time taken if monster used weaponif (wpn_speed > 0){// only get one third penalty/bonus for second weapons.if (runthru > 0)wpn_speed = (20 + wpn_speed) / 3;attacker->speed_increment -= (wpn_speed - 10) / 2;}
mons_lose_attack_energy(attacker, wpn_speed, runthru);
// speed adjustment for weapon using monstersif (wpn_speed > 0){// only get one third penalty/bonus for second weapons.if (runthru > 0)wpn_speed = (20 + wpn_speed) / 3;attacker->speed_increment -= (wpn_speed - 10) / 2;}
mons_lose_attack_energy(attacker, wpn_speed, runthru);