ee6211e2033f5b393f97dcd20f2d7a9bac2ad0e3
[crawl.git] / crawl-ref / source / attack.cc
1 /*
2  *  File:       attack.cc
3  *  Summary:    Methods of the attack class, generalized functions which may
4  *              be overloaded by inheriting classes.
5  *  Written by: Robert Burnham
6  */
7
8 #include "AppHdr.h"
9
10 #include "attack.h"
11
12 #include <algorithm>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cstring>
16
17 #include "art-enum.h"
18 #include "delay.h"
19 #include "english.h"
20 #include "env.h"
21 #include "exercise.h"
22 #include "fight.h"
23 #include "fineff.h"
24 #include "godconduct.h"
25 #include "itemname.h"
26 #include "itemprop.h"
27 #include "message.h"
28 #include "misc.h"
29 #include "mon-behv.h"
30 #include "mon-clone.h"
31 #include "mon-death.h"
32 #include "mon-poly.h"
33 #include "spl-miscast.h"
34 #include "state.h"
35 #include "stepdown.h"
36 #include "stringutil.h"
37 #include "transform.h"
38 #include "xom.h"
39
40 /*
41  **************************************************
42  *             BEGIN PUBLIC FUNCTIONS             *
43  **************************************************
44 */
45 attack::attack(actor *attk, actor *defn, actor *blame)
46     : attacker(attk), defender(defn), responsible(blame ? blame : attk),
47       attack_occurred(false), cancel_attack(false), did_hit(false),
48       needs_message(false), attacker_visible(false), defender_visible(false),
49       perceived_attack(false), obvious_effect(false), to_hit(0),
50       damage_done(0), special_damage(0), aux_damage(0), min_delay(0),
51       final_attack_delay(0), special_damage_flavour(BEAM_NONE),
52       stab_attempt(false), stab_bonus(0), apply_bleeding(false),
53       ev_margin(0), weapon(nullptr),
54       damage_brand(SPWPN_NORMAL), wpn_skill(SK_UNARMED_COMBAT),
55       shield(nullptr), art_props(0), unrand_entry(nullptr),
56       attacker_to_hit_penalty(0), attack_verb("bug"), verb_degree(),
57       no_damage_message(), special_damage_message(), aux_attack(), aux_verb(),
58       attacker_armour_tohit_penalty(0), attacker_shield_tohit_penalty(0),
59       defender_shield(nullptr), miscast_level(-1), miscast_type(SPTYP_NONE),
60       miscast_target(nullptr), fake_chaos_attack(false), simu(false),
61       aux_source(""), kill_type(KILLED_BY_MONSTER)
62 {
63     // No effective code should execute, we'll call init_attack again from
64     // the child class, since initializing an attack will vary based the within
65     // type of attack actually being made (melee, ranged, etc.)
66 }
67
68 bool attack::handle_phase_attempted()
69 {
70     return true;
71 }
72
73 bool attack::handle_phase_blocked()
74 {
75     damage_done = 0;
76     return true;
77 }
78
79 bool attack::handle_phase_damaged()
80 {
81     // We have to check in_bounds() because removed kraken tentacles are
82     // temporarily returned to existence (without a position) when they
83     // react to damage.
84     if (defender->can_bleed()
85         && !defender->is_summoned()
86         && !defender->submerged()
87         && in_bounds(defender->pos())
88         && !simu)
89     {
90         int blood = damage_done;
91         if (blood > defender->stat_hp())
92             blood = defender->stat_hp();
93         if (blood)
94             blood_fineff::schedule(defender, defender->pos(), blood);
95     }
96
97     announce_hit();
98     // Inflict stored damage
99     damage_done = inflict_damage(damage_done);
100
101     // TODO: Unify these, added here so we can get rid of player_attack
102     if (attacker->is_player())
103     {
104         if (damage_done)
105             player_exercise_combat_skills();
106
107         if (defender->alive())
108         {
109             // Actually apply the bleeding effect, this can come from an
110             // aux claw or a main hand claw attack and up to now has not
111             // actually happened.
112             const int degree = you.has_usable_claws();
113             if (apply_bleeding && defender->can_bleed()
114                 && degree > 0 && damage_done > 0)
115             {
116                 defender->as_monster()->bleed(attacker,
117                                               3 + roll_dice(degree, 3),
118                                               degree);
119             }
120         }
121     }
122     else
123     {
124         if (!mons_attack_effects())
125             return false;
126     }
127
128     // It's okay if a monster took lethal damage, but we should stop
129     // the combat if it was already reset (e.g. a spectral weapon that
130     // took damage and then noticed that its caster is gone).
131     return defender->is_player() || !invalid_monster(defender->as_monster());
132 }
133
134 bool attack::handle_phase_killed()
135 {
136     monster * const mon = defender->as_monster();
137     if (!invalid_monster(mon))
138         monster_die(mon, attacker);
139
140     return true;
141 }
142
143 bool attack::handle_phase_end()
144 {
145     // This may invalidate both the attacker and defender.
146     fire_final_effects();
147
148     return true;
149 }
150
151 /**
152  * Calculate the to-hit for an attacker
153  *
154  * @param random If false, calculate average to-hit deterministically.
155  */
156 int attack::calc_to_hit(bool random)
157 {
158     int mhit = attacker->is_player() ?
159                 15 + (calc_stat_to_hit_base() / 2)
160               : calc_mon_to_hit_base();
161
162 #ifdef DEBUG_DIAGNOSTICS
163     const int base_hit = mhit;
164 #endif
165
166     // This if statement is temporary, it should be removed when the
167     // implementation of a more universal (and elegant) to-hit calculation
168     // is designed. The actual code is copied from the old mons_to_hit and
169     // player_to_hit methods.
170     if (attacker->is_player())
171     {
172         // fighting contribution
173         mhit += maybe_random_div(you.skill(SK_FIGHTING, 100), 100, random);
174
175         // weapon skill contribution
176         if (using_weapon())
177         {
178             if (wpn_skill != SK_FIGHTING)
179             {
180                 if (you.skill(wpn_skill) < 1 && player_in_a_dangerous_place())
181                     xom_is_stimulated(10); // Xom thinks that is mildly amusing.
182
183                 mhit += maybe_random_div(you.skill(wpn_skill, 100), 100,
184                                          random);
185             }
186         }
187         else if (you.form_uses_xl())
188             mhit += maybe_random_div(you.experience_level * 100, 100, random);
189         else
190         {                       // ...you must be unarmed or throwing
191             // Members of clawed species have presumably been using the claws,
192             // making them more practiced and thus more accurate in unarmed
193             // combat. They keep this benefit even when the claws are covered
194             // (or missing because of a change in form).
195             mhit += you.innate_mutation[MUT_CLAWS]
196                     && wpn_skill == SK_UNARMED_COMBAT ? 4 : 2;
197
198             mhit += maybe_random_div(you.skill(wpn_skill, 100), 100,
199                                      random);
200         }
201
202         // weapon bonus contribution
203         if (using_weapon())
204         {
205             if (weapon->base_type == OBJ_WEAPONS)
206             {
207                 mhit += weapon->plus;
208                 mhit += property(*weapon, PWPN_HIT);
209             }
210             else if (weapon->base_type == OBJ_STAVES)
211                 mhit += property(*weapon, PWPN_HIT);
212             else if (weapon->base_type == OBJ_RODS)
213             {
214                 mhit += property(*weapon, PWPN_HIT);
215                 mhit += weapon->special;
216             }
217         }
218
219         // slaying bonus
220         mhit += slaying_bonus(wpn_skill == SK_THROWING
221                               || (weapon && is_range_weapon(*weapon)
222                                          && using_weapon()));
223
224         // horror penalty
225         if (you.duration[DUR_HORROR])
226             mhit -= you.props[HORROR_PENALTY_KEY].get_int();
227
228         // hunger penalty
229         if (you.hunger_state == HS_STARVING)
230             mhit -= 3;
231
232         // armour penalty
233         mhit -= (attacker_armour_tohit_penalty + attacker_shield_tohit_penalty);
234
235         // mutation
236         if (player_mutation_level(MUT_EYEBALLS))
237             mhit += 2 * player_mutation_level(MUT_EYEBALLS) + 1;
238
239         // hit roll
240         mhit = maybe_random2(mhit, random);
241     }
242     else    // Monster to-hit.
243     {
244         if (using_weapon())
245             mhit += weapon->plus + property(*weapon, PWPN_HIT);
246
247         const int jewellery = attacker->as_monster()->inv[MSLOT_JEWELLERY];
248         if (jewellery != NON_ITEM
249             && mitm[jewellery].is_type(OBJ_JEWELLERY, RING_SLAYING))
250         {
251             mhit += mitm[jewellery].plus;
252         }
253
254         mhit += attacker->scan_artefacts(ARTP_SLAYING);
255
256         if (using_weapon() && weapon->base_type == OBJ_RODS)
257             mhit += weapon->special;
258     }
259
260     // Penalties for both players and monsters:
261
262     if (attacker->inaccuracy())
263         mhit -= 5;
264
265     // If you can't see yourself, you're a little less accurate.
266     if (!attacker->visible_to(attacker))
267         mhit -= 5;
268
269     if (attacker->confused())
270         mhit -= 5;
271
272     if (using_weapon() && is_unrandom_artefact(*weapon, UNRAND_WOE))
273         return AUTOMATIC_HIT;
274
275     // If no defender, we're calculating to-hit for debug-display
276     // purposes, so don't drop down to defender code below
277     if (defender == nullptr)
278         return mhit;
279
280     if (!defender->visible_to(attacker))
281         if (attacker->is_player())
282             mhit -= 6;
283         else
284             mhit = mhit * 65 / 100;
285     else
286     {
287         // This can only help if you're visible!
288         const int how_transparent = player_mutation_level(MUT_TRANSLUCENT_SKIN);
289         if (defender->is_player() && how_transparent)
290             mhit -= 2 * how_transparent;
291
292         if (defender->backlit(false))
293             mhit += 2 + random2(8);
294         else if (!attacker->nightvision()
295                  && defender->umbra())
296             mhit -= 2 + random2(4);
297     }
298     // Don't delay doing this roll until test_hit().
299     if (!attacker->is_player())
300         mhit = random2(mhit + 1);
301
302     dprf(DIAG_COMBAT, "%s: Base to-hit: %d, Final to-hit: %d",
303          attacker->name(DESC_PLAIN).c_str(),
304          base_hit, mhit);
305
306     return mhit;
307 }
308
309 /* Returns an actor's name
310  *
311  * Takes into account actor visibility/invisibility and the type of description
312  * to be used (capitalization, possessiveness, etc.)
313  */
314 string attack::actor_name(const actor *a, description_level_type desc,
315                           bool actor_visible)
316 {
317     return actor_visible ? a->name(desc) : anon_name(desc);
318 }
319
320 /* Returns an actor's pronoun
321  *
322  * Takes into account actor visibility
323  */
324 string attack::actor_pronoun(const actor *a, pronoun_type pron,
325                              bool actor_visible)
326 {
327     return actor_visible ? a->pronoun(pron) : anon_pronoun(pron);
328 }
329
330 /* Returns an anonymous actor's name
331  *
332  * Given the actor visible or invisible, returns the
333  * appropriate possessive pronoun.
334  */
335 string attack::anon_name(description_level_type desc)
336 {
337     switch (desc)
338     {
339     case DESC_NONE:
340         return "";
341     case DESC_YOUR:
342     case DESC_ITS:
343         return "its";
344     case DESC_THE:
345     case DESC_A:
346     case DESC_PLAIN:
347     default:
348         return "something";
349     }
350 }
351
352 /* Returns an anonymous actor's pronoun
353  *
354  * Given invisibility (whether out of LOS or just invisible), returns the
355  * appropriate possessive, inflexive, capitalised pronoun.
356  */
357 string attack::anon_pronoun(pronoun_type pron)
358 {
359     return decline_pronoun(GENDER_NEUTER, pron);
360 }
361
362 /* Initializes an attack, setting up base variables and values
363  *
364  * Does not make any changes to any actors, items, or the environment,
365  * in case the attack is cancelled or otherwise fails. Only initializations
366  * that are universal to all types of attacks should go into this method,
367  * any initialization properties that are specific to one attack or another
368  * should go into their respective init_attack.
369  *
370  * Although this method will get overloaded by the derived class, we are
371  * calling it from attack::attack(), before the overloading has taken place.
372  */
373 void attack::init_attack(skill_type unarmed_skill, int attack_number)
374 {
375     weapon          = attacker->weapon(attack_number);
376
377     wpn_skill       = weapon ? item_attack_skill(*weapon) : unarmed_skill;
378     if (attacker->is_player() && you.form_uses_xl())
379         wpn_skill = SK_FIGHTING; // for stabbing, mostly
380
381     attacker_armour_tohit_penalty =
382         div_rand_round(attacker->armour_tohit_penalty(true, 20), 20);
383     attacker_shield_tohit_penalty =
384         div_rand_round(attacker->shield_tohit_penalty(true, 20), 20);
385     to_hit          = calc_to_hit(true);
386
387     shield = attacker->shield();
388     defender_shield = defender ? defender->shield() : defender_shield;
389
390     if (weapon && weapon->base_type == OBJ_WEAPONS && is_artefact(*weapon))
391     {
392         artefact_properties(*weapon, art_props);
393         if (is_unrandom_artefact(*weapon))
394             unrand_entry = get_unrand_entry(weapon->special);
395     }
396
397     attacker_visible   = attacker->observable();
398     defender_visible   = defender && defender->observable();
399     needs_message      = (attacker_visible || defender_visible);
400
401     if (attacker->is_monster())
402     {
403         mon_attack_def mon_attk = mons_attack_spec(attacker->as_monster(),
404                                                    attack_number);
405
406         attk_type       = mon_attk.type;
407         attk_flavour    = mon_attk.flavour;
408
409         // Don't scale damage for YOU_FAULTLESS etc.
410         if (attacker->get_experience_level() == 0)
411             attk_damage = mon_attk.damage;
412         else
413         {
414             attk_damage = div_rand_round(mon_attk.damage
415                                              * attacker->get_hit_dice(),
416                                          attacker->get_experience_level());
417         }
418
419         if (attk_type == AT_WEAP_ONLY)
420         {
421             int weap = attacker->as_monster()->inv[MSLOT_WEAPON];
422             if (weap == NON_ITEM || is_range_weapon(mitm[weap]))
423                 attk_type = AT_NONE;
424             else
425                 attk_type = AT_HIT;
426         }
427         else if (attk_type == AT_TRUNK_SLAP && attacker->type == MONS_SKELETON)
428         {
429             // Elephant trunks have no bones inside.
430             attk_type = AT_NONE;
431         }
432     }
433     else
434     {
435         attk_type    = AT_HIT;
436         attk_flavour = AF_PLAIN;
437     }
438 }
439
440 void attack::alert_defender()
441 {
442     // Allow monster attacks to draw the ire of the defender. Player
443     // attacks are handled elsewhere.
444     if (perceived_attack
445         && defender->is_monster()
446         && attacker->is_monster()
447         && attacker->alive() && defender->alive()
448         && (defender->as_monster()->foe == MHITNOT || one_chance_in(3)))
449     {
450         behaviour_event(defender->as_monster(), ME_WHACK, attacker);
451     }
452
453     // If an enemy attacked a friend, set the pet target if it isn't set
454     // already, but not if sanctuary is in effect (pet target must be
455     // set explicitly by the player during sanctuary).
456     if (perceived_attack && attacker->alive()
457         && (defender->is_player() || defender->as_monster()->friendly())
458         && !attacker->is_player()
459         && !crawl_state.game_is_arena()
460         && !attacker->as_monster()->wont_attack())
461     {
462         if (defender->is_player())
463             interrupt_activity(AI_MONSTER_ATTACKS, attacker->as_monster());
464         if (you.pet_target == MHITNOT && env.sanctuary_time <= 0)
465             you.pet_target = attacker->mindex();
466     }
467 }
468
469 bool attack::distortion_affects_defender()
470 {
471     //jmf: blink frogs *like* distortion
472     // I think could be amended to let blink frogs "grow" like
473     // jellies do {dlb}
474     if (defender->is_monster()
475         && mons_genus(defender->type) == MONS_BLINK_FROG)
476     {
477         if (one_chance_in(5))
478         {
479             if (defender_visible)
480             {
481                 special_damage_message =
482                     make_stringf("%s %s in the distortional energy.",
483                                  defender_name(false).c_str(),
484                                  defender->conj_verb("bask").c_str());
485             }
486
487             defender->heal(1 + random2avg(7, 2), true); // heh heh
488         }
489         return false;
490     }
491
492     if (one_chance_in(3))
493     {
494         special_damage_message =
495             make_stringf("Space bends around %s.",
496             defender_name(false).c_str());
497         special_damage += 1 + random2avg(7, 2);
498         return false;
499     }
500
501     if (one_chance_in(3))
502     {
503         special_damage_message =
504             make_stringf("Space warps horribly around %s!",
505                          defender_name(false).c_str());
506         special_damage += 3 + random2avg(24, 2);
507         return false;
508     }
509
510     if (simu)
511         return false;
512
513     if (one_chance_in(3))
514     {
515         if (defender_visible)
516             obvious_effect = true;
517         if (!defender->no_tele(true, false))
518             blink_fineff::schedule(defender);
519         return false;
520     }
521
522     if (!one_chance_in(3))
523     {
524         if (defender_visible)
525             obvious_effect = true;
526         if (crawl_state.game_is_sprint() && defender->is_player()
527             || defender->no_tele())
528         {
529             if (defender->is_player())
530                 canned_msg(MSG_STRANGE_STASIS);
531         }
532         else if (coinflip())
533             distortion_tele_fineff::schedule(defender);
534         else
535             defender->teleport();
536         return false;
537     }
538
539     if (!player_in_branch(BRANCH_ABYSS) && coinflip())
540     {
541         if (defender_visible)
542             obvious_effect = true;
543
544         defender->banish(attacker, attacker->name(DESC_PLAIN, true));
545         return true;
546     }
547
548     return false;
549 }
550
551 void attack::antimagic_affects_defender(int pow)
552 {
553     obvious_effect =
554         enchant_actor_with_flavour(defender, nullptr, BEAM_DRAIN_MAGIC, pow);
555 }
556
557 void attack::pain_affects_defender()
558 {
559     if (defender->res_negative_energy())
560         return;
561
562     if (!one_chance_in(attacker->skill_rdiv(SK_NECROMANCY) + 1))
563     {
564         if (defender_visible)
565         {
566             special_damage_message =
567                 make_stringf("%s %s in agony.",
568                              defender->name(DESC_THE).c_str(),
569                              defender->conj_verb("writhe").c_str());
570         }
571         special_damage += random2(1 + attacker->skill_rdiv(SK_NECROMANCY));
572     }
573
574     attacker->god_conduct(DID_NECROMANCY, 4);
575 }
576
577 // TODO: Move this somewhere sane
578 enum chaos_type
579 {
580     CHAOS_CLONE,
581     CHAOS_POLY,
582     CHAOS_POLY_UP,
583     CHAOS_MAKE_SHIFTER,
584     CHAOS_MISCAST,
585     CHAOS_RAGE,
586     CHAOS_HEAL,
587     CHAOS_HASTE,
588     CHAOS_INVIS,
589     CHAOS_SLOW,
590     CHAOS_PARALYSIS,
591     CHAOS_PETRIFY,
592     NUM_CHAOS_TYPES
593 };
594
595 // XXX: We might want to vary the probabilities for the various effects
596 // based on whether the source is a weapon of chaos or a monster with
597 // AF_CHAOS.
598 void attack::chaos_affects_defender()
599 {
600     monster * const mon   = defender->as_monster();
601     const bool firewood   = mon && mons_is_firewood(mon);
602     const bool immune     = mon && mons_immune_magic(mon);
603     const bool is_natural = mon && defender->holiness() == MH_NATURAL;
604     const bool is_shifter = mon && mon->is_shapeshifter();
605     const bool can_clone  = mon && mons_clonable(mon, true);
606     const bool can_poly   = is_shifter || (defender->can_safely_mutate()
607                                            && !immune && !firewood);
608     const bool can_rage   = defender->can_go_berserk();
609     const bool can_slow   = !firewood;
610     const bool can_petrify= mon && !defender->res_petrify();
611
612     int clone_chance   = can_clone                      ?  1 : 0;
613     int poly_chance    = can_poly                       ?  1 : 0;
614     int poly_up_chance = can_poly                && mon ?  1 : 0;
615     int shifter_chance = can_poly  && is_natural && mon ?  1 : 0;
616     int rage_chance    = can_rage                       ? 10 : 0;
617     int miscast_chance = 10;
618     int slowpara_chance= can_slow                       ? 10 : 0;
619     int petrify_chance = can_slow && can_petrify        ? 10 : 0;
620
621     // Already a shifter?
622     if (is_shifter)
623         shifter_chance = 0;
624
625     // A chaos self-attack increases the chance of certain effects,
626     // due to a short-circuit/feedback/resonance/whatever.
627     if (attacker == defender)
628     {
629         clone_chance   *= 2;
630         poly_chance    *= 2;
631         poly_up_chance *= 2;
632         shifter_chance *= 2;
633         miscast_chance *= 2;
634
635         // Inform player that something is up.
636         if (!fake_chaos_attack && you.see_cell(defender->pos()))
637         {
638             if (defender->is_player())
639                 mpr("You give off a flash of multicoloured light!");
640             else if (you.can_see(defender))
641             {
642                 simple_monster_message(mon, " gives off a flash of"
643                                             " multicoloured light!");
644             }
645             else
646                 mpr("There is a flash of multicoloured light!");
647         }
648     }
649
650     // NOTE: Must appear in exact same order as in chaos_type enumeration.
651     int probs[NUM_CHAOS_TYPES] =
652     {
653         clone_chance,   // CHAOS_CLONE
654         poly_chance,    // CHAOS_POLY
655         poly_up_chance, // CHAOS_POLY_UP
656         shifter_chance, // CHAOS_MAKE_SHIFTER
657         miscast_chance, // CHAOS_MISCAST
658         rage_chance,    // CHAOS_RAGE
659
660         10,             // CHAOS_HEAL
661         slowpara_chance,// CHAOS_HASTE
662         10,             // CHAOS_INVIS
663
664         slowpara_chance,// CHAOS_SLOW
665         slowpara_chance,// CHAOS_PARALYSIS
666         petrify_chance, // CHAOS_PETRIFY
667     };
668
669     bolt beam;
670     beam.flavour = BEAM_NONE;
671
672     int choice = choose_random_weighted(probs, probs + NUM_CHAOS_TYPES);
673 #ifdef NOTE_DEBUG_CHAOS_EFFECTS
674     string chaos_effect = "CHAOS effect: ";
675     switch (choice)
676     {
677     case CHAOS_CLONE:           chaos_effect += "clone"; break;
678     case CHAOS_POLY:            chaos_effect += "polymorph"; break;
679     case CHAOS_POLY_UP:         chaos_effect += "polymorph PPT_MORE"; break;
680     case CHAOS_MAKE_SHIFTER:    chaos_effect += "shifter"; break;
681     case CHAOS_MISCAST:         chaos_effect += "miscast"; break;
682     case CHAOS_RAGE:            chaos_effect += "berserk"; break;
683     case CHAOS_HEAL:            chaos_effect += "healing"; break;
684     case CHAOS_HASTE:           chaos_effect += "hasting"; break;
685     case CHAOS_INVIS:           chaos_effect += "invisible"; break;
686     case CHAOS_SLOW:            chaos_effect += "slowing"; break;
687     case CHAOS_PARALYSIS:       chaos_effect += "paralysis"; break;
688     case CHAOS_PETRIFY:         chaos_effect += "petrify"; break;
689     default:                    chaos_effect += "(other)"; break;
690     }
691
692     take_note(Note(NOTE_MESSAGE, 0, 0, chaos_effect.c_str()), true);
693 #endif
694
695     switch (static_cast<chaos_type>(choice))
696     {
697     case CHAOS_CLONE:
698     {
699         ASSERT(can_clone);
700         ASSERT(clone_chance > 0);
701         ASSERT(defender->is_monster());
702
703         if (monster *clone = clone_mons(mon, true, &obvious_effect))
704         {
705             if (obvious_effect)
706             {
707                 special_damage_message =
708                     make_stringf("%s is duplicated!",
709                                  defender_name(false).c_str());
710             }
711
712             // The player shouldn't get new permanent followers from cloning.
713             if (clone->attitude == ATT_FRIENDLY && !clone->is_summoned())
714                 clone->mark_summoned(6, true, MON_SUMM_CLONE);
715
716             // Monsters being cloned is interesting.
717             xom_is_stimulated(clone->friendly() ? 12 : 25);
718         }
719         break;
720     }
721
722     case CHAOS_POLY:
723         ASSERT(can_poly);
724         ASSERT(poly_chance > 0);
725         beam.flavour = BEAM_POLYMORPH;
726         break;
727
728     case CHAOS_POLY_UP:
729         ASSERT(can_poly);
730         ASSERT(poly_up_chance > 0);
731         ASSERT(defender->is_monster());
732
733         obvious_effect = you.can_see(defender);
734         monster_polymorph(mon, RANDOM_MONSTER, PPT_MORE);
735         break;
736
737     case CHAOS_MAKE_SHIFTER:
738     {
739         ASSERT(can_poly);
740         ASSERT(shifter_chance > 0);
741         ASSERT(!is_shifter);
742         ASSERT(defender->is_monster());
743
744         obvious_effect = you.can_see(defender);
745         mon->add_ench(one_chance_in(3) ? ENCH_GLOWING_SHAPESHIFTER
746                                        : ENCH_SHAPESHIFTER);
747         // Immediately polymorph monster, just to make the effect obvious.
748         monster_polymorph(mon, RANDOM_MONSTER);
749
750         // Xom loves it if this happens!
751         const int friend_factor = mon->friendly() ? 1 : 2;
752         const int glow_factor   = mon->has_ench(ENCH_SHAPESHIFTER) ? 1 : 2;
753         xom_is_stimulated(64 * friend_factor * glow_factor);
754         break;
755     }
756     case CHAOS_MISCAST:
757     {
758         int level = defender->get_hit_dice();
759
760         // At level == 27 there's a 13.9% chance of a level 3 miscast.
761         int level0_chance = level;
762         int level1_chance = max(0, level - 7);
763         int level2_chance = max(0, level - 12);
764         int level3_chance = max(0, level - 17);
765
766         level = random_choose_weighted(
767             level0_chance, 0,
768             level1_chance, 1,
769             level2_chance, 2,
770             level3_chance, 3,
771             0);
772
773         miscast_level  = level;
774         miscast_type   = SPTYP_RANDOM;
775         miscast_target = defender;
776         break;
777     }
778
779     case CHAOS_RAGE:
780         ASSERT(can_rage);
781         ASSERT(rage_chance > 0);
782         defender->go_berserk(false);
783         obvious_effect = you.can_see(defender);
784         break;
785
786     // For these, obvious_effect is computed during beam.fire() below.
787     case CHAOS_HEAL:
788         beam.flavour = BEAM_HEALING;
789         break;
790     case CHAOS_HASTE:
791         beam.flavour = BEAM_HASTE;
792         break;
793     case CHAOS_INVIS:
794         beam.flavour = BEAM_INVISIBILITY;
795         break;
796     case CHAOS_SLOW:
797         beam.flavour = BEAM_SLOW;
798         break;
799     case CHAOS_PARALYSIS:
800         beam.flavour = BEAM_PARALYSIS;
801         break;
802     case CHAOS_PETRIFY:
803         beam.flavour = BEAM_PETRIFY;
804         break;
805
806     default:
807         die("Invalid chaos effect type");
808         break;
809     }
810
811     if (beam.flavour != BEAM_NONE)
812     {
813         beam.glyph        = 0;
814         beam.range        = 0;
815         beam.colour       = BLACK;
816         beam.effect_known = false;
817         // Wielded brand is always known, but maybe this was from a call
818         // to chaos_affect_actor.
819         beam.effect_wanton = !fake_chaos_attack;
820
821         if (using_weapon() && you.can_see(attacker))
822         {
823             beam.name = wep_name(DESC_YOUR);
824             beam.item = weapon;
825         }
826         else
827             beam.name = atk_name(DESC_THE);
828
829         beam.thrower =
830             (attacker->is_player())           ? KILL_YOU
831             : attacker->as_monster()->confused_by_you() ? KILL_YOU_CONF
832                                                         : KILL_MON;
833
834         if (beam.thrower == KILL_YOU || attacker->as_monster()->friendly())
835             beam.attitude = ATT_FRIENDLY;
836
837         beam.source_id = attacker->mid;
838
839         beam.source = defender->pos();
840         beam.target = defender->pos();
841
842         beam.damage = dice_def(damage_done + special_damage + aux_damage, 1);
843
844         beam.ench_power = beam.damage.num;
845
846         const bool you_could_see = you.can_see(defender);
847         beam.fire();
848
849         if (you_could_see)
850             obvious_effect = beam.obvious_effect;
851     }
852
853     if (!you.can_see(attacker))
854         obvious_effect = false;
855 }
856
857 // NOTE: random_chaos_brand() and random_chaos_attack_flavour() should
858 // return a set of effects that are roughly the same, to make it easy
859 // for chaos_affects_defender() not to do duplicate effects caused
860 // by the non-chaos brands/flavours they return.
861 brand_type attack::random_chaos_brand()
862 {
863     brand_type brand = SPWPN_NORMAL;
864     // Assuming the chaos to be mildly intelligent, try to avoid brands
865     // that clash with the most basic resists of the defender,
866     // i.e. its holiness.
867     while (true)
868     {
869         brand = (random_choose_weighted(
870                      5, SPWPN_VORPAL,
871                     10, SPWPN_FLAMING,
872                     10, SPWPN_FREEZING,
873                     10, SPWPN_ELECTROCUTION,
874                     10, SPWPN_VENOM,
875                     10, SPWPN_CHAOS,
876                      5, SPWPN_DRAINING,
877                      5, SPWPN_VAMPIRISM,
878                      5, SPWPN_HOLY_WRATH,
879                      5, SPWPN_ANTIMAGIC,
880                      2, SPWPN_CONFUSE,
881                      2, SPWPN_DISTORTION,
882                      0));
883
884         if (one_chance_in(3))
885             break;
886
887         bool susceptible = true;
888         switch (brand)
889         {
890         case SPWPN_FLAMING:
891             if (defender->is_fiery())
892                 susceptible = false;
893             break;
894         case SPWPN_FREEZING:
895             if (defender->is_icy())
896                 susceptible = false;
897             break;
898         case SPWPN_VENOM:
899             if (defender->holiness() == MH_UNDEAD)
900                 susceptible = false;
901             break;
902         case SPWPN_VAMPIRISM:
903             if (defender->is_summoned())
904             {
905                 susceptible = false;
906                 break;
907             }
908             // intentional fall-through
909         case SPWPN_DRAINING:
910             if (defender->holiness() != MH_NATURAL)
911                 susceptible = false;
912             break;
913         case SPWPN_HOLY_WRATH:
914             if (!defender->holy_wrath_susceptible())
915                 susceptible = false;
916             break;
917         case SPWPN_CONFUSE:
918             if (defender->holiness() == MH_NONLIVING
919                 || defender->holiness() == MH_PLANT)
920             {
921                 susceptible = false;
922             }
923             break;
924         case SPWPN_ANTIMAGIC:
925             if (!defender->antimagic_susceptible())
926                 susceptible = false;
927             break;
928         default:
929             break;
930         }
931
932         if (susceptible)
933             break;
934     }
935 #ifdef NOTE_DEBUG_CHAOS_BRAND
936     string brand_name = "CHAOS brand: ";
937     switch (brand)
938     {
939     case SPWPN_NORMAL:          brand_name += "(plain)"; break;
940     case SPWPN_FLAMING:         brand_name += "flaming"; break;
941     case SPWPN_FREEZING:        brand_name += "freezing"; break;
942     case SPWPN_HOLY_WRATH:      brand_name += "holy wrath"; break;
943     case SPWPN_ELECTROCUTION:   brand_name += "electrocution"; break;
944     case SPWPN_VENOM:           brand_name += "venom"; break;
945     case SPWPN_DRAINING:        brand_name += "draining"; break;
946     case SPWPN_DISTORTION:      brand_name += "distortion"; break;
947     case SPWPN_VAMPIRISM:     brand_name += "vampirism"; break;
948     case SPWPN_VORPAL:          brand_name += "vorpal"; break;
949     case SPWPN_ANTIMAGIC:       brand_name += "antimagic"; break;
950
951     // both ranged and non-ranged
952     case SPWPN_CHAOS:           brand_name += "chaos"; break;
953     case SPWPN_CONFUSE:         brand_name += "confusion"; break;
954     default:                    brand_name += "(other)"; break;
955     }
956
957     // Pretty much duplicated by the chaos effect note,
958     // which will be much more informative.
959     if (brand != SPWPN_CHAOS)
960         take_note(Note(NOTE_MESSAGE, 0, 0, brand_name.c_str()), true);
961 #endif
962     return brand;
963 }
964
965 void attack::do_miscast()
966 {
967     if (miscast_level == -1)
968         return;
969
970     ASSERT(miscast_target != nullptr);
971     ASSERT_RANGE(miscast_level, 0, 4);
972     ASSERT(count_bits(miscast_type) == 1);
973
974     if (!miscast_target->alive())
975         return;
976
977     if (miscast_target->is_player() && you.banished)
978         return;
979
980     const bool chaos_brand =
981         using_weapon() && get_weapon_brand(*weapon) == SPWPN_CHAOS;
982
983     // If the miscast is happening on the attacker's side and is due to
984     // a chaos weapon then make smoke/sand/etc pour out of the weapon
985     // instead of the attacker's hands.
986     string hand_str;
987
988     string cause = atk_name(DESC_THE);
989
990     const int ignore_mask = ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES;
991
992     if (attacker->is_player())
993     {
994         if (chaos_brand)
995         {
996             cause = "a chaos effect from ";
997             // Ignore a lot of item flags to make cause as short as possible,
998             // so it will (hopefully) fit onto a single line in the death
999             // cause screen.
1000             cause += wep_name(DESC_YOUR, ignore_mask | ISFLAG_COSMETIC_MASK);
1001
1002             if (miscast_target == attacker)
1003                 hand_str = wep_name(DESC_PLAIN, ignore_mask);
1004         }
1005     }
1006     else
1007     {
1008         if (chaos_brand && miscast_target == attacker
1009             && you.can_see(attacker))
1010         {
1011             hand_str = wep_name(DESC_PLAIN, ignore_mask);
1012         }
1013     }
1014
1015     MiscastEffect(miscast_target, attacker, MELEE_MISCAST,
1016                   (spschool_flag_type) miscast_type, miscast_level, cause,
1017                   NH_NEVER, 0, hand_str, false);
1018
1019     // Don't do miscast twice for one attack.
1020     miscast_level = -1;
1021 }
1022
1023 void attack::drain_defender()
1024 {
1025     if (defender->is_monster() && coinflip())
1026         return;
1027
1028     if (defender->holiness() != MH_NATURAL)
1029         return;
1030
1031     special_damage = resist_adjust_damage(defender, BEAM_NEG,
1032                                           (1 + random2(damage_done)) / 2);
1033
1034     if (defender->drain_exp(attacker, true, 20 + min(35, damage_done)))
1035     {
1036         if (defender->is_player())
1037             obvious_effect = true;
1038         else if (defender_visible)
1039         {
1040             special_damage_message =
1041                 make_stringf(
1042                     "%s %s %s!",
1043                     atk_name(DESC_THE).c_str(),
1044                     attacker->conj_verb("drain").c_str(),
1045                     defender_name(true).c_str());
1046         }
1047
1048         attacker->god_conduct(DID_NECROMANCY, 2);
1049     }
1050 }
1051
1052 void attack::drain_defender_speed()
1053 {
1054     if (!defender->res_negative_energy())
1055     {
1056         if (needs_message)
1057         {
1058             mprf("%s %s %s vigour!",
1059                  atk_name(DESC_THE).c_str(),
1060                  attacker->conj_verb("drain").c_str(),
1061                  def_name(DESC_ITS).c_str());
1062         }
1063
1064         special_damage = 1 + random2(damage_done) / 2;
1065         defender->slow_down(attacker, 5 + random2(7));
1066     }
1067 }
1068
1069 int attack::inflict_damage(int dam, beam_type flavour, bool clean)
1070 {
1071     if (flavour == NUM_BEAMS)
1072         flavour = special_damage_flavour;
1073     // Auxes temporarily clear damage_brand so we don't need to check
1074     if (damage_brand == SPWPN_REAPING ||
1075         damage_brand == SPWPN_CHAOS && one_chance_in(100))
1076     {
1077         defender->props["reaping_damage"].get_int() += dam;
1078         // With two reapers of different friendliness, the most recent one
1079         // gets the zombie. Too rare a case to care any more.
1080         defender->props["reaper"].get_int() = attacker->mid;
1081     }
1082     return defender->hurt(responsible, dam, flavour, kill_type,
1083                           "", aux_source.c_str(), clean);
1084 }
1085
1086 /* If debug, return formatted damage done
1087  *
1088  */
1089 string attack::debug_damage_number()
1090 {
1091 #ifdef DEBUG_DIAGNOSTICS
1092     return make_stringf(" for %d", damage_done);
1093 #else
1094     return "";
1095 #endif
1096 }
1097
1098 /* Returns standard attack punctuation
1099  *
1100  * Used in player / monster (both primary and aux) attacks
1101  */
1102 string attack::attack_strength_punctuation(int dmg)
1103 {
1104     if (dmg < HIT_WEAK)
1105         return ".";
1106     else if (dmg < HIT_MED)
1107         return "!";
1108     else if (dmg < HIT_STRONG)
1109         return "!!";
1110     else
1111     {
1112         string ret = "!!!";
1113         int tmpdamage = dmg;
1114         while (tmpdamage >= 2*HIT_STRONG)
1115         {
1116             ret += "!";
1117             tmpdamage >>= 1;
1118         }
1119         return ret;
1120     }
1121 }
1122
1123 /* Returns evasion adverb
1124  *
1125  */
1126 string attack::evasion_margin_adverb()
1127 {
1128     return (ev_margin <= -20) ? " completely" :
1129            (ev_margin <= -12) ? "" :
1130            (ev_margin <= -6)  ? " closely"
1131                               : " barely";
1132 }
1133
1134 void attack::stab_message()
1135 {
1136     defender->props["helpless"] = true;
1137
1138     switch (stab_bonus)
1139     {
1140     case 6:     // big melee, monster surrounded/not paying attention
1141         if (coinflip())
1142         {
1143             mprf("You %s %s from a blind spot!",
1144                   (you.species == SP_FELID) ? "pounce on" : "strike",
1145                   defender->name(DESC_THE).c_str());
1146         }
1147         else
1148         {
1149             mprf("You catch %s momentarily off-guard.",
1150                   defender->name(DESC_THE).c_str());
1151         }
1152         break;
1153     case 4:     // confused/fleeing
1154         if (!one_chance_in(3))
1155         {
1156             mprf("You catch %s completely off-guard!",
1157                   defender->name(DESC_THE).c_str());
1158         }
1159         else
1160         {
1161             mprf("You %s %s from behind!",
1162                   (you.species == SP_FELID) ? "pounce on" : "strike",
1163                   defender->name(DESC_THE).c_str());
1164         }
1165         break;
1166     case 2:
1167     case 1:
1168         if (you.species == SP_FELID && coinflip())
1169         {
1170             mprf("You pounce on the unaware %s!",
1171                  defender->name(DESC_PLAIN).c_str());
1172             break;
1173         }
1174         mprf("%s fails to defend %s.",
1175               defender->name(DESC_THE).c_str(),
1176               defender->pronoun(PRONOUN_REFLEXIVE).c_str());
1177         break;
1178     }
1179
1180     defender->props.erase("helpless");
1181 }
1182
1183 /* Returns the attacker's name
1184  *
1185  * Helper method to easily access the attacker's name
1186  */
1187 string attack::atk_name(description_level_type desc)
1188 {
1189     return actor_name(attacker, desc, attacker_visible);
1190 }
1191
1192 /* Returns the defender's name
1193  *
1194  * Helper method to easily access the defender's name
1195  */
1196 string attack::def_name(description_level_type desc)
1197 {
1198     return actor_name(defender, desc, defender_visible);
1199 }
1200
1201 /* Returns the attacking weapon's name
1202  *
1203  * Sets upthe appropriate descriptive level and obtains the name of a weapon
1204  * based on if the attacker is a player or non-player (non-players use a
1205  * plain name and a manually entered pronoun)
1206  */
1207 string attack::wep_name(description_level_type desc, iflags_t ignre_flags)
1208 {
1209     ASSERT(weapon != nullptr);
1210
1211     if (attacker->is_player())
1212         return weapon->name(desc, false, false, false, false, ignre_flags);
1213
1214     string name;
1215     bool possessive = false;
1216     if (desc == DESC_YOUR)
1217     {
1218         desc       = DESC_THE;
1219         possessive = true;
1220     }
1221
1222     if (possessive)
1223         name = apostrophise(atk_name(desc)) + " ";
1224
1225     name += weapon->name(DESC_PLAIN, false, false, false, false, ignre_flags);
1226
1227     return name;
1228 }
1229
1230 /* TODO: Remove this!
1231  * Removing it may not really be practical, in retrospect. Its only used
1232  * below, in calc_elemental_brand_damage, which is called for both frost and
1233  * flame brands for both players and monsters.
1234  */
1235 string attack::defender_name(bool allow_reflexive)
1236 {
1237     if (allow_reflexive && attacker == defender)
1238         return actor_pronoun(attacker, PRONOUN_REFLEXIVE, attacker_visible);
1239     else
1240         return def_name(DESC_THE);
1241 }
1242
1243 int attack::player_stat_modify_damage(int damage)
1244 {
1245     int dammod = 39;
1246     const int dam_stat_val = calc_stat_to_dam_base();
1247
1248     if (dam_stat_val > 11)
1249         dammod += (random2(dam_stat_val - 11) * 2);
1250     else if (dam_stat_val < 9)
1251         dammod -= (random2(9 - dam_stat_val) * 3);
1252
1253     damage *= dammod;
1254     damage /= 39;
1255
1256     return damage;
1257 }
1258
1259 int attack::player_apply_weapon_skill(int damage)
1260 {
1261     if (using_weapon())
1262     {
1263         damage *= 2500 + (random2(you.skill(wpn_skill, 100) + 1));
1264         damage /= 2500;
1265     }
1266
1267     return damage;
1268 }
1269
1270 int attack::player_apply_fighting_skill(int damage, bool aux)
1271 {
1272     const int base = aux? 40 : 30;
1273
1274     damage *= base * 100 + (random2(you.skill(SK_FIGHTING, 100) + 1));
1275     damage /= base * 100;
1276
1277     return damage;
1278 }
1279
1280 int attack::player_apply_misc_modifiers(int damage)
1281 {
1282     return damage;
1283 }
1284
1285 /**
1286  * Get the damage bonus from a weapon's enchantment.
1287  */
1288 int attack::get_weapon_plus()
1289 {
1290     if (weapon->base_type == OBJ_RODS)
1291         return weapon->special;
1292     if (weapon->base_type == OBJ_STAVES || weapon->sub_type == WPN_BLOWGUN)
1293         return 0;
1294     return weapon->plus;
1295 }
1296
1297 // Slaying and weapon enchantment. Apply this for slaying even if not
1298 // using a weapon to attack.
1299 int attack::player_apply_slaying_bonuses(int damage, bool aux)
1300 {
1301     int damage_plus = 0;
1302     if (!aux && using_weapon())
1303     {
1304         damage_plus = get_weapon_plus();
1305         if (you.duration[DUR_CORROSION])
1306             damage_plus -= 3 * you.props["corrosion_amount"].get_int();
1307     }
1308     damage_plus += slaying_bonus(!weapon && wpn_skill == SK_THROWING
1309                                  || (weapon && is_range_weapon(*weapon)
1310                                             && using_weapon()));
1311
1312     damage += (damage_plus > -1) ? (random2(1 + damage_plus))
1313                                  : (-random2(1 - damage_plus));
1314     return damage;
1315 }
1316
1317 int attack::player_apply_final_multipliers(int damage)
1318 {
1319     // Can't affect much of anything as a shadow.
1320     if (you.form == TRAN_SHADOW)
1321         damage = div_rand_round(damage, 2);
1322
1323     return damage;
1324 }
1325
1326 void attack::player_exercise_combat_skills()
1327 {
1328 }
1329
1330 /* Returns attacker base unarmed damage
1331  *
1332  * Scales for current mutations and unarmed effects
1333  * TODO: Complete symmetry for base_unarmed damage
1334  * between monsters and players.
1335  */
1336 int attack::calc_base_unarmed_damage()
1337 {
1338     // Should only get here if we're not wielding something that's a weapon.
1339     // If there's a non-weapon in hand, it has no base damage.
1340     if (weapon)
1341         return 0;
1342
1343     if (!attacker->is_player())
1344         return 0;
1345
1346     int damage = get_form()->get_base_unarmed_damage();
1347
1348     if (you.has_usable_claws())
1349     {
1350         // Claw damage only applies for bare hands.
1351         damage += you.has_claws(false) * 2;
1352         apply_bleeding = true;
1353     }
1354
1355     if (you.form_uses_xl())
1356         damage += you.experience_level;
1357     else if (you.form == TRAN_BAT || you.form == TRAN_PORCUPINE)
1358     {
1359         // Bats really don't do a lot of damage.
1360         damage += you.skill_rdiv(wpn_skill, 1, 5);
1361     }
1362     else
1363         damage += you.skill_rdiv(wpn_skill);
1364
1365     if (damage < 0)
1366         damage = 0;
1367
1368     return damage;
1369 }
1370
1371 // TODO: Potentially remove, consider integrating with other to-hit or stat
1372 // calculating methods
1373 // weighted average of strength and dex, between (str+dex)/2 and dex
1374 int attack::calc_stat_to_hit_base()
1375 {
1376     const int weight = weapon ? weapon_str_weight(*weapon) : 4;
1377
1378     // dex is modified by strength towards the average, by the
1379     // weighted amount weapon_str_weight() / 20.
1380     return you.dex() + (you.strength() - you.dex()) * weight / 20;
1381 }
1382
1383 // weighted average of strength and dex, between str and (str+dex)/2
1384 int attack::calc_stat_to_dam_base()
1385 {
1386     const int weight = weapon ? 10 - weapon_str_weight(*weapon) : 6;
1387     return you.strength() + (you.dex() - you.strength()) * weight / 20;
1388 }
1389
1390 int attack::calc_damage()
1391 {
1392     if (attacker->is_monster())
1393     {
1394         int damage = 0;
1395         int damage_max = 0;
1396         if (using_weapon() || wpn_skill == SK_THROWING)
1397         {
1398             damage_max = weapon_damage();
1399             damage += random2(damage_max);
1400
1401             int wpn_damage_plus = 0;
1402             if (weapon) // can be 0 for throwing projectiles
1403                 wpn_damage_plus = get_weapon_plus();
1404
1405             const int jewellery = attacker->as_monster()->inv[MSLOT_JEWELLERY];
1406             if (jewellery != NON_ITEM
1407                 && mitm[jewellery].is_type(OBJ_JEWELLERY, RING_SLAYING))
1408             {
1409                 wpn_damage_plus += mitm[jewellery].plus;
1410             }
1411
1412             wpn_damage_plus += attacker->scan_artefacts(ARTP_SLAYING);
1413
1414             if (wpn_damage_plus >= 0)
1415                 damage += random2(wpn_damage_plus);
1416             else
1417                 damage -= random2(1 - wpn_damage_plus);
1418
1419             damage -= 1 + random2(3);
1420         }
1421
1422         damage_max += attk_damage;
1423         damage     += 1 + random2(attk_damage);
1424
1425         damage = apply_damage_modifiers(damage, damage_max);
1426
1427         set_attack_verb(damage);
1428         return apply_defender_ac(damage, damage_max);
1429     }
1430     else
1431     {
1432         int potential_damage, damage;
1433
1434         potential_damage = using_weapon() || wpn_skill == SK_THROWING
1435             ? weapon_damage() : calc_base_unarmed_damage();
1436
1437         potential_damage = player_stat_modify_damage(potential_damage);
1438
1439         damage = random2(potential_damage+1);
1440
1441         damage = player_apply_weapon_skill(damage);
1442         damage = player_apply_fighting_skill(damage, false);
1443         damage = player_apply_misc_modifiers(damage);
1444         damage = player_apply_slaying_bonuses(damage, false);
1445         damage = player_stab(damage);
1446         // A failed stab may have awakened monsters, but that could have
1447         // caused the defender to cease to exist (spectral weapons with
1448         // missing summoners; or pacified monsters on a stair). FIXME:
1449         // The correct thing to do would be either to delay the call to
1450         // alert_nearby_monsters (currently in player_stab) until later
1451         // in the attack; or to avoid removing monsters in handle_behaviour.
1452         if (!defender->alive())
1453             return 0;
1454         damage = player_apply_final_multipliers(damage);
1455         damage = apply_defender_ac(damage);
1456
1457         damage = max(0, damage);
1458         set_attack_verb(damage);
1459
1460         return damage;
1461     }
1462
1463     return 0;
1464 }
1465
1466 int attack::test_hit(int to_land, int ev, bool randomise_ev)
1467 {
1468     int margin = AUTOMATIC_HIT;
1469     if (randomise_ev)
1470         ev = random2avg(2*ev, 2);
1471     if (to_land >= AUTOMATIC_HIT)
1472         return true;
1473     else if (x_chance_in_y(MIN_HIT_MISS_PERCENTAGE, 100))
1474         margin = (random2(2) ? 1 : -1) * AUTOMATIC_HIT;
1475     else
1476         margin = to_land - ev;
1477
1478 #ifdef DEBUG_DIAGNOSTICS
1479     dprf(DIAG_COMBAT, "to hit: %d; ev: %d; result: %s (%d)",
1480          to_hit, ev, (margin >= 0) ? "hit" : "miss", margin);
1481 #endif
1482
1483     return margin;
1484 }
1485
1486 int attack::apply_defender_ac(int damage, int damage_max) const
1487 {
1488     ASSERT(defender);
1489     int stab_bypass = 0;
1490     if (stab_bonus)
1491     {
1492         stab_bypass = you.skill(wpn_skill, 50) + you.skill(SK_STEALTH, 50);
1493         stab_bypass = random2(div_rand_round(stab_bypass, 100 * stab_bonus));
1494     }
1495     int after_ac = defender->apply_ac(damage, damage_max,
1496                                       AC_NORMAL, stab_bypass);
1497     dprf(DIAG_COMBAT, "AC: att: %s, def: %s, ac: %d, gdr: %d, dam: %d -> %d",
1498                  attacker->name(DESC_PLAIN, true).c_str(),
1499                  defender->name(DESC_PLAIN, true).c_str(),
1500                  defender->armour_class(),
1501                  defender->gdr_perc(),
1502                  damage,
1503                  after_ac);
1504
1505     return after_ac;
1506 }
1507
1508 bool attack::attack_warded_off()
1509 {
1510     const int WARDING_CHECK = 60;
1511
1512     if (defender->warding()
1513         && attacker->is_summoned()
1514         && attacker->as_monster()->check_res_magic(WARDING_CHECK) <= 0)
1515     {
1516         if (needs_message)
1517         {
1518             mprf("%s attack is warded away.",
1519                  attacker->name(DESC_ITS).c_str());
1520         }
1521         return true;
1522     }
1523
1524     return false;
1525 }
1526
1527 /* Determine whether a block occurred
1528  *
1529  * No blocks if defender is incapacitated, would be nice to eventually expand
1530  * this method to handle partial blocks as well as full blocks (although this
1531  * would serve as a nerf to shields and - while more realistic - may not be a
1532  * good mechanic for shields.
1533  *
1534  * Returns (block_occurred)
1535  */
1536 bool attack::attack_shield_blocked(bool verbose)
1537 {
1538     if (defender == attacker)
1539         return false; // You can't block your own attacks!
1540
1541     if (defender->incapacitated())
1542         return false;
1543
1544     const int con_block = random2(attacker->shield_bypass_ability(to_hit)
1545                                   + defender->shield_block_penalty());
1546     int pro_block = defender->shield_bonus();
1547
1548     if (!attacker->visible_to(defender))
1549         pro_block /= 3;
1550
1551     dprf(DIAG_COMBAT, "Defender: %s, Pro-block: %d, Con-block: %d",
1552          def_name(DESC_PLAIN).c_str(), pro_block, con_block);
1553
1554     if (pro_block >= con_block)
1555     {
1556         perceived_attack = true;
1557
1558         if (attack_ignores_shield(verbose))
1559             return false;
1560
1561         if (needs_message && verbose)
1562         {
1563             mprf("%s %s %s attack.",
1564                  defender_name(false).c_str(),
1565                  defender->conj_verb("block").c_str(),
1566                  attacker == defender ? "its own"
1567                                       : atk_name(DESC_ITS).c_str());
1568         }
1569
1570         defender->shield_block_succeeded(attacker);
1571
1572         return true;
1573     }
1574
1575     return false;
1576 }
1577
1578 attack_flavour attack::random_chaos_attack_flavour()
1579 {
1580     attack_flavour flavours[] =
1581         {AF_FIRE, AF_COLD, AF_ELEC, AF_POISON, AF_VAMPIRIC, AF_DISTORT,
1582          AF_CONFUSE, AF_CHAOS};
1583     return RANDOM_ELEMENT(flavours);
1584 }
1585
1586 bool attack::apply_damage_brand(const char *what)
1587 {
1588     bool brand_was_known = false;
1589     int brand = 0;
1590     bool ret = false;
1591
1592     if (using_weapon())
1593     {
1594         if (is_artefact(*weapon))
1595             brand_was_known = artefact_known_property(*weapon, ARTP_BRAND);
1596         else
1597             brand_was_known = item_type_known(*weapon);
1598     }
1599
1600     special_damage = 0;
1601     obvious_effect = false;
1602     brand = damage_brand == SPWPN_CHAOS ? random_chaos_brand() : damage_brand;
1603
1604     if (brand != SPWPN_FLAMING && brand != SPWPN_FREEZING
1605         && brand != SPWPN_ELECTROCUTION && brand != SPWPN_VAMPIRISM
1606         && !defender->alive())
1607     {
1608         // Most brands have no extra effects on just killed enemies, and the
1609         // effect would be often inappropriate.
1610         return false;
1611     }
1612
1613     if (!damage_done
1614         && (brand == SPWPN_FLAMING || brand == SPWPN_FREEZING
1615             || brand == SPWPN_HOLY_WRATH || brand == SPWPN_ANTIMAGIC
1616             || brand == SPWPN_VORPAL || brand == SPWPN_VAMPIRISM))
1617     {
1618         // These brands require some regular damage to function.
1619         return false;
1620     }
1621
1622     switch (brand)
1623     {
1624     case SPWPN_FLAMING:
1625         calc_elemental_brand_damage(BEAM_FIRE,
1626                                     defender->is_icy() ? "melt" : "burn",
1627                                     what);
1628         attacker->god_conduct(DID_FIRE, 1);
1629         break;
1630
1631     case SPWPN_FREEZING:
1632         calc_elemental_brand_damage(BEAM_COLD, "freeze", what);
1633         break;
1634
1635     case SPWPN_HOLY_WRATH:
1636         if (defender->holy_wrath_susceptible())
1637             special_damage = 1 + (random2(damage_done * 15) / 10);
1638
1639         if (special_damage && defender_visible)
1640         {
1641             special_damage_message =
1642                 make_stringf(
1643                     "%s %s%s",
1644                     defender_name(false).c_str(),
1645                     defender->conj_verb("convulse").c_str(),
1646                     attack_strength_punctuation(special_damage).c_str());
1647         }
1648         break;
1649
1650     case SPWPN_ELECTROCUTION:
1651         if (defender->res_elec() > 0)
1652             break;
1653         else if (one_chance_in(3))
1654         {
1655             special_damage_message =
1656                 defender->is_player()?
1657                    "You are electrocuted!"
1658                 :  "There is a sudden explosion of sparks!";
1659             special_damage = 8 + random2(13);
1660             special_damage_flavour = BEAM_ELECTRICITY;
1661         }
1662
1663         break;
1664
1665     case SPWPN_VENOM:
1666         if (!one_chance_in(4))
1667         {
1668             int old_poison;
1669
1670             if (defender->is_player())
1671                 old_poison = you.duration[DUR_POISONING];
1672             else
1673             {
1674                 old_poison =
1675                     (defender->as_monster()->get_ench(ENCH_POISON)).degree;
1676             }
1677
1678             defender->poison(attacker, 6 + random2(8) + random2(damage_done * 3 / 2));
1679
1680             if (defender->is_player()
1681                    && old_poison < you.duration[DUR_POISONING]
1682                 || !defender->is_player()
1683                    && old_poison <
1684                       (defender->as_monster()->get_ench(ENCH_POISON)).degree)
1685             {
1686                 obvious_effect = true;
1687             }
1688
1689         }
1690         break;
1691
1692     case SPWPN_DRAINING:
1693         drain_defender();
1694         break;
1695
1696     case SPWPN_VORPAL:
1697         special_damage = 1 + random2(damage_done) / 3;
1698         // Note: Leaving special_damage_message empty because there isn't one.
1699         break;
1700
1701     case SPWPN_VAMPIRISM:
1702     {
1703         if (!weapon
1704             || defender->holiness() != MH_NATURAL
1705             || defender->res_negative_energy()
1706             || damage_done < 1
1707             || attacker->stat_hp() == attacker->stat_maxhp()
1708             || !defender->is_player()
1709                && defender->as_monster()->is_summoned()
1710             || attacker->is_player() && you.duration[DUR_DEATHS_DOOR]
1711             || !attacker->is_player()
1712                && attacker->as_monster()->has_ench(ENCH_DEATHS_DOOR)
1713             || x_chance_in_y(2, 5) && !is_unrandom_artefact(*weapon, UNRAND_LEECH))
1714         {
1715             break;
1716         }
1717
1718         obvious_effect = true;
1719
1720         // Handle weapon effects.
1721         // We only get here if we've done base damage, so no
1722         // worries on that score.
1723         if (attacker->is_player())
1724             mpr("You feel better.");
1725         else if (attacker_visible)
1726         {
1727             if (defender->is_player())
1728             {
1729                 mprf("%s draws strength from your injuries!",
1730                      attacker->name(DESC_THE).c_str());
1731             }
1732             else
1733             {
1734                 mprf("%s is healed.",
1735                      attacker->name(DESC_THE).c_str());
1736             }
1737         }
1738
1739         int hp_boost = is_unrandom_artefact(*weapon, UNRAND_VAMPIRES_TOOTH)
1740                        ? damage_done : 1 + random2(damage_done);
1741
1742         dprf(DIAG_COMBAT, "Vampiric Healing: damage %d, healed %d",
1743              damage_done, hp_boost);
1744         attacker->heal(hp_boost);
1745
1746         attacker->god_conduct(DID_NECROMANCY, 2);
1747         break;
1748     }
1749     case SPWPN_PAIN:
1750         pain_affects_defender();
1751         break;
1752
1753     case SPWPN_DISTORTION:
1754         ret = distortion_affects_defender();
1755         break;
1756
1757     case SPWPN_CONFUSE:
1758     {
1759         // This was originally for confusing touch and it doesn't really
1760         // work on the player, but a monster with a chaos weapon will
1761         // occasionally come up with this brand. -cao
1762         if (defender->is_player())
1763             break;
1764
1765         // Also used for players in fungus form.
1766         if (attacker->is_player()
1767             && you.form == TRAN_FUNGUS
1768             && !you.duration[DUR_CONFUSING_TOUCH]
1769             && defender->is_unbreathing())
1770         {
1771             break;
1772         }
1773
1774         const int hdcheck =
1775             (defender->holiness() == MH_NATURAL ? random2(30) : random2(22));
1776
1777         if (hdcheck < defender->get_hit_dice()
1778             || one_chance_in(5)
1779             || defender->as_monster()->check_clarity(false))
1780         {
1781             break;
1782         }
1783
1784         // Declaring these just to pass to the enchant function.
1785         bolt beam_temp;
1786         beam_temp.thrower   = attacker->is_player() ? KILL_YOU : KILL_MON;
1787         beam_temp.flavour   = BEAM_CONFUSION;
1788         beam_temp.source_id = attacker->mid;
1789         beam_temp.apply_enchantment_to_monster(defender->as_monster());
1790         obvious_effect = beam_temp.obvious_effect;
1791
1792         if (attacker->is_player() && damage_brand == SPWPN_CONFUSE
1793             && you.duration[DUR_CONFUSING_TOUCH])
1794         {
1795             you.duration[DUR_CONFUSING_TOUCH] = 1;
1796             obvious_effect = false;
1797         }
1798         break;
1799     }
1800
1801     case SPWPN_CHAOS:
1802         chaos_affects_defender();
1803         break;
1804
1805     case SPWPN_ANTIMAGIC:
1806         antimagic_affects_defender(damage_done * 8);
1807         break;
1808
1809     default:
1810         if (using_weapon() && is_unrandom_artefact(*weapon, UNRAND_HELLFIRE))
1811         {
1812             calc_elemental_brand_damage(BEAM_HELLFIRE,
1813                                         defender->is_icy() ? "melt" : "burn",
1814                                         what);
1815             defender->expose_to_element(BEAM_HELLFIRE);
1816             attacker->god_conduct(DID_UNHOLY, 2 + random2(3));
1817             attacker->god_conduct(DID_FIRE, 10 + random2(5));
1818         }
1819         break;
1820     }
1821
1822     if (damage_brand == SPWPN_CHAOS)
1823     {
1824         if (brand != SPWPN_CHAOS && !ret
1825             && miscast_level == -1 && one_chance_in(20))
1826         {
1827             miscast_level  = 0;
1828             miscast_type   = SPTYP_RANDOM;
1829             miscast_target = coinflip() ? attacker : defender;
1830         }
1831
1832         if (responsible->is_player())
1833             did_god_conduct(DID_CHAOS, 2 + random2(3), brand_was_known);
1834     }
1835
1836     if (!obvious_effect)
1837         obvious_effect = !special_damage_message.empty();
1838
1839     if (needs_message && !special_damage_message.empty())
1840     {
1841         mpr(special_damage_message);
1842
1843         special_damage_message.clear();
1844         // Don't do message-only miscasts along with a special
1845         // damage message.
1846         if (miscast_level == 0)
1847             miscast_level = -1;
1848     }
1849
1850     if (special_damage > 0)
1851         inflict_damage(special_damage, special_damage_flavour);
1852
1853     if (defender->alive())
1854     {
1855         switch (brand)
1856         {
1857         case SPWPN_FLAMING:
1858             defender->expose_to_element(BEAM_FIRE);
1859             break;
1860
1861         case SPWPN_FREEZING:
1862             defender->expose_to_element(BEAM_COLD, 2);
1863             break;
1864         default:
1865             break;
1866         }
1867     }
1868
1869     if (obvious_effect && attacker_visible && using_weapon())
1870     {
1871         if (is_artefact(*weapon))
1872             artefact_learn_prop(*weapon, ARTP_BRAND);
1873         else
1874             set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
1875     }
1876
1877     return ret;
1878 }
1879
1880 /* Calculates special damage, prints appropriate combat text
1881  *
1882  * Applies a particular damage brand to the current attack, the setup and
1883  * calculation of base damage and other effects varies based on the type
1884  * of attack, but the calculation of elemental damage should be consistent.
1885  */
1886 void attack::calc_elemental_brand_damage(beam_type flavour,
1887                                          const char *verb,
1888                                          const char *what)
1889 {
1890     special_damage = resist_adjust_damage(defender, flavour,
1891                                           random2(damage_done) / 2 + 1);
1892
1893     if (needs_message && special_damage > 0 && verb)
1894     {
1895         // XXX: assumes "what" is singular
1896         special_damage_message = make_stringf(
1897             "%s %s %s%s",
1898             what ? what : atk_name(DESC_THE).c_str(),
1899             what ? conjugate_verb(verb, false).c_str()
1900                  : attacker->conj_verb(verb).c_str(),
1901             // Don't allow reflexive if the subject wasn't the attacker.
1902             defender_name(!what).c_str(),
1903             attack_strength_punctuation(special_damage).c_str());
1904     }
1905 }
1906
1907 int attack::player_stab_weapon_bonus(int damage)
1908 {
1909     int stab_skill = you.skill(wpn_skill, 50) + you.skill(SK_STEALTH, 50);
1910
1911     if (player_good_stab())
1912     {
1913         // We might be unarmed if we're using the boots of the Assassin.
1914         const bool extra_good = using_weapon() && weapon->sub_type == WPN_DAGGER;
1915         int bonus = you.dex() * (stab_skill + 100) / (extra_good ? 500 : 1000);
1916
1917         bonus   = stepdown_value(bonus, 10, 10, 30, 30);
1918         damage += bonus;
1919         damage *= 10 + div_rand_round(stab_skill, 100 * stab_bonus);
1920         damage /= 10;
1921     }
1922
1923     damage *= 12 + div_rand_round(stab_skill, 100 * stab_bonus);
1924     damage /= 12;
1925
1926     return damage;
1927 }
1928
1929 int attack::player_stab(int damage)
1930 {
1931     // The stabbing message looks better here:
1932     if (stab_attempt)
1933     {
1934         // Construct reasonable message.
1935         stab_message();
1936
1937         practise(EX_WILL_STAB);
1938     }
1939     else
1940     {
1941         stab_bonus = 0;
1942         // Ok.. if you didn't backstab, you wake up the neighborhood.
1943         // I can live with that.
1944         alert_nearby_monsters();
1945     }
1946
1947     if (stab_bonus)
1948     {
1949         // Let's make sure we have some damage to work with...
1950         damage = max(1, damage);
1951
1952         damage = player_stab_weapon_bonus(damage);
1953     }
1954
1955     return damage;
1956 }
1957
1958 /* Check for stab and prepare combat for stab-values
1959  *
1960  * Grant an automatic stab if paralyzed or sleeping (with highest damage value)
1961  * stab_bonus is used as the divisor in damage calculations, so lower values
1962  * will yield higher damage. Normal stab chance is (stab_skill + dex + 1 / roll)
1963  * This averages out to about 1/3 chance for a non extended-endgame stabber.
1964  */
1965 void attack::player_stab_check()
1966 {
1967     if (you.duration[DUR_CLUMSY] || you.confused())
1968     {
1969         stab_attempt = false;
1970         stab_bonus = 0;
1971         return;
1972     }
1973
1974     const stab_type st = find_stab_type(&you, defender);
1975     stab_attempt = (st != STAB_NO_STAB);
1976     const bool roll_needed = (st != STAB_SLEEPING && st != STAB_PARALYSED);
1977
1978     int roll = 100;
1979     if (st == STAB_INVISIBLE)
1980         roll -= 10;
1981
1982     switch (st)
1983     {
1984     case STAB_NO_STAB:
1985     case NUM_STAB:
1986         stab_bonus = 0;
1987         break;
1988     case STAB_SLEEPING:
1989     case STAB_PARALYSED:
1990         stab_bonus = 1;
1991         break;
1992     case STAB_HELD_IN_NET:
1993     case STAB_PETRIFYING:
1994     case STAB_PETRIFIED:
1995         stab_bonus = 2;
1996         break;
1997     case STAB_INVISIBLE:
1998     case STAB_CONFUSED:
1999     case STAB_FLEEING:
2000     case STAB_ALLY:
2001         stab_bonus = 4;
2002         break;
2003     case STAB_DISTRACTED:
2004         stab_bonus = 6;
2005         break;
2006     }
2007
2008     // See if we need to roll against dexterity / stabbing.
2009     if (stab_attempt && roll_needed)
2010     {
2011         stab_attempt = x_chance_in_y(you.skill_rdiv(wpn_skill, 1, 2)
2012                                      + you.skill_rdiv(SK_STEALTH, 1, 2)
2013                                      + you.dex() + 1,
2014                                      roll);
2015     }
2016
2017     if (stab_attempt)
2018         count_action(CACT_STAB, st);
2019 }