3 * @brief melee_attack class and associated melee_attack methods
8 #include "melee_attack.h"
17 #include "attitude-change.h"
18 #include "bloodspatter.h"
28 #include "godconduct.h"
37 #include "mon-tentacle.h"
40 #include "spl-summoning.h"
42 #include "stringutil.h"
45 #include "transform.h"
51 #ifdef NOTE_DEBUG_CHAOS_BRAND
52 #define NOTE_DEBUG_CHAOS_EFFECTS
55 #ifdef NOTE_DEBUG_CHAOS_EFFECTS
60 **************************************************
61 * BEGIN PUBLIC FUNCTIONS *
62 **************************************************
64 melee_attack::melee_attack(actor *attk, actor *defn,
65 int attack_num, int effective_attack_num,
66 bool is_cleaving, coord_def attack_pos)
67 : // Call attack's constructor
70 attack_number(attack_num), effective_attack_number(effective_attack_num),
73 attack_occurred = false;
74 damage_brand = attacker->damage_brand(attack_number);
75 init_attack(SK_UNARMED_COMBAT, attack_number);
76 if (weapon && !using_weapon())
77 wpn_skill = SK_FIGHTING;
79 attack_position = attacker->pos();
82 bool melee_attack::can_reach()
84 return attk_type == AT_HIT && weapon && weapon_reach(*weapon) > REACH_NONE
85 || attk_flavour == AF_REACH
86 || attk_type == AT_REACH_STING;
89 bool melee_attack::handle_phase_attempted()
91 // Skip invalid and dummy attacks.
92 if (defender && (!adjacent(attack_position, defender->pos())
94 || attk_type == AT_CONSTRICT
95 && (!attacker->can_constrict(defender)
96 || attacker->is_monster() && attacker->mid == MID_PLAYER))
98 --effective_attack_number;
103 if (attacker->is_player() && defender && defender->is_monster())
105 if (weapon && is_unrandom_artefact(*weapon, UNRAND_DEVASTATOR))
107 const char* verb = "attack";
112 verb = (bad_attack(defender->as_monster(),
114 ? "attack" : "attack near");
117 targetter_smite hitfunc(attacker, 1, 1, 1, false);
118 hitfunc.set_aim(defender->pos());
120 if (stop_attack_prompt(hitfunc, verb))
122 cancel_attack = true;
126 else if (!cleave_targets.empty())
128 targetter_cleave hitfunc(attacker, defender->pos());
129 if (stop_attack_prompt(hitfunc, "attack"))
131 cancel_attack = true;
135 else if (stop_attack_prompt(defender->as_monster(), false,
138 cancel_attack = true;
143 if (attacker->is_player())
145 // Set delay now that we know the attack won't be cancelled.
146 you.time_taken = you.attack_delay(weapon);
149 if (weapon->base_type == OBJ_WEAPONS)
150 if (is_unrandom_artefact(*weapon)
151 && get_unrand_entry(weapon->special)->type_name)
153 count_action(CACT_MELEE, weapon->special);
156 count_action(CACT_MELEE, weapon->sub_type);
157 else if (weapon->base_type == OBJ_RODS)
158 count_action(CACT_MELEE, WPN_ROD);
159 else if (weapon->base_type == OBJ_STAVES)
160 count_action(CACT_MELEE, WPN_STAFF);
163 count_action(CACT_MELEE, -1);
167 // Only the first attack costs any energy.
168 if (!effective_attack_number)
170 int energy = attacker->as_monster()->action_energy(EUT_ATTACK);
171 int delay = attacker->attack_delay(weapon);
172 dprf(DIAG_COMBAT, "Attack delay %d, multiplier %1.1f", delay, energy * 0.1);
176 attacker->as_monster()->speed_increment
177 -= div_rand_round(energy * delay, 10);
180 // Statues and other special monsters which have AT_NONE need to lose
181 // energy, but otherwise should exit the melee attack now.
182 if (attk_type == AT_NONE)
186 if (attacker != defender)
188 // Allow setting of your allies' target, etc.
189 attacker->attacking(defender);
194 // The attacker loses nutrition.
195 attacker->make_hungry(3, true);
197 // Xom thinks fumbles are funny...
198 if (attacker->fumbles_attack())
200 // ... and thinks fumbling when trying to hit yourself is just
202 xom_is_stimulated(attacker == defender ? 200 : 10);
205 // Non-fumbled self-attacks due to confusion are still pretty funny, though.
206 else if (attacker == defender && attacker->confused())
208 // And is still hilarious if it's the player.
209 xom_is_stimulated(attacker->is_player() ? 200 : 100);
212 // Any attack against a monster we're afraid of has a chance to fail
213 if (attacker->is_player() && you.afraid_of(defender->as_monster())
216 mprf("You attempt to attack %s, but flinch away in fear!",
217 defender->name(DESC_THE).c_str());
221 if (attk_flavour == AF_SHADOWSTAB && defender && !defender->can_see(attacker))
223 if (you.see_cell(attack_position))
225 mprf("%s strikes at %s from the darkness!",
226 attacker->name(DESC_THE, true).c_str(),
227 defender->name(DESC_THE).c_str());
229 to_hit = AUTOMATIC_HIT;
230 needs_message = false;
232 else if (attacker->is_monster()
233 && attacker->type == MONS_DROWNED_SOUL)
235 to_hit = AUTOMATIC_HIT;
238 attack_occurred = true;
240 // Check for player practicing dodging
241 if (one_chance_in(3) && defender->is_player())
242 practise(EX_MONSTER_MAY_HIT);
247 bool melee_attack::handle_phase_dodged()
251 const int ev = defender->evasion(EV_IGNORE_NONE, attacker);
252 const int ev_nophase = defender->evasion(EV_IGNORE_PHASESHIFT, attacker);
254 if (ev_margin + (ev - ev_nophase) > 0)
256 if (needs_message && defender_visible)
258 mprf("%s momentarily %s out as %s "
259 "attack passes through %s%s",
260 defender->name(DESC_THE).c_str(),
261 defender->conj_verb("phase").c_str(),
262 atk_name(DESC_ITS).c_str(),
263 defender->pronoun(PRONOUN_OBJECTIVE).c_str(),
264 attack_strength_punctuation(damage_done).c_str());
271 // TODO: Unify these, placed player_warn_miss here so I can remove
273 if (attacker->is_player())
277 mprf("%s%s misses %s%s",
278 atk_name(DESC_THE).c_str(),
279 evasion_margin_adverb().c_str(),
280 defender_name(true).c_str(),
281 attack_strength_punctuation(damage_done).c_str());
286 if (attacker != defender && adjacent(defender->pos(), attack_position))
288 if (attacker->alive()
289 && (defender->is_player() ?
290 you.species == SP_MINOTAUR :
291 mons_species(mons_base_type(defender->as_monster()))
293 && defender->can_see(attacker)
294 // Retaliation only works on the first attack in a round.
295 // FIXME: player's attack is -1, even for auxes
296 && effective_attack_number <= 0)
298 do_minotaur_retaliation();
301 // Retaliations can kill!
302 if (!attacker->alive())
309 static bool _flavour_triggers_damageless(attack_flavour flavour)
311 return flavour == AF_CRUSH
312 || flavour == AF_ENGULF
313 || flavour == AF_PURE_FIRE
314 || flavour == AF_SHADOWSTAB
315 || flavour == AF_DROWN
316 || flavour == AF_CORRODE
317 || flavour == AF_SCARAB;
320 void melee_attack::apply_black_mark_effects()
322 // Slightly weaker and less reliable effects for players.
323 if (attacker->is_player()
324 && you.mutation[MUT_BLACK_MARK]
327 if (you.hp < you.hp_max
328 && !you.duration[DUR_DEATHS_DOOR]
329 && !defender->as_monster()->is_summoned())
331 mpr("You feel better.");
332 attacker->heal(random2(damage_done));
335 if (!defender->alive())
341 antimagic_affects_defender(damage_done * 8);
344 defender->weaken(attacker, 2);
347 defender->drain_exp(attacker);
351 else if (attacker->is_monster()
352 && attacker->as_monster()->has_ench(ENCH_BLACK_MARK))
354 monster* mon = attacker->as_monster();
356 if (mon->heal(random2avg(damage_done, 2)))
357 simple_monster_message(mon, " is healed.");
359 if (!defender->alive())
365 antimagic_affects_defender(damage_done * 8);
368 defender->slow_down(attacker, 5 + random2(7));
371 defender->drain_exp(attacker, false, 10);
377 /* An attack has been determined to have hit something
379 * Handles to-hit effects for both attackers and defenders,
380 * Determines damage and passes off execution to handle_phase_damaged
381 * Also applies weapon brands
383 * Returns true if combat should continue, false if it should end here.
385 bool melee_attack::handle_phase_hit()
388 perceived_attack = true;
389 bool hit_woke_orc = false;
391 if (attacker->is_player())
393 if (crawl_state.game_is_hints())
394 Hints.hints_melee_counter++;
396 // TODO: Remove this (placed here so I can get rid of player_attack)
397 if (in_good_standing(GOD_BEOGH, 2)
398 && mons_genus(defender->mons_species()) == MONS_ORC
399 && !defender->is_summoned()
400 && !defender->as_monster()->is_shapeshifter()
401 && mons_near(defender->as_monster()) && defender->asleep())
408 // Slimify does no damage and serves as an on-hit effect, handle it
409 if (attacker->is_player() && you.duration[DUR_SLIMIFY]
410 && mon_can_be_slimified(defender->as_monster())
413 // Bail out after sliming so we don't get aux unarmed and
414 // attack a fellow slime.
415 slimify_monster(defender->as_monster());
416 you.duration[DUR_SLIMIFY] = 0;
421 if (attacker->is_player() && you.duration[DUR_INFUSION])
423 if (enough_mp(1, true, false))
425 // infusion_power is set when the infusion spell is cast
426 const int pow = you.props["infusion_power"].get_int();
427 const int dmg = 2 + div_rand_round(pow, 25);
428 const int hurt = defender->apply_ac(dmg);
430 dprf(DIAG_COMBAT, "Infusion: dmg = %d hurt = %d", dmg, hurt);
440 // This does more than just calculate the damage, it also sets up
441 // messages, etc. It also wakes nearby creatures on a failed stab,
442 // meaning it could have made the attacked creature vanish. That
443 // will be checked early in player_monattack_hit_effects
444 damage_done += calc_damage();
446 bool stop_hit = false;
447 // Check if some hit-effect killed the monster.
448 if (attacker->is_player())
449 stop_hit = !player_monattk_hit_effects();
451 // check_unrand_effects is safe to call with a dead defender, so always
452 // call it, even if the hit effects said to stop.
455 check_unrand_effects();
459 if (damage_done > 0 || _flavour_triggers_damageless(attk_flavour))
461 if (!handle_phase_damaged())
464 // TODO: Remove this, (placed here to remove player_attack)
465 if (attacker->is_player() && hit_woke_orc)
467 // Call function of orcs first noticing you, but with
468 // beaten-up conversion messages (if applicable).
469 beogh_follower_convert(defender->as_monster(), true);
472 else if (needs_message)
474 attack_verb = attacker->is_player()
476 : attacker->conj_verb(mons_attack_verb());
478 // TODO: Clean this up if possible, checking atype for do / does is ugly
479 mprf("%s %s %s but %s no damage.",
480 attacker->name(DESC_THE).c_str(),
482 defender_name(true).c_str(),
483 attacker->is_player() ? "do" : "does");
486 // Check for weapon brand & inflict that damage too
487 apply_damage_brand();
489 if (check_unrand_effects())
493 apply_black_mark_effects();
495 if (attacker->is_player())
497 // Always upset monster regardless of damage.
498 // However, successful stabs inhibit shouting.
499 behaviour_event(defender->as_monster(), ME_WHACK, attacker,
500 coord_def(), !stab_attempt);
502 // [ds] Monster may disappear after behaviour event.
503 if (!defender->alive())
506 else if (defender->is_player())
508 // These effects (mutations right now) are only triggered when
509 // the player is hit, each of them will verify their own required
512 #if TAG_MAJOR_VERSION == 34
521 bool melee_attack::handle_phase_damaged()
523 bool shroud_broken = false;
525 // TODO: Move this somewhere else, this is a terrible place for a
526 // block-like (prevents all damage) effect.
527 if (attacker != defender
528 && (defender->is_player() && you.duration[DUR_SHROUD_OF_GOLUBRIA]
529 || defender->is_monster()
530 && defender->as_monster()->has_ench(ENCH_SHROUD))
531 && !one_chance_in(3))
533 // Chance of the shroud falling apart increases based on the
534 // strain of it, i.e. the damage it is redirecting.
535 if (x_chance_in_y(damage_done, 10+damage_done))
537 // Delay the message for the shroud breaking until after
538 // the attack message.
539 shroud_broken = true;
540 if (defender->is_player())
541 you.duration[DUR_SHROUD_OF_GOLUBRIA] = 0;
543 defender->as_monster()->del_ench(ENCH_SHROUD);
549 mprf("%s shroud bends %s attack away%s",
550 def_name(DESC_ITS).c_str(),
551 atk_name(DESC_ITS).c_str(),
552 attack_strength_punctuation(damage_done).c_str());
561 if (!attack::handle_phase_damaged())
564 if (shroud_broken && needs_message)
566 mprf(defender->is_player() ? MSGCH_WARN : MSGCH_PLAIN,
567 "%s shroud falls apart!",
568 def_name(DESC_ITS).c_str());
574 bool melee_attack::handle_phase_aux()
576 if (attacker->is_player())
578 // returns whether an aux attack successfully took place
579 // additional attacks from cleave don't get aux
580 if (!defender->as_monster()->friendly()
581 && adjacent(defender->pos(), attack_position)
584 player_aux_unarmed();
587 // Don't print wounds after the first attack with Gyre/Gimble.
588 // DUR_CLEAVE and Gyre/Gimble interact poorly together at the moment,
589 // so don't try to skip print_wounds in that case.
590 if (!(weapon && is_unrandom_artefact(*weapon, UNRAND_GYRE)
591 && !cleaving && !you.duration[DUR_CLEAVE]))
593 print_wounds(defender->as_monster());
601 * Devour a monster whole!.
603 * @param defender The monster in question.
605 static void _hydra_devour(monster &victim)
607 // what's the highest hunger level this lets the player get to?
608 const hunger_state_t max_hunger =
609 static_cast<hunger_state_t>(HS_SATIATED + player_likes_chunks());
611 // will eating this actually fill the player up?
612 const bool filling = !in_good_standing(GOD_GOZAG)
613 && player_mutation_level(MUT_HERBIVOROUS, false) < 3
614 && you.hunger_state <= max_hunger
615 && you.hunger_state < HS_ENGORGED;
617 mprf("You %sdevour %s!",
618 filling ? "hungrily " : "",
619 victim.name(DESC_THE).c_str());
624 const int equiv_chunks =
625 1 + random2(max_corpse_chunks(victim.type));
626 lessen_hunger(CHUNK_BASE_NUTRITION * equiv_chunks, false, max_hunger);
630 if (!you.duration[DUR_DEATHS_DOOR])
632 const int healing = 1 + victim.get_experience_level() * 3 / 4
633 + random2(victim.get_experience_level() * 3 / 4);
636 mpr("You feel better.");
637 dprf("healed for %d (%d hd)", healing, victim.get_experience_level());
640 // and devour the corpse.
641 victim.props[NEVER_CORPSE_KEY] = true;
645 * Possibly devour the defender whole.
647 * @param defender The defender in question.
649 static void _hydra_consider_devouring(monster &defender)
651 ASSERT(!crawl_state.game_is_arena());
653 dprf("considering devouring");
656 if (determine_chunk_effect(mons_corpse_effect(defender.type)) != CE_CLEAN)
661 // shapeshifters are mutagenic
662 if (defender.is_shapeshifter())
664 // handle this carefully, so the player knows what's going on
665 mprf("You spit out %s as %s twists & changes in your mouth!",
666 defender.name(DESC_THE).c_str(),
667 defender.pronoun(PRONOUN_SUBJECTIVE).c_str());
673 // or food that would incur divine penance...
674 if (god_hates_eating(you.religion, defender.type))
679 // can't eat enemies that leave no corpses...
680 if (!mons_class_can_leave_corpse(mons_species(defender.type))
681 || defender.is_summoned()
682 || defender.flags & MF_HARD_RESET)
689 // or monsters as large as you are!
690 if (defender.body_size() >= you.body_size())
696 _hydra_devour(defender);
700 * Handle effects that fire when the defender (the target of the attack) is
703 * @return Not sure; it seems to never be checked & always be true?
705 bool melee_attack::handle_phase_killed()
707 if (attacker->is_player() && you.form == TRAN_HYDRA
708 && defender->is_monster() // better safe than sorry
709 && defender->type != MONS_NO_MONSTER) // already reset
711 _hydra_consider_devouring(*defender->as_monster());
714 return attack::handle_phase_killed();
717 bool melee_attack::handle_phase_end()
719 if (!cleave_targets.empty())
721 attack_cleave_targets(*attacker, cleave_targets, attack_number,
722 effective_attack_number);
725 // Check for passive mutation effects.
726 if (defender->is_player() && defender->alive() && attacker != defender)
728 mons_do_eyeball_confusion();
730 monster* mon = attacker->as_monster();
731 // some rounding errors here, but not significant
732 const int adj_mon_hd = mon->is_fighter() ? mon->get_hit_dice() * 3/2
733 : mon->get_hit_dice();
735 if (player_mutation_level(MUT_TENDRILS)
737 && (random2(you.dex()) > adj_mon_hd
738 || random2(you.strength()) > adj_mon_hd))
740 item_def* mons_wpn = mon->disarm();
743 mprf("Your tendrils lash around %s %s and pull it to the ground!",
744 apostrophise(mon->name(DESC_THE)).c_str(),
745 mons_wpn->name(DESC_PLAIN).c_str());
750 return attack::handle_phase_end();
753 /* Initiate the processing of the attack
755 * Called from the main code (fight.cc), this method begins the actual combat
756 * for a particular attack and is responsible for looping through each of the
757 * appropriate phases (which then can call other related phases within
760 * Returns whether combat was completely successful
761 * If combat was not successful, it could be any number of reasons, like
762 * the defender or attacker dying during the attack? or a defender moving
763 * from its starting position.
765 bool melee_attack::attack()
767 if (!cleaving && !handle_phase_attempted())
770 if (attacker != defender && attacker->self_destructs())
771 return did_hit = perceived_attack = true;
777 const bool gyre = weapon && is_unrandom_artefact(*weapon, UNRAND_GYRE);
778 if (gyre && !weapon->props.exists(ARTEFACT_NAME_KEY))
779 set_artefact_name(*weapon, get_artefact_name(*weapon));
780 unwind_var<string> gyre_name(gyre ? weapon->props[ARTEFACT_NAME_KEY].get_string()
785 set_artefact_name(*weapon, "quick blade \"Gyre\"");
787 set_artefact_name(*weapon, "quick blade \"Gimble\"");
790 // Attacker might have died from effects of cleaving handled prior to this
791 if (!attacker->alive())
794 // We might have killed the kraken target by cleaving a tentacle.
795 if (!defender->alive())
797 handle_phase_killed();
799 return attack_occurred;
802 // Apparently I'm insane for believing that we can still stay general past
803 // this point in the combat code, mebe I am! --Cryptic
805 // Calculate various ev values and begin to check them to determine the
806 // correct handle_phase_ handler.
807 const int ev = defender->evasion(EV_IGNORE_NONE, attacker);
808 ev_margin = test_hit(to_hit, ev, !attacker->is_player());
809 bool shield_blocked = attack_shield_blocked(true);
811 // Stuff for god conduct, this has to remain here for scope reasons.
812 god_conduct_trigger conducts[3];
813 disable_attack_conducts(conducts);
815 if (attacker->is_player() && attacker != defender)
817 set_attack_conducts(conducts, defender->as_monster());
819 if (player_under_penance(GOD_ELYVILON)
820 && god_hates_your_god(GOD_ELYVILON)
822 && one_chance_in(20))
824 simple_god_message(" blocks your attack.", GOD_ELYVILON);
828 // Check for stab (and set stab_attempt and stab_bonus)
830 // Make sure we hit if we passed the stab check.
831 if (stab_attempt && stab_bonus > 0)
833 ev_margin = AUTOMATIC_HIT;
834 shield_blocked = false;
839 handle_phase_blocked();
842 if (attacker != defender && adjacent(defender->pos(), attack_position))
844 // Check for defender Spines
848 if (!attacker->alive())
854 if (attacker != defender && attack_warded_off())
856 perceived_attack = true;
861 bool cont = handle_phase_hit();
863 attacker_sustain_passive_damage();
867 if (!defender->alive())
868 handle_phase_killed();
874 handle_phase_dodged();
877 // Remove sanctuary if - through some attack - it was violated.
878 if (env.sanctuary_time > 0 && attack_occurred && !cancel_attack
879 && attacker != defender && !attacker->confused()
880 && (is_sanctuary(attack_position) || is_sanctuary(defender->pos()))
881 && (attacker->is_player() || attacker->as_monster()->friendly()))
883 remove_sanctuary(true);
886 if (attacker->is_player())
889 // don't crash on banishment
890 if (!defender->pos().origin())
891 handle_noise(defender->pos());
894 if (attacker->is_player()
896 && is_artefact(*weapon)
897 && artefact_property(*weapon, ARTP_NOISES))
904 if (!defender->alive())
905 handle_phase_killed();
911 enable_attack_conducts(conducts);
913 return attack_occurred;
916 void melee_attack::check_autoberserk()
918 if (attacker->is_player())
920 for (int i = EQ_WEAPON; i < NUM_EQUIP; ++i)
922 const item_def *item = you.slot_item(static_cast<equipment_type>(i));
926 if (!is_artefact(*item))
929 if (x_chance_in_y(artefact_property(*item, ARTP_ANGRY), 100))
931 attacker->go_berserk(false);
938 for (int i = MSLOT_WEAPON; i <= MSLOT_JEWELLERY; ++i)
940 const item_def *item =
941 attacker->as_monster()->mslot_item(static_cast<mon_inv_type>(i));
945 if (!is_artefact(*item))
948 if (x_chance_in_y(artefact_property(*item, ARTP_ANGRY), 100))
950 attacker->go_berserk(false);
957 bool melee_attack::check_unrand_effects()
959 if (unrand_entry && unrand_entry->melee_effects && weapon)
961 // Recent merge added damage_done to this method call
962 unrand_entry->melee_effects(weapon, attacker, defender,
963 !defender->alive(), damage_done);
964 return !defender->alive();
970 class AuxConstrict: public AuxAttackType
974 : AuxAttackType(0, "grab") { };
977 class AuxKick: public AuxAttackType
981 : AuxAttackType(-1, "kick") { };
983 int get_damage() const
985 if (you.has_usable_hooves())
987 // Max hoof damage: 10.
988 return player_mutation_level(MUT_HOOVES) * 5 / 3;
991 if (you.has_usable_talons())
993 // Max talon damage: 9.
994 return 1 + player_mutation_level(MUT_TALONS);
997 // Max spike damage: 8.
998 // ... yes, apparently tentacle spikes are "kicks".
999 return player_mutation_level(MUT_TENTACLE_SPIKE);
1002 string get_verb() const
1004 if (you.has_usable_talons())
1006 if (player_mutation_level(MUT_TENTACLE_SPIKE))
1011 string get_name() const
1013 if (player_mutation_level(MUT_TENTACLE_SPIKE))
1014 return "tentacle spike";
1019 class AuxHeadbutt: public AuxAttackType
1023 : AuxAttackType(5, "headbutt") { };
1025 int get_damage() const
1027 return damage + player_mutation_level(MUT_HORNS) * 3;
1031 class AuxPeck: public AuxAttackType
1035 : AuxAttackType(6, "peck") { };
1038 class AuxTailslap: public AuxAttackType
1042 : AuxAttackType(6, "tail-slap") { };
1044 int get_damage() const
1046 return damage + max(0, player_mutation_level(MUT_STINGER) * 2 - 1);
1049 int get_brand() const
1051 return player_mutation_level(MUT_STINGER) ? SPWPN_VENOM : SPWPN_NORMAL;
1055 class AuxPunch: public AuxAttackType
1059 : AuxAttackType(5, "punch") { };
1061 int get_damage() const
1063 const int base_dam = damage + you.skill_rdiv(SK_UNARMED_COMBAT, 1, 2);
1065 if (you.form == TRAN_BLADE_HANDS)
1066 return base_dam + 6;
1068 if (you.has_usable_claws())
1069 return base_dam + roll_dice(you.has_claws(), 3);
1074 string get_name() const
1076 if (you.form == TRAN_BLADE_HANDS)
1079 if (you.has_usable_claws())
1082 if (you.has_usable_tentacles())
1083 return "tentacle-slap";
1090 class AuxBite: public AuxAttackType
1094 : AuxAttackType(0, "bite") { };
1096 int get_damage() const
1098 const int fang_damage = you.has_usable_fangs() * 2;
1099 if (player_mutation_level(MUT_ANTIMAGIC_BITE))
1100 return fang_damage + div_rand_round(you.get_hit_dice(), 3);
1102 const int str_damage = div_rand_round(max(you.strength()-10, 0), 5);
1104 if (player_mutation_level(MUT_ACIDIC_BITE))
1105 return fang_damage + str_damage + roll_dice(2,4);
1107 return fang_damage + str_damage;
1110 int get_brand() const
1112 if (player_mutation_level(MUT_ANTIMAGIC_BITE))
1113 return SPWPN_ANTIMAGIC;
1115 if (player_mutation_level(MUT_ACIDIC_BITE))
1118 return SPWPN_NORMAL;
1122 class AuxPseudopods: public AuxAttackType
1126 : AuxAttackType(4, "bludgeon") { };
1128 int get_damage() const { return damage * you.has_usable_pseudopods(); }
1131 class AuxTentacles: public AuxAttackType
1135 : AuxAttackType(12, "squeeze") { };
1139 static const AuxConstrict AUX_CONSTRICT = AuxConstrict();
1140 static const AuxKick AUX_KICK = AuxKick();
1141 static const AuxPeck AUX_PECK = AuxPeck();
1142 static const AuxHeadbutt AUX_HEADBUTT = AuxHeadbutt();
1143 static const AuxTailslap AUX_TAILSLAP = AuxTailslap();
1144 static const AuxPunch AUX_PUNCH = AuxPunch();
1145 static const AuxBite AUX_BITE = AuxBite();
1146 static const AuxPseudopods AUX_PSEUDOPODS = AuxPseudopods();
1147 static const AuxTentacles AUX_TENTACLES = AuxTentacles();
1149 static const AuxAttackType* const aux_attack_types[] =
1163 /* Setup all unarmed (non attack_type) variables
1165 * Clears any previous unarmed attack information and sets everything from
1166 * noise_factor to verb and damage. Called after player_aux_choose_uc_attack
1168 void melee_attack::player_aux_setup(unarmed_attack_type atk)
1170 const int num_aux_objs = ARRAYSZ(aux_attack_types);
1171 const int num_aux_atks = UNAT_LAST_ATTACK - UNAT_FIRST_ATTACK + 1;
1172 COMPILE_CHECK(num_aux_objs == num_aux_atks);
1174 ASSERT(atk >= UNAT_FIRST_ATTACK);
1175 ASSERT(atk <= UNAT_LAST_ATTACK);
1176 const AuxAttackType* const aux = aux_attack_types[atk - UNAT_FIRST_ATTACK];
1178 aux_damage = aux->get_damage();
1179 damage_brand = (brand_type)aux->get_brand();
1180 aux_attack = aux->get_name();
1181 aux_verb = aux->get_verb();
1184 // prob of vampiric bite:
1185 // 1/4 when non-thirsty, 1/2 when thirsty, 100% when
1187 if (atk == UNAT_BITE
1188 && _vamp_wants_blood_from_monster(defender->as_monster())
1189 && (you.hunger_state == HS_STARVING
1190 || you.hunger_state < HS_SATIATED && coinflip()
1191 || you.hunger_state >= HS_SATIATED && one_chance_in(4)))
1193 damage_brand = SPWPN_VAMPIRISM;
1198 * Decide whether the player gets a bonus punch attack.
1202 * @return Whether the player gets a bonus punch aux attack on this attack.
1204 bool melee_attack::player_gets_aux_punch()
1206 if (!get_form()->can_offhand_punch())
1209 // roll for punch chance based on uc skill & armour penalty
1210 if (!attacker->fights_well_unarmed(attacker_armour_tohit_penalty
1211 + attacker_shield_tohit_penalty))
1216 // No punching with a shield or 2-handed wpn.
1217 // Octopodes aren't affected by this, though!
1218 if (you.species != SP_OCTOPODE && !you.has_usable_offhand())
1221 // Octopodes get more tentacle-slaps.
1222 return x_chance_in_y(you.species == SP_OCTOPODE ? 3 : 2,
1226 bool melee_attack::player_aux_test_hit()
1228 // XXX We're clobbering did_hit
1231 const int evasion = defender->evasion(EV_IGNORE_NONE, attacker);
1233 if (player_under_penance(GOD_ELYVILON)
1234 && god_hates_your_god(GOD_ELYVILON)
1235 && to_hit >= evasion
1236 && one_chance_in(20))
1238 simple_god_message(" blocks your attack.", GOD_ELYVILON);
1242 bool auto_hit = one_chance_in(30);
1244 if (to_hit >= evasion || auto_hit)
1247 const int phaseless_evasion =
1248 defender->evasion(EV_IGNORE_PHASESHIFT, attacker);
1250 if (to_hit >= phaseless_evasion && defender_visible)
1252 mprf("Your %s passes through %s as %s momentarily phases out.",
1254 defender->name(DESC_THE).c_str(),
1255 defender->pronoun(PRONOUN_SUBJECTIVE).c_str());
1259 mprf("Your %s misses %s.", aux_attack.c_str(),
1260 defender->name(DESC_THE).c_str());
1266 /* Controls the looping on available unarmed attacks
1268 * As the master method for unarmed player combat, this loops through
1269 * available unarmed attacks, determining whether they hit and - if so -
1270 * calculating and applying their damage.
1272 * Returns (defender dead)
1274 bool melee_attack::player_aux_unarmed()
1276 unwind_var<brand_type> save_brand(damage_brand);
1278 for (int i = UNAT_FIRST_ATTACK; i <= UNAT_LAST_ATTACK; ++i)
1280 if (!defender->alive())
1283 unarmed_attack_type atk = static_cast<unarmed_attack_type>(i);
1285 if (!_extra_aux_attack(atk))
1288 // Determine and set damage and attack words.
1289 player_aux_setup(atk);
1291 if (atk == UNAT_CONSTRICT && !attacker->can_constrict(defender))
1294 to_hit = random2(calc_your_to_hit_unarmed(atk,
1295 damage_brand == SPWPN_VAMPIRISM));
1297 handle_noise(defender->pos());
1298 alert_nearby_monsters();
1300 // [ds] kraken can flee when near death, causing the tentacle
1301 // the player was beating up to "die" and no longer be
1302 // available to answer questions beyond this point.
1303 // handle_noise stirs up all nearby monsters with a stick, so
1304 // the player may be beating up a tentacle, but the main body
1305 // of the kraken still gets a chance to act and submerge
1306 // tentacles before we get here.
1307 if (!defender->alive())
1310 if (player_aux_test_hit())
1312 // Upset the monster.
1313 behaviour_event(defender->as_monster(), ME_WHACK, attacker);
1314 if (!defender->alive())
1317 if (attack_shield_blocked(true))
1319 if (player_aux_apply(atk))
1327 bool melee_attack::player_aux_apply(unarmed_attack_type atk)
1331 aux_damage = player_aux_stat_modify_damage(aux_damage);
1333 aux_damage = random2(aux_damage);
1335 aux_damage = player_apply_fighting_skill(aux_damage, true);
1337 aux_damage = player_apply_misc_modifiers(aux_damage);
1339 aux_damage = player_apply_slaying_bonuses(aux_damage, true);
1341 aux_damage = player_apply_final_multipliers(aux_damage);
1343 if (atk == UNAT_CONSTRICT)
1346 aux_damage = apply_defender_ac(aux_damage);
1348 aux_damage = inflict_damage(aux_damage, BEAM_MISSILE);
1349 damage_done = aux_damage;
1354 apply_bleeding = true;
1357 case UNAT_CONSTRICT:
1358 attacker->start_constricting(*defender);
1365 if (damage_done > 0 || atk == UNAT_CONSTRICT)
1367 player_announce_aux_hit();
1369 if (damage_brand == SPWPN_ACID)
1371 mprf("%s is splashed with acid.",
1372 defender->name(DESC_THE).c_str());
1373 defender->splash_with_acid(&you);
1376 if (damage_brand == SPWPN_VENOM && coinflip())
1377 poison_monster(defender->as_monster(), &you);
1379 // Normal vampiric biting attack, not if already got stabbing special.
1380 if (damage_brand == SPWPN_VAMPIRISM && you.species == SP_VAMPIRE
1381 && (!stab_attempt || stab_bonus <= 0))
1383 _player_vampire_draws_blood(defender->as_monster(), damage_done);
1386 if (damage_brand == SPWPN_ANTIMAGIC && you.mutation[MUT_ANTIMAGIC_BITE]
1389 const bool spell_user = defender->antimagic_susceptible();
1391 antimagic_affects_defender(damage_done * 32);
1392 mprf("You drain %s %s.",
1393 defender->as_monster()->pronoun(PRONOUN_POSSESSIVE).c_str(),
1394 spell_user ? "magic" : "power");
1396 if (you.magic_points != you.max_magic_points
1397 && !defender->as_monster()->is_summoned()
1398 && !mons_is_firewood(defender->as_monster()))
1400 int drain = random2(damage_done * 2) + 1;
1401 //Augment mana drain--1.25 "standard" effectiveness at 0 mp,
1402 //.25 at mana == max_mana
1403 drain = (int)((1.25 - you.magic_points / you.max_magic_points)
1407 mpr("You feel invigorated.");
1413 else // no damage was done
1415 mprf("You %s %s%s.",
1417 defender->name(DESC_THE).c_str(),
1418 you.can_see(defender) ? ", but do no damage" : "");
1421 if (defender->as_monster()->hit_points < 1)
1423 handle_phase_killed();
1430 void melee_attack::player_announce_aux_hit()
1432 mprf("You %s %s%s%s",
1434 defender->name(DESC_THE).c_str(),
1435 debug_damage_number().c_str(),
1436 attack_strength_punctuation(damage_done).c_str());
1439 string melee_attack::player_why_missed()
1441 const int ev = defender->evasion(EV_IGNORE_NONE, attacker);
1442 const int combined_penalty =
1443 attacker_armour_tohit_penalty + attacker_shield_tohit_penalty;
1444 if (to_hit < ev && to_hit + combined_penalty >= ev)
1446 const bool armour_miss =
1447 (attacker_armour_tohit_penalty
1448 && to_hit + attacker_armour_tohit_penalty >= ev);
1449 const bool shield_miss =
1450 (attacker_shield_tohit_penalty
1451 && to_hit + attacker_shield_tohit_penalty >= ev);
1453 const item_def *armour = you.slot_item(EQ_BODY_ARMOUR, false);
1454 const string armour_name = armour ? armour->name(DESC_BASENAME)
1457 if (armour_miss && !shield_miss)
1458 return "Your " + armour_name + " prevents you from hitting ";
1459 else if (shield_miss && !armour_miss)
1460 return "Your shield prevents you from hitting ";
1462 return "Your shield and " + armour_name
1463 + " prevent you from hitting ";
1466 return "You" + evasion_margin_adverb() + " miss ";
1469 void melee_attack::player_warn_miss()
1474 player_why_missed().c_str(),
1475 defender->name(DESC_THE).c_str());
1477 // Upset only non-sleeping non-fleeing monsters if we missed.
1478 if (!defender->asleep() && !mons_is_fleeing(defender->as_monster()))
1479 behaviour_event(defender->as_monster(), ME_WHACK, attacker);
1482 int melee_attack::player_aux_stat_modify_damage(int damage)
1485 // Use the same str/dex weighting that unarmed combat does, for now.
1486 const int dam_stat_val = (7 * you.strength() + 3 * you.dex())/10;
1488 if (dam_stat_val > 10)
1489 dammod += random2(dam_stat_val - 9);
1490 else if (dam_stat_val < 10)
1491 dammod -= random2(11 - dam_stat_val);
1499 // A couple additive modifiers that should be applied to both unarmed and
1501 int melee_attack::player_apply_misc_modifiers(int damage)
1503 if (you.duration[DUR_MIGHT] || you.duration[DUR_BERSERK])
1504 damage += 1 + random2(10);
1506 if (you.species != SP_VAMPIRE && you.hunger_state == HS_STARVING)
1507 damage -= random2(5);
1512 // Multipliers to be applied to the final (pre-stab, pre-AC) damage.
1513 // It might be tempting to try to pick and choose what pieces of the damage
1514 // get affected by such multipliers, but putting them at the end is the
1515 // simplest effect to understand if they aren't just going to be applied
1516 // to the base damage of the weapon.
1517 int melee_attack::player_apply_final_multipliers(int damage)
1519 //cleave damage modifier
1521 damage = cleave_damage_mod(damage);
1523 // not additive, statues are supposed to be bad with tiny toothpicks but
1524 // deal crushing blows with big weapons
1525 if (you.form == TRAN_STATUE)
1526 damage = div_rand_round(damage * 3, 2);
1528 // Can't affect much of anything as a shadow.
1529 if (you.form == TRAN_SHADOW)
1530 damage = div_rand_round(damage, 2);
1532 if (you.duration[DUR_WEAK])
1533 damage = div_rand_round(damage * 3, 4);
1535 if (you.duration[DUR_CONFUSING_TOUCH] && wpn_skill == SK_UNARMED_COMBAT)
1541 void melee_attack::set_attack_verb(int damage)
1543 if (!attacker->is_player())
1546 int weap_type = WPN_UNKNOWN;
1548 if (Options.has_fake_lang(FLANG_GRUNT))
1549 damage = HIT_STRONG + 1;
1552 weap_type = WPN_UNARMED;
1553 else if (weapon->base_type == OBJ_STAVES)
1554 weap_type = WPN_STAFF;
1555 else if (weapon->base_type == OBJ_RODS)
1556 weap_type = WPN_ROD;
1557 else if (weapon->base_type == OBJ_WEAPONS
1558 && !is_range_weapon(*weapon))
1560 weap_type = weapon->sub_type;
1563 // All weak hits with weapons look the same.
1564 if (damage < HIT_WEAK
1565 && weap_type != WPN_UNARMED)
1567 if (weap_type != WPN_UNKNOWN)
1568 attack_verb = "hit";
1570 attack_verb = "clumsily bash";
1574 // Take normal hits into account. If the hit is from a weapon with
1575 // more than one damage type, randomly choose one damage type from
1577 monster_type defender_genus = mons_genus(defender->type);
1578 switch (weapon ? single_damage_type(*weapon) : -1)
1581 if (damage < HIT_MED)
1582 attack_verb = "puncture";
1583 else if (damage < HIT_STRONG)
1584 attack_verb = "impale";
1587 if (defender->is_monster()
1589 && defender_genus == MONS_HOG)
1591 attack_verb = "spit";
1592 verb_degree = "like the proverbial pig";
1594 else if (defender_genus == MONS_CRAB
1595 && Options.has_fake_lang(FLANG_GRUNT))
1597 attack_verb = "attack";
1598 verb_degree = "'s weak point";
1602 static const char * const pierce_desc[][2] =
1604 {"spit", "like a pig"},
1605 {"skewer", "like a kebab"},
1606 {"stick", "like a pincushion"},
1607 {"perforate", "like a sieve"}
1609 const int choice = random2(ARRAYSZ(pierce_desc));
1610 attack_verb = pierce_desc[choice][0];
1611 verb_degree = pierce_desc[choice][1];
1617 if (damage < HIT_MED)
1618 attack_verb = "slash";
1619 else if (damage < HIT_STRONG)
1620 attack_verb = "slice";
1621 else if (defender_genus == MONS_OGRE)
1623 attack_verb = "dice";
1624 verb_degree = "like an onion";
1626 else if (defender_genus == MONS_SKELETON)
1628 attack_verb = "fracture";
1629 verb_degree = "into splinters";
1631 else if (defender_genus == MONS_HOG)
1633 attack_verb = "carve";
1634 verb_degree = "like the proverbial ham";
1636 else if (defender_genus == MONS_TENGU && one_chance_in(3))
1638 attack_verb = "carve";
1639 verb_degree = "like a turkey";
1641 else if ((defender_genus == MONS_YAK || defender_genus == MONS_YAKTAUR)
1642 && Options.has_fake_lang(FLANG_GRUNT))
1643 attack_verb = "shave";
1646 static const char * const slice_desc[][2] =
1648 {"open", "like a pillowcase"},
1649 {"slice", "like a ripe choko"},
1650 {"cut", "into ribbons"},
1651 {"carve", "like a ham"},
1652 {"chop", "into pieces"}
1654 const int choice = random2(ARRAYSZ(slice_desc));
1655 attack_verb = slice_desc[choice][0];
1656 verb_degree = slice_desc[choice][1];
1661 if (damage < HIT_MED)
1662 attack_verb = one_chance_in(4) ? "thump" : "sock";
1663 else if (damage < HIT_STRONG)
1664 attack_verb = "bludgeon";
1665 else if (defender_genus == MONS_SKELETON)
1667 attack_verb = "shatter";
1668 verb_degree = "into splinters";
1670 else if (defender->type == MONS_GREAT_ORB_OF_EYES)
1672 attack_verb = "splatter";
1673 verb_degree = "into a gooey mess";
1677 static const char * const bludgeon_desc[][2] =
1679 {"crush", "like a grape"},
1680 {"beat", "like a drum"},
1681 {"hammer", "like a gong"},
1682 {"pound", "like an anvil"},
1683 {"flatten", "like a pancake"}
1685 const int choice = random2(ARRAYSZ(bludgeon_desc));
1686 attack_verb = bludgeon_desc[choice][0];
1687 verb_degree = bludgeon_desc[choice][1];
1692 if (damage < HIT_MED)
1693 attack_verb = "whack";
1694 else if (damage < HIT_STRONG)
1695 attack_verb = "thrash";
1698 switch (defender->holiness())
1703 attack_verb = "punish";
1704 verb_degree = ", causing immense pain";
1707 attack_verb = "devastate";
1714 const FormAttackVerbs verbs = get_form(you.form)->uc_attack_verbs;
1715 if (verbs.weak != nullptr)
1717 if (damage < HIT_WEAK)
1718 attack_verb = verbs.weak;
1719 else if (damage < HIT_MED)
1720 attack_verb = verbs.medium;
1721 else if (damage < HIT_STRONG)
1722 attack_verb = verbs.strong;
1724 attack_verb = verbs.devastating;
1728 if (you.damage_type() == DVORP_CLAWING)
1730 if (damage < HIT_WEAK)
1731 attack_verb = "scratch";
1732 else if (damage < HIT_MED)
1733 attack_verb = "claw";
1734 else if (damage < HIT_STRONG)
1735 attack_verb = "mangle";
1737 attack_verb = "eviscerate";
1739 else if (you.damage_type() == DVORP_TENTACLE)
1741 if (damage < HIT_WEAK)
1742 attack_verb = "tentacle-slap";
1743 else if (damage < HIT_MED)
1744 attack_verb = "bludgeon";
1745 else if (damage < HIT_STRONG)
1746 attack_verb = "batter";
1748 attack_verb = "thrash";
1752 if (damage < HIT_WEAK)
1753 attack_verb = "hit";
1754 else if (damage < HIT_MED)
1755 attack_verb = "punch";
1756 else if (damage < HIT_STRONG)
1757 attack_verb = "pummel";
1758 else if (defender->is_monster()
1759 && (mons_genus(defender->type) == MONS_WORKER_ANT
1760 || mons_genus(defender->type) == MONS_FORMICID))
1762 attack_verb = "squash";
1763 verb_degree = "like the proverbial ant";
1767 static const char * const punch_desc[][2] =
1769 {"pound", "into fine dust"},
1770 {"pummel", "like a punching bag"},
1772 {"squash", "like an ant"}
1774 const int choice = random2(ARRAYSZ(punch_desc));
1775 // XXX: could this distinction work better?
1777 && defender->is_monster()
1778 && mons_has_blood(defender->type))
1780 attack_verb = "beat";
1781 verb_degree = "into a bloody pulp";
1785 attack_verb = punch_desc[choice][0];
1786 verb_degree = punch_desc[choice][1];
1795 attack_verb = "hit";
1800 void melee_attack::player_exercise_combat_skills()
1802 if (defender->cannot_fight())
1805 int damage = 10; // Default for unarmed.
1806 if (weapon && is_weapon(*weapon) && !is_range_weapon(*weapon))
1807 damage = property(*weapon, PWPN_DAMAGE);
1809 // Slow down the practice of low-damage weapons.
1810 if (x_chance_in_y(damage, 20))
1811 practise(EX_WILL_HIT, wpn_skill);
1815 * Applies god conduct for weapon ego
1817 * Using speed brand as a chei worshipper, or holy/unholy weapons
1819 void melee_attack::player_weapon_upsets_god()
1821 if (weapon && weapon->base_type == OBJ_WEAPONS)
1823 if (is_holy_item(*weapon))
1824 did_god_conduct(DID_HOLY, 1);
1825 else if (is_demonic(*weapon))
1826 did_god_conduct(DID_UNHOLY, 1);
1827 else if (get_weapon_brand(*weapon) == SPWPN_SPEED
1828 || weapon->sub_type == WPN_QUICK_BLADE)
1830 did_god_conduct(DID_HASTY, 1);
1833 else if (weapon && weapon->is_type(OBJ_STAVES, STAFF_FIRE))
1834 did_god_conduct(DID_FIRE, 1);
1837 /* Apply player-specific effects as well as brand damage.
1839 * Called after damage is calculated, but before unrand effects and before
1842 * Returns true if combat should continue, false if it should end here.
1844 bool melee_attack::player_monattk_hit_effects()
1846 player_weapon_upsets_god();
1848 // Don't even check vampire bloodletting if the monster has already
1849 // been reset (for example, a spectral weapon who noticed in
1850 // player_stab_check that it shouldn't exist anymore).
1851 if (defender->type == MONS_NO_MONSTER)
1854 // Thirsty vampires will try to use a stabbing situation to draw blood.
1855 if (you.species == SP_VAMPIRE && you.hunger_state < HS_SATIATED
1856 && damage_done > 0 && stab_attempt && stab_bonus > 0)
1858 _player_vampire_draws_blood(defender->as_monster(), damage_done, true);
1861 if (!defender->alive())
1864 // These effects apply only to monsters that are still alive:
1866 // Returns true if a head was cut off *and* the wound was cauterized,
1867 // in which case the cauterization was the ego effect, so don't burn
1868 // the hydra some more.
1870 // Also returns true if the hydra's last head was cut off, in which
1871 // case nothing more should be done to the hydra.
1872 if (consider_decapitation(damage_done))
1873 return defender->alive();
1875 // Mutually exclusive with (overrides) brand damage!
1877 apply_staff_damage();
1879 if (!defender->alive())
1882 if (special_damage || special_damage_flavour)
1884 dprf(DIAG_COMBAT, "Special damage to %s: %d, flavour: %d",
1885 defender->name(DESC_THE).c_str(),
1886 special_damage, special_damage_flavour);
1888 special_damage = inflict_damage(special_damage);
1889 if (special_damage > 0)
1890 defender->expose_to_element(special_damage_flavour, 2);
1896 void melee_attack::rot_defender(int amount)
1898 if (defender->rot(attacker, amount, true))
1900 // XXX: why is this message separate here?
1901 if (defender->is_player())
1903 special_damage_message =
1904 make_stringf("You feel your flesh rotting away!");
1906 else if (defender->is_monster() && defender_visible)
1908 special_damage_message =
1910 "%s looks less resilient!",
1911 defender_name(false).c_str());
1916 void melee_attack::handle_noise(const coord_def & pos)
1918 // Successful stabs make no noise.
1922 int loudness = damage_done / 4;
1924 // All non-stab melee attacks make some noise.
1925 loudness = max(1, loudness);
1927 // Cap melee noise at shouting volume.
1928 loudness = min(12, loudness);
1930 noisy(loudness, pos, attacker->mid);
1934 * If appropriate, chop a head off the defender. (Usually a hydra.)
1936 * @param dam The damage done in the attack that may or may not chop
1938 * @param damage_type The type of damage done in the attack.
1939 * @return Whether a head was chopped off & cauterized, or whether
1940 * the defender is now entirely headless.
1941 * (relevant for considering whether to do fire damage.)
1943 bool melee_attack::consider_decapitation(int dam, int damage_type)
1945 const int dam_type = (damage_type != -1) ? damage_type :
1946 attacker->damage_type();
1947 const brand_type wpn_brand = attacker->damage_brand();
1949 if (!attack_chops_heads(dam, dam_type, wpn_brand))
1952 decapitate(dam_type);
1954 if (!defender->alive())
1957 // if your last head got chopped off, don't 'cauterize the wound'.
1958 if (defender->is_player() && you.form != TRAN_HYDRA)
1961 // Only living hydras get to regenerate heads.
1962 if (defender->holiness() != MH_NATURAL)
1965 // What's the largest number of heads the defender can have?
1966 const int limit = defender->type == MONS_LERNAEAN_HYDRA ? 27
1969 if (wpn_brand == SPWPN_FLAMING)
1971 if (defender_visible)
1972 mpr("The flame cauterises the wound!");
1976 int heads = defender->heads();
1977 if (heads >= limit - 1)
1978 return false; // don't overshoot the head limit!
1980 if (defender->is_monster())
1982 simple_monster_message(defender->as_monster(), " grows two more!");
1983 defender->as_monster()->num_heads += 2;
1984 defender->heal(8 + random2(8), true);
1988 mpr("You grow two more!");
1989 set_hydra_form_heads(heads + 2);
1996 * Can the given actor lose its heads? (Is it hydra or hydra-like?)
1998 * @param defender The actor in question.
1999 * @return Whether the given actor is susceptible to head-choppage.
2001 static bool actor_can_lose_heads(const actor* defender)
2003 if (defender->is_monster()
2004 && defender->as_monster()->has_hydra_multi_attack()
2005 && defender->type != MONS_SPECTRAL_THING
2006 && defender->as_monster()->mons_species() != MONS_SERPENT_OF_HELL)
2011 if (defender->is_player() && you.form == TRAN_HYDRA)
2018 * Does this attack chop off one of the defender's heads? (Generally only
2019 * relevant for hydra defenders)
2021 * @param dam The damage done in the attack in question.
2022 * @param dam_type The vorpal_damage_type of the attack.
2023 * @param wpn_brand The brand_type of the attack.
2024 * @return Whether the attack will chop off a head.
2026 bool melee_attack::attack_chops_heads(int dam, int dam_type, int wpn_brand)
2028 // hydras and hydra-like things only.
2029 if (!actor_can_lose_heads(defender))
2032 // Monster attackers+defenders have only a 25% chance of making the
2033 // chop-check to prevent runaway head inflation.
2034 // XXX: Tentatively making an exception for spectral weapons
2035 const bool player_spec_weap = attacker->is_monster()
2036 && attacker->type == MONS_SPECTRAL_WEAPON
2037 && attacker->as_monster()->summoner
2039 if (attacker->is_monster() && defender->is_monster()
2040 && !player_spec_weap && !one_chance_in(4))
2045 // Only cutting implements.
2046 if (dam_type != DVORP_SLICING && dam_type != DVORP_CHOPPING
2047 && dam_type != DVORP_CLAWING)
2052 // Small claws are not big enough.
2053 if (dam_type == DVORP_CLAWING && attacker->has_claws() < 3)
2056 // you need to have done at least some damage.
2060 // usually at least 4 damage, unless you are an unlucky vorpal user.
2061 if (dam < 4 && wpn_brand != SPWPN_VORPAL && coinflip())
2069 * Decapitate the (hydra or hydra-like) defender!
2071 * @param dam_type The vorpal_damage_type of the attack.
2073 void melee_attack::decapitate(int dam_type)
2075 const char *verb = nullptr;
2077 if (dam_type == DVORP_CLAWING)
2079 static const char *claw_verbs[] = { "rip", "tear", "claw" };
2080 verb = RANDOM_ELEMENT(claw_verbs);
2084 static const char *slice_verbs[] =
2086 "slice", "lop", "chop", "hack"
2088 verb = RANDOM_ELEMENT(slice_verbs);
2091 int heads = defender->heads();
2092 if (heads == 1) // will be zero afterwards
2094 if (defender_visible)
2096 mprf("%s %s %s last head off!",
2097 atk_name(DESC_THE).c_str(),
2098 attacker->conj_verb(verb).c_str(),
2099 apostrophise(defender_name(true)).c_str());
2103 if (defender->is_player())
2109 if (!defender->is_summoned())
2111 bleed_onto_floor(defender->pos(), defender->type,
2112 defender->as_monster()->hit_points, true);
2115 defender->hurt(attacker, INSTANT_DEATH);
2120 if (defender_visible)
2122 mprf("%s %s one of %s heads off!",
2123 atk_name(DESC_THE).c_str(),
2124 attacker->conj_verb(verb).c_str(),
2125 apostrophise(defender_name(true)).c_str());
2128 if (defender->is_player())
2129 set_hydra_form_heads(heads - 1);
2131 defender->as_monster()->num_heads--;
2135 * Apply passive retaliation damage from hitting acid monsters.
2137 void melee_attack::attacker_sustain_passive_damage()
2139 // If the defender has been cleaned up, it's too late for anything.
2140 if (!defender->alive())
2143 if (!mons_class_flag(defender->type, M_ACID_SPLASH))
2146 if (attacker->res_acid() >= 3)
2149 const int acid_strength = resist_adjust_damage(attacker, BEAM_ACID, 5);
2151 const item_def *weap = weapon ? weapon : attacker->slot_item(EQ_GLOVES);
2153 // Spectral weapons can't be corroded (but can take acid damage).
2154 const bool avatar = attacker->is_monster()
2155 && mons_is_avatar(attacker->as_monster()->type);
2157 if (weap && !avatar)
2159 if (x_chance_in_y(acid_strength + 1, 30))
2160 attacker->corrode_equipment();
2164 if (attacker->is_player())
2165 mpr(you.hands_act("burn", "!"));
2168 simple_monster_message(attacker->as_monster(),
2169 " is burned by acid!");
2171 attacker->hurt(defender, roll_dice(1, acid_strength), BEAM_ACID,
2172 KILLED_BY_ACID, "", "", false);
2176 int melee_attack::staff_damage(skill_type skill)
2178 if (x_chance_in_y(attacker->skill(SK_EVOCATIONS, 200)
2179 + attacker->skill(skill, 100), 3000))
2181 return random2((attacker->skill(skill, 100)
2182 + attacker->skill(SK_EVOCATIONS, 50)) / 80);
2187 void melee_attack::apply_staff_damage()
2192 if (player_mutation_level(MUT_NO_ARTIFICE))
2195 if (weapon->base_type != OBJ_STAVES)
2198 switch (weapon->sub_type)
2202 resist_adjust_damage(defender,
2204 staff_damage(SK_AIR_MAGIC));
2208 special_damage_message =
2209 make_stringf("%s %s electrocuted!",
2210 defender->name(DESC_THE).c_str(),
2211 defender->conj_verb("are").c_str());
2212 special_damage_flavour = BEAM_ELECTRICITY;
2219 resist_adjust_damage(defender,
2221 staff_damage(SK_ICE_MAGIC));
2225 special_damage_message =
2228 attacker->name(DESC_THE).c_str(),
2229 attacker->is_player() ? "" : "s",
2230 defender->name(DESC_THE).c_str());
2231 special_damage_flavour = BEAM_COLD;
2236 special_damage = staff_damage(SK_EARTH_MAGIC);
2237 special_damage = apply_defender_ac(special_damage);
2239 if (special_damage > 0)
2241 special_damage_message =
2244 attacker->name(DESC_THE).c_str(),
2245 attacker->is_player() ? "" : "es",
2246 defender->name(DESC_THE).c_str());
2252 resist_adjust_damage(defender,
2254 staff_damage(SK_FIRE_MAGIC));
2258 special_damage_message =
2261 attacker->name(DESC_THE).c_str(),
2262 attacker->is_player() ? "" : "s",
2263 defender->name(DESC_THE).c_str());
2264 special_damage_flavour = BEAM_FIRE;
2270 if (random2(300) >= attacker->skill(SK_EVOCATIONS, 20) + attacker->skill(SK_POISON_MAGIC, 10))
2273 // Base chance at 50% -- like mundane weapons.
2274 if (x_chance_in_y(80 + attacker->skill(SK_POISON_MAGIC, 10), 160))
2275 defender->poison(attacker, 2);
2280 if (defender->res_negative_energy())
2283 special_damage = staff_damage(SK_NECROMANCY);
2287 special_damage_message =
2289 "%s convulse%s in agony!",
2290 defender->name(DESC_THE).c_str(),
2291 defender->is_player() ? "" : "s");
2293 attacker->god_conduct(DID_NECROMANCY, 4);
2297 case STAFF_SUMMONING:
2299 case STAFF_CONJURATION:
2300 #if TAG_MAJOR_VERSION == 34
2301 case STAFF_ENCHANTMENT:
2304 case STAFF_WIZARDRY:
2308 die("Invalid staff type: %d", weapon->sub_type);
2313 * Calculate the to-hit for an attacker
2315 * @param random If false, calculate average to-hit deterministically.
2317 int melee_attack::calc_to_hit(bool random)
2319 int mhit = attack::calc_to_hit(random);
2321 if (attacker->is_player() && !weapon)
2323 // Just trying to touch is easier than trying to damage.
2324 if (you.duration[DUR_CONFUSING_TOUCH])
2325 mhit += maybe_random2(you.dex(), random);
2327 // TODO: Review this later (transformations getting extra hit
2328 // almost across the board seems bad) - Cryp71c
2329 mhit += maybe_random2(get_form()->unarmed_hit_bonus, random);
2335 void melee_attack::player_stab_check()
2337 attack::player_stab_check();
2341 * Can we get a good stab with this weapon?
2343 bool melee_attack::player_good_stab()
2345 return wpn_skill == SK_SHORT_BLADES
2346 || player_mutation_level(MUT_PAWS)
2347 || player_equip_unrand(UNRAND_BOOTS_ASSASSIN)
2348 && (!weapon || is_melee_weapon(*weapon));
2351 bool melee_attack::attack_ignores_shield(bool verbose)
2356 /* Select the attack verb for attacker
2358 * If klown, select randomly from klown_attack, otherwise check for any special
2359 * case attack verbs (tentacles or door/fountain-mimics) and if all else fails,
2360 * select an attack verb from attack_types based on the ENUM value of attk_type.
2362 * Returns (attack_verb)
2364 string melee_attack::mons_attack_verb()
2366 static const char *klown_attack[] =
2390 if (attacker->type == MONS_KILLER_KLOWN && attk_type == AT_HIT)
2391 return RANDOM_ELEMENT(klown_attack);
2393 //XXX: then why give them it in the first place?
2394 if (attk_type == AT_TENTACLE_SLAP && mons_is_tentacle(attacker->type))
2397 static const char *attack_types[] =
2399 "hit", // including weapon attacks
2404 "release spores at",
2419 #if TAG_MAJOR_VERSION == 34
2426 COMPILE_CHECK(ARRAYSZ(attack_types) == AT_LAST_REAL_ATTACK);
2428 const int verb_index = attk_type - AT_FIRST_ATTACK;
2429 ASSERT(verb_index < (int)ARRAYSZ(attack_types));
2430 return attack_types[verb_index];
2433 string melee_attack::mons_attack_desc()
2435 if (!you.can_see(attacker))
2439 int dist = (attack_position - defender->pos()).abs();
2442 ASSERT(can_reach());
2446 if (weapon && attacker->type != MONS_DANCING_WEAPON && attacker->type != MONS_SPECTRAL_WEAPON)
2447 ret += " with " + weapon->name(DESC_A);
2452 void melee_attack::announce_hit()
2454 if (!needs_message || attk_flavour == AF_CRUSH)
2457 if (attacker->is_monster())
2459 mprf("%s %s %s%s%s%s",
2460 atk_name(DESC_THE).c_str(),
2461 attacker->conj_verb(mons_attack_verb()).c_str(),
2462 defender_name(true).c_str(),
2463 debug_damage_number().c_str(),
2464 mons_attack_desc().c_str(),
2465 attack_strength_punctuation(damage_done).c_str());
2469 if (!verb_degree.empty() && verb_degree[0] != ' '
2470 && verb_degree[0] != ',' && verb_degree[0] != '\'')
2472 verb_degree = " " + verb_degree;
2475 mprf("You %s %s%s%s%s",
2476 attack_verb.c_str(),
2477 defender->name(DESC_THE).c_str(),
2478 verb_degree.c_str(), debug_damage_number().c_str(),
2479 attack_strength_punctuation(damage_done).c_str());
2483 // Returns if the target was actually poisoned by this attack
2484 bool melee_attack::mons_do_poison()
2489 if (attk_flavour == AF_POISON_STRONG)
2491 amount = random_range(attacker->get_hit_dice() * 11 / 3,
2492 attacker->get_hit_dice() * 13 / 2);
2496 amount = random_range(attacker->get_hit_dice() * 2,
2497 attacker->get_hit_dice() * 4);
2500 if (!defender->poison(attacker, amount, force))
2505 mprf("%s poisons %s!",
2506 atk_name(DESC_THE).c_str(),
2507 defender_name(true).c_str());
2510 mprf("%s partially resist%s.",
2511 defender_name(false).c_str(),
2512 defender->is_player() ? "" : "s");
2519 void melee_attack::mons_do_napalm()
2521 if (defender->res_sticky_flame())
2524 if (one_chance_in(20) || (damage_done > 2 && one_chance_in(3)))
2528 mprf("%s %s covered in liquid flames%s",
2529 defender_name(false).c_str(),
2530 defender->conj_verb("are").c_str(),
2531 attack_strength_punctuation(special_damage).c_str());
2534 if (defender->is_player())
2535 napalm_player(random2avg(7, 3) + 1, atk_name(DESC_A));
2539 defender->as_monster(),
2541 min(4, 1 + random2(attacker->get_hit_dice())/2));
2546 void melee_attack::splash_defender_with_acid(int strength)
2548 if (defender->is_player())
2549 mpr("You are splashed with acid!");
2552 special_damage += roll_dice(2, 4);
2553 if (defender_visible)
2554 mprf("%s is splashed with acid.", defender->name(DESC_THE).c_str());
2556 defender->splash_with_acid(attacker, strength);
2559 static void _print_resist_messages(actor* defender, int base_damage,
2562 // check_your_resists is used for the player case to get additional
2563 // effects such as Xom amusement, melting of icy effects, etc.
2564 // mons_adjust_flavoured is used for the monster case to get all of the
2565 // special message handling ("The ice beast melts!") correct.
2566 // XXX: there must be a nicer way to do this, especially because we're
2567 // basically calculating the damage twice in the case where messages
2569 if (defender->is_player())
2570 (void)check_your_resists(base_damage, flavour, "");
2574 beam.flavour = flavour;
2575 (void)mons_adjust_flavoured(defender->as_monster(),
2582 bool melee_attack::mons_attack_effects()
2584 // Monsters attacking themselves don't get attack flavour.
2585 // The message sequences look too weird. Also, stealing
2586 // attacks aren't handled until after the damage msg. Also,
2587 // no attack flavours for dead defenders
2588 if (attacker != defender && defender->alive())
2590 mons_apply_attack_flavour();
2592 if (needs_message && !special_damage_message.empty())
2593 mpr(special_damage_message);
2595 if (special_damage > 0)
2597 inflict_damage(special_damage, special_damage_flavour);
2599 special_damage_message.clear();
2600 special_damage_flavour = BEAM_NONE;
2603 apply_staff_damage();
2605 if (needs_message && !special_damage_message.empty())
2606 mpr(special_damage_message);
2608 if (special_damage > 0
2609 && inflict_damage(special_damage, special_damage_flavour))
2611 defender->expose_to_element(special_damage_flavour, 2);
2615 if (defender->is_player())
2616 practise(EX_MONSTER_WILL_HIT);
2618 // A tentacle may have banished its own parent/sibling and thus itself.
2619 if (!attacker->alive())
2621 if (miscast_target == defender)
2622 do_miscast(); // Will handle a missing defender, too.
2626 // consider_decapitation() returns true if the wound was cauterized or the
2627 // last head was removed. In the former case, we shouldn't apply
2628 // the brand damage (so we return here). If the monster was killed
2629 // by the decapitation, we should stop the rest of the attack, too.
2630 if (consider_decapitation(damage_done,
2631 attacker->damage_type(attack_number)))
2633 return defender->alive();
2636 if (attacker != defender && attk_flavour == AF_TRAMPLE)
2640 special_damage_message.clear();
2641 special_damage_flavour = BEAM_NONE;
2643 // Defender banished. Bail since the defender is still alive in the
2645 if (defender->is_banished())
2651 if (!defender->alive())
2654 return attacker->alive();
2657 // Bail if the monster is attacking itself without a weapon, since
2658 // intrinsic monster attack flavours aren't applied for self-attacks.
2659 if (attacker == defender && !weapon)
2661 if (miscast_target == defender)
2666 if (!defender->alive())
2669 return attacker->alive();
2672 if (miscast_target == defender)
2675 // Miscast explosions may kill the attacker.
2676 if (!attacker->alive())
2679 if (miscast_target == attacker)
2682 // Miscast might have killed the attacker.
2683 if (!attacker->alive())
2689 void melee_attack::mons_apply_attack_flavour()
2691 // Most of this is from BWR 4.1.2.
2692 int base_damage = 0;
2694 attack_flavour flavour = attk_flavour;
2695 if (flavour == AF_CHAOS)
2696 flavour = random_chaos_attack_flavour();
2698 // Note that if damage_done == 0 then this code won't be reached
2699 // unless the flavour is in _flavour_triggers_damageless.
2703 // Just to trigger special melee damage effects for regular attacks
2704 // (e.g. Qazlal's elemental adaptation).
2705 defender->expose_to_element(BEAM_MISSILE, 2);
2709 if (one_chance_in(4))
2711 defender->malmutate(you.can_see(attacker) ?
2712 apostrophise(attacker->name(DESC_PLAIN)) + " mutagenic touch" :
2718 case AF_POISON_STRONG:
2719 if (one_chance_in(3))
2724 if (one_chance_in(20) || (damage_done > 2 && one_chance_in(3)))
2725 rot_defender(damage_done > 5 ? 2 : 1);
2729 base_damage = attacker->get_hit_dice()
2730 + random2(attacker->get_hit_dice());
2732 resist_adjust_damage(defender,
2735 special_damage_flavour = BEAM_FIRE;
2737 if (needs_message && base_damage)
2739 mprf("%s %s engulfed in flames%s",
2740 defender_name(false).c_str(),
2741 defender->conj_verb("are").c_str(),
2742 attack_strength_punctuation(special_damage).c_str());
2744 _print_resist_messages(defender, base_damage, BEAM_FIRE);
2747 defender->expose_to_element(BEAM_FIRE, 2);
2751 base_damage = attacker->get_hit_dice()
2752 + random2(2 * attacker->get_hit_dice());
2754 resist_adjust_damage(defender,
2757 special_damage_flavour = BEAM_COLD;
2759 if (needs_message && base_damage)
2762 atk_name(DESC_THE).c_str(),
2763 attacker->conj_verb("freeze").c_str(),
2764 defender_name(true).c_str(),
2765 attack_strength_punctuation(special_damage).c_str());
2767 _print_resist_messages(defender, base_damage, BEAM_COLD);
2770 defender->expose_to_element(BEAM_COLD, 2);
2774 base_damage = attacker->get_hit_dice()
2775 + random2(attacker->get_hit_dice() / 2);
2778 resist_adjust_damage(defender,
2781 special_damage_flavour = BEAM_ELECTRICITY;
2783 if (needs_message && base_damage)
2786 atk_name(DESC_THE).c_str(),
2787 attacker->conj_verb("shock").c_str(),
2788 defender_name(true).c_str(),
2789 attack_strength_punctuation(special_damage).c_str());
2791 _print_resist_messages(defender, base_damage, BEAM_ELECTRICITY);
2794 dprf(DIAG_COMBAT, "Shock damage: %d", special_damage);
2795 defender->expose_to_element(BEAM_ELECTRICITY, 2);
2798 // Combines drain speed and vampiric.
2800 if (x_chance_in_y(3, 5))
2801 drain_defender_speed();
2803 // deliberate fall-through
2805 // Only may bite non-vampiric monsters (or player) capable of bleeding.
2806 if (!defender->can_bleed())
2809 // Disallow draining of summoned monsters since they can't bleed.
2810 // XXX: Is this too harsh?
2811 if (defender->is_summoned())
2814 if (defender->res_negative_energy())
2817 if (defender->stat_hp() < defender->stat_maxhp())
2819 if (attacker->heal(1 + random2(damage_done)) && needs_message)
2821 mprf("%s %s strength from %s injuries!",
2822 atk_name(DESC_THE).c_str(),
2823 attacker->conj_verb("draw").c_str(),
2824 def_name(DESC_ITS).c_str());
2832 if (one_chance_in(20) || one_chance_in(3))
2834 stat_type drained_stat = (flavour == AF_DRAIN_STR ? STAT_STR :
2835 flavour == AF_DRAIN_INT ? STAT_INT
2837 defender->drain_stat(drained_stat, 1);
2842 if (defender->holiness() == MH_UNDEAD)
2845 defender->make_hungry(you.hunger / 4, false);
2849 // blinking can kill, delay the call
2850 if (one_chance_in(3))
2851 blink_fineff::schedule(attacker);
2855 if (attk_type == AT_SPORE)
2857 if (defender->is_unbreathing())
2860 monster *attkmon = attacker->as_monster();
2861 attkmon->set_hit_dice(attkmon->get_experience_level() - 1);
2862 if (attkmon->get_experience_level() <= 0)
2863 attacker->as_monster()->suicide();
2865 if (defender_visible)
2867 mprf("%s %s engulfed in a cloud of spores!",
2868 defender->name(DESC_THE).c_str(),
2869 defender->conj_verb("are").c_str());
2873 if (one_chance_in(10)
2874 || (damage_done > 2 && one_chance_in(3)))
2876 defender->confuse(attacker,
2877 1 + random2(3+attacker->get_hit_dice()));
2882 if (one_chance_in(30) || (damage_done > 5 && coinflip()))
2888 // Only wasps at the moment, so Zin vitalisation
2889 // protects from the paralysis and slow.
2890 if (defender->is_player() && you.duration[DUR_DIVINE_STAMINA] > 0)
2892 mpr("Your divine stamina protects you from poison!");
2896 // doesn't affect poison-immune enemies
2897 if (defender->res_poison() >= 3)
2900 if (attacker->type == MONS_HORNET || one_chance_in(3))
2902 int dmg = random_range(attacker->get_hit_dice() * 3 / 2,
2903 attacker->get_hit_dice() * 5 / 2);
2904 defender->poison(attacker, dmg);
2907 int paralyse_roll = (damage_done > 4 ? 3 : 20);
2908 if (attacker->type == MONS_WASP)
2911 const int flat_bonus = attacker->type == MONS_HORNET ? 1 : 0;
2912 const bool strong_result = one_chance_in(paralyse_roll);
2914 if (strong_result && defender->res_poison() <= 0)
2915 defender->paralyse(attacker, flat_bonus + roll_dice(1, 3));
2916 else if (strong_result || defender->res_poison() <= 0)
2917 defender->slow_down(attacker, flat_bonus + roll_dice(1, 3));
2923 splash_defender_with_acid(3);
2927 if (defender->slot_item(EQ_BODY_ARMOUR))
2928 defender->corrode_equipment(atk_name(DESC_THE).c_str());
2932 distortion_affects_defender();
2936 if (!one_chance_in(3) || !defender->can_go_berserk())
2942 atk_name(DESC_THE).c_str(),
2943 attacker->conj_verb("infuriate").c_str(),
2944 defender_name(true).c_str());
2947 defender->go_berserk(false);
2950 case AF_STICKY_FLAME:
2955 chaos_affects_defender();
2959 // Ignore monsters, for now.
2960 if (!defender->is_player())
2963 attacker->as_monster()->steal_item_from_player();
2967 if (defender->holy_wrath_susceptible())
2968 special_damage = attk_damage * 0.75;
2970 if (needs_message && special_damage)
2973 atk_name(DESC_THE).c_str(),
2974 attacker->conj_verb("sear").c_str(),
2975 defender_name(true).c_str(),
2976 attack_strength_punctuation(special_damage).c_str());
2982 antimagic_affects_defender(attacker->get_hit_dice() * 12);
2984 if (mons_genus(attacker->type) == MONS_VINE_STALKER
2985 && attacker->is_monster())
2987 const bool spell_user = defender->antimagic_susceptible();
2989 if (you.can_see(attacker) || you.can_see(defender))
2991 mprf("%s drains %s %s.",
2992 attacker->name(DESC_THE).c_str(),
2993 defender->pronoun(PRONOUN_POSSESSIVE).c_str(),
2994 spell_user ? "magic" : "power");
2997 monster* vine = attacker->as_monster();
2998 if (vine->has_ench(ENCH_ANTIMAGIC)
2999 && (defender->is_player()
3000 || (!defender->as_monster()->is_summoned()
3001 && !mons_is_firewood(defender->as_monster()))))
3003 mon_enchant me = vine->get_ench(ENCH_ANTIMAGIC);
3004 vine->lose_ench_duration(me, random2(damage_done) + 1);
3005 simple_monster_message(attacker->as_monster(),
3007 ? " looks very invigorated."
3008 : " looks invigorated.");
3014 pain_affects_defender();
3018 if (one_chance_in(3))
3026 atk_name(DESC_THE).c_str(),
3027 attacker->conj_verb("grab").c_str(),
3028 defender_name(true).c_str());
3030 attacker->start_constricting(*defender);
3031 // if you got grabbed, interrupt stair climb and passwall
3032 if (defender->is_player())
3037 if (x_chance_in_y(2, 3) && attacker->can_constrict(defender))
3039 if (defender->is_player() && !you.duration[DUR_WATER_HOLD]
3040 && !you.duration[DUR_WATER_HOLD_IMMUNITY])
3042 you.duration[DUR_WATER_HOLD] = 10;
3043 you.props["water_holder"].get_int() = attacker->as_monster()->mid;
3045 else if (defender->is_monster()
3046 && !defender->as_monster()->has_ench(ENCH_WATER_HOLD))
3048 defender->as_monster()->add_ench(mon_enchant(ENCH_WATER_HOLD, 1,
3052 return; //Didn't apply effect; no message
3056 mprf("%s %s %s in water!",
3057 atk_name(DESC_THE).c_str(),
3058 attacker->conj_verb("engulf").c_str(),
3059 defender_name(true).c_str());
3063 defender->expose_to_element(BEAM_WATER, 0);
3067 if (attacker->type == MONS_FIRE_VORTEX)
3068 attacker->as_monster()->suicide(-10);
3070 special_damage = (attacker->get_hit_dice() * 3 / 2
3071 + random2(attacker->get_hit_dice()));
3072 special_damage = defender->apply_ac(special_damage, 0, AC_HALF);
3073 special_damage = resist_adjust_damage(defender,
3077 if (needs_message && special_damage)
3080 atk_name(DESC_THE).c_str(),
3081 attacker->conj_verb("burn").c_str(),
3082 defender_name(true).c_str());
3084 _print_resist_messages(defender, special_damage, BEAM_FIRE);
3087 defender->expose_to_element(BEAM_FIRE, 2);
3090 case AF_DRAIN_SPEED:
3091 if (x_chance_in_y(3, 5))
3092 drain_defender_speed();
3096 if (one_chance_in(3))
3098 bool visible_effect = false;
3099 if (defender->is_player())
3101 if (!you.duration[DUR_LOWERED_MR])
3102 visible_effect = true;
3103 you.increase_duration(DUR_LOWERED_MR, 20 + random2(20), 40);
3107 if (!defender->as_monster()->has_ench(ENCH_LOWERED_MR))
3108 visible_effect = true;
3109 mon_enchant lowered_mr(ENCH_LOWERED_MR, 1, attacker,
3110 (20 + random2(20)) * BASELINE_DELAY);
3111 defender->as_monster()->add_ench(lowered_mr);
3114 if (needs_message && visible_effect)
3116 mprf("%s magical defenses are stripped away!",
3117 def_name(DESC_ITS).c_str());
3122 case AF_WEAKNESS_POISON:
3123 if (coinflip() && mons_do_poison())
3124 defender->weaken(attacker, 12);
3128 attacker->as_monster()->del_ench(ENCH_INVIS, true);
3132 if (attacker->type == MONS_DROWNED_SOUL)
3133 attacker->as_monster()->suicide(-1000);
3135 if (defender->res_water_drowning() <= 0)
3137 special_damage = attacker->get_hit_dice() * 3 / 4
3138 + random2(attacker->get_hit_dice() * 3 / 4);
3139 special_damage_flavour = BEAM_WATER;
3140 kill_type = KILLED_BY_WATER;
3145 atk_name(DESC_THE).c_str(),
3146 attacker->conj_verb("drown").c_str(),
3147 defender_name(true).c_str(),
3148 attack_strength_punctuation(special_damage).c_str());
3154 base_damage = attacker->get_hit_dice()
3155 + random2(attacker->get_hit_dice());
3157 resist_adjust_damage(defender,
3160 special_damage_flavour = BEAM_FIRE;
3166 mprf("The air around %s erupts in flames!",
3167 defender_name(false).c_str());
3169 for (adjacent_iterator ai(defender->pos()); ai; ++ai)
3171 if (!cell_is_solid(*ai)
3172 && (env.cgrid(*ai) == EMPTY_CLOUD
3173 || env.cloud[env.cgrid(*ai)].type == CLOUD_FIRE))
3175 // Don't place clouds under non-resistant allies
3176 const actor* act = actor_at(*ai);
3177 if (act && mons_aligned(attacker, act)
3178 && act->res_fire() < 1)
3183 place_cloud(CLOUD_FIRE, *ai, 4 + random2(9), attacker);
3187 _print_resist_messages(defender, base_damage, BEAM_FIRE);
3191 defender->expose_to_element(BEAM_FIRE, 2);
3196 void melee_attack::do_passive_freeze()
3198 if (you.mutation[MUT_PASSIVE_FREEZE]
3199 && attacker->alive()
3200 && adjacent(you.pos(), attacker->as_monster()->pos()))
3203 beam.flavour = BEAM_COLD;
3204 beam.thrower = KILL_YOU;
3206 monster* mon = attacker->as_monster();
3208 const int orig_hurted = random2(11);
3209 int hurted = mons_adjust_flavoured(mon, beam, orig_hurted);
3214 simple_monster_message(mon, " is very cold.");
3216 #ifndef USE_TILE_LOCAL
3217 flash_monster_colour(mon, LIGHTBLUE, 200);
3220 mon->hurt(&you, hurted);
3224 mon->expose_to_element(BEAM_COLD, orig_hurted);
3230 #if TAG_MAJOR_VERSION == 34
3231 void melee_attack::do_passive_heat()
3233 if (you.species == SP_LAVA_ORC && temperature_effect(LORC_PASSIVE_HEAT)
3234 && attacker->alive()
3235 && grid_distance(you.pos(), attacker->as_monster()->pos()) == 1)
3238 beam.flavour = BEAM_FIRE;
3239 beam.thrower = KILL_YOU;
3241 monster* mon = attacker->as_monster();
3243 const int orig_hurted = random2(5);
3244 int hurted = mons_adjust_flavoured(mon, beam, orig_hurted);
3249 simple_monster_message(mon, " is singed by your heat.");
3252 flash_monster_colour(mon, LIGHTRED, 200);
3255 mon->hurt(&you, hurted);
3259 mon->expose_to_element(BEAM_FIRE, orig_hurted);
3266 void melee_attack::mons_do_eyeball_confusion()
3268 if (you.mutation[MUT_EYEBALLS]
3269 && attacker->alive()
3270 && adjacent(you.pos(), attacker->as_monster()->pos())
3271 && x_chance_in_y(player_mutation_level(MUT_EYEBALLS), 20))
3273 const int ench_pow = player_mutation_level(MUT_EYEBALLS) * 30;
3274 monster* mon = attacker->as_monster();
3276 if (mon->check_res_magic(ench_pow) <= 0)
3278 mprf("The eyeballs on your body gaze at %s.",
3279 mon->name(DESC_THE).c_str());
3281 if (!mon->check_clarity(false))
3283 mon->add_ench(mon_enchant(ENCH_CONFUSION, 0, &you,
3284 30 + random2(100)));
3290 void melee_attack::do_spines()
3292 // Monsters only get struck on their first attack per round
3293 if (attacker->is_monster() && effective_attack_number > 0)
3296 if (defender->is_player())
3298 const int mut = (you.form == TRAN_PORCUPINE) ? 3
3299 : player_mutation_level(MUT_SPINY);
3301 if (mut && attacker->alive()
3302 && x_chance_in_y(2, (13 - (mut * 2)) * 3))
3304 int dmg = roll_dice(2 + div_rand_round(mut - 1, 2), 5);
3305 int hurt = attacker->apply_ac(dmg);
3307 dprf(DIAG_COMBAT, "Spiny: dmg = %d hurt = %d", dmg, hurt);
3312 simple_monster_message(attacker->as_monster(),
3313 " is struck by your spines.");
3315 attacker->hurt(&you, hurt);
3318 else if (defender->as_monster()->is_spiny())
3320 // Thorn hunters can attack their own brambles without injury
3321 if (defender->type == MONS_BRIAR_PATCH
3322 && attacker->type == MONS_THORN_HUNTER
3323 // Dithmenos' shadow can't take damage, don't spam.
3324 || attacker->type == MONS_PLAYER_SHADOW)
3329 if (attacker->alive() && one_chance_in(3))
3331 int dmg = roll_dice(5, 4);
3332 int hurt = attacker->apply_ac(dmg);
3333 dprf(DIAG_COMBAT, "Spiny: dmg = %d hurt = %d", dmg, hurt);
3337 if (you.can_see(defender) || attacker->is_player())
3339 mprf("%s %s struck by %s %s.", attacker->name(DESC_THE).c_str(),
3340 attacker->conj_verb("are").c_str(),
3341 defender->name(DESC_ITS).c_str(),
3342 defender->type == MONS_BRIAR_PATCH ? "thorns"
3345 attacker->hurt(defender, hurt, BEAM_MISSILE, KILLED_BY_SPINES);
3350 void melee_attack::emit_foul_stench()
3352 monster* mon = attacker->as_monster();
3354 if (you.mutation[MUT_FOUL_STENCH]
3355 && attacker->alive()
3356 && adjacent(you.pos(), mon->pos()))
3358 const int mut = player_mutation_level(MUT_FOUL_STENCH);
3360 if (one_chance_in(3))
3361 mon->sicken(50 + random2(100));
3363 if (damage_done > 4 && x_chance_in_y(mut, 5)
3364 && !cell_is_solid(mon->pos())
3365 && env.cgrid(mon->pos()) == EMPTY_CLOUD)
3367 mpr("You emit a cloud of foul miasma!");
3368 place_cloud(CLOUD_MIASMA, mon->pos(), 5 + random2(6), &you);
3373 void melee_attack::do_minotaur_retaliation()
3375 if (defender->cannot_act()
3376 || defender->confused()
3377 || !attacker->alive()
3378 || defender->is_player() && you.duration[DUR_LIFESAVING])
3383 if (!defender->is_player())
3385 // monsters have no STR or DEX
3386 if (x_chance_in_y(2, 5))
3388 int hurt = attacker->apply_ac(random2(21));
3389 if (you.see_cell(defender->pos()))
3391 const string defname = defender->name(DESC_THE);
3392 mprf("%s furiously retaliates!", defname.c_str());
3395 mprf("%s headbutts %s, but does no damage.", defname.c_str(),
3396 attacker->name(DESC_THE).c_str());
3400 mprf("%s headbutts %s%s", defname.c_str(),
3401 attacker->name(DESC_THE).c_str(),
3402 attack_strength_punctuation(hurt).c_str());
3407 attacker->hurt(defender, hurt, BEAM_MISSILE,
3408 KILLED_BY_HEADBUTT);
3414 if (!form_keeps_mutations())
3416 // You are in a non-minotaur form.
3419 // This will usually be 2, but could be 3 if the player mutated more.
3420 const int mut = player_mutation_level(MUT_HORNS);
3422 if (5 * you.strength() + 7 * you.dex() > random2(600))
3424 // Use the same damage formula as a regular headbutt.
3425 int dmg = 5 + mut * 3;
3426 dmg = player_aux_stat_modify_damage(dmg);
3428 dmg = player_apply_fighting_skill(dmg, true);
3429 dmg = player_apply_misc_modifiers(dmg);
3430 dmg = player_apply_slaying_bonuses(dmg, true);
3431 dmg = player_apply_final_multipliers(dmg);
3432 int hurt = attacker->apply_ac(dmg);
3434 mpr("You furiously retaliate!");
3435 dprf(DIAG_COMBAT, "Retaliation: dmg = %d hurt = %d", dmg, hurt);
3438 mprf("You headbutt %s, but do no damage.",
3439 attacker->name(DESC_THE).c_str());
3444 mprf("You headbutt %s%s",
3445 attacker->name(DESC_THE).c_str(),
3446 attack_strength_punctuation(hurt).c_str());
3447 attacker->hurt(&you, hurt);
3452 bool melee_attack::do_knockback(bool trample)
3454 if (defender->is_stationary())
3455 return false; // don't even print a message
3457 const int size_diff =
3458 attacker->body_size(PSIZE_BODY) - defender->body_size(PSIZE_BODY);
3459 const coord_def old_pos = defender->pos();
3460 const coord_def new_pos = old_pos + old_pos - attack_position;
3462 if (!x_chance_in_y(size_diff + 3, 6)
3463 // need a valid tile
3464 || !defender->is_habitable_feat(grd(new_pos))
3465 // don't trample into a monster - or do we want to cause a chain
3467 || actor_at(new_pos)
3468 // Prevent trample/drown combo when flight is expiring