Add two new Ru sacrifices: resistance and eye
[crawl.git] / crawl-ref / source / melee_attack.cc
1 /**
2  * @file
3  * @brief melee_attack class and associated melee_attack methods
4  */
5
6 #include "AppHdr.h"
7
8 #include "melee_attack.h"
9
10 #include <algorithm>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14
15 #include "areas.h"
16 #include "art-enum.h"
17 #include "attitude-change.h"
18 #include "bloodspatter.h"
19 #include "butcher.h"
20 #include "cloud.h"
21 #include "coordit.h"
22 #include "delay.h"
23 #include "english.h"
24 #include "env.h"
25 #include "exercise.h"
26 #include "fineff.h"
27 #include "food.h"
28 #include "godconduct.h"
29 #include "goditem.h"
30 #include "hints.h"
31 #include "itemprop.h"
32 #include "mapdef.h"
33 #include "message.h"
34 #include "misc.h"
35 #include "mon-behv.h"
36 #include "mon-poly.h"
37 #include "mon-tentacle.h"
38 #include "religion.h"
39 #include "shout.h"
40 #include "spl-summoning.h"
41 #include "state.h"
42 #include "stringutil.h"
43 #include "target.h"
44 #include "terrain.h"
45 #include "transform.h"
46 #include "traps.h"
47 #include "unwind.h"
48 #include "view.h"
49 #include "xom.h"
50
51 #ifdef NOTE_DEBUG_CHAOS_BRAND
52     #define NOTE_DEBUG_CHAOS_EFFECTS
53 #endif
54
55 #ifdef NOTE_DEBUG_CHAOS_EFFECTS
56     #include "notes.h"
57 #endif
58
59 /*
60  **************************************************
61  *             BEGIN PUBLIC FUNCTIONS             *
62  **************************************************
63 */
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
68     ::attack(attk, defn),
69
70     attack_number(attack_num), effective_attack_number(effective_attack_num),
71     cleaving(is_cleaving)
72 {
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;
78
79     attack_position = attacker->pos();
80 }
81
82 bool melee_attack::can_reach()
83 {
84     return attk_type == AT_HIT && weapon && weapon_reach(*weapon) > REACH_NONE
85            || attk_flavour == AF_REACH
86            || attk_type == AT_REACH_STING;
87 }
88
89 bool melee_attack::handle_phase_attempted()
90 {
91     // Skip invalid and dummy attacks.
92     if (defender && (!adjacent(attack_position, defender->pos())
93                      && !can_reach())
94         || attk_type == AT_CONSTRICT
95            && (!attacker->can_constrict(defender)
96                || attacker->is_monster() && attacker->mid == MID_PLAYER))
97     {
98         --effective_attack_number;
99
100         return false;
101     }
102
103     if (attacker->is_player() && defender && defender->is_monster())
104     {
105         if (weapon && is_unrandom_artefact(*weapon, UNRAND_DEVASTATOR))
106         {
107             const char* verb = "attack";
108             string junk1, junk2;
109             bool junk3 = false;
110             if (defender)
111             {
112                 verb = (bad_attack(defender->as_monster(),
113                                    junk1, junk2, junk3)
114                         ? "attack" : "attack near");
115             }
116
117             targetter_smite hitfunc(attacker, 1, 1, 1, false);
118             hitfunc.set_aim(defender->pos());
119
120             if (stop_attack_prompt(hitfunc, verb))
121             {
122                 cancel_attack = true;
123                 return false;
124             }
125         }
126         else if (!cleave_targets.empty())
127         {
128             targetter_cleave hitfunc(attacker, defender->pos());
129             if (stop_attack_prompt(hitfunc, "attack"))
130             {
131                 cancel_attack = true;
132                 return false;
133             }
134         }
135         else if (stop_attack_prompt(defender->as_monster(), false,
136                                     attack_position))
137         {
138             cancel_attack = true;
139             return false;
140         }
141     }
142
143     if (attacker->is_player())
144     {
145         // Set delay now that we know the attack won't be cancelled.
146         you.time_taken = you.attack_delay(weapon);
147         if (weapon)
148         {
149             if (weapon->base_type == OBJ_WEAPONS)
150                 if (is_unrandom_artefact(*weapon)
151                     && get_unrand_entry(weapon->special)->type_name)
152                 {
153                     count_action(CACT_MELEE, weapon->special);
154                 }
155                 else
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);
161         }
162         else
163             count_action(CACT_MELEE, -1);
164     }
165     else
166     {
167         // Only the first attack costs any energy.
168         if (!effective_attack_number)
169         {
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);
173             ASSERT(energy > 0);
174             ASSERT(delay > 0);
175
176             attacker->as_monster()->speed_increment
177                 -= div_rand_round(energy * delay, 10);
178         }
179
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)
183             return false;
184     }
185
186     if (attacker != defender)
187     {
188         // Allow setting of your allies' target, etc.
189         attacker->attacking(defender);
190
191         check_autoberserk();
192     }
193
194     // The attacker loses nutrition.
195     attacker->make_hungry(3, true);
196
197     // Xom thinks fumbles are funny...
198     if (attacker->fumbles_attack())
199     {
200         // ... and thinks fumbling when trying to hit yourself is just
201         // hilarious.
202         xom_is_stimulated(attacker == defender ? 200 : 10);
203         return false;
204     }
205     // Non-fumbled self-attacks due to confusion are still pretty funny, though.
206     else if (attacker == defender && attacker->confused())
207     {
208         // And is still hilarious if it's the player.
209         xom_is_stimulated(attacker->is_player() ? 200 : 100);
210     }
211
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())
214         && one_chance_in(3))
215     {
216         mprf("You attempt to attack %s, but flinch away in fear!",
217              defender->name(DESC_THE).c_str());
218         return false;
219     }
220
221     if (attk_flavour == AF_SHADOWSTAB && defender && !defender->can_see(attacker))
222     {
223         if (you.see_cell(attack_position))
224         {
225             mprf("%s strikes at %s from the darkness!",
226                  attacker->name(DESC_THE, true).c_str(),
227                  defender->name(DESC_THE).c_str());
228         }
229         to_hit = AUTOMATIC_HIT;
230         needs_message = false;
231     }
232     else if (attacker->is_monster()
233              && attacker->type == MONS_DROWNED_SOUL)
234     {
235         to_hit = AUTOMATIC_HIT;
236     }
237
238     attack_occurred = true;
239
240     // Check for player practicing dodging
241     if (one_chance_in(3) && defender->is_player())
242         practise(EX_MONSTER_MAY_HIT);
243
244     return true;
245 }
246
247 bool melee_attack::handle_phase_dodged()
248 {
249     did_hit = false;
250
251     const int ev = defender->evasion(EV_IGNORE_NONE, attacker);
252     const int ev_nophase = defender->evasion(EV_IGNORE_PHASESHIFT, attacker);
253
254     if (ev_margin + (ev - ev_nophase) > 0)
255     {
256         if (needs_message && defender_visible)
257         {
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());
265         }
266     }
267     else
268     {
269         if (needs_message)
270         {
271             // TODO: Unify these, placed player_warn_miss here so I can remove
272             // player_attack
273             if (attacker->is_player())
274                 player_warn_miss();
275             else
276             {
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());
282             }
283         }
284     }
285
286     if (attacker != defender && adjacent(defender->pos(), attack_position))
287     {
288         if (attacker->alive()
289             && (defender->is_player() ?
290                    you.species == SP_MINOTAUR :
291                    mons_species(mons_base_type(defender->as_monster()))
292                       == MONS_MINOTAUR)
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)
297         {
298             do_minotaur_retaliation();
299         }
300
301         // Retaliations can kill!
302         if (!attacker->alive())
303             return false;
304     }
305
306     return true;
307 }
308
309 static bool _flavour_triggers_damageless(attack_flavour flavour)
310 {
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;
318 }
319
320 void melee_attack::apply_black_mark_effects()
321 {
322     // Slightly weaker and less reliable effects for players.
323     if (attacker->is_player()
324         && you.mutation[MUT_BLACK_MARK]
325         && one_chance_in(5))
326     {
327         if (you.hp < you.hp_max
328             && !you.duration[DUR_DEATHS_DOOR]
329             && !defender->as_monster()->is_summoned())
330         {
331             mpr("You feel better.");
332             attacker->heal(random2(damage_done));
333         }
334
335         if (!defender->alive())
336             return;
337
338         switch (random2(3))
339         {
340             case 0:
341                 antimagic_affects_defender(damage_done * 8);
342                 break;
343             case 1:
344                 defender->weaken(attacker, 2);
345                 break;
346             case 2:
347                 defender->drain_exp(attacker);
348                 break;
349         }
350     }
351     else if (attacker->is_monster()
352              && attacker->as_monster()->has_ench(ENCH_BLACK_MARK))
353     {
354         monster* mon = attacker->as_monster();
355
356         if (mon->heal(random2avg(damage_done, 2)))
357             simple_monster_message(mon, " is healed.");
358
359         if (!defender->alive())
360             return;
361
362         switch (random2(3))
363         {
364             case 0:
365                 antimagic_affects_defender(damage_done * 8);
366                 break;
367             case 1:
368                 defender->slow_down(attacker, 5 + random2(7));
369                 break;
370             case 2:
371                 defender->drain_exp(attacker, false, 10);
372                 break;
373         }
374     }
375 }
376
377 /* An attack has been determined to have hit something
378  *
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
382  *
383  * Returns true if combat should continue, false if it should end here.
384  */
385 bool melee_attack::handle_phase_hit()
386 {
387     did_hit = true;
388     perceived_attack = true;
389     bool hit_woke_orc = false;
390
391     if (attacker->is_player())
392     {
393         if (crawl_state.game_is_hints())
394             Hints.hints_melee_counter++;
395
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())
402         {
403             hit_woke_orc = true;
404         }
405     }
406
407     damage_done = 0;
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())
411         && !cleaving)
412     {
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;
417
418         return false;
419     }
420
421     if (attacker->is_player() && you.duration[DUR_INFUSION])
422     {
423         if (enough_mp(1, true, false))
424         {
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);
429
430             dprf(DIAG_COMBAT, "Infusion: dmg = %d hurt = %d", dmg, hurt);
431
432             if (hurt > 0)
433             {
434                 damage_done = hurt;
435                 dec_mp(1);
436             }
437         }
438     }
439
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();
445
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();
450
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.
453     if (stop_hit)
454     {
455         check_unrand_effects();
456         return false;
457     }
458
459     if (damage_done > 0 || _flavour_triggers_damageless(attk_flavour))
460     {
461         if (!handle_phase_damaged())
462             return false;
463
464         // TODO: Remove this, (placed here to remove player_attack)
465         if (attacker->is_player() && hit_woke_orc)
466         {
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);
470         }
471     }
472     else if (needs_message)
473     {
474         attack_verb = attacker->is_player()
475                       ? attack_verb
476                       : attacker->conj_verb(mons_attack_verb());
477
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(),
481              attack_verb.c_str(),
482              defender_name(true).c_str(),
483              attacker->is_player() ? "do" : "does");
484     }
485
486     // Check for weapon brand & inflict that damage too
487     apply_damage_brand();
488
489     if (check_unrand_effects())
490         return false;
491
492     if (damage_done > 0)
493         apply_black_mark_effects();
494
495     if (attacker->is_player())
496     {
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);
501
502         // [ds] Monster may disappear after behaviour event.
503         if (!defender->alive())
504             return true;
505     }
506     else if (defender->is_player())
507     {
508         // These effects (mutations right now) are only triggered when
509         // the player is hit, each of them will verify their own required
510         // parameters.
511         do_passive_freeze();
512 #if TAG_MAJOR_VERSION == 34
513         do_passive_heat();
514 #endif
515         emit_foul_stench();
516     }
517
518     return true;
519 }
520
521 bool melee_attack::handle_phase_damaged()
522 {
523     bool shroud_broken = false;
524
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))
532     {
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))
536         {
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;
542             else
543                 defender->as_monster()->del_ench(ENCH_SHROUD);
544         }
545         else
546         {
547             if (needs_message)
548             {
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());
553             }
554             did_hit = false;
555             damage_done = 0;
556
557             return false;
558         }
559     }
560
561     if (!attack::handle_phase_damaged())
562         return false;
563
564     if (shroud_broken && needs_message)
565     {
566         mprf(defender->is_player() ? MSGCH_WARN : MSGCH_PLAIN,
567              "%s shroud falls apart!",
568              def_name(DESC_ITS).c_str());
569     }
570
571     return true;
572 }
573
574 bool melee_attack::handle_phase_aux()
575 {
576     if (attacker->is_player())
577     {
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)
582             && !cleaving)
583         {
584             player_aux_unarmed();
585         }
586
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]))
592         {
593             print_wounds(defender->as_monster());
594         }
595     }
596
597     return true;
598 }
599
600 /**
601  * Devour a monster whole!.
602  *
603  * @param defender  The monster in question.
604  */
605 static void _hydra_devour(monster &victim)
606 {
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());
610
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;
616
617     mprf("You %sdevour %s!",
618          filling ? "hungrily " : "",
619          victim.name(DESC_THE).c_str());
620
621     // nutrition (maybe)
622     if (filling)
623     {
624         const int equiv_chunks =
625             1 + random2(max_corpse_chunks(victim.type));
626         lessen_hunger(CHUNK_BASE_NUTRITION * equiv_chunks, false, max_hunger);
627     }
628
629     // healing
630     if (!you.duration[DUR_DEATHS_DOOR])
631     {
632         const int healing = 1 + victim.get_experience_level() * 3 / 4
633                               + random2(victim.get_experience_level() * 3 / 4);
634         you.heal(healing);
635         calc_hp();
636         mpr("You feel better.");
637         dprf("healed for %d (%d hd)", healing, victim.get_experience_level());
638     }
639
640     // and devour the corpse.
641     victim.props[NEVER_CORPSE_KEY] = true;
642 }
643
644 /**
645  * Possibly devour the defender whole.
646  *
647  * @param defender  The defender in question.
648  */
649 static void _hydra_consider_devouring(monster &defender)
650 {
651     ASSERT(!crawl_state.game_is_arena());
652
653     dprf("considering devouring");
654
655     // no unhealthy food
656     if (determine_chunk_effect(mons_corpse_effect(defender.type)) != CE_CLEAN)
657         return;
658
659     dprf("chunk ok");
660
661     // shapeshifters are mutagenic
662     if (defender.is_shapeshifter())
663     {
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());
668         return;
669     }
670
671     dprf("shifter ok");
672
673     // or food that would incur divine penance...
674     if (god_hates_eating(you.religion, defender.type))
675         return;
676
677     dprf("god ok");
678
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)
683     {
684         return;
685     }
686
687     dprf("corpse ok");
688
689     // or monsters as large as you are!
690     if (defender.body_size() >= you.body_size())
691         return;
692
693     dprf("size ok");
694
695     // chow down.
696     _hydra_devour(defender);
697 }
698
699 /**
700  * Handle effects that fire when the defender (the target of the attack) is
701  * killed.
702  *
703  * @return  Not sure; it seems to never be checked & always be true?
704  */
705 bool melee_attack::handle_phase_killed()
706 {
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
710     {
711         _hydra_consider_devouring(*defender->as_monster());
712     }
713
714     return attack::handle_phase_killed();
715 }
716
717 bool melee_attack::handle_phase_end()
718 {
719     if (!cleave_targets.empty())
720     {
721         attack_cleave_targets(*attacker, cleave_targets, attack_number,
722                               effective_attack_number);
723     }
724
725     // Check for passive mutation effects.
726     if (defender->is_player() && defender->alive() && attacker != defender)
727     {
728         mons_do_eyeball_confusion();
729
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();
734
735         if (player_mutation_level(MUT_TENDRILS)
736             && one_chance_in(5)
737             && (random2(you.dex()) > adj_mon_hd
738                 || random2(you.strength()) > adj_mon_hd))
739         {
740             item_def* mons_wpn = mon->disarm();
741             if (mons_wpn)
742             {
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());
746             }
747         }
748     }
749
750     return attack::handle_phase_end();
751 }
752
753 /* Initiate the processing of the attack
754  *
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
758  * themselves).
759  *
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.
764  */
765 bool melee_attack::attack()
766 {
767     if (!cleaving && !handle_phase_attempted())
768         return false;
769
770     if (attacker != defender && attacker->self_destructs())
771         return did_hit = perceived_attack = true;
772
773     if (!cleaving)
774         cleave_setup();
775
776     string dummy;
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()
781                                       : dummy);
782     if (gyre)
783     {
784         if (!cleaving)
785             set_artefact_name(*weapon, "quick blade \"Gyre\"");
786         else
787             set_artefact_name(*weapon, "quick blade \"Gimble\"");
788     }
789
790     // Attacker might have died from effects of cleaving handled prior to this
791     if (!attacker->alive())
792         return false;
793
794     // We might have killed the kraken target by cleaving a tentacle.
795     if (!defender->alive())
796     {
797         handle_phase_killed();
798         handle_phase_end();
799         return attack_occurred;
800     }
801
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
804
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);
810
811     // Stuff for god conduct, this has to remain here for scope reasons.
812     god_conduct_trigger conducts[3];
813     disable_attack_conducts(conducts);
814
815     if (attacker->is_player() && attacker != defender)
816     {
817         set_attack_conducts(conducts, defender->as_monster());
818
819         if (player_under_penance(GOD_ELYVILON)
820             && god_hates_your_god(GOD_ELYVILON)
821             && ev_margin >= 0
822             && one_chance_in(20))
823         {
824             simple_god_message(" blocks your attack.", GOD_ELYVILON);
825             handle_phase_end();
826             return false;
827         }
828         // Check for stab (and set stab_attempt and stab_bonus)
829         player_stab_check();
830         // Make sure we hit if we passed the stab check.
831         if (stab_attempt && stab_bonus > 0)
832         {
833             ev_margin = AUTOMATIC_HIT;
834             shield_blocked = false;
835         }
836     }
837
838     if (shield_blocked)
839         handle_phase_blocked();
840     else
841     {
842         if (attacker != defender && adjacent(defender->pos(), attack_position))
843         {
844             // Check for defender Spines
845             do_spines();
846
847             // Spines can kill!
848             if (!attacker->alive())
849                 return false;
850         }
851
852         if (ev_margin >= 0)
853         {
854             if (attacker != defender && attack_warded_off())
855             {
856                 perceived_attack = true;
857                 handle_phase_end();
858                 return false;
859             }
860
861             bool cont = handle_phase_hit();
862
863             attacker_sustain_passive_damage();
864
865             if (!cont)
866             {
867                 if (!defender->alive())
868                     handle_phase_killed();
869                 handle_phase_end();
870                 return false;
871             }
872         }
873         else
874             handle_phase_dodged();
875     }
876
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()))
882     {
883         remove_sanctuary(true);
884     }
885
886     if (attacker->is_player())
887         do_miscast();
888
889     // don't crash on banishment
890     if (!defender->pos().origin())
891         handle_noise(defender->pos());
892
893     // Noisy weapons.
894     if (attacker->is_player()
895         && weapon
896         && is_artefact(*weapon)
897         && artefact_property(*weapon, ARTP_NOISES))
898     {
899         noisy_equipment();
900     }
901
902     alert_defender();
903
904     if (!defender->alive())
905         handle_phase_killed();
906
907     handle_phase_aux();
908
909     handle_phase_end();
910
911     enable_attack_conducts(conducts);
912
913     return attack_occurred;
914 }
915
916 void melee_attack::check_autoberserk()
917 {
918     if (attacker->is_player())
919     {
920         for (int i = EQ_WEAPON; i < NUM_EQUIP; ++i)
921         {
922             const item_def *item = you.slot_item(static_cast<equipment_type>(i));
923             if (!item)
924                 continue;
925
926             if (!is_artefact(*item))
927                 continue;
928
929             if (x_chance_in_y(artefact_property(*item, ARTP_ANGRY), 100))
930             {
931                 attacker->go_berserk(false);
932                 return;
933             }
934         }
935     }
936     else
937     {
938         for (int i = MSLOT_WEAPON; i <= MSLOT_JEWELLERY; ++i)
939         {
940             const item_def *item =
941                 attacker->as_monster()->mslot_item(static_cast<mon_inv_type>(i));
942             if (!item)
943                 continue;
944
945             if (!is_artefact(*item))
946                 continue;
947
948             if (x_chance_in_y(artefact_property(*item, ARTP_ANGRY), 100))
949             {
950                 attacker->go_berserk(false);
951                 return;
952             }
953         }
954     }
955 }
956
957 bool melee_attack::check_unrand_effects()
958 {
959     if (unrand_entry && unrand_entry->melee_effects && weapon)
960     {
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();
965     }
966
967     return false;
968 }
969
970 class AuxConstrict: public AuxAttackType
971 {
972 public:
973     AuxConstrict()
974     : AuxAttackType(0, "grab") { };
975 };
976
977 class AuxKick: public AuxAttackType
978 {
979 public:
980     AuxKick()
981     : AuxAttackType(-1, "kick") { };
982
983     int get_damage() const
984     {
985         if (you.has_usable_hooves())
986         {
987             // Max hoof damage: 10.
988             return player_mutation_level(MUT_HOOVES) * 5 / 3;
989         }
990
991         if (you.has_usable_talons())
992         {
993             // Max talon damage: 9.
994             return 1 + player_mutation_level(MUT_TALONS);
995         }
996
997         // Max spike damage: 8.
998         // ... yes, apparently tentacle spikes are "kicks".
999         return player_mutation_level(MUT_TENTACLE_SPIKE);
1000     }
1001
1002     string get_verb() const
1003     {
1004         if (you.has_usable_talons())
1005             return "claw";
1006         if (player_mutation_level(MUT_TENTACLE_SPIKE))
1007             return "pierce";
1008         return name;
1009     }
1010
1011     string get_name() const
1012     {
1013         if (player_mutation_level(MUT_TENTACLE_SPIKE))
1014             return "tentacle spike";
1015         return name;
1016     }
1017 };
1018
1019 class AuxHeadbutt: public AuxAttackType
1020 {
1021 public:
1022     AuxHeadbutt()
1023     : AuxAttackType(5, "headbutt") { };
1024
1025     int get_damage() const
1026     {
1027         return damage + player_mutation_level(MUT_HORNS) * 3;
1028     }
1029 };
1030
1031 class AuxPeck: public AuxAttackType
1032 {
1033 public:
1034     AuxPeck()
1035     : AuxAttackType(6, "peck") { };
1036 };
1037
1038 class AuxTailslap: public AuxAttackType
1039 {
1040 public:
1041     AuxTailslap()
1042     : AuxAttackType(6, "tail-slap") { };
1043
1044     int get_damage() const
1045     {
1046         return damage + max(0, player_mutation_level(MUT_STINGER) * 2 - 1);
1047     }
1048
1049     int get_brand() const
1050     {
1051         return player_mutation_level(MUT_STINGER) ? SPWPN_VENOM : SPWPN_NORMAL;
1052     }
1053 };
1054
1055 class AuxPunch: public AuxAttackType
1056 {
1057 public:
1058     AuxPunch()
1059     : AuxAttackType(5, "punch") { };
1060
1061     int get_damage() const
1062     {
1063         const int base_dam = damage + you.skill_rdiv(SK_UNARMED_COMBAT, 1, 2);
1064
1065         if (you.form == TRAN_BLADE_HANDS)
1066             return base_dam + 6;
1067
1068         if (you.has_usable_claws())
1069             return base_dam + roll_dice(you.has_claws(), 3);
1070
1071         return base_dam;
1072     }
1073
1074     string get_name() const
1075     {
1076         if (you.form == TRAN_BLADE_HANDS)
1077             return "slash";
1078
1079         if (you.has_usable_claws())
1080             return "claw";
1081
1082         if (you.has_usable_tentacles())
1083             return "tentacle-slap";
1084
1085         return name;
1086     }
1087
1088 };
1089
1090 class AuxBite: public AuxAttackType
1091 {
1092 public:
1093     AuxBite()
1094     : AuxAttackType(0, "bite") { };
1095
1096     int get_damage() const
1097     {
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);
1101
1102         const int str_damage = div_rand_round(max(you.strength()-10, 0), 5);
1103
1104         if (player_mutation_level(MUT_ACIDIC_BITE))
1105             return fang_damage + str_damage + roll_dice(2,4);
1106
1107         return fang_damage + str_damage;
1108     }
1109
1110     int get_brand() const
1111     {
1112         if (player_mutation_level(MUT_ANTIMAGIC_BITE))
1113             return SPWPN_ANTIMAGIC;
1114
1115         if (player_mutation_level(MUT_ACIDIC_BITE))
1116             return SPWPN_ACID;
1117
1118         return SPWPN_NORMAL;
1119     }
1120 };
1121
1122 class AuxPseudopods: public AuxAttackType
1123 {
1124 public:
1125     AuxPseudopods()
1126     : AuxAttackType(4, "bludgeon") { };
1127
1128     int get_damage() const { return damage * you.has_usable_pseudopods(); }
1129 };
1130
1131 class AuxTentacles: public AuxAttackType
1132 {
1133 public:
1134     AuxTentacles()
1135     : AuxAttackType(12, "squeeze") { };
1136 };
1137
1138
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();
1148
1149 static const AuxAttackType* const aux_attack_types[] =
1150 {
1151     &AUX_CONSTRICT,
1152     &AUX_KICK,
1153     &AUX_HEADBUTT,
1154     &AUX_PECK,
1155     &AUX_TAILSLAP,
1156     &AUX_PUNCH,
1157     &AUX_BITE,
1158     &AUX_PSEUDOPODS,
1159     &AUX_TENTACLES,
1160 };
1161
1162
1163 /* Setup all unarmed (non attack_type) variables
1164  *
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
1167  */
1168 void melee_attack::player_aux_setup(unarmed_attack_type atk)
1169 {
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);
1173
1174     ASSERT(atk >= UNAT_FIRST_ATTACK);
1175     ASSERT(atk <= UNAT_LAST_ATTACK);
1176     const AuxAttackType* const aux = aux_attack_types[atk - UNAT_FIRST_ATTACK];
1177
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();
1182
1183
1184     // prob of vampiric bite:
1185     // 1/4 when non-thirsty, 1/2 when thirsty, 100% when
1186     // bloodless
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)))
1192     {
1193         damage_brand = SPWPN_VAMPIRISM;
1194     }
1195 }
1196
1197 /**
1198  * Decide whether the player gets a bonus punch attack.
1199  *
1200  * Partially random.
1201  *
1202  * @return  Whether the player gets a bonus punch aux attack on this attack.
1203  */
1204 bool melee_attack::player_gets_aux_punch()
1205 {
1206     if (!get_form()->can_offhand_punch())
1207         return false;
1208
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))
1212     {
1213         return false;
1214     }
1215
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())
1219         return false;
1220
1221     // Octopodes get more tentacle-slaps.
1222     return x_chance_in_y(you.species == SP_OCTOPODE ? 3 : 2,
1223                          6);
1224 }
1225
1226 bool melee_attack::player_aux_test_hit()
1227 {
1228     // XXX We're clobbering did_hit
1229     did_hit = false;
1230
1231     const int evasion = defender->evasion(EV_IGNORE_NONE, attacker);
1232
1233     if (player_under_penance(GOD_ELYVILON)
1234         && god_hates_your_god(GOD_ELYVILON)
1235         && to_hit >= evasion
1236         && one_chance_in(20))
1237     {
1238         simple_god_message(" blocks your attack.", GOD_ELYVILON);
1239         return false;
1240     }
1241
1242     bool auto_hit = one_chance_in(30);
1243
1244     if (to_hit >= evasion || auto_hit)
1245         return true;
1246
1247     const int phaseless_evasion =
1248         defender->evasion(EV_IGNORE_PHASESHIFT, attacker);
1249
1250     if (to_hit >= phaseless_evasion && defender_visible)
1251     {
1252         mprf("Your %s passes through %s as %s momentarily phases out.",
1253             aux_attack.c_str(),
1254             defender->name(DESC_THE).c_str(),
1255             defender->pronoun(PRONOUN_SUBJECTIVE).c_str());
1256     }
1257     else
1258     {
1259         mprf("Your %s misses %s.", aux_attack.c_str(),
1260              defender->name(DESC_THE).c_str());
1261     }
1262
1263     return false;
1264 }
1265
1266 /* Controls the looping on available unarmed attacks
1267  *
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.
1271  *
1272  * Returns (defender dead)
1273  */
1274 bool melee_attack::player_aux_unarmed()
1275 {
1276     unwind_var<brand_type> save_brand(damage_brand);
1277
1278     for (int i = UNAT_FIRST_ATTACK; i <= UNAT_LAST_ATTACK; ++i)
1279     {
1280         if (!defender->alive())
1281             break;
1282
1283         unarmed_attack_type atk = static_cast<unarmed_attack_type>(i);
1284
1285         if (!_extra_aux_attack(atk))
1286             continue;
1287
1288         // Determine and set damage and attack words.
1289         player_aux_setup(atk);
1290
1291         if (atk == UNAT_CONSTRICT && !attacker->can_constrict(defender))
1292             continue;
1293
1294         to_hit = random2(calc_your_to_hit_unarmed(atk,
1295                          damage_brand == SPWPN_VAMPIRISM));
1296
1297         handle_noise(defender->pos());
1298         alert_nearby_monsters();
1299
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())
1308             return true;
1309
1310         if (player_aux_test_hit())
1311         {
1312             // Upset the monster.
1313             behaviour_event(defender->as_monster(), ME_WHACK, attacker);
1314             if (!defender->alive())
1315                 return true;
1316
1317             if (attack_shield_blocked(true))
1318                 continue;
1319             if (player_aux_apply(atk))
1320                 return true;
1321         }
1322     }
1323
1324     return false;
1325 }
1326
1327 bool melee_attack::player_aux_apply(unarmed_attack_type atk)
1328 {
1329     did_hit = true;
1330
1331     aux_damage  = player_aux_stat_modify_damage(aux_damage);
1332
1333     aux_damage  = random2(aux_damage);
1334
1335     aux_damage  = player_apply_fighting_skill(aux_damage, true);
1336
1337     aux_damage  = player_apply_misc_modifiers(aux_damage);
1338
1339     aux_damage  = player_apply_slaying_bonuses(aux_damage, true);
1340
1341     aux_damage  = player_apply_final_multipliers(aux_damage);
1342
1343     if (atk == UNAT_CONSTRICT)
1344         aux_damage = 0;
1345     else
1346         aux_damage = apply_defender_ac(aux_damage);
1347
1348     aux_damage = inflict_damage(aux_damage, BEAM_MISSILE);
1349     damage_done = aux_damage;
1350
1351     switch (atk)
1352     {
1353         case UNAT_PUNCH:
1354             apply_bleeding = true;
1355             break;
1356
1357         case UNAT_CONSTRICT:
1358             attacker->start_constricting(*defender);
1359             break;
1360
1361         default:
1362             break;
1363     }
1364
1365     if (damage_done > 0 || atk == UNAT_CONSTRICT)
1366     {
1367         player_announce_aux_hit();
1368
1369         if (damage_brand == SPWPN_ACID)
1370         {
1371             mprf("%s is splashed with acid.",
1372                  defender->name(DESC_THE).c_str());
1373             defender->splash_with_acid(&you);
1374         }
1375
1376         if (damage_brand == SPWPN_VENOM && coinflip())
1377             poison_monster(defender->as_monster(), &you);
1378
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))
1382         {
1383             _player_vampire_draws_blood(defender->as_monster(), damage_done);
1384         }
1385
1386         if (damage_brand == SPWPN_ANTIMAGIC && you.mutation[MUT_ANTIMAGIC_BITE]
1387             && damage_done > 0)
1388         {
1389             const bool spell_user = defender->antimagic_susceptible();
1390
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");
1395
1396             if (you.magic_points != you.max_magic_points
1397                 && !defender->as_monster()->is_summoned()
1398                 && !mons_is_firewood(defender->as_monster()))
1399             {
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)
1404                               * drain);
1405                 if (drain)
1406                 {
1407                     mpr("You feel invigorated.");
1408                     inc_mp(drain);
1409                 }
1410             }
1411         }
1412     }
1413     else // no damage was done
1414     {
1415         mprf("You %s %s%s.",
1416              aux_verb.c_str(),
1417              defender->name(DESC_THE).c_str(),
1418              you.can_see(defender) ? ", but do no damage" : "");
1419     }
1420
1421     if (defender->as_monster()->hit_points < 1)
1422     {
1423         handle_phase_killed();
1424         return true;
1425     }
1426
1427     return false;
1428 }
1429
1430 void melee_attack::player_announce_aux_hit()
1431 {
1432     mprf("You %s %s%s%s",
1433          aux_verb.c_str(),
1434          defender->name(DESC_THE).c_str(),
1435          debug_damage_number().c_str(),
1436          attack_strength_punctuation(damage_done).c_str());
1437 }
1438
1439 string melee_attack::player_why_missed()
1440 {
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)
1445     {
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);
1452
1453         const item_def *armour = you.slot_item(EQ_BODY_ARMOUR, false);
1454         const string armour_name = armour ? armour->name(DESC_BASENAME)
1455                                           : string("armour");
1456
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 ";
1461         else
1462             return "Your shield and " + armour_name
1463                    + " prevent you from hitting ";
1464     }
1465
1466     return "You" + evasion_margin_adverb() + " miss ";
1467 }
1468
1469 void melee_attack::player_warn_miss()
1470 {
1471     did_hit = false;
1472
1473     mprf("%s%s.",
1474          player_why_missed().c_str(),
1475          defender->name(DESC_THE).c_str());
1476
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);
1480 }
1481
1482 int melee_attack::player_aux_stat_modify_damage(int damage)
1483 {
1484     int dammod = 20;
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;
1487
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);
1492
1493     damage *= dammod;
1494     damage /= 20;
1495
1496     return damage;
1497 }
1498
1499 // A couple additive modifiers that should be applied to both unarmed and
1500 // armed attacks.
1501 int melee_attack::player_apply_misc_modifiers(int damage)
1502 {
1503     if (you.duration[DUR_MIGHT] || you.duration[DUR_BERSERK])
1504         damage += 1 + random2(10);
1505
1506     if (you.species != SP_VAMPIRE && you.hunger_state == HS_STARVING)
1507         damage -= random2(5);
1508
1509     return damage;
1510 }
1511
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)
1518 {
1519     //cleave damage modifier
1520     if (cleaving)
1521         damage = cleave_damage_mod(damage);
1522
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);
1527
1528     // Can't affect much of anything as a shadow.
1529     if (you.form == TRAN_SHADOW)
1530         damage = div_rand_round(damage, 2);
1531
1532     if (you.duration[DUR_WEAK])
1533         damage = div_rand_round(damage * 3, 4);
1534
1535     if (you.duration[DUR_CONFUSING_TOUCH] && wpn_skill == SK_UNARMED_COMBAT)
1536         return 0;
1537
1538     return damage;
1539 }
1540
1541 void melee_attack::set_attack_verb(int damage)
1542 {
1543     if (!attacker->is_player())
1544         return;
1545
1546     int weap_type = WPN_UNKNOWN;
1547
1548     if (Options.has_fake_lang(FLANG_GRUNT))
1549         damage = HIT_STRONG + 1;
1550
1551     if (!weapon)
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))
1559     {
1560         weap_type = weapon->sub_type;
1561     }
1562
1563     // All weak hits with weapons look the same.
1564     if (damage < HIT_WEAK
1565         && weap_type != WPN_UNARMED)
1566     {
1567         if (weap_type != WPN_UNKNOWN)
1568             attack_verb = "hit";
1569         else
1570             attack_verb = "clumsily bash";
1571         return;
1572     }
1573
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
1576     // it.
1577     monster_type defender_genus = mons_genus(defender->type);
1578     switch (weapon ? single_damage_type(*weapon) : -1)
1579     {
1580     case DAM_PIERCE:
1581         if (damage < HIT_MED)
1582             attack_verb = "puncture";
1583         else if (damage < HIT_STRONG)
1584             attack_verb = "impale";
1585         else
1586         {
1587             if (defender->is_monster()
1588                 && defender_visible
1589                 && defender_genus == MONS_HOG)
1590             {
1591                 attack_verb = "spit";
1592                 verb_degree = "like the proverbial pig";
1593             }
1594             else if (defender_genus == MONS_CRAB
1595                      && Options.has_fake_lang(FLANG_GRUNT))
1596             {
1597                 attack_verb = "attack";
1598                 verb_degree = "'s weak point";
1599             }
1600             else
1601             {
1602                 static const char * const pierce_desc[][2] =
1603                 {
1604                     {"spit", "like a pig"},
1605                     {"skewer", "like a kebab"},
1606                     {"stick", "like a pincushion"},
1607                     {"perforate", "like a sieve"}
1608                 };
1609                 const int choice = random2(ARRAYSZ(pierce_desc));
1610                 attack_verb = pierce_desc[choice][0];
1611                 verb_degree = pierce_desc[choice][1];
1612             }
1613         }
1614         break;
1615
1616     case DAM_SLICE:
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)
1622         {
1623             attack_verb = "dice";
1624             verb_degree = "like an onion";
1625         }
1626         else if (defender_genus == MONS_SKELETON)
1627         {
1628             attack_verb = "fracture";
1629             verb_degree = "into splinters";
1630         }
1631         else if (defender_genus == MONS_HOG)
1632         {
1633             attack_verb = "carve";
1634             verb_degree = "like the proverbial ham";
1635         }
1636         else if (defender_genus == MONS_TENGU && one_chance_in(3))
1637         {
1638             attack_verb = "carve";
1639             verb_degree = "like a turkey";
1640         }
1641         else if ((defender_genus == MONS_YAK || defender_genus == MONS_YAKTAUR)
1642                  && Options.has_fake_lang(FLANG_GRUNT))
1643             attack_verb = "shave";
1644         else
1645         {
1646             static const char * const slice_desc[][2] =
1647             {
1648                 {"open",    "like a pillowcase"},
1649                 {"slice",   "like a ripe choko"},
1650                 {"cut",     "into ribbons"},
1651                 {"carve",   "like a ham"},
1652                 {"chop",    "into pieces"}
1653             };
1654             const int choice = random2(ARRAYSZ(slice_desc));
1655             attack_verb = slice_desc[choice][0];
1656             verb_degree = slice_desc[choice][1];
1657         }
1658         break;
1659
1660     case DAM_BLUDGEON:
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)
1666         {
1667             attack_verb = "shatter";
1668             verb_degree = "into splinters";
1669         }
1670         else if (defender->type == MONS_GREAT_ORB_OF_EYES)
1671         {
1672             attack_verb = "splatter";
1673             verb_degree = "into a gooey mess";
1674         }
1675         else
1676         {
1677             static const char * const bludgeon_desc[][2] =
1678             {
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"}
1684             };
1685             const int choice = random2(ARRAYSZ(bludgeon_desc));
1686             attack_verb = bludgeon_desc[choice][0];
1687             verb_degree = bludgeon_desc[choice][1];
1688         }
1689         break;
1690
1691     case DAM_WHIP:
1692         if (damage < HIT_MED)
1693             attack_verb = "whack";
1694         else if (damage < HIT_STRONG)
1695             attack_verb = "thrash";
1696         else
1697         {
1698             switch (defender->holiness())
1699             {
1700             case MH_HOLY:
1701             case MH_NATURAL:
1702             case MH_DEMONIC:
1703                 attack_verb = "punish";
1704                 verb_degree = ", causing immense pain";
1705                 break;
1706             default:
1707                 attack_verb = "devastate";
1708             }
1709         }
1710         break;
1711
1712     case -1: // unarmed
1713     {
1714         const FormAttackVerbs verbs = get_form(you.form)->uc_attack_verbs;
1715         if (verbs.weak != nullptr)
1716         {
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;
1723             else
1724                 attack_verb = verbs.devastating;
1725             break;
1726         }
1727
1728         if (you.damage_type() == DVORP_CLAWING)
1729         {
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";
1736             else
1737                 attack_verb = "eviscerate";
1738         }
1739         else if (you.damage_type() == DVORP_TENTACLE)
1740         {
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";
1747             else
1748                 attack_verb = "thrash";
1749         }
1750         else
1751         {
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))
1761             {
1762                 attack_verb = "squash";
1763                 verb_degree = "like the proverbial ant";
1764             }
1765             else
1766             {
1767                 static const char * const punch_desc[][2] =
1768                 {
1769                     {"pound",     "into fine dust"},
1770                     {"pummel",    "like a punching bag"},
1771                     {"pulverise", ""},
1772                     {"squash",    "like an ant"}
1773                 };
1774                 const int choice = random2(ARRAYSZ(punch_desc));
1775                 // XXX: could this distinction work better?
1776                 if (choice == 0
1777                     && defender->is_monster()
1778                     && mons_has_blood(defender->type))
1779                 {
1780                     attack_verb = "beat";
1781                     verb_degree = "into a bloody pulp";
1782                 }
1783                 else
1784                 {
1785                     attack_verb = punch_desc[choice][0];
1786                     verb_degree = punch_desc[choice][1];
1787                 }
1788             }
1789         }
1790         break;
1791     }
1792
1793     case WPN_UNKNOWN:
1794     default:
1795         attack_verb = "hit";
1796         break;
1797     }
1798 }
1799
1800 void melee_attack::player_exercise_combat_skills()
1801 {
1802     if (defender->cannot_fight())
1803         return;
1804
1805     int damage = 10; // Default for unarmed.
1806     if (weapon && is_weapon(*weapon) && !is_range_weapon(*weapon))
1807         damage = property(*weapon, PWPN_DAMAGE);
1808
1809     // Slow down the practice of low-damage weapons.
1810     if (x_chance_in_y(damage, 20))
1811         practise(EX_WILL_HIT, wpn_skill);
1812 }
1813
1814 /*
1815  * Applies god conduct for weapon ego
1816  *
1817  * Using speed brand as a chei worshipper, or holy/unholy weapons
1818  */
1819 void melee_attack::player_weapon_upsets_god()
1820 {
1821     if (weapon && weapon->base_type == OBJ_WEAPONS)
1822     {
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)
1829         {
1830             did_god_conduct(DID_HASTY, 1);
1831         }
1832     }
1833     else if (weapon && weapon->is_type(OBJ_STAVES, STAFF_FIRE))
1834         did_god_conduct(DID_FIRE, 1);
1835 }
1836
1837 /* Apply player-specific effects as well as brand damage.
1838  *
1839  * Called after damage is calculated, but before unrand effects and before
1840  * damage is dealt.
1841  *
1842  * Returns true if combat should continue, false if it should end here.
1843  */
1844 bool melee_attack::player_monattk_hit_effects()
1845 {
1846     player_weapon_upsets_god();
1847
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)
1852         return false;
1853
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)
1857     {
1858         _player_vampire_draws_blood(defender->as_monster(), damage_done, true);
1859     }
1860
1861     if (!defender->alive())
1862         return false;
1863
1864     // These effects apply only to monsters that are still alive:
1865
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.
1869     //
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();
1874
1875     // Mutually exclusive with (overrides) brand damage!
1876     special_damage = 0;
1877     apply_staff_damage();
1878
1879     if (!defender->alive())
1880         return false;
1881
1882     if (special_damage || special_damage_flavour)
1883     {
1884         dprf(DIAG_COMBAT, "Special damage to %s: %d, flavour: %d",
1885              defender->name(DESC_THE).c_str(),
1886              special_damage, special_damage_flavour);
1887
1888         special_damage = inflict_damage(special_damage);
1889         if (special_damage > 0)
1890             defender->expose_to_element(special_damage_flavour, 2);
1891     }
1892
1893     return true;
1894 }
1895
1896 void melee_attack::rot_defender(int amount)
1897 {
1898     if (defender->rot(attacker, amount, true))
1899     {
1900         // XXX: why is this message separate here?
1901         if (defender->is_player())
1902         {
1903             special_damage_message =
1904                 make_stringf("You feel your flesh rotting away!");
1905         }
1906         else if (defender->is_monster() && defender_visible)
1907         {
1908             special_damage_message =
1909                 make_stringf(
1910                     "%s looks less resilient!",
1911                     defender_name(false).c_str());
1912         }
1913     }
1914 }
1915
1916 void melee_attack::handle_noise(const coord_def & pos)
1917 {
1918     // Successful stabs make no noise.
1919     if (stab_attempt)
1920         return;
1921
1922     int loudness = damage_done / 4;
1923
1924     // All non-stab melee attacks make some noise.
1925     loudness = max(1, loudness);
1926
1927     // Cap melee noise at shouting volume.
1928     loudness = min(12, loudness);
1929
1930     noisy(loudness, pos, attacker->mid);
1931 }
1932
1933 /**
1934  * If appropriate, chop a head off the defender. (Usually a hydra.)
1935  *
1936  * @param dam           The damage done in the attack that may or may not chop
1937   *                     off a head.
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.)
1942  */
1943 bool melee_attack::consider_decapitation(int dam, int damage_type)
1944 {
1945     const int dam_type = (damage_type != -1) ? damage_type :
1946                                                attacker->damage_type();
1947     const brand_type wpn_brand = attacker->damage_brand();
1948
1949     if (!attack_chops_heads(dam, dam_type, wpn_brand))
1950         return false;
1951
1952     decapitate(dam_type);
1953
1954     if (!defender->alive())
1955         return true;
1956
1957     // if your last head got chopped off, don't 'cauterize the wound'.
1958     if (defender->is_player() && you.form != TRAN_HYDRA)
1959         return false;
1960
1961     // Only living hydras get to regenerate heads.
1962     if (defender->holiness() != MH_NATURAL)
1963         return false;
1964
1965     // What's the largest number of heads the defender can have?
1966     const int limit = defender->type == MONS_LERNAEAN_HYDRA ? 27
1967                                                             : MAX_HYDRA_HEADS;
1968
1969     if (wpn_brand == SPWPN_FLAMING)
1970     {
1971         if (defender_visible)
1972             mpr("The flame cauterises the wound!");
1973         return true;
1974     }
1975
1976     int heads = defender->heads();
1977     if (heads >= limit - 1)
1978         return false; // don't overshoot the head limit!
1979
1980     if (defender->is_monster())
1981     {
1982         simple_monster_message(defender->as_monster(), " grows two more!");
1983         defender->as_monster()->num_heads += 2;
1984         defender->heal(8 + random2(8), true);
1985     }
1986     else
1987     {
1988         mpr("You grow two more!");
1989         set_hydra_form_heads(heads + 2);
1990     }
1991
1992     return false;
1993 }
1994
1995 /**
1996  * Can the given actor lose its heads? (Is it hydra or hydra-like?)
1997  *
1998  * @param defender  The actor in question.
1999  * @return          Whether the given actor is susceptible to head-choppage.
2000  */
2001 static bool actor_can_lose_heads(const actor* defender)
2002 {
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)
2007     {
2008         return true;
2009     }
2010
2011     if (defender->is_player() && you.form == TRAN_HYDRA)
2012         return true;
2013
2014     return false;
2015 }
2016
2017 /**
2018  * Does this attack chop off one of the defender's heads? (Generally only
2019  * relevant for hydra defenders)
2020  *
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.
2025  */
2026 bool melee_attack::attack_chops_heads(int dam, int dam_type, int wpn_brand)
2027 {
2028     // hydras and hydra-like things only.
2029     if (!actor_can_lose_heads(defender))
2030         return false;
2031
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
2038                                         == MID_PLAYER;
2039     if (attacker->is_monster() && defender->is_monster()
2040         && !player_spec_weap && !one_chance_in(4))
2041     {
2042         return false;
2043     }
2044
2045     // Only cutting implements.
2046     if (dam_type != DVORP_SLICING && dam_type != DVORP_CHOPPING
2047         && dam_type != DVORP_CLAWING)
2048     {
2049         return false;
2050     }
2051
2052     // Small claws are not big enough.
2053     if (dam_type == DVORP_CLAWING && attacker->has_claws() < 3)
2054         return false;
2055
2056     // you need to have done at least some damage.
2057     if (dam <= 0)
2058         return false;
2059
2060     // usually at least 4 damage, unless you are an unlucky vorpal user.
2061     if (dam < 4 && wpn_brand != SPWPN_VORPAL && coinflip())
2062         return false;
2063
2064     // ok, good enough!
2065     return true;
2066 }
2067
2068 /**
2069  * Decapitate the (hydra or hydra-like) defender!
2070  *
2071  * @param dam_type      The vorpal_damage_type of the attack.
2072  */
2073 void melee_attack::decapitate(int dam_type)
2074 {
2075     const char *verb = nullptr;
2076
2077     if (dam_type == DVORP_CLAWING)
2078     {
2079         static const char *claw_verbs[] = { "rip", "tear", "claw" };
2080         verb = RANDOM_ELEMENT(claw_verbs);
2081     }
2082     else
2083     {
2084         static const char *slice_verbs[] =
2085         {
2086             "slice", "lop", "chop", "hack"
2087         };
2088         verb = RANDOM_ELEMENT(slice_verbs);
2089     }
2090
2091     int heads = defender->heads();
2092     if (heads == 1) // will be zero afterwards
2093     {
2094         if (defender_visible)
2095         {
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());
2100         }
2101
2102
2103         if (defender->is_player())
2104         {
2105             untransform();
2106             return;
2107         }
2108
2109         if (!defender->is_summoned())
2110         {
2111             bleed_onto_floor(defender->pos(), defender->type,
2112                              defender->as_monster()->hit_points, true);
2113         }
2114
2115         defender->hurt(attacker, INSTANT_DEATH);
2116
2117         return;
2118     }
2119
2120     if (defender_visible)
2121     {
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());
2126     }
2127
2128     if (defender->is_player())
2129         set_hydra_form_heads(heads - 1);
2130     else
2131         defender->as_monster()->num_heads--;
2132 }
2133
2134 /**
2135  * Apply passive retaliation damage from hitting acid monsters.
2136  */
2137 void melee_attack::attacker_sustain_passive_damage()
2138 {
2139     // If the defender has been cleaned up, it's too late for anything.
2140     if (!defender->alive())
2141         return;
2142
2143     if (!mons_class_flag(defender->type, M_ACID_SPLASH))
2144         return;
2145
2146     if (attacker->res_acid() >= 3)
2147         return;
2148
2149     const int acid_strength = resist_adjust_damage(attacker, BEAM_ACID, 5);
2150
2151     const item_def *weap = weapon ? weapon : attacker->slot_item(EQ_GLOVES);
2152
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);
2156
2157     if (weap && !avatar)
2158     {
2159         if (x_chance_in_y(acid_strength + 1, 30))
2160             attacker->corrode_equipment();
2161     }
2162     else
2163     {
2164         if (attacker->is_player())
2165             mpr(you.hands_act("burn", "!"));
2166         else
2167         {
2168             simple_monster_message(attacker->as_monster(),
2169                                    " is burned by acid!");
2170         }
2171         attacker->hurt(defender, roll_dice(1, acid_strength), BEAM_ACID,
2172                        KILLED_BY_ACID, "", "", false);
2173     }
2174 }
2175
2176 int melee_attack::staff_damage(skill_type skill)
2177 {
2178     if (x_chance_in_y(attacker->skill(SK_EVOCATIONS, 200)
2179                     + attacker->skill(skill, 100), 3000))
2180     {
2181         return random2((attacker->skill(skill, 100)
2182                       + attacker->skill(SK_EVOCATIONS, 50)) / 80);
2183     }
2184     return 0;
2185 }
2186
2187 void melee_attack::apply_staff_damage()
2188 {
2189     if (!weapon)
2190         return;
2191
2192     if (player_mutation_level(MUT_NO_ARTIFICE))
2193         return;
2194
2195     if (weapon->base_type != OBJ_STAVES)
2196         return;
2197
2198     switch (weapon->sub_type)
2199     {
2200     case STAFF_AIR:
2201         special_damage =
2202             resist_adjust_damage(defender,
2203                                  BEAM_ELECTRICITY,
2204                                  staff_damage(SK_AIR_MAGIC));
2205
2206         if (special_damage)
2207         {
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;
2213         }
2214
2215         break;
2216
2217     case STAFF_COLD:
2218         special_damage =
2219             resist_adjust_damage(defender,
2220                                  BEAM_COLD,
2221                                  staff_damage(SK_ICE_MAGIC));
2222
2223         if (special_damage)
2224         {
2225             special_damage_message =
2226                 make_stringf(
2227                     "%s freeze%s %s!",
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;
2232         }
2233         break;
2234
2235     case STAFF_EARTH:
2236         special_damage = staff_damage(SK_EARTH_MAGIC);
2237         special_damage = apply_defender_ac(special_damage);
2238
2239         if (special_damage > 0)
2240         {
2241             special_damage_message =
2242                 make_stringf(
2243                     "%s crush%s %s!",
2244                     attacker->name(DESC_THE).c_str(),
2245                     attacker->is_player() ? "" : "es",
2246                     defender->name(DESC_THE).c_str());
2247         }
2248         break;
2249
2250     case STAFF_FIRE:
2251         special_damage =
2252             resist_adjust_damage(defender,
2253                                  BEAM_FIRE,
2254                                  staff_damage(SK_FIRE_MAGIC));
2255
2256         if (special_damage)
2257         {
2258             special_damage_message =
2259                 make_stringf(
2260                     "%s burn%s %s!",
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;
2265         }
2266         break;
2267
2268     case STAFF_POISON:
2269     {
2270         if (random2(300) >= attacker->skill(SK_EVOCATIONS, 20) + attacker->skill(SK_POISON_MAGIC, 10))
2271             return;
2272
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);
2276         break;
2277     }
2278
2279     case STAFF_DEATH:
2280         if (defender->res_negative_energy())
2281             break;
2282
2283         special_damage = staff_damage(SK_NECROMANCY);
2284
2285         if (special_damage)
2286         {
2287             special_damage_message =
2288                 make_stringf(
2289                     "%s convulse%s in agony!",
2290                     defender->name(DESC_THE).c_str(),
2291                     defender->is_player() ? "" : "s");
2292
2293             attacker->god_conduct(DID_NECROMANCY, 4);
2294         }
2295         break;
2296
2297     case STAFF_SUMMONING:
2298     case STAFF_POWER:
2299     case STAFF_CONJURATION:
2300 #if TAG_MAJOR_VERSION == 34
2301     case STAFF_ENCHANTMENT:
2302 #endif
2303     case STAFF_ENERGY:
2304     case STAFF_WIZARDRY:
2305         break;
2306
2307     default:
2308         die("Invalid staff type: %d", weapon->sub_type);
2309     }
2310 }
2311
2312 /**
2313  * Calculate the to-hit for an attacker
2314  *
2315  * @param random If false, calculate average to-hit deterministically.
2316  */
2317 int melee_attack::calc_to_hit(bool random)
2318 {
2319     int mhit = attack::calc_to_hit(random);
2320
2321     if (attacker->is_player() && !weapon)
2322     {
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);
2326
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);
2330     }
2331
2332     return mhit;
2333 }
2334
2335 void melee_attack::player_stab_check()
2336 {
2337     attack::player_stab_check();
2338 }
2339
2340 /**
2341  * Can we get a good stab with this weapon?
2342  */
2343 bool melee_attack::player_good_stab()
2344 {
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));
2349 }
2350
2351 bool melee_attack::attack_ignores_shield(bool verbose)
2352 {
2353     return false;
2354 }
2355
2356 /* Select the attack verb for attacker
2357  *
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.
2361  *
2362  * Returns (attack_verb)
2363  */
2364 string melee_attack::mons_attack_verb()
2365 {
2366     static const char *klown_attack[] =
2367     {
2368         "hit",
2369         "poke",
2370         "prod",
2371         "flog",
2372         "pound",
2373         "slap",
2374         "tickle",
2375         "defenestrate",
2376         "sucker-punch",
2377         "elbow",
2378         "pinch",
2379         "strangle-hug",
2380         "squeeze",
2381         "tease",
2382         "eye-gouge",
2383         "karate-kick",
2384         "headlock",
2385         "wrestle",
2386         "trip-wire",
2387         "kneecap"
2388     };
2389
2390     if (attacker->type == MONS_KILLER_KLOWN && attk_type == AT_HIT)
2391         return RANDOM_ELEMENT(klown_attack);
2392
2393     //XXX: then why give them it in the first place?
2394     if (attk_type == AT_TENTACLE_SLAP && mons_is_tentacle(attacker->type))
2395         return "slap";
2396
2397     static const char *attack_types[] =
2398     {
2399         "hit",         // including weapon attacks
2400         "bite",
2401         "sting",
2402
2403         // spore
2404         "release spores at",
2405
2406         "touch",
2407         "engulf",
2408         "claw",
2409         "peck",
2410         "headbutt",
2411         "punch",
2412         "kick",
2413         "tentacle-slap",
2414         "tail-slap",
2415         "gore",
2416         "constrict",
2417         "trample",
2418         "trunk-slap",
2419 #if TAG_MAJOR_VERSION == 34
2420         "snap closed at",
2421         "splash",
2422 #endif
2423         "pounce on",
2424         "sting",
2425     };
2426     COMPILE_CHECK(ARRAYSZ(attack_types) == AT_LAST_REAL_ATTACK);
2427
2428     const int verb_index = attk_type - AT_FIRST_ATTACK;
2429     ASSERT(verb_index < (int)ARRAYSZ(attack_types));
2430     return attack_types[verb_index];
2431 }
2432
2433 string melee_attack::mons_attack_desc()
2434 {
2435     if (!you.can_see(attacker))
2436         return "";
2437
2438     string ret;
2439     int dist = (attack_position - defender->pos()).abs();
2440     if (dist > 2)
2441     {
2442         ASSERT(can_reach());
2443         ret = " from afar";
2444     }
2445
2446     if (weapon && attacker->type != MONS_DANCING_WEAPON && attacker->type != MONS_SPECTRAL_WEAPON)
2447         ret += " with " + weapon->name(DESC_A);
2448
2449     return ret;
2450 }
2451
2452 void melee_attack::announce_hit()
2453 {
2454     if (!needs_message || attk_flavour == AF_CRUSH)
2455         return;
2456
2457     if (attacker->is_monster())
2458     {
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());
2466     }
2467     else
2468     {
2469         if (!verb_degree.empty() && verb_degree[0] != ' '
2470             && verb_degree[0] != ',' && verb_degree[0] != '\'')
2471         {
2472             verb_degree = " " + verb_degree;
2473         }
2474
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());
2480     }
2481 }
2482
2483 // Returns if the target was actually poisoned by this attack
2484 bool melee_attack::mons_do_poison()
2485 {
2486     int amount = 1;
2487     bool force = false;
2488
2489     if (attk_flavour == AF_POISON_STRONG)
2490     {
2491         amount = random_range(attacker->get_hit_dice() * 11 / 3,
2492                               attacker->get_hit_dice() * 13 / 2);
2493     }
2494     else
2495     {
2496         amount = random_range(attacker->get_hit_dice() * 2,
2497                               attacker->get_hit_dice() * 4);
2498     }
2499
2500     if (!defender->poison(attacker, amount, force))
2501         return false;
2502
2503     if (needs_message)
2504     {
2505         mprf("%s poisons %s!",
2506                 atk_name(DESC_THE).c_str(),
2507                 defender_name(true).c_str());
2508         if (force)
2509         {
2510             mprf("%s partially resist%s.",
2511                 defender_name(false).c_str(),
2512                 defender->is_player() ? "" : "s");
2513         }
2514     }
2515
2516     return true;
2517 }
2518
2519 void melee_attack::mons_do_napalm()
2520 {
2521     if (defender->res_sticky_flame())
2522         return;
2523
2524     if (one_chance_in(20) || (damage_done > 2 && one_chance_in(3)))
2525     {
2526         if (needs_message)
2527         {
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());
2532         }
2533
2534         if (defender->is_player())
2535             napalm_player(random2avg(7, 3) + 1, atk_name(DESC_A));
2536         else
2537         {
2538             napalm_monster(
2539                 defender->as_monster(),
2540                 attacker,
2541                 min(4, 1 + random2(attacker->get_hit_dice())/2));
2542         }
2543     }
2544 }
2545
2546 void melee_attack::splash_defender_with_acid(int strength)
2547 {
2548     if (defender->is_player())
2549         mpr("You are splashed with acid!");
2550     else
2551     {
2552         special_damage += roll_dice(2, 4);
2553         if (defender_visible)
2554             mprf("%s is splashed with acid.", defender->name(DESC_THE).c_str());
2555     }
2556     defender->splash_with_acid(attacker, strength);
2557 }
2558
2559 static void _print_resist_messages(actor* defender, int base_damage,
2560                                    beam_type flavour)
2561 {
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
2568     // are needed.
2569     if (defender->is_player())
2570         (void)check_your_resists(base_damage, flavour, "");
2571     else
2572     {
2573         bolt beam;
2574         beam.flavour = flavour;
2575         (void)mons_adjust_flavoured(defender->as_monster(),
2576                                     beam,
2577                                     base_damage,
2578                                     true);
2579     }
2580 }
2581
2582 bool melee_attack::mons_attack_effects()
2583 {
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())
2589     {
2590         mons_apply_attack_flavour();
2591
2592         if (needs_message && !special_damage_message.empty())
2593             mpr(special_damage_message);
2594
2595         if (special_damage > 0)
2596         {
2597             inflict_damage(special_damage, special_damage_flavour);
2598             special_damage = 0;
2599             special_damage_message.clear();
2600             special_damage_flavour = BEAM_NONE;
2601         }
2602
2603         apply_staff_damage();
2604
2605         if (needs_message && !special_damage_message.empty())
2606             mpr(special_damage_message);
2607
2608         if (special_damage > 0
2609             && inflict_damage(special_damage, special_damage_flavour))
2610         {
2611             defender->expose_to_element(special_damage_flavour, 2);
2612         }
2613     }
2614
2615     if (defender->is_player())
2616         practise(EX_MONSTER_WILL_HIT);
2617
2618     // A tentacle may have banished its own parent/sibling and thus itself.
2619     if (!attacker->alive())
2620     {
2621         if (miscast_target == defender)
2622             do_miscast(); // Will handle a missing defender, too.
2623         return false;
2624     }
2625
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)))
2632     {
2633         return defender->alive();
2634     }
2635
2636     if (attacker != defender && attk_flavour == AF_TRAMPLE)
2637         do_knockback();
2638
2639     special_damage = 0;
2640     special_damage_message.clear();
2641     special_damage_flavour = BEAM_NONE;
2642
2643     // Defender banished. Bail since the defender is still alive in the
2644     // Abyss.
2645     if (defender->is_banished())
2646     {
2647         do_miscast();
2648         return false;
2649     }
2650
2651     if (!defender->alive())
2652     {
2653         do_miscast();
2654         return attacker->alive();
2655     }
2656
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)
2660     {
2661         if (miscast_target == defender)
2662             do_miscast();
2663         return false;
2664     }
2665
2666     if (!defender->alive())
2667     {
2668         do_miscast();
2669         return attacker->alive();
2670     }
2671
2672     if (miscast_target == defender)
2673         do_miscast();
2674
2675     // Miscast explosions may kill the attacker.
2676     if (!attacker->alive())
2677         return false;
2678
2679     if (miscast_target == attacker)
2680         do_miscast();
2681
2682     // Miscast might have killed the attacker.
2683     if (!attacker->alive())
2684         return false;
2685
2686     return true;
2687 }
2688
2689 void melee_attack::mons_apply_attack_flavour()
2690 {
2691     // Most of this is from BWR 4.1.2.
2692     int base_damage = 0;
2693
2694     attack_flavour flavour = attk_flavour;
2695     if (flavour == AF_CHAOS)
2696         flavour = random_chaos_attack_flavour();
2697
2698     // Note that if damage_done == 0 then this code won't be reached
2699     // unless the flavour is in _flavour_triggers_damageless.
2700     switch (flavour)
2701     {
2702     default:
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);
2706         break;
2707
2708     case AF_MUTATE:
2709         if (one_chance_in(4))
2710         {
2711             defender->malmutate(you.can_see(attacker) ?
2712                 apostrophise(attacker->name(DESC_PLAIN)) + " mutagenic touch" :
2713                 "mutagenic touch");
2714         }
2715         break;
2716
2717     case AF_POISON:
2718     case AF_POISON_STRONG:
2719         if (one_chance_in(3))
2720             mons_do_poison();
2721         break;
2722
2723     case AF_ROT:
2724         if (one_chance_in(20) || (damage_done > 2 && one_chance_in(3)))
2725             rot_defender(damage_done > 5 ? 2 : 1);
2726         break;
2727
2728     case AF_FIRE:
2729         base_damage = attacker->get_hit_dice()
2730                       + random2(attacker->get_hit_dice());
2731         special_damage =
2732             resist_adjust_damage(defender,
2733                                  BEAM_FIRE,
2734                                  base_damage);
2735         special_damage_flavour = BEAM_FIRE;
2736
2737         if (needs_message && base_damage)
2738         {
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());
2743
2744             _print_resist_messages(defender, base_damage, BEAM_FIRE);
2745         }
2746
2747         defender->expose_to_element(BEAM_FIRE, 2);
2748         break;
2749
2750     case AF_COLD:
2751         base_damage = attacker->get_hit_dice()
2752                       + random2(2 * attacker->get_hit_dice());
2753         special_damage =
2754             resist_adjust_damage(defender,
2755                                  BEAM_COLD,
2756                                  base_damage);
2757         special_damage_flavour = BEAM_COLD;
2758
2759         if (needs_message && base_damage)
2760         {
2761             mprf("%s %s %s%s",
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());
2766
2767             _print_resist_messages(defender, base_damage, BEAM_COLD);
2768         }
2769
2770         defender->expose_to_element(BEAM_COLD, 2);
2771         break;
2772
2773     case AF_ELEC:
2774         base_damage = attacker->get_hit_dice()
2775                       + random2(attacker->get_hit_dice() / 2);
2776
2777         special_damage =
2778             resist_adjust_damage(defender,
2779                                  BEAM_ELECTRICITY,
2780                                  base_damage);
2781         special_damage_flavour = BEAM_ELECTRICITY;
2782
2783         if (needs_message && base_damage)
2784         {
2785             mprf("%s %s %s%s",
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());
2790
2791             _print_resist_messages(defender, base_damage, BEAM_ELECTRICITY);
2792         }
2793
2794         dprf(DIAG_COMBAT, "Shock damage: %d", special_damage);
2795         defender->expose_to_element(BEAM_ELECTRICITY, 2);
2796         break;
2797
2798         // Combines drain speed and vampiric.
2799     case AF_SCARAB:
2800         if (x_chance_in_y(3, 5))
2801             drain_defender_speed();
2802
2803         // deliberate fall-through
2804     case AF_VAMPIRIC:
2805         // Only may bite non-vampiric monsters (or player) capable of bleeding.
2806         if (!defender->can_bleed())
2807             break;
2808
2809         // Disallow draining of summoned monsters since they can't bleed.
2810         // XXX: Is this too harsh?
2811         if (defender->is_summoned())
2812             break;
2813
2814         if (defender->res_negative_energy())
2815             break;
2816
2817         if (defender->stat_hp() < defender->stat_maxhp())
2818         {
2819             if (attacker->heal(1 + random2(damage_done)) && needs_message)
2820             {
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());
2825             }
2826         }
2827         break;
2828
2829     case AF_DRAIN_STR:
2830     case AF_DRAIN_INT:
2831     case AF_DRAIN_DEX:
2832         if (one_chance_in(20) || one_chance_in(3))
2833         {
2834             stat_type drained_stat = (flavour == AF_DRAIN_STR ? STAT_STR :
2835                                       flavour == AF_DRAIN_INT ? STAT_INT
2836                                                               : STAT_DEX);
2837             defender->drain_stat(drained_stat, 1);
2838         }
2839         break;
2840
2841     case AF_HUNGER:
2842         if (defender->holiness() == MH_UNDEAD)
2843             break;
2844
2845         defender->make_hungry(you.hunger / 4, false);
2846         break;
2847
2848     case AF_BLINK:
2849         // blinking can kill, delay the call
2850         if (one_chance_in(3))
2851             blink_fineff::schedule(attacker);
2852         break;
2853
2854     case AF_CONFUSE:
2855         if (attk_type == AT_SPORE)
2856         {
2857             if (defender->is_unbreathing())
2858                 break;
2859
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();
2864
2865             if (defender_visible)
2866             {
2867                 mprf("%s %s engulfed in a cloud of spores!",
2868                      defender->name(DESC_THE).c_str(),
2869                      defender->conj_verb("are").c_str());
2870             }
2871         }
2872
2873         if (one_chance_in(10)
2874             || (damage_done > 2 && one_chance_in(3)))
2875         {
2876             defender->confuse(attacker,
2877                               1 + random2(3+attacker->get_hit_dice()));
2878         }
2879         break;
2880
2881     case AF_DRAIN_XP:
2882         if (one_chance_in(30) || (damage_done > 5 && coinflip()))
2883             drain_defender();
2884         break;
2885
2886     case AF_PARALYSE:
2887     {
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)
2891         {
2892             mpr("Your divine stamina protects you from poison!");
2893             break;
2894         }
2895
2896         // doesn't affect poison-immune enemies
2897         if (defender->res_poison() >= 3)
2898             break;
2899
2900         if (attacker->type == MONS_HORNET || one_chance_in(3))
2901         {
2902             int dmg = random_range(attacker->get_hit_dice() * 3 / 2,
2903                                    attacker->get_hit_dice() * 5 / 2);
2904             defender->poison(attacker, dmg);
2905         }
2906
2907         int paralyse_roll = (damage_done > 4 ? 3 : 20);
2908         if (attacker->type == MONS_WASP)
2909             paralyse_roll += 3;
2910
2911         const int flat_bonus  = attacker->type == MONS_HORNET ? 1 : 0;
2912         const bool strong_result = one_chance_in(paralyse_roll);
2913
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));
2918
2919         break;
2920     }
2921
2922     case AF_ACID:
2923         splash_defender_with_acid(3);
2924         break;
2925
2926     case AF_CORRODE:
2927         if (defender->slot_item(EQ_BODY_ARMOUR))
2928             defender->corrode_equipment(atk_name(DESC_THE).c_str());
2929         break;
2930
2931     case AF_DISTORT:
2932         distortion_affects_defender();
2933         break;
2934
2935     case AF_RAGE:
2936         if (!one_chance_in(3) || !defender->can_go_berserk())
2937             break;
2938
2939         if (needs_message)
2940         {
2941             mprf("%s %s %s!",
2942                  atk_name(DESC_THE).c_str(),
2943                  attacker->conj_verb("infuriate").c_str(),
2944                  defender_name(true).c_str());
2945         }
2946
2947         defender->go_berserk(false);
2948         break;
2949
2950     case AF_STICKY_FLAME:
2951         mons_do_napalm();
2952         break;
2953
2954     case AF_CHAOS:
2955         chaos_affects_defender();
2956         break;
2957
2958     case AF_STEAL:
2959         // Ignore monsters, for now.
2960         if (!defender->is_player())
2961             break;
2962
2963         attacker->as_monster()->steal_item_from_player();
2964         break;
2965
2966     case AF_HOLY:
2967         if (defender->holy_wrath_susceptible())
2968             special_damage = attk_damage * 0.75;
2969
2970         if (needs_message && special_damage)
2971         {
2972             mprf("%s %s %s%s",
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());
2977
2978         }
2979         break;
2980
2981     case AF_ANTIMAGIC:
2982         antimagic_affects_defender(attacker->get_hit_dice() * 12);
2983
2984         if (mons_genus(attacker->type) == MONS_VINE_STALKER
2985             && attacker->is_monster())
2986         {
2987             const bool spell_user = defender->antimagic_susceptible();
2988
2989             if (you.can_see(attacker) || you.can_see(defender))
2990             {
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");
2995             }
2996
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()))))
3002             {
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(),
3006                                        spell_user
3007                                        ? " looks very invigorated."
3008                                        : " looks invigorated.");
3009             }
3010         }
3011         break;
3012
3013     case AF_PAIN:
3014         pain_affects_defender();
3015         break;
3016
3017     case AF_ENSNARE:
3018         if (one_chance_in(3))
3019             ensnare(defender);
3020         break;
3021
3022     case AF_CRUSH:
3023         if (needs_message)
3024         {
3025             mprf("%s %s %s.",
3026                  atk_name(DESC_THE).c_str(),
3027                  attacker->conj_verb("grab").c_str(),
3028                  defender_name(true).c_str());
3029         }
3030         attacker->start_constricting(*defender);
3031         // if you got grabbed, interrupt stair climb and passwall
3032         if (defender->is_player())
3033             stop_delay(true);
3034         break;
3035
3036     case AF_ENGULF:
3037         if (x_chance_in_y(2, 3) && attacker->can_constrict(defender))
3038         {
3039             if (defender->is_player() && !you.duration[DUR_WATER_HOLD]
3040                 && !you.duration[DUR_WATER_HOLD_IMMUNITY])
3041             {
3042                 you.duration[DUR_WATER_HOLD] = 10;
3043                 you.props["water_holder"].get_int() = attacker->as_monster()->mid;
3044             }
3045             else if (defender->is_monster()
3046                      && !defender->as_monster()->has_ench(ENCH_WATER_HOLD))
3047             {
3048                 defender->as_monster()->add_ench(mon_enchant(ENCH_WATER_HOLD, 1,
3049                                                              attacker, 1));
3050             }
3051             else
3052                 return; //Didn't apply effect; no message
3053
3054             if (needs_message)
3055             {
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());
3060             }
3061         }
3062
3063         defender->expose_to_element(BEAM_WATER, 0);
3064         break;
3065
3066     case AF_PURE_FIRE:
3067         if (attacker->type == MONS_FIRE_VORTEX)
3068             attacker->as_monster()->suicide(-10);
3069
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,
3074                                               BEAM_FIRE,
3075                                               special_damage);
3076
3077         if (needs_message && special_damage)
3078         {
3079             mprf("%s %s %s!",
3080                     atk_name(DESC_THE).c_str(),
3081                     attacker->conj_verb("burn").c_str(),
3082                     defender_name(true).c_str());
3083
3084             _print_resist_messages(defender, special_damage, BEAM_FIRE);
3085         }
3086
3087         defender->expose_to_element(BEAM_FIRE, 2);
3088         break;
3089
3090     case AF_DRAIN_SPEED:
3091         if (x_chance_in_y(3, 5))
3092             drain_defender_speed();
3093         break;
3094
3095     case AF_VULN:
3096         if (one_chance_in(3))
3097         {
3098             bool visible_effect = false;
3099             if (defender->is_player())
3100             {
3101                 if (!you.duration[DUR_LOWERED_MR])
3102                     visible_effect = true;
3103                 you.increase_duration(DUR_LOWERED_MR, 20 + random2(20), 40);
3104             }
3105             else
3106             {
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);
3112             }
3113
3114             if (needs_message && visible_effect)
3115             {
3116                 mprf("%s magical defenses are stripped away!",
3117                      def_name(DESC_ITS).c_str());
3118             }
3119         }
3120         break;
3121
3122     case AF_WEAKNESS_POISON:
3123         if (coinflip() && mons_do_poison())
3124             defender->weaken(attacker, 12);
3125         break;
3126
3127     case AF_SHADOWSTAB:
3128         attacker->as_monster()->del_ench(ENCH_INVIS, true);
3129         break;
3130
3131     case AF_DROWN:
3132         if (attacker->type == MONS_DROWNED_SOUL)
3133             attacker->as_monster()->suicide(-1000);
3134
3135         if (defender->res_water_drowning() <= 0)
3136         {
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;
3141
3142             if (needs_message)
3143             {
3144                 mprf("%s %s %s%s",
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());
3149             }
3150         }
3151         break;
3152
3153     case AF_FIREBRAND:
3154         base_damage = attacker->get_hit_dice()
3155                       + random2(attacker->get_hit_dice());
3156         special_damage =
3157             resist_adjust_damage(defender,
3158                                  BEAM_FIRE,
3159                                  base_damage);
3160         special_damage_flavour = BEAM_FIRE;
3161
3162         if (base_damage)
3163         {
3164             if (needs_message)
3165             {
3166                 mprf("The air around %s erupts in flames!",
3167                     defender_name(false).c_str());
3168
3169                 for (adjacent_iterator ai(defender->pos()); ai; ++ai)
3170                 {
3171                     if (!cell_is_solid(*ai)
3172                         && (env.cgrid(*ai) == EMPTY_CLOUD
3173                             || env.cloud[env.cgrid(*ai)].type == CLOUD_FIRE))
3174                     {
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)
3179                         {
3180                             continue;
3181                         }
3182
3183                         place_cloud(CLOUD_FIRE, *ai, 4 + random2(9), attacker);
3184                     }
3185                 }
3186
3187                 _print_resist_messages(defender, base_damage, BEAM_FIRE);
3188             }
3189         }
3190
3191         defender->expose_to_element(BEAM_FIRE, 2);
3192         break;
3193     }
3194 }
3195
3196 void melee_attack::do_passive_freeze()
3197 {
3198     if (you.mutation[MUT_PASSIVE_FREEZE]
3199         && attacker->alive()
3200         && adjacent(you.pos(), attacker->as_monster()->pos()))
3201     {
3202         bolt beam;
3203         beam.flavour = BEAM_COLD;
3204         beam.thrower = KILL_YOU;
3205
3206         monster* mon = attacker->as_monster();
3207
3208         const int orig_hurted = random2(11);
3209         int hurted = mons_adjust_flavoured(mon, beam, orig_hurted);
3210
3211         if (!hurted)
3212             return;
3213
3214         simple_monster_message(mon, " is very cold.");
3215
3216 #ifndef USE_TILE_LOCAL
3217         flash_monster_colour(mon, LIGHTBLUE, 200);
3218 #endif
3219
3220         mon->hurt(&you, hurted);
3221
3222         if (mon->alive())
3223         {
3224             mon->expose_to_element(BEAM_COLD, orig_hurted);
3225             print_wounds(mon);
3226         }
3227     }
3228 }
3229
3230 #if TAG_MAJOR_VERSION == 34
3231 void melee_attack::do_passive_heat()
3232 {
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)
3236     {
3237         bolt beam;
3238         beam.flavour = BEAM_FIRE;
3239         beam.thrower = KILL_YOU;
3240
3241         monster* mon = attacker->as_monster();
3242
3243         const int orig_hurted = random2(5);
3244         int hurted = mons_adjust_flavoured(mon, beam, orig_hurted);
3245
3246         if (!hurted)
3247             return;
3248
3249         simple_monster_message(mon, " is singed by your heat.");
3250
3251 #ifndef USE_TILE
3252         flash_monster_colour(mon, LIGHTRED, 200);
3253 #endif
3254
3255         mon->hurt(&you, hurted);
3256
3257         if (mon->alive())
3258         {
3259             mon->expose_to_element(BEAM_FIRE, orig_hurted);
3260             print_wounds(mon);
3261         }
3262     }
3263 }
3264 #endif
3265
3266 void melee_attack::mons_do_eyeball_confusion()
3267 {
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))
3272     {
3273         const int ench_pow = player_mutation_level(MUT_EYEBALLS) * 30;
3274         monster* mon = attacker->as_monster();
3275
3276         if (mon->check_res_magic(ench_pow) <= 0)
3277         {
3278             mprf("The eyeballs on your body gaze at %s.",
3279                  mon->name(DESC_THE).c_str());
3280
3281             if (!mon->check_clarity(false))
3282             {
3283                 mon->add_ench(mon_enchant(ENCH_CONFUSION, 0, &you,
3284                                           30 + random2(100)));
3285             }
3286         }
3287     }
3288 }
3289
3290 void melee_attack::do_spines()
3291 {
3292     // Monsters only get struck on their first attack per round
3293     if (attacker->is_monster() && effective_attack_number > 0)
3294         return;
3295
3296     if (defender->is_player())
3297     {
3298         const int mut = (you.form == TRAN_PORCUPINE) ? 3
3299                         : player_mutation_level(MUT_SPINY);
3300
3301         if (mut && attacker->alive()
3302             && x_chance_in_y(2, (13 - (mut * 2)) * 3))
3303         {
3304             int dmg = roll_dice(2 + div_rand_round(mut - 1, 2), 5);
3305             int hurt = attacker->apply_ac(dmg);
3306
3307             dprf(DIAG_COMBAT, "Spiny: dmg = %d hurt = %d", dmg, hurt);
3308
3309             if (hurt <= 0)
3310                 return;
3311
3312             simple_monster_message(attacker->as_monster(),
3313                                    " is struck by your spines.");
3314
3315             attacker->hurt(&you, hurt);
3316         }
3317     }
3318     else if (defender->as_monster()->is_spiny())
3319     {
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)
3325         {
3326             return;
3327         }
3328
3329         if (attacker->alive() && one_chance_in(3))
3330         {
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);
3334
3335             if (hurt <= 0)
3336                 return;
3337             if (you.can_see(defender) || attacker->is_player())
3338             {
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"
3343                                                         : "spines");
3344             }
3345             attacker->hurt(defender, hurt, BEAM_MISSILE, KILLED_BY_SPINES);
3346         }
3347     }
3348 }
3349
3350 void melee_attack::emit_foul_stench()
3351 {
3352     monster* mon = attacker->as_monster();
3353
3354     if (you.mutation[MUT_FOUL_STENCH]
3355         && attacker->alive()
3356         && adjacent(you.pos(), mon->pos()))
3357     {
3358         const int mut = player_mutation_level(MUT_FOUL_STENCH);
3359
3360         if (one_chance_in(3))
3361             mon->sicken(50 + random2(100));
3362
3363         if (damage_done > 4 && x_chance_in_y(mut, 5)
3364             && !cell_is_solid(mon->pos())
3365             && env.cgrid(mon->pos()) == EMPTY_CLOUD)
3366         {
3367             mpr("You emit a cloud of foul miasma!");
3368             place_cloud(CLOUD_MIASMA, mon->pos(), 5 + random2(6), &you);
3369         }
3370     }
3371 }
3372
3373 void melee_attack::do_minotaur_retaliation()
3374 {
3375     if (defender->cannot_act()
3376         || defender->confused()
3377         || !attacker->alive()
3378         || defender->is_player() && you.duration[DUR_LIFESAVING])
3379     {
3380         return;
3381     }
3382
3383     if (!defender->is_player())
3384     {
3385         // monsters have no STR or DEX
3386         if (x_chance_in_y(2, 5))
3387         {
3388             int hurt = attacker->apply_ac(random2(21));
3389             if (you.see_cell(defender->pos()))
3390             {
3391                 const string defname = defender->name(DESC_THE);
3392                 mprf("%s furiously retaliates!", defname.c_str());
3393                 if (hurt <= 0)
3394                 {
3395                     mprf("%s headbutts %s, but does no damage.", defname.c_str(),
3396                          attacker->name(DESC_THE).c_str());
3397                 }
3398                 else
3399                 {
3400                     mprf("%s headbutts %s%s", defname.c_str(),
3401                          attacker->name(DESC_THE).c_str(),
3402                          attack_strength_punctuation(hurt).c_str());
3403                 }
3404             }
3405             if (hurt > 0)
3406             {
3407                 attacker->hurt(defender, hurt, BEAM_MISSILE,
3408                                KILLED_BY_HEADBUTT);
3409             }
3410         }
3411         return;
3412     }
3413
3414     if (!form_keeps_mutations())
3415     {
3416         // You are in a non-minotaur form.
3417         return;
3418     }
3419     // This will usually be 2, but could be 3 if the player mutated more.
3420     const int mut = player_mutation_level(MUT_HORNS);
3421
3422     if (5 * you.strength() + 7 * you.dex() > random2(600))
3423     {
3424         // Use the same damage formula as a regular headbutt.
3425         int dmg = 5 + mut * 3;
3426         dmg = player_aux_stat_modify_damage(dmg);
3427         dmg = random2(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);
3433
3434         mpr("You furiously retaliate!");
3435         dprf(DIAG_COMBAT, "Retaliation: dmg = %d hurt = %d", dmg, hurt);
3436         if (hurt <= 0)
3437         {
3438             mprf("You headbutt %s, but do no damage.",
3439                  attacker->name(DESC_THE).c_str());
3440             return;
3441         }
3442         else
3443         {
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);
3448         }
3449     }
3450 }
3451
3452 bool melee_attack::do_knockback(bool trample)
3453 {
3454     if (defender->is_stationary())
3455         return false; // don't even print a message
3456
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;
3461
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
3466         // reaction here?
3467         || actor_at(new_pos)
3468         // Prevent trample/drown combo when flight is expiring