Fixed tracer explosion beams generating clouds.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@959 c06c8d41-db1a-0410-9941-cceddc491573
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC RIMJO42HB75SAZH44KZ2UH2QULOPIJLMEN4CR2CYNR2EKEKLFHSQC TPSCOEB3X6LNZ7F5UBMHDZ4IUE4H3RLX6IGNW65VSJBDMNNZ3FMAC GBUB77EAYHOFY6GQ5IY3ZSBC7FSQFZZKYNBD5QMCQFIKFLYLWHOQC IJ7CEBTMSNGTBLUYTRT57MAUKCN5VALWIJ4T34ULGP3JYFWALPMQC NVZRXXE5HL76ZOGL6H4LXJJMTWCULFGUJMOZKE7UQBAVDKJRMF3QC QDWDUURSNLMT6AXNNJ3DEQCWAKCAIHV6MP5F7QGIBGXOG2BI2NPQC R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC 77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC 33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC NFOXLH722RGWYY5D63VV6SF2XEJBEOQEFQME6FSA4HZRK3CPLSRQC RI5TNMRQUYPOFGT3LBGNSIYVU2IAQ2F6BT2AMUMM3EFJXOZRWPAQC ABPRQBBNMOXUJJNZXAJBIIUULMCB23MKAM5T3M5YFXDORJ3IY3JAC ITDUEUO7XAZANPC4GRB3SEDFBOV7GLFPNPTYE5LYNC3CS6BSVZTQC JW2KRJHES33W7UTWZ6NDO4TLMK4EFU4HKZXBWR2UJOMPCCOTR4CQC ZMYT53SCUSEG26QOTSRBQ3TWMSQTGBXZNEDPLPHM5U3VHALVOOIQC 3WRAJZ5ZLOSIZHFBUH5552QC4F3GAK7AXF6VIQFVN6VY7PUO6HPQC return (desc == DESC_CAP_A || desc == DESC_CAP_THE? "You" : "you");
switch (desc){case DESC_CAP_A: case DESC_CAP_THE:return "You";case DESC_NOCAP_A: case DESC_NOCAP_THE:default:return "you";case DESC_CAP_YOUR:return "Your";case DESC_NOCAP_YOUR:return "your";}
{if (hunger_increase > 0)::make_hungry(hunger_increase, silent);else if (hunger_increase < 0)::lessen_hunger(-hunger_increase, silent);}int player::holy_aura() const{return (duration[DUR_REPEL_UNDEAD]? piety : 0);}int player::warding() const{if (wearing_amulet(AMU_WARDING))return (30);if (religion == GOD_VEHUMET && duration[DUR_PRAYER]&& !player_under_penance() && piety >= piety_breakpoint(2)){// Clamp piety at 160 and scale that down to a max of 30.const int wardpiety = piety > 160? 160 : piety;return (wardpiety * 3 / 16);}return (0);}bool player::paralysed() const{return (paralysis);}bool player::confused() const
::make_hungry(hunger_increase, silent);
return (conf);}int player::shield_block_penalty() const{return (5 * shield_blocks * shield_blocks);}int player::shield_bonus() const{return random2(player_shield_class())+ (random2(dex) / 4)+ (random2(skill_bump(SK_SHIELDS)) / 4)- 1;}int player::shield_bypass_ability(int tohit) const{return (10 + tohit * 2);}void player::shield_block_succeeded(){shield_blocks++;if (one_chance_in(4))exercise(SK_SHIELDS, 1);}bool player::wearing_light_armour(bool with_skill) const{return (player_light_armour(with_skill));}void player::exercise(skill_type sk, int qty){::exercise(sk, qty);}int player::skill(skill_type sk, bool bump) const{return (bump? skill_bump(sk) : skills[sk]);}int player::armour_class() const{return (player_AC());}int player::melee_evasion(const actor *act) const{return (random2limit(player_evasion(), 40)+ random2(you.dex) / 3- (act->visible()? 2 : 14)- (you_are_delayed()? 5 : 0));}void player::heal(int amount, bool max_too){::inc_hp(amount, max_too);}int player::holiness() const{if (is_undead)return (MH_UNDEAD);if (species == SP_DEMONSPAWN)return (MH_DEMONIC);return (MH_NATURAL);}int player::res_fire() const{return (player_res_fire());}int player::res_cold() const{return (player_res_cold());}int player::res_elec() const{return (player_res_electricity());}int player::res_poison() const{return (player_res_poison());}int player::res_negative_energy() const{return (player_prot_life());}bool player::levitates() const{return (player_is_levitating());}int player::mons_species() const{switch (species){case SP_HILL_ORC:return (MONS_ORC);case SP_ELF: case SP_HIGH_ELF: case SP_GREY_ELF:case SP_DEEP_ELF: case SP_SLUDGE_ELF:return (MONS_ELF);default:return (MONS_HUMAN);}}void player::poison(actor*, int amount){::poison_player(amount);}void player::expose_to_element(beam_type element, int st){::expose_player_to_element(element, st);}void player::blink(){random_blink(true);}void player::teleport(bool now, bool abyss_shift){if (now)you_teleport2(true, abyss_shift);elseyou_teleport();}void player::hurt(actor *agent, int amount){if (agent->atype() == ACT_MONSTER)ouch(amount, monster_index( dynamic_cast<monsters*>(agent) ),KILLED_BY_MONSTER);else{// Should never happen!ASSERT(false);ouch(amount, 0, KILLED_BY_SOMETHING);}if (religion == GOD_XOM && hp <= hp_max / 3&& one_chance_in(10)){Xom_acts(true, experience_level, false);}}void player::drain_stat(int stat, int amount){lose_stat(stat, amount);}void player::rot(actor *who, int rotlevel, int immed_rot){if (is_undead)return;if (rotlevel)rot_player( rotlevel );if (immed_rot)rot_hp(immed_rot);if (rotlevel && one_chance_in(4))disease_player( 50 + random2(100) );
void player::confuse(int str){confuse_player(str);}void player::paralyse(int str){mprf( "You %s the ability to move!",(paralysis) ? "still haven't" : "suddenly lose" );if (str > paralysis)paralysis = str;if (paralysis > 13)paralysis = 13;}void player::slow_down(int str){::slow_player( str );}
// hpdice[4]: [0]=HD [1]=min_hp [2]=rand_hp [3]=add_hp// min hp = [0]*[1]+[3] & max hp = [0]*([1]+[2])+[3])// example: the Iron Golem, hpdice={15,7,4,0}// 15*7 < hp < 15*(7+4),// 105 < hp < 165// hp will be around 135 each time. (assuming an good random number generator)// !!!!!!! The system is exactly the same as before, only the way of writing changed !!!!unsigned char hpdice[4]; // until we have monsters with 32767 hp,this is easily possible
// hpdice[4]: [0]=HD [1]=min_hp [2]=rand_hp [3]=add_hp// min hp = [0]*[1]+[3] & max hp = [0]*([1]+[2])+[3])// example: the Iron Golem, hpdice={15,7,4,0}// 15*7 < hp < 15*(7+4),// 105 < hp < 165// hp will be around 135 each time.unsigned hpdice[4];
ASSERT(rt >= 0);ASSERT(rt <= 3);
switch (monster->type){case MONS_ZOMBIE_SMALL: case MONS_ZOMBIE_LARGE:case MONS_SKELETON_SMALL: case MONS_SKELETON_LARGE:case MONS_SIMULACRUM_SMALL: case MONS_SIMULACRUM_LARGE:case MONS_SPECTRAL_THING:return (true);default:return (false);}}
if (rt < 0 || rt > 3) // make it fool-proofreturn (0);
int downscale_zombie_damage(int damage){// these are cumulative, of course: {dlb}if (damage > 1)damage--;if (damage > 4)damage--;if (damage > 11)damage--;if (damage > 14)damage--;
return (smc->damage[rt]);
mon_attack_def downscale_zombie_attack(const monsters *mons,mon_attack_def attk){switch (attk.type){case AT_STING: case AT_SPORE:case AT_TOUCH: case AT_ENGULF:attk.type = AT_HIT;break;default:break;}if (mons->type == MONS_SIMULACRUM_LARGE|| mons->type == MONS_SIMULACRUM_SMALL){attk.flavour = AF_COLD;}else{attk.flavour = AF_PLAIN;}attk.damage = downscale_zombie_damage(attk.damage);return (attk);}mon_attack_def mons_attack_spec(const monsters *mons, int attk_number){int mc = mons->type;const bool zombified = mons_is_zombified(mons);if ((attk_number < 0 || attk_number > 3) || mc == MONS_HYDRA)attk_number = 0;if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)return mon_attack_def::attk(ghost.values[GVAL_DAMAGE]);if (zombified)mc = mons_zombie_base(mons);mon_attack_def attk = smc->attack[attk_number];if (attk.flavour == AF_KLOWN){switch (random2(6)){case 0: attk.flavour = AF_POISON_NASTY; break;case 1: attk.flavour = AF_ROT; break;case 2: attk.flavour = AF_DRAIN_XP; break;case 3: attk.flavour = AF_FIRE; break;case 4: attk.flavour = AF_COLD; break;case 5: attk.flavour = AF_BLINK; break;}}return (zombified? downscale_zombie_attack(mons, attk) : attk);}int mons_damage(int mc, int rt){if (rt < 0 || rt > 3)rt = 0;return smc->attack[rt].damage;
}static int equip_slot_to_mslot(equipment_type eq){switch (eq){case EQ_WEAPON: return MSLOT_WEAPON;case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;default: return (-1);}}item_def *monsters::slot_item(equipment_type eq){int mslot = equip_slot_to_mslot(eq);int mindex = mslot == -1? NON_ITEM : inv[mslot];return (mindex == NON_ITEM? NULL: &mitm[mindex]);
{}void monsters::expose_to_element(beam_type, int){}void monsters::banish(){// [dshaligram] FIXME: We should really put these monsters on a// queue and load them when the player enters the Abyss.monster_die(this, KILL_RESET, 0);}int monsters::holy_aura() const{return ((type == MONS_DAEVA || type == MONS_ANGEL)? hit_dice : 0);}bool monsters::visible() const{return (mons_near(this) && player_monster_visible(this));}bool monsters::confused() const{return (mons_is_confused(this));}bool monsters::paralysed() const{return (mons_is_paralysed(this));}bool monsters::asleep() const{return (mons_is_sleeping(this));}int monsters::shield_bonus() const{// XXX: Monsters don't actually get shields yet.const item_def *shld = const_cast<monsters*>(this)->shield();if (shld){const int shld_c = property(*shld, PARM_AC);return (random2(shld_c + random2(hit_dice / 2)) / 2);}return (0);}int monsters::shield_block_penalty() const{return (0);}int monsters::shield_bypass_ability(int) const{return (15 + hit_dice / 2);}int monsters::armour_class() const{return (ac);}int monsters::melee_evasion(const actor *act) const{int evasion = ev;if (paralysed() || asleep() || one_chance_in(20))evasion = 0;else if (confused())evasion /= 2;return (evasion);}void monsters::heal(int amount, bool max_too){hit_points += amount;if (max_too)max_hit_points += amount;if (hit_points > max_hit_points)hit_points = max_hit_points;}int monsters::holiness() const{return (mons_holiness(this));}int monsters::res_fire() const{return (mons_res_fire(this));}int monsters::res_cold() const{return (mons_res_cold(this));}int monsters::res_elec() const{return (mons_res_elec(this));}int monsters::res_poison() const{return (mons_res_poison(this));}int monsters::res_negative_energy() const{return (mons_res_negative_energy(this));}bool monsters::levitates() const{return (mons_flies(this));}int monsters::mons_species() const{return ::mons_species(type);}void monsters::poison(actor *agent, int amount){if (amount <= 0)return;// Scale poison down for monsters.if (!(amount /= 2))amount = 1;poison_monster(this, agent->atype() == ACT_PLAYER, amount);}int monsters::skill(skill_type sk, bool) const{switch (sk){case SK_NECROMANCY:return (holiness() == MH_UNDEAD? hit_dice / 2 : hit_dice / 3);default:return (0);}}void monsters::blink(){monster_blink(this);}void monsters::teleport(bool now, bool){monster_teleport(this, now, false);}bool monsters::alive() const{return (hit_points > 0 && type != -1);}void monsters::hurt(actor *agent, int amount){if (amount <= 0)return;hit_points -= amount;if ((hit_points < 1 || hit_dice < 1) && type != -1){if (agent->atype() == ACT_PLAYER)monster_die(this, KILL_YOU, 0);elsemonster_die(this, KILL_MON,monster_index( dynamic_cast<monsters*>(agent) ));}}void monsters::rot(actor *agent, int rotlevel, int immed_rot)
if (mons_holiness(this) != MH_NATURAL)return;// Apply immediate damage because we can't handle rotting for monsters yet.const int damage = immed_rot + random2(rotlevel * 3);if (damage){if (mons_near(this) && player_monster_visible(this))mprf("%s %s!",name(DESC_CAP_THE).c_str(),rotlevel == 0? "looks less resilient" : "rots");hurt(agent, damage);if (alive()){max_hit_points -= immed_rot * 2;if (hit_points > max_hit_points)hit_points = max_hit_points;}}
void monsters::confuse(int strength){bolt beam_temp;beam_temp.flavour = BEAM_CONFUSION;mons_ench_f2( this, beam_temp );}void monsters::paralyse(int strength){bolt paralysis;paralysis.flavour = BEAM_PARALYSIS;mons_ench_f2(this, paralysis);}void monsters::slow_down(int strength){bolt slow;slow.flavour = BEAM_SLOW;mons_ench_f2(this, slow);}
0, 10, MONS_QUASIT, MONS_QUASIT, MH_DEMONIC, 50,{ 3, 2, 2, 0 },
0, 10, MONS_QUASIT, MONS_QUASIT, MH_DEMONIC, 5,{ {AT_BITE, AF_DRAIN_DEX, 3}, {AT_CLAW, AF_DRAIN_DEX, 2}, {AT_CLAW, AF_DRAIN_DEX, 2}, {AT_NONE, AF_PLAIN, 0} },
MR_RES_FIRE | MR_RES_COLD | MR_RES_POISON,0, 15, MONS_HUMAN, MONS_KILLER_KLOWN, MH_NATURAL, MAG_IMMUNE,{ 30, 0, 0, 0 },
MR_NO_FLAGS,0, 15, MONS_HUMAN, MONS_KILLER_KLOWN, MH_NATURAL, -6,{ {AT_HIT, AF_KLOWN, 30}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
0, 10, MONS_CLAY_GOLEM, MONS_ELECTRIC_GOLEM, MH_NONLIVING, MAG_IMMUNE,{ 12, 12, 12, 12 },
0, 10, MONS_CLAY_GOLEM, MONS_ELECTRIC_GOLEM, MH_NONLIVING, -8,{ {AT_HIT, AF_ELEC, 12}, {AT_HIT, AF_ELEC, 12}, {AT_HIT, AF_ELEC, 12}, {AT_HIT, AF_PLAIN, 12} },
snprintf( info, INFO_SIZE, "You %s the ability to move!",(you.paralysis) ? "still haven't" : "suddenly lose" );mpr( info, MSGCH_WARN );new_value = 2 + random2( 6 + you.paralysis );if (new_value > you.paralysis)you.paralysis = new_value;if (you.paralysis > 13)you.paralysis = 13;
you.paralyse(2 + random2( 6 + you.paralysis ));
bool attack_shield_blocked(bool verbose);bool apply_damage_brand();void calc_elemental_brand_damage(int res, const char *verb);int resist_adjust_damage(int res, int rawdamage);int fire_res_apply_cerebov_downgrade(int res);void drain_defender();void drain_player();void drain_monster();void check_defender_train_armour();void check_defender_train_dodging();void splash_defender_with_acid(int strength);void splash_monster_with_acid(int strength);
bool mons_self_destructs();bool mons_attack_warded_off();int mons_attk_delay();int mons_calc_damage(const mon_attack_def &attk);void mons_apply_attack_flavour(const mon_attack_def &attk);int mons_apply_defender_ac(int damage, int damage_max);bool mons_perform_attack();void mons_perform_attack_rounds();void mons_check_attack_perceived();std::string mons_attack_verb(const mon_attack_def &attk);std::string mons_weapon_desc();void mons_announce_hit(const mon_attack_def &attk);void mons_announce_dud_hit(const mon_attack_def &attk);void mons_set_weapon(const mon_attack_def &attk);void mons_do_poison(const mon_attack_def &attk);std::string mons_defender_name();void wasp_paralyse_defender();
void melee_attack::player_calc_brand_damage(
int melee_attack::resist_adjust_damage(int res, int rawdamage){if (res > 0){if (defender->atype() == ACT_MONSTER)rawdamage = 0;elserawdamage /= 1 + res * res;}else if (res < 0)rawdamage *= 2;if (rawdamage < 0)rawdamage = 0;return (rawdamage);}void melee_attack::calc_elemental_brand_damage(
bool melee_attack::player_apply_damage_brand()
void melee_attack::drain_defender(){// What to do, they're different...if (defender->atype() == ACT_PLAYER)drain_player();elsedrain_monster();}void melee_attack::drain_player(){drain_exp();special_damage =random2(damage_done) / (2 + defender->res_negative_energy()) + 1;// Noop for monsters, but what the heck.attacker->god_conduct(DID_NECROMANCY, 2);}void melee_attack::drain_monster(){if (defender->res_negative_energy() > 0 || one_chance_in(3))return;special_damage_message =make_stringf("%s %s %s!",attacker->name(DESC_CAP_THE).c_str(),attacker->conj_verb("drain").c_str(),defender->name(DESC_NOCAP_THE).c_str());if (one_chance_in(5))def->hit_dice--;def->max_hit_points -= 2 + random2(3);def->hit_points -= 2 + random2(3);if (def->hit_points >= def->max_hit_points)def->hit_points = def->max_hit_points;if (def->hit_dice < 1)def->hit_points = 0;special_damage = 1 + (random2(damage_done) / 2);attacker->god_conduct(DID_NECROMANCY, 2);}bool melee_attack::apply_damage_brand()
res = mons_res_fire(def);if (weapon && weapon->special == SPWPN_SWORD_OF_CEREBOV && res >= 0)res = (res > 0) - 1;player_calc_brand_damage(res, "You burn %s%s");
res = fire_res_apply_cerebov_downgrade( defender->res_fire() );calc_elemental_brand_damage(res, "burn");defender->expose_to_element(BEAM_FIRE);
special_damage_message ="There is a sudden explosion of sparks!";special_damage = random2avg(28, 3);
special_damage_message =defender->atype() == ACT_PLAYER?"You are electrocuted!": "There is a sudden explosion of sparks!";special_damage = 10 + random2(15);
if (mons_res_negative_energy(def) > 0 || one_chance_in(3))break;special_damage_message =make_stringf("You drain %s!",defender->name(DESC_NOCAP_THE).c_str());if (one_chance_in(5))def->hit_dice--;def->max_hit_points -= 2 + random2(3);def->hit_points -= 2 + random2(3);
drain_defender();break;
if (def->hit_points >= def->max_hit_points)def->hit_points = def->max_hit_points;if (def->hit_dice < 1)def->hit_points = 0;special_damage = 1 + (random2(damage_done) / 2);did_god_conduct( DID_NECROMANCY, 2 );break;
if (mons_holiness(def) != MH_NATURAL ||mons_res_negative_energy(def) > 0 ||damage_done < 1 || you.hp == you.hp_max ||
if (defender->holiness() != MH_NATURAL ||defender->res_negative_energy() > 0 ||damage_done < 1 || attacker->stat_hp() == attacker->stat_maxhp() ||
inc_hp(1 + random2(damage_done), false);
int hp_boost = 0;// thus is probably more valuable on larger weapons?if (weapon&& is_fixed_artefact( *weapon )&& weapon->special == SPWPN_VAMPIRES_TOOTH){hp_boost = damage_done;}else{hp_boost = 1 + random2(damage_done);}attacker->heal(hp_boost);
str_simple_monster_message(def, " convulses in agony.");special_damage += random2( 1 + you.skills[SK_NECROMANCY] );
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) );
simple_monster_message(def," basks in the translocular energy." );heal_monster(def, 1 + random2avg(7, 2), true); // heh heh
special_damage_message =make_stringf("%s %s in the translocular energy.",defender->name(DESC_CAP_THE).c_str(),defender->conj_verb("bask").c_str());defender->heal(1 + random2avg(7, 2), true); // heh heh
if (coinflip())
// Used to be coinflip() || coinflip() for players, just coinflip()// for monsters; this is a compromise. Note that it makes banishment// a touch more likely for players, and a shade less likely for// monsters.if (!one_chance_in(3))
{return (false);}bool melee_attack::mons_attack_you(){return (false);}int melee_attack::mons_to_hit()
// TODOreturn 0;}///////////////////////////////////////////////////////////////////////////static void tutorial_weapon_check(const item_def *weapon){if (weapon &&(weapon->base_type != OBJ_WEAPONS|| is_range_weapon(*weapon)))
mons_perform_attack();if (perceived_attack && (def->foe == MHITNOT || one_chance_in(3))&& atk->alive())
}// Returns true if you hit the monster.bool you_attack(int monster_attacked, bool unarmed_attacks){monsters *defender = &menv[monster_attacked];melee_attack attk(&you, defender, unarmed_attacks);// We're trying to hit a monster, break out of travel/explore now.interrupt_activity(AI_HIT_MONSTER, defender);// For tutorials, check if the player is fighting with something unsuitabletutorial_weapon_check(attk.weapon);return attk.attack();
return (did_hit);
struct monsters *attacker = &menv[monster_attacking];int damage_taken = 0;bool hit = false;bool blocked = false;// being attacked by a water creature while standing in water?bool water_attack = false;bool bearing_shield = (you.equip[EQ_SHIELD] != -1);int mmov_x = 0;int specdam = 0;char heads = 0; // for hydras {dlb}int hand_used = 0;int extraDamage = 0; // from special mon. attacks (burn, freeze, etc)int resistValue = 0; // player resist value (varies)int wpn_speed;char str_pass[ ITEMNAME_SIZE ];#if DEBUG_DIAGNOSTICSchar st_prn[ 20 ];#endifif (attacker->type == MONS_HYDRA)heads = attacker->number;if (mons_friendly(attacker))return;if (attacker->type == MONS_GIANT_SPORE|| attacker->type == MONS_BALL_LIGHTNING)
const int holy = defender->holy_aura();if (holy && mons_holiness(atk) == MH_UNDEAD&& !check_mons_resist_magic( atk, holy ))
attacker->hit_points = -1;return;}// if a friend wants to help, they can attack <monster_attacking>if (you.pet_target == MHITNOT)you.pet_target = monster_attacking;if (mons_has_ench( attacker, ENCH_SUBMERGED ))return;// If a mimic is attacking the player, it is thereafter known.if (mons_is_mimic(attacker->type))attacker->flags |= MF_KNOWN_MIMIC;if (you.duration[DUR_REPEL_UNDEAD]&& mons_holiness( attacker ) == MH_UNDEAD&& !check_mons_resist_magic( attacker, you.piety )){if (simple_monster_message(attacker," tries to attack you, but is repelled by your holy aura."))interrupt_activity( AI_MONSTER_ATTACKS, attacker );return;}if (wearing_amulet(AMU_WARDING)|| (you.religion == GOD_VEHUMET && you.duration[DUR_PRAYER]&& (!player_under_penance() && you.piety >= piety_breakpoint(2)))){if (mons_has_ench(attacker, ENCH_ABJ_I, ENCH_ABJ_VI))
if (needs_message)
// should be scaled {dlb}if (coinflip()){if (simple_monster_message(attacker," tries to attack you, but flinches away."))interrupt_activity( AI_MONSTER_ATTACKS, attacker );return;}
mprf("%s tries to attack %s, but is repelled by %s holy auro.",atk->name(DESC_CAP_THE).c_str(),defender->name(DESC_NOCAP_THE).c_str(),defender->pronoun(PRONOUN_NOCAP_POSSESSIVE).c_str());
if (grd[attacker->x][attacker->y] == DNGN_SHALLOW_WATER&& !mons_flies( attacker )&& !mons_class_flag( attacker->type, M_AMPHIBIOUS )&& monster_habitat( attacker->type ) == DNGN_FLOOR&& one_chance_in(4))
// [dshaligram] Note: warding is no longer a simple 50% chance.const int warding = defender->warding();if (warding&& mons_is_summoned(atk)&& !check_mons_resist_magic( atk, warding ))
if (simple_monster_message(attacker, " splashes around in the water."))interrupt_activity( AI_MONSTER_ATTACKS, attacker );return;}if (player_in_water()&& !player_is_swimming()&& monster_habitat( attacker->type ) == DNGN_DEEP_WATER){water_attack = true;simple_monster_message(attacker," uses the watery terrain to its advantage.");}char runthru;bool player_perceives_attack = false;for (runthru = 0; runthru < 4; runthru++){blocked = false;wpn_speed = 0; // 0 = didn't attack w/ weaponif (attacker->type == MONS_HYDRA)
if (needs_message)
if (attacker->type == MONS_ZOMBIE_SMALL|| attacker->type == MONS_ZOMBIE_LARGE|| attacker->type == MONS_SKELETON_SMALL|| attacker->type == MONS_SKELETON_LARGE|| attacker->type == MONS_SIMULACRUM_SMALL|| attacker->type == MONS_SIMULACRUM_LARGE|| attacker->type == MONS_SPECTRAL_THING){mdam = mons_damage(attacker->number, runthru);
int melee_attack::mons_attk_delay(){return (weapon? property(*weapon, PWPN_SPEED) : 0);}
if ((attacker->type == MONS_TWO_HEADED_OGRE|| attacker->type == MONS_ETTIN)&& runthru == 1){hand_used = 1;}
const int con_block = random2(attacker->shield_bypass_ability(to_hit)+ defender->shield_block_penalty());const int pro_block = defender->shield_bonus();if (pro_block >= con_block){perceived_attack = true;
damage_taken = 0;int mons_to_hit = 16 + attacker->hit_dice; //* attacker->hit_dice;//* 3if (water_attack)mons_to_hit += 5;if (attacker->inv[hand_used] != NON_ITEM&& mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS){mons_to_hit += mitm[attacker->inv[hand_used]].plus;mons_to_hit += property( mitm[attacker->inv[hand_used]], PWPN_HIT );wpn_speed = property( mitm[attacker->inv[hand_used]], PWPN_SPEED );}// Factors against blocking// [dshaligram] Scaled back HD effect to 50% of previous, reduced// shield_blocks multiplier to 5.const int con_block =random2(15 + attacker->hit_dice / 2+ (5 * you.shield_blocks * you.shield_blocks));// Factors for blocking:// [dshaligram] Added weighting for shields skill, increased dex bonus// from .2 to .25const int pro_block =random2(player_shield_class())+ (random2(you.dex) / 4)+ (random2(skill_bump(SK_SHIELDS)) / 4)- 1;
if (needs_message && verbose)mprf("%s %s %s attack.",defender->name(DESC_CAP_THE).c_str(),defender->conj_verb("block").c_str(),attacker->name(DESC_NOCAP_YOUR).c_str());
if (!you.paralysis && !you_are_delayed() && !you.conf&& player_monster_visible( attacker )&& player_shield_class() > 0&& con_block <= pro_block){you.shield_blocks++;
defender->shield_block_succeeded();
blocked = true;hit = false;player_perceives_attack = true;
int melee_attack::mons_calc_damage(const mon_attack_def &attk){int damage = 0;int damage_max = 0;if (weapon&& weapon->base_type == OBJ_WEAPONS&& !is_range_weapon(*weapon)){damage_max = property( *weapon, PWPN_DAMAGE );damage += random2( damage_max );
if (bearing_shield && one_chance_in(4))exercise(SK_SHIELDS, 1);}else if (player_light_armour(true) && one_chance_in(3))
if (get_equip_race(*weapon) == ISFLAG_ORCISH&& mons_species(atk->type) == MONS_ORC&& coinflip())
const int player_dodge = random2limit(player_evasion(), 40)+ random2(you.dex) / 3- (player_monster_visible(attacker) ? 2 : 14)- (you_are_delayed() ? 5 : 0);if (!blocked&& (random2(mons_to_hit) >= player_dodge || one_chance_in(30))){hit = true;int damage_size = 0;if (attacker->inv[hand_used] != NON_ITEM&& mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS&& (mitm[attacker->inv[hand_used]].sub_type < WPN_SLING|| mitm[attacker->inv[hand_used]].sub_type > WPN_CROSSBOW)){damage_size = property( mitm[attacker->inv[hand_used]],PWPN_DAMAGE );damage_taken = random2(damage_size);if (get_equip_race(mitm[attacker->inv[hand_used]]) == ISFLAG_ORCISH&& mons_species(attacker->type) == MONS_ORC&& coinflip()){damage_taken++;}if (mitm[attacker->inv[hand_used]].plus2 >= 0){/* + or 0 to-dam */damage_taken += random2(mitm[attacker->inv[hand_used]].plus2 + 1);}else{/* - to-dam */damage_taken -= (random2(1 + abs(mitm[attacker->inv[hand_used]].plus2)));}damage_taken -= 1 + random2(3); //1;}damage_size += mdam;damage_taken += 1 + random2(mdam);if (water_attack)damage_taken *= 2;int ac = player_AC();if (ac > 0){int damage_reduction = random2(ac + 1);if (!player_light_armour()){const int body_arm_ac = property( you.inv[you.equip[EQ_BODY_ARMOUR]],PARM_AC );int percent = 2 * (you.skills[SK_ARMOUR] + body_arm_ac);if (percent > 50)percent = 50;int min = 1 + (damage_size * percent) / 100;
}else if (!blocked){hit = false;if (simple_monster_message(attacker, " misses you."))player_perceives_attack = true;}
if (water_attack)damage *= 2;
if ((hit && !blocked) || damage_taken > 0)player_perceives_attack = true;if (damage_taken < 1 && hit && !blocked){mprf("%s hits you but doesn't do any damage.",ptr_monam(attacker, DESC_CAP_THE));}
return (mons_apply_defender_ac(damage, damage_max));}
hit = true;mmov_x = attacker->inv[hand_used];strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " hits you");#if DEBUG_DIAGNOSTICSstrcat(info, " for ");// note: doesn't take account of special weapons etcitoa( damage_taken, st_prn, 10 );strcat( info, st_prn );#endifif (attacker->type != MONS_DANCING_WEAPON && mmov_x != NON_ITEM&& mitm[mmov_x].base_type == OBJ_WEAPONS&& !is_range_weapon( mitm[mmov_x] ))
if (const item_def *arm = defender->slot_item(EQ_BODY_ARMOUR))
strcat(info, "!");mpr( info, MSGCH_PLAIN );if (hit){if (you.equip[EQ_BODY_ARMOUR] != -1){const int body_arm_mass = item_mass( you.inv[you.equip[EQ_BODY_ARMOUR]] );
int min = 1 + (damage_max * perc) / 100;if (min > ac / 2)min = ac / 2;
// Being generous here...this can train both Armour// and Dodging.if (!player_light_armour(false) && coinflip()&& random2(1000) <= body_arm_mass){// raised from 1 {bwross}exercise(SK_ARMOUR, (coinflip() ? 2 : 1));}}
if (damage_reduction < min)damage_reduction = min;
/* special attacks: */int mclas = attacker->type;if (mclas == MONS_KILLER_KLOWN){switch (random2(6)){case 0:// comment and enum do not match {dlb}mclas = MONS_SNAKE; // scorpbreak;case 1:mclas = MONS_NECROPHAGE;break;case 2:mclas = MONS_WRAITH;break;case 3:mclas = MONS_FIRE_ELEMENTAL;break;case 4:mclas = MONS_ICE_BEAST;break;case 5:mclas = MONS_PHANTOM;break;}}switch (mclas){case MONS_GILA_MONSTER:case MONS_GIANT_ANT:case MONS_WOLF_SPIDER:case MONS_REDBACK:if (player_res_poison())break;if (one_chance_in(20)|| (damage_taken > 3 && one_chance_in(4))){simple_monster_message( attacker,"'s bite was poisonous!" );if (attacker->type == MONS_REDBACK)poison_player( random2avg(9, 2) + 3 );elsepoison_player(1);}break;case MONS_KILLER_BEE:case MONS_BUMBLEBEE:if (!player_res_poison()&& (one_chance_in(20)|| (damage_taken > 2 && one_chance_in(3)))){simple_monster_message( attacker, " stings you!" );if (attacker->type == MONS_BUMBLEBEE)poison_player( random2(3) );elsepoison_player(1);}break;case MONS_ROTTING_DEVIL:case MONS_NECROPHAGE:case MONS_GHOUL:case MONS_DEATH_OOZE:if (you.is_undead)break;// both sides call random2() - looking familiar by now {dlb}if (one_chance_in(20) || (damage_taken > 2 && one_chance_in(3))){rot_player( 2 + random2(3) );if (damage_taken > 5)rot_hp(1);}if (one_chance_in(4))disease_player( 50 + random2(100) );break;case MONS_KOMODO_DRAGON:case MONS_GIANT_MOSQUITO:if (!one_chance_in(3))disease_player( 50 + random2(100) );break;case MONS_FIRE_VORTEX:attacker->hit_points = -10;// fall through -- intentional? {dlb}case MONS_FIRE_ELEMENTAL:case MONS_BALRUG:case MONS_SUN_DEMON:strcpy(info, "You are engulfed in flames");resistValue = player_res_fire();extraDamage = 15 + random2(15);if (resistValue > 0){extraDamage /= (1 + resistValue * resistValue);}else{if (resistValue < 0)extraDamage += 8 + random2(8);}strcat(info, (extraDamage < 10) ? "." :(extraDamage < 25) ? "!" :"!!");mpr(info);if (you.duration[DUR_CONDENSATION_SHIELD] > 0){mpr("Your icy shield dissipates!", MSGCH_DURATION);you.duration[DUR_CONDENSATION_SHIELD] = 0;you.redraw_armour_class = 1;}damage_taken += extraDamage;expose_player_to_element(BEAM_FIRE, 1);break;case MONS_SMALL_SNAKE:case MONS_SNAKE:case MONS_GIANT_MITE:case MONS_GOLD_MIMIC:case MONS_WEAPON_MIMIC:case MONS_ARMOUR_MIMIC:case MONS_SCROLL_MIMIC:case MONS_POTION_MIMIC:if (!player_res_poison()&& (one_chance_in(20)|| (damage_taken > 2 && one_chance_in(4)))){poison_player(1);}break;case MONS_QUEEN_BEE:case MONS_GIANT_CENTIPEDE:case MONS_SOLDIER_ANT:case MONS_QUEEN_ANT:if (!player_res_poison()){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings you!");mpr(info);poison_player(2);}break;case MONS_SCORPION:case MONS_BROWN_SNAKE:case MONS_BLACK_SNAKE:case MONS_YELLOW_SNAKE:case MONS_SPINY_FROG:if (!player_res_poison()&& (one_chance_in(15)|| (damage_taken > 2 && one_chance_in(4))))// ^^^yep, this should be a function^^^ {dlb}{strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " poisons you!");mpr(info);poison_player(1);}break;case MONS_SHADOW_DRAGON:case MONS_SPECTRAL_THING:if (coinflip())break;// fall-through {dlb}case MONS_WIGHT: // less likely because wights do less damagecase MONS_WRAITH:// enum does not match comment 14jan2000 {dlb}case MONS_SOUL_EATER: // shadow devil// enum does not match comment 14jan2000 {dlb}case MONS_SPECTRAL_WARRIOR: // spectrecase MONS_SHADOW_FIEND:case MONS_ORANGE_RAT:case MONS_SHADOW_WRAITH:case MONS_ANCIENT_LICH:case MONS_LICH:case MONS_BORIS:if (one_chance_in(30) || (damage_taken > 5 && coinflip()))drain_exp();break;case MONS_RED_WASP:if (!player_res_poison())poison_player( (coinflip() ? 2 : 1) );// intentional fall-through {dlb}case MONS_YELLOW_WASP:strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings you.");mpr(info);if (!player_res_poison()&& (one_chance_in(20)|| (damage_taken > 2 && !one_chance_in(3))))// maybe I should flip back the other way? {dlb}{if (you.paralysis > 0)mpr("You still can't move!", MSGCH_WARN);elsempr("You suddenly lose the ability to move!",MSGCH_WARN);if ( you.paralysis == 0 || mclas == MONS_RED_WASP )you.paralysis += 1 + random2(3);}break;case MONS_SPINY_WORM:if (!player_res_poison()){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings you!");mpr(info);poison_player( 2 + random2(4) );}// intentional fall-through {dlb}case MONS_BROWN_OOZE:case MONS_ACID_BLOB:case MONS_ROYAL_JELLY:case MONS_JELLY:mpr("You are splashed with acid!");splash_with_acid(3);break;case MONS_SIMULACRUM_SMALL:case MONS_SIMULACRUM_LARGE:resistValue = player_res_cold();if (resistValue > 0)extraDamage = 0;else if (resistValue == 0){extraDamage += roll_dice( 1, 4 );mprf("%s chills you.", ptr_monam(attacker, DESC_CAP_THE));}else if (resistValue < 0){extraDamage = roll_dice( 2, 4 );mprf("%s freezes you.", ptr_monam(attacker, DESC_CAP_THE));}damage_taken += extraDamage;expose_player_to_element(BEAM_COLD, 1);break;case MONS_ICE_DEVIL:case MONS_ICE_BEAST:case MONS_FREEZING_WRAITH:case MONS_ICE_FIEND:case MONS_WHITE_IMP:case MONS_ANTAEUS:case MONS_AZURE_JELLY:extraDamage = attacker->hit_dice + random2(attacker->hit_dice * 2);resistValue = player_res_cold();if (resistValue > 0){extraDamage /= (1 + resistValue * resistValue);}if (resistValue < 0){extraDamage += attacker->hit_dice +random2(attacker->hit_dice * 2);}if (extraDamage > 4){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));if (extraDamage < 10)strcat(info, " chills you.");elsestrcat(info, " freezes you!");if (extraDamage > 19)strcat(info, "!");mpr(info);}damage_taken += extraDamage;expose_player_to_element(BEAM_COLD, 1);break;case MONS_ELECTRIC_GOLEM:if (!player_res_electricity()){damage_taken += attacker->hit_dice+ random2(attacker->hit_dice * 2);strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " shocks you!");mpr(info);}break;case MONS_VAMPIRE:if (you.is_undead)break;/* ******************************************************************if ( damage_taken > 6 && one_chance_in(3) || !one_chance_in(20)){mpr("You feel less resilient.");you.hp_max -= ( coinflip() ? 2 : 1 );deflate_hp(you.hp_max, false);heal_monster(attacker, 5 + random2(8), true);}****************************************************************** */// heh heh {dlb}// oh, this is mean! {gdl}if (heal_monster(attacker, random2(damage_taken), true))simple_monster_message(attacker, " draws strength from your injuries!");break;case MONS_SHADOW:if (player_prot_life() <= random2(3)&& (one_chance_in(20)|| (damage_taken > 0 && one_chance_in(3)))){lose_stat(STAT_STRENGTH, 1);}break;case MONS_HUNGRY_GHOST:if (you.is_undead == US_UNDEAD)break;if (one_chance_in(20) || (damage_taken > 0 && coinflip()))make_hungry(400, false);break;case MONS_GUARDIAN_NAGA:break;case MONS_PHANTOM:case MONS_INSUBSTANTIAL_WISP:case MONS_BLINK_FROG:case MONS_MIDGE:if (one_chance_in(3)){simple_monster_message(attacker, " blinks.");monster_blink(attacker);}break;case MONS_JELLYFISH:case MONS_ORANGE_DEMON:// if ( !one_chance_in(3) ) break;if (player_res_poison())break;if (attacker->type == MONS_ORANGE_DEMON&& (!one_chance_in(4) || runthru != 1)){break;}strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings you!");mpr(info);poison_player(1);lose_stat(STAT_STRENGTH, 1);break;case MONS_PULSATING_LUMP:if (one_chance_in(3)){if (one_chance_in(5))mutate(100);elsegive_bad_mutation();}break;case MONS_MOTH_OF_WRATH:if (one_chance_in(3)){simple_monster_message(attacker, " infuriates you!");go_berserk(false);}break;default:break;} // end of switch for special attacks./* use break for level drain, maybe with beam variables,because so many creatures use it. */
/* special weapons */if (hit&& (attacker->inv[hand_used] != NON_ITEM|| ((attacker->type == MONS_PLAYER_GHOST|| attacker->type == MONS_PANDEMONIUM_DEMON)&& ghost.values[ GVAL_BRAND ] != SPWPN_NORMAL))){unsigned char itdam;if (attacker->type == MONS_PLAYER_GHOST|| attacker->type == MONS_PANDEMONIUM_DEMON){itdam = ghost.values[ GVAL_BRAND ];}else{const item_def& mons_weapon = mitm[attacker->inv[hand_used]];if ( is_range_weapon(mons_weapon) )itdam = SPWPN_NORMAL;elseitdam = mons_weapon.special;}specdam = 0;switch (itdam){case SPWPN_NORMAL:default:break;case SPWPN_SWORD_OF_CEREBOV:case SPWPN_FLAMING:specdam = 0;resistValue = player_res_fire();if (itdam == SPWPN_SWORD_OF_CEREBOV)resistValue -= 1;if (resistValue > 0){damage_taken += (random2(damage_taken) / 2 + 1) /(1 + (resistValue * resistValue));}if (resistValue <= 0)specdam = random2(damage_taken) / 2 + 1;if (resistValue < 0)specdam += random2(damage_taken) / 2 + 1;if (specdam){simple_monster_message(attacker, " burns you.");/* **********************commented out for nowif (specdam < 3)strcat(info, ".");if (specdam >= 3 && specdam < 7)strcat(info, "!");if (specdam >= 7)strcat(info, "!!");*********************** */}if (you.duration[DUR_CONDENSATION_SHIELD] > 0){mpr("Your icy shield dissipates!", MSGCH_DURATION);you.duration[DUR_CONDENSATION_SHIELD] = 0;you.redraw_armour_class = 1;}break;case SPWPN_FREEZING:specdam = 0;resistValue = player_res_cold();if (resistValue <= 0)specdam = random2(damage_taken) / 2 + 1;if (resistValue < 0)specdam += random2(damage_taken) / 2 + 1;if (resistValue > 0){damage_taken += (random2(damage_taken) / 2 + 1) /(1 + (resistValue * resistValue));}if (specdam){simple_monster_message(attacker, " freezes you.");/* **********************commented out for nowif (specdam < 3)strcat(info, ".");if (specdam >= 3 && specdam < 7)strcat(info, "!");if (specdam >= 7)strcat(info, "!!");*********************** */}break;case SPWPN_HOLY_WRATH:if (attacker->type == MONS_PLAYER_GHOST)break; // ghosts can't wield holy wrathif (you.is_undead){specdam = random2(damage_taken);if (specdam){strcpy(info, "The wound is extremely painful");if (specdam < 3)strcat(info, ".");else if (specdam < 7)strcat(info, "!");elsestrcat(info, "!!");mpr(info);}}break;case SPWPN_ELECTROCUTION:// This runs the risk of making levitation into a// cheap version of the Resist spell (with added// bonuses), so it shouldn't be used anywhere else,// and should possibly be removed from this case as// well. -- bwrif (player_is_levitating()) // you're not groundedbreak;
damage -= damage_reduction;}
specdam = 0;// This is related to old code where elec wpns had charges#if 0if (menv[monster_attacking].type != MONS_PLAYER_GHOST&& (mitm[attacker->inv[hand_used]].plus2 <= 0|| item_cursed( mitm[attacker->inv[hand_used]] ))){break;}#endif
std::string melee_attack::mons_attack_verb(const mon_attack_def &attk){static const char *attack_types[] ={"","hit", // including weapon attacks"bite","sting",
case SPWPN_STAFF_OF_OLGREB:case SPWPN_VENOM:if (!player_res_poison() && one_chance_in(3)){simple_monster_message(attacker,(attacker->type == MONS_DANCING_WEAPON)? " is poisoned!" : "'s weapon is poisoned!");poison_player(2);}break;case SPWPN_PROTECTION:break;case SPWPN_DRAINING:drain_exp();specdam = random2(damage_taken) / (2 + player_prot_life()) + 1;break;case SPWPN_SPEED:wpn_speed = (wpn_speed + 1) / 2;break;case SPWPN_VORPAL:specdam = 1 + (random2(damage_taken) / 2);break;case SPWPN_VAMPIRES_TOOTH:case SPWPN_VAMPIRICISM:specdam = 0; // note does no extra damageif (you.is_undead)break;if (one_chance_in(5))break;// heh heh {dlb}if (heal_monster(attacker, 1 + random2(damage_taken), true))simple_monster_message(attacker, " draws strength from your injuries!");break;case SPWPN_DISRUPTION:if (attacker->type == MONS_PLAYER_GHOST)break;if (you.is_undead){specdam = random2(damage_taken) + random2(damage_taken)+ random2(damage_taken) + random2(damage_taken);if (specdam){strcpy(info, "You are blasted by holy energy");if (specdam < 7)strcat(info, ".");else if (specdam < 15)strcat(info, "!");elsestrcat(info, "!!");mpr(info);}}break;case SPWPN_DISTORTION:if (one_chance_in(3)){mpr("Your body is twisted painfully.");specdam += 1 + random2avg(7, 2);break;}if (one_chance_in(3)){mpr("Your body is terribly warped!");specdam += 3 + random2avg(24, 2);break;}if (one_chance_in(3)){random_blink(true);break;}
void melee_attack::mons_announce_hit(const mon_attack_def &attk){if (water_attack && attacker_visible && attacker != defender)mprf("%s uses the watery terrain to its advantage.",attacker->name(DESC_CAP_THE).c_str());mprf("%s %s %s%s%s%s",attacker->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(),mons_weapon_desc().c_str(),attack_strength_punctuation().c_str());}
if (coinflip()){you_teleport();break;}
void melee_attack::mons_announce_dud_hit(const mon_attack_def &attk){mprf("%s %s %s but doesn't do any damage.",attacker->name(DESC_CAP_THE).c_str(),attacker->conj_verb( mons_attack_verb(attk) ).c_str(),mons_defender_name().c_str());}
if (coinflip()){you_teleport2( true, one_chance_in(5) );break;}
void melee_attack::check_defender_train_dodging(){if (defender->wearing_light_armour(false)&& attacker_visible&& one_chance_in(3)){perceived_attack = true;defender->exercise(SK_DODGING, 1);}}
if (coinflip() && you.level_type != LEVEL_ABYSS){you.banished = true;break;}break;} // end of switch} // end of special weapons
void melee_attack::check_defender_train_armour(){if (defender->wearing_light_armour())return;const item_def *arm = defender->slot_item(EQ_BODY_ARMOUR);if (arm && coinflip() && random2(1000) <= item_mass(*arm))defender->exercise(SK_ARMOUR, coinflip()? 2 : 1);}
if (damage_taken > 0)
void melee_attack::mons_do_poison(const mon_attack_def &attk){if (defender->res_poison() > 0)return;if (attk.flavour == AF_POISON_NASTY|| one_chance_in( 15 + 5 * (attk.flavour == AF_POISON) )|| (damage_done > 2&& one_chance_in( attk.flavour == AF_POISON? 4 : 3 ))){if (needs_message)
mons_lose_attack_energy(attacker, wpn_speed, runthru);} // end of for runthruif (player_perceives_attack)interrupt_activity(AI_MONSTER_ATTACKS, attacker);
int amount = 1;if (attk.flavour == AF_POISON_NASTY)amount++;else if (attk.flavour == AF_POISON_MEDIUM)amount += random2(3);else if (attk.flavour == AF_POISON_STRONG)amount += roll_dice(2, 5);
struct monsters *attacker = &menv[monster_attacking];struct monsters *defender = &menv[monster_attacked];
// [dshaligram] Adopted 4.1.2's wasp mechanics, in slightly modified form.if (attacker->id() == MONS_RED_WASP)defender->poison( attacker, coinflip()? 2 : 1 );
int weapon = -1; // monster weapon, if anyint damage_taken = 0;bool hit = false;// int mmov_x = 0;bool water_attack = false;int specdam = 0;int hand_used = 0;bool sees = false;int wpn_speed; // 0 == didn't use actual weaponint habitat = monster_habitat( attacker->type );char str_pass[ ITEMNAME_SIZE ];
if (!defender->res_poison() && one_chance_in( damage_done > 4? 3 : 20 ))defender->paralyse( roll_dice(1, 3) );elsedefender->slow_down( roll_dice(1, 3) );}
if (attacker->type == MONS_GIANT_SPORE|| attacker->type == MONS_BALL_LIGHTNING){attacker->hit_points = -1;return false;}if (mons_has_ench( attacker, ENCH_SUBMERGED )&& habitat != DNGN_FLOOR&& habitat != monster_habitat( defender->type )){return false;}if (attacker->fumbles_attack(true))return true;// habitat is the favoured habitat of the attackerwater_attack = defender->floundering() && attacker->swimming();
void melee_attack::splash_defender_with_acid(int strength){if (defender->atype() == ACT_PLAYER)splash_with_acid(strength);elsesplash_monster_with_acid(strength);}
if (mons_near(attacker) && mons_near(defender))sees = true;// Any objects seen in combat are thereafter known mimics.if (mons_is_mimic(attacker->type) && mons_near(attacker))attacker->flags |= MF_KNOWN_MIMIC;if (mons_is_mimic(defender->type) && mons_near(defender))defender->flags |= MF_KNOWN_MIMIC;// now disturb defender, regardlessbehaviour_event(defender, ME_WHACK, monster_attacking);int heads = 0;if (attacker->type == MONS_HYDRA)heads = attacker->number;
void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk){// Most of this is from BWR 4.1.2.
int mdam = mons_damage(attacker->type, runthru);wpn_speed = 0;
case AF_POISON:case AF_POISON_NASTY:case AF_POISON_MEDIUM:case AF_POISON_STRONG:mons_do_poison(attk);break;
if (attacker->type == MONS_ZOMBIE_SMALL|| attacker->type == MONS_ZOMBIE_LARGE|| attacker->type == MONS_SKELETON_SMALL|| attacker->type == MONS_SKELETON_LARGE|| attacker->type == MONS_SIMULACRUM_SMALL|| attacker->type == MONS_SIMULACRUM_LARGE|| attacker->type == MONS_SPECTRAL_THING)// what do these things have in common? {dlb}
case AF_POISON_STR:res = defender->res_poison();if (res <= 0)
mdam = mons_damage(attacker->number, runthru);// cumulative reductions - series of if-conditions// is necessary: {dlb}if (mdam > 1)mdam--;if (mdam > 2)mdam--;if (mdam > 5)mdam--;if (mdam > 9)mdam--; // was: "-= 2" {dlb}
defender->poison( attacker, roll_dice(1,3) );if (one_chance_in(4))defender->drain_stat( STAT_STRENGTH, 1 );
if (mons_wields_two_weapons(attacker)&& runthru == 1 && attacker->inv[MSLOT_MISSILE] != NON_ITEM){hand_used = 1;}
case AF_DISEASE:if (defender->atype() == ACT_PLAYER)disease_player( 50 + random2(100) );break;
int mons_to_hit = 20 + attacker->hit_dice * 5;// * menv [monster_attacking].hit_dice; // * 3
special_damage =resist_adjust_damage(defender->res_fire(),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(),defender->conj_verb("are").c_str(),special_attack_punctuation().c_str());
weapon = attacker->inv[hand_used];
case AF_COLD:special_damage =resist_adjust_damage(defender->res_cold(),atk->hit_dice + random2( 2 * atk->hit_dice ));if (needs_message && special_damage)mprf("%s %s %s!",attacker->name(DESC_CAP_THE).c_str(),attacker->conj_verb("freeze").c_str(),defender->name(DESC_NOCAP_THE).c_str());break;
if (weapon != NON_ITEM){mons_to_hit += mitm[weapon].plus;// mons_to_hit += 3 * property( mitm[weapon], PWPN_HIT );mons_to_hit += property( mitm[weapon], PWPN_HIT );
case AF_ELEC:special_damage =resist_adjust_damage(defender->res_elec(),atk->hit_dice + random2( 2 * atk->hit_dice ));if (defender->levitates())special_damage = special_damage * 2 / 3;
damage_taken = random2(property( mitm[attacker->inv[hand_used]],PWPN_DAMAGE ));if (get_equip_race(mitm[attacker->inv[hand_used]]) == ISFLAG_ORCISH&& mons_species(attacker->type) == MONS_ORC&& coinflip()){damage_taken++;}//if (mitm[mons_inv[i][0]].plus > 80) damage_taken -= 100;// damage_taken += mitm[mons_inv[i][0]].plus;if (mitm[attacker->inv[hand_used]].plus2 >= 0){/* + or 0 to-dam */damage_taken += random2(mitm[attacker->inv[hand_used]].plus2 + 1);}else{/* - to-dam */damage_taken -= random2(abs(mitm[attacker->inv[hand_used]].plus2 + 1));}damage_taken -= 1 + random2(3); //1;
mprf("%s %s strength from %s injuries!",attacker->name(DESC_CAP_THE).c_str(),attacker->conj_verb("draw").c_str(),defender->name(DESC_NOCAP_YOUR).c_str());
if (water_attack)damage_taken *= 2;damage_taken -= random2(1 + defender->armour_class);if (damage_taken < 1)damage_taken = 0;}else{hit = false;if (sees)
// 4.1.2 actually drains max hp; we're being nicer and just doing// a rot effect.if ((damage_done > 6 && one_chance_in(3)) || one_chance_in(20))
strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " misses ");if (attacker == defender)strcat(info,mons_pronoun(attacker->type, PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);
if (defender->atype() == ACT_PLAYER)mprf("You feel less resilient.");defender->rot( attacker, 0, coinflip()? 2 : 1 );
if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " hits ");if ( attacker == defender )strcat(info,mons_pronoun(attacker->type, PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));#if DEBUG_DIAGNOSTICSstrcat(info, " for ");// note: doesn't take account of special weapons etcitoa(damage_taken, st_prn, 10);strcat(info, st_prn);#endifstrcat(info, "."); // but doesn't do any you.damage.");mpr(info);}
defender->drain_stat(STAT_STRENGTH, 1);
int mmov_x = attacker->inv[hand_used];if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " hits ");if (attacker == defender)strcat(info,mons_pronoun(attacker->type, PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));if (attacker->type != MONS_DANCING_WEAPON&& attacker->inv[hand_used] != NON_ITEM&& mitm[attacker->inv[hand_used]].base_type == OBJ_WEAPONS&& !is_range_weapon( mitm[attacker->inv[hand_used]] )){strcat(info, " with ");it_name(mmov_x, DESC_NOCAP_A, str_pass); // was 7strcat(info, str_pass);}strcat(info, "! ");mpr(info);}if (actor_decapitates_hydra(attacker, defender, damage_taken)){mons_lose_attack_energy(attacker, wpn_speed, runthru);if (defender->hit_points < 1){monster_die(defender, KILL_MON, monster_attacking);return (true);}// Skip rest of attack.continue;}// special attacks:switch (attacker->type){// enum does not match comment 14jan2000 {dlb}case MONS_CENTAUR: // cockatricecase MONS_JELLY:case MONS_GUARDIAN_NAGA:break;case MONS_GIANT_ANT:case MONS_WOLF_SPIDER:case MONS_REDBACK:case MONS_SPINY_WORM:case MONS_JELLYFISH:case MONS_ORANGE_DEMON:if (attacker->type == MONS_SPINY_WORM || one_chance_in(20)|| (damage_taken > 3 && one_chance_in(4))){if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}poison_monster(defender, false);}break;case MONS_KILLER_BEE:case MONS_BUMBLEBEE:if (one_chance_in(20)|| (damage_taken > 2 && one_chance_in(3))){if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}poison_monster(defender, false);}break;case MONS_NECROPHAGE:case MONS_ROTTING_DEVIL:case MONS_GHOUL:case MONS_DEATH_OOZE:if (mons_res_negative_energy( defender ))break;if (one_chance_in(20)|| (damage_taken > 2 && one_chance_in(3))){defender->max_hit_points -= 1 + random2(3);
defender->drain_stat(STAT_DEXTERITY, 1);}break;
case MONS_FIRE_VORTEX:attacker->hit_points = -10;// deliberate fall-throughcase MONS_FIRE_ELEMENTAL:case MONS_BALRUG:case MONS_SUN_DEMON:specdam = 0;if (mons_res_fire(defender) == 0)specdam = 15 + random2(15);else if (mons_res_fire(defender) < 0)specdam = 20 + random2(25);
if (one_chance_in(20) || (damage_done > 0 && coinflip()))defender->make_hungry(400, false);break;
case MONS_QUEEN_BEE:case MONS_GIANT_CENTIPEDE:case MONS_SOLDIER_ANT:case MONS_QUEEN_ANT://if ((damage_taken > 2 && one_chance_in(3) ) || one_chance_in(20) )//{if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " stings ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}poison_monster(defender, false);//}break;
if (--atk->hit_dice <= 0)atk->hit_points = -1;
// enum does not match comment 14jan2000 {dlb}case MONS_SCORPION: // snakecase MONS_BROWN_SNAKE:case MONS_BLACK_SNAKE:case MONS_YELLOW_SNAKE:case MONS_GOLD_MIMIC:case MONS_WEAPON_MIMIC:case MONS_ARMOUR_MIMIC:case MONS_SCROLL_MIMIC:case MONS_POTION_MIMIC:if (one_chance_in(20) || (damage_taken > 2 && one_chance_in(4)))poison_monster(defender, false);break;
if (needs_message)mprf("%s %s engulfed in a cloud of spores!",defender->name(DESC_CAP_THE).c_str(),defender->conj_verb("are").c_str());}
case MONS_SHADOW_DRAGON:case MONS_SPECTRAL_THING:if (coinflip())break;// intentional fall-throughcase MONS_WIGHT:case MONS_WRAITH:case MONS_SOUL_EATER:case MONS_SHADOW_FIEND:case MONS_SPECTRAL_WARRIOR:case MONS_ORANGE_RAT:case MONS_ANCIENT_LICH:case MONS_LICH:case MONS_BORIS:if (mons_res_negative_energy( defender ))break;
if (one_chance_in(10)|| (damage_done > 2 && one_chance_in(3))){defender->confuse( 1 + random2( 3 + atk->hit_dice ) );}break;
if (defender->hit_points >= defender->max_hit_points)defender->hit_points = defender->max_hit_points;
case AF_ACID:if (attacker->id() == MONS_SPINY_WORM && defender->res_poison() <= 0)defender->poison( attacker, 2 + random2(4) );splash_defender_with_acid(3);break;}}
if (defender->hit_points < 1 || defender->hit_dice < 1){monster_die(defender, KILL_MON, monster_attacking);return true;}}break;// enum does not match comment 14jan2000 {dlb}case MONS_WORM: // giant waspbreak;case MONS_SIMULACRUM_SMALL:case MONS_SIMULACRUM_LARGE:specdam = 0;if (mons_res_cold(defender) == 0)specdam = roll_dice( 1, 4 );else if (mons_res_cold(defender) < 0)specdam = roll_dice( 2, 4 );if (specdam && sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " freezes ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}
void melee_attack::mons_perform_attack_rounds(){const int nrounds = atk->type == MONS_HYDRA? atk->number : 4;#ifdef DEBUG_DIAGNOSTICSmprf(MSGCH_DIAGNOSTICS, "%s gets %d attacks",attacker->name(DESC_CAP_THE).c_str(),nrounds);#endif
case MONS_ICE_DEVIL:case MONS_ICE_BEAST:case MONS_FREEZING_WRAITH:case MONS_ICE_FIEND:case MONS_WHITE_IMP:case MONS_AZURE_JELLY:case MONS_ANTAEUS:specdam = 0;if (mons_res_cold(defender) == 0){specdam = attacker->hit_dice + random2(attacker->hit_dice * 2);}else if (mons_res_cold(defender) < 0){specdam = random2(attacker->hit_dice * 3) + (attacker->hit_dice * 2);}
// Monsters hitting themselves get just one round.if (attack_number > 0 && attacker == defender)break;const mon_attack_def attk = mons_attack_spec(atk, attack_number);if (attk.type == AT_NONE)break;
if (specdam && sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " freezes ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}damage_taken += specdam;break;
damage_done = 0;mons_set_weapon(attk);to_hit = mons_to_hit();
case MONS_ELECTRIC_GOLEM:if (mons_flies(defender) == 0 && mons_res_elec(defender) == 0){specdam = attacker->hit_dice + random2(attacker->hit_dice * 2);}
final_attack_delay = mons_attk_delay();if (damage_brand == SPWPN_SPEED)final_attack_delay = final_attack_delay / 2 + 1;
if (specdam && sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " shocks ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}damage_taken += specdam;break;
mons_lose_attack_energy(atk, final_attack_delay, attack_number);
// heh heh {dlb}if (heal_monster(attacker, random2(damage_taken), true))simple_monster_message(attacker, " is healed.");break;
if (attacker != defender){if (attack_shield_blocked(true)){shield_blocked = true;perceived_attack = true;this_round_hit = did_hit = true;
if (specdam){if (sees){strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " burns ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE ));
if (damage_done > 0){mons_announce_hit(attk);check_defender_train_armour();
case SPWPN_FREEZING:specdam = 0;
// Monsters attacking themselves don't get attack flavour, the// message sequences look too weird.if (attacker != defender)mons_apply_attack_flavour(attk);if (!special_damage_message.empty())mprf("%s", special_damage_message.c_str());defender->hurt(attacker, damage_done + special_damage);if (!defender->alive() || attacker == defender)return;
strcpy(info, ptr_monam(attacker, DESC_CAP_THE));strcat(info, " freezes ");if (attacker == defender)strcat(info, mons_pronoun(attacker->type,PRONOUN_REFLEXIVE));elsestrcat(info, ptr_monam(defender, DESC_NOCAP_THE));
if (special_damage > 0)defender->hurt(attacker, special_damage);}}}
if (specdam < 3)strcat(info, ".");else if (specdam < 7)strcat(info, "!");elsestrcat(info, "!!");
bool melee_attack::mons_perform_attack(){if (attacker != defender && mons_self_destructs())return (did_hit = perceived_attack = true);
case SPWPN_HOLY_WRATH:if (attacker->type == MONS_PLAYER_GHOST)break;specdam = 0;switch (mons_holiness(defender)){case MH_HOLY:// I would think that it would do zero damage {dlb}damage_taken -= 5 + random2(5);break;
mons_perform_attack_rounds();return (did_hit);}
case MH_DEMONIC:specdam += 1 + (random2(damage_taken) * 15) / 10;break;
if (defender->atype() == ACT_PLAYER){interrupt_activity(AI_MONSTER_ATTACKS, atk);// if a friend wants to help, they can attack <monster_attacking>if (you.pet_target == MHITNOT)you.pet_target = monster_index(atk);}}
case SPWPN_ELECTROCUTION://if ( attacker->type == MONS_PLAYER_GHOST ) break;if (mons_flies(defender) > 0 || mons_res_elec(defender) > 0)break;
int melee_attack::mons_to_hit(){int mhit = 16 + atk->hit_dice;if (water_attack)mhit += 5;
specdam += 10 + random2(15);//mitm[attacker->inv[hand_used]].plus2 --;}break;
static void tutorial_weapon_check(const item_def *weapon){if (weapon &&(weapon->base_type != OBJ_WEAPONS|| is_range_weapon(*weapon))){learned_something_new(TUT_WIELD_WEAPON);}}
case SPWPN_ORC_SLAYING:if (mons_species(defender->type) == MONS_ORC)hurt_monster(defender, 1 + random2(damage_taken));break;
// Returns true if you hit the monster.bool you_attack(int monster_attacked, bool unarmed_attacks){monsters *defender = &menv[monster_attacked];melee_attack attk(&you, defender, unarmed_attacks);
//case 7: // protectioncase SPWPN_DRAINING:if (!mons_res_negative_energy( defender )&& (one_chance_in(30)|| (damage_taken > 5 && coinflip()))){simple_monster_message(defender, " is drained");if (one_chance_in(5))defender->hit_dice--;defender->max_hit_points -= 2 + random2(3);defender->hit_points -= 2 + random2(3);if (defender->hit_points >= defender->max_hit_points)defender->hit_points = defender->max_hit_points;if (defender->hit_points < 1|| defender->hit_dice < 1){monster_die(defender, KILL_MON, monster_attacking);return true;}specdam = 1 + (random2(damage_taken) / 2);}break;case SPWPN_SPEED:wpn_speed = (wpn_speed + 1) / 2;break;case SPWPN_VORPAL:specdam += 1 + (random2(damage_taken) / 2);break;case SPWPN_VAMPIRES_TOOTH:case SPWPN_VAMPIRICISM:specdam = 0; // note does no extra damageif (mons_res_negative_energy( defender ))break;if (one_chance_in(5))break;// heh heh {dlb}if (heal_monster(attacker, 1 + random2(damage_taken), true))simple_monster_message(attacker, " is healed.");break;case SPWPN_DISRUPTION:if (attacker->type == MONS_PLAYER_GHOST)break;specdam = 0;if (mons_holiness(defender) == MH_UNDEAD&& !one_chance_in(3)){simple_monster_message(defender, " shudders.");specdam += random2avg(1 + (3 * damage_taken), 3);}break;case SPWPN_DISTORTION:if (one_chance_in(3)){if (mons_near(defender)&& player_monster_visible(defender)){strcpy(info, "Space bends around ");strcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, ".");mpr(info);}specdam += 1 + random2avg(7, 2);break;}if (one_chance_in(3)){if (mons_near(defender)&& player_monster_visible(defender)){strcpy(info, "Space warps horribly around ");strcat(info, ptr_monam(defender, DESC_NOCAP_THE));strcat(info, "!");mpr(info);}
// For tutorials, check if the player is fighting with something unsuitabletutorial_weapon_check(attk.weapon);
if (one_chance_in(3)){monster_blink(defender);break;}
// Lose attack energy for attacking with a weapon. The monster has already lost// the base attack cost by this point.static void mons_lose_attack_energy(monsters *attacker, int wpn_speed,int which_attack){// Monsters lose energy only for the first two weapon attacks; subsequent// hits are free.if (which_attack > 1)return;// 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;
if (coinflip()){monster_die(defender, KILL_RESET, monster_attacking);break;}break;}}} // end of if special weapon
void monster_attack(int monster_attacking){monsters *attacker = &menv[monster_attacking];if (mons_friendly(attacker) && !mons_is_confused(attacker))return;
if (damage_taken > 0){hurt_monster(defender, damage_taken);if (defender->hit_points < 1){monster_die(defender, KILL_MON, monster_attacking);return true;}}mons_lose_attack_energy(attacker, wpn_speed, runthru);} // end of for runthru
bool monsters_fight(int monster_attacking, int monster_attacked){monsters *attacker = &menv[monster_attacking];monsters *defender = &menv[monster_attacked];
virtual void hurt(actor *attacker, int amount) = 0;virtual void heal(int amount, bool max_too = false) = 0;virtual void banish() = 0;virtual void blink() = 0;virtual void teleport(bool right_now = false, bool abyss_shift = false) = 0;virtual void poison(actor *attacker, int amount = 1) = 0;virtual void paralyse(int strength) = 0;virtual void slow_down(int strength) = 0;virtual void confuse(int strength) = 0;virtual void rot(actor *attacker, int rotlevel, int immediate_rot) = 0;virtual void expose_to_element(beam_type element, int strength = 0) = 0;virtual void drain_stat(int stat, int amount) { }virtual bool wearing_light_armour(bool = true) const { return (true); }virtual int skill(skill_type sk, bool skill_bump = false) const{return (0);}virtual void exercise(skill_type sk, int qty) { }virtual int stat_hp() const = 0;virtual int stat_maxhp() const = 0;virtual int armour_class() const = 0;virtual int melee_evasion(const actor *attacker) const = 0;virtual int shield_bonus() const = 0;virtual int shield_block_penalty() const = 0;virtual int shield_bypass_ability(int tohit) const = 0;virtual void shield_block_succeeded() { }virtual int mons_species() const = 0;virtual int holiness() const = 0;virtual int res_fire() const = 0;virtual int res_cold() const = 0;virtual int res_elec() const = 0;virtual int res_poison() const = 0;virtual int res_negative_energy() const = 0;virtual bool levitates() const = 0;virtual bool paralysed() const = 0;virtual bool confused() const = 0;virtual bool asleep() const { return (false); }virtual void god_conduct(int thing_done, int level) { }virtual bool incapacitated() const{return paralysed() || confused();}virtual int holy_aura() const{return (0);}virtual int warding() const{return (0);}virtual bool visible() const{return (true);}
actor_type atype() const { return ACT_PLAYER; }
int hunger_level() const { return hunger_state; }void make_hungry(int nutrition, bool silent = true);void poison(actor *agent, int amount = 1);void paralyse(int str);void slow_down(int str);void confuse(int strength);void rot(actor *agent, int rotlevel, int immed_rot);void heal(int amount, bool max_too = false);void hurt(actor *agent, int amount);int holy_aura() const;int warding() const;int mons_species() const;int holiness() const;int res_fire() const;int res_cold() const;int res_elec() const;int res_poison() const;int res_negative_energy() const;bool levitates() const;bool paralysed() const;bool confused() const;int armour_class() const;int melee_evasion(const actor *attacker) const;int stat_hp() const { return hp; }int stat_maxhp() const { return hp_max; }int shield_bonus() const;int shield_block_penalty() const;int shield_bypass_ability(int tohit) const;void shield_block_succeeded();bool wearing_light_armour(bool with_skill = true) const;void exercise(skill_type skill, int qty);int skill(skill_type skill, bool skill_bump = false) const;
int mons_species() const;int holiness() const;int res_fire() const;int res_cold() const;int res_elec() const;int res_poison() const;int res_negative_energy() const;bool levitates() const;bool paralysed() const;bool confused() const;bool asleep() const;int holy_aura() const;int armour_class() const;int melee_evasion(const actor *attacker) const;void poison(actor *agent, int amount = 1);void paralyse(int str);void slow_down(int str);void confuse(int strength);void rot(actor *agent, int rotlevel, int immed_rot);void hurt(actor *agent, int amount);void heal(int amount, bool max_too = false);void blink();void teleport(bool right_now = false, bool abyss_shift = false);int stat_hp() const { return hit_points; }int stat_maxhp() const { return max_hit_points; }int shield_bonus() const;int shield_block_penalty() const;int shield_bypass_ability(int tohit) const;
enum mon_attack_type{AT_NONE,AT_HIT, // including weapon attacksAT_BITE,AT_STING,AT_SPORE,AT_TOUCH,AT_ENGULF,AT_CLAW,AT_TAIL_SLAP};enum mon_attack_flavour{AF_PLAIN,AF_ACID,AF_BLINK,AF_COLD,AF_CONFUSE,AF_DISEASE,AF_DRAIN_DEX,AF_DRAIN_STR,AF_DRAIN_XP,AF_ELEC,AF_FIRE,AF_HUNGER,AF_MUTATE,AF_BAD_MUTATE,AF_PARALYSE,AF_POISON,AF_POISON_NASTY,AF_POISON_MEDIUM,AF_POISON_STRONG,AF_POISON_STR,AF_ROT,AF_VAMPIRIC,AF_KLOWN};