1 /**
2  * @file
3  * @brief functions used during combat
4  */
5 
6 #include "AppHdr.h"
7 
8 #include "fight.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 
16 #include "art-enum.h"
17 #include "coord.h"
18 #include "coordit.h"
19 #include "delay.h"
20 #include "english.h"
21 #include "env.h"
22 #include "fineff.h"
23 #include "fprop.h"
24 #include "god-passive.h" // passive_t::shadow_attacks
25 #include "hints.h"
26 #include "invent.h"
27 #include "item-prop.h"
28 #include "item-use.h"
29 #include "melee-attack.h"
30 #include "message.h"
31 #include "misc.h"
32 #include "mon-behv.h"
33 #include "mon-cast.h"
34 #include "mon-place.h"
35 #include "mon-util.h"
36 #include "options.h"
37 #include "ouch.h"
38 #include "player.h"
39 #include "prompt.h"
40 #include "random-var.h"
41 #include "religion.h"
42 #include "shopping.h"
43 #include "spl-summoning.h"
44 #include "state.h"
45 #include "stringutil.h"
46 #include "target.h"
47 #include "terrain.h"
48 #include "transform.h"
49 #include "traps.h"
50 #include "travel.h"
51 
52 /**
53  * What are the odds of an HD-checking confusion effect (e.g. Confusing Touch,
54  * Fungus Form, SPWPN_CHAOS maybe) to confuse a monster of the given HD?
55  *
56  * @param HD    The current hit dice (level) of the monster to confuse.
57  * @return      A percentage chance (0-100) of confusing that monster.
58  *              (Except it tops out at 80%.)
59  */
melee_confuse_chance(int HD)60 int melee_confuse_chance(int HD)
61 {
62     return max(80 * (24 - HD) / 24, 0);
63 }
64 
65 /**
66  * Return the odds of an attack with the given to-hit bonus hitting a defender with the
67  * given EV, rounded to the nearest percent.
68  *
69  * @return                  To-hit percent between 0 and 100 (inclusive).
70  */
to_hit_pct(const monster_info & mi,attack & atk,bool melee)71 int to_hit_pct(const monster_info& mi, attack &atk, bool melee)
72 {
73     const int to_land = atk.calc_pre_roll_to_hit(false);
74     int ev = mi.ev;
75     if (to_land >= AUTOMATIC_HIT)
76         return 100;
77 
78     if (ev <= 0)
79         return 100 - MIN_HIT_MISS_PERCENTAGE / 2;
80 
81     int hits = 0;
82     for (int rolled_mhit = 0; rolled_mhit < to_land; rolled_mhit++)
83     {
84         // Apply post-roll manipulations:
85         int adjusted_mhit = rolled_mhit + mi.lighting_modifiers();
86 
87         adjusted_mhit += atk.post_roll_to_hit_modifiers(adjusted_mhit, false);
88 
89         // Duplicates ranged_attack::post_roll_to_hit_modifiers().
90         if (!melee && mi.is(MB_REPEL_MSL))
91             adjusted_mhit -= (adjusted_mhit + 1) / 2;
92 
93         if (adjusted_mhit >= ev)
94             hits++;
95     }
96 
97     double hit_chance = ((double)hits) / to_land;
98     // Apply Bayes Theorem to account for auto hit and miss.
99     hit_chance = hit_chance * (1 - MIN_HIT_MISS_PERCENTAGE / 200.0) + (1 - hit_chance) * MIN_HIT_MISS_PERCENTAGE / 200.0;
100 
101     return (int)(hit_chance*100);
102 }
103 
104 /**
105  * Return the base to-hit bonus that a monster with the given HD gets.
106  * @param hd               The hit dice (level) of the monster.
107  * @param skilled    Does the monster have bonus to-hit from the fighter or archer flag?
108  * @param ranged      Is this attack ranged or melee?
109  *
110  * @return         A base to-hit value, before equipment, statuses, etc.
111  */
mon_to_hit_base(int hd,bool skilled,bool ranged)112 int mon_to_hit_base(int hd, bool skilled, bool ranged)
113 {
114     if (ranged)
115     {
116         const int hd_mult = skilled ? 15 : 9;
117         return 18 + hd * hd_mult / 6;
118     }
119     const int hd_mult = skilled ? 25 : 15;
120     return 18 + hd * hd_mult / 10;
121 }
122 
mon_shield_bypass(int hd)123 int mon_shield_bypass(int hd)
124 {
125     return 15 + hd * 2 / 3;
126 }
127 
128 /**
129  * Return the odds of a monster attack with the given to-hit bonus hitting the given ev with the
130  * given EV, rounded to the nearest percent.
131  *
132  * TODO: deduplicate with to_hit_pct().
133  *
134  * @return                  To-hit percent between 0 and 100 (inclusive).
135  */
mon_to_hit_pct(int to_land,int ev)136 int mon_to_hit_pct(int to_land, int ev)
137 {
138     if (to_land >= AUTOMATIC_HIT)
139         return 100;
140 
141     if (ev <= 0)
142         return 100 - MIN_HIT_MISS_PERCENTAGE / 2;
143 
144     ++to_land; // per calc_to_hit()
145 
146     int hits = 0;
147     for (int ev1 = 0; ev1 < ev; ev1++)
148         for (int ev2 = 0; ev2 < ev; ev2++)
149             hits += max(0, to_land - (ev1 + ev2));
150 
151     double hit_chance = ((double)hits) / (to_land * ev * ev);
152 
153     // Apply Bayes Theorem to account for auto hit and miss.
154     hit_chance = hit_chance * (1 - MIN_HIT_MISS_PERCENTAGE / 200.0)
155               + (1 - hit_chance) * MIN_HIT_MISS_PERCENTAGE / 200.0;
156 
157     return (int)(hit_chance*100);
158 }
159 
mon_beat_sh_pct(int bypass,int sh)160 int mon_beat_sh_pct(int bypass, int sh)
161 {
162     if (sh <= 0)
163         return 100;
164 
165     sh *= 2; // per shield_bonus()
166 
167     int hits = 0;
168     for (int sh1 = 0; sh1 < sh; sh1++)
169     {
170         for (int sh2 = 0; sh2 < sh; sh2++)
171         {
172             int adj_sh = (sh1 + sh2) / (3*2) - 1;
173             hits += max(0, bypass - adj_sh);
174         }
175     }
176     const int denom = sh * sh * bypass;
177     return hits * 100 / denom;
178 }
179 
180 /**
181  * Switch from a bad weapon to melee.
182  *
183  * This function assumes some weapon is being wielded.
184  * @return whether a swap did occur.
185  */
_autoswitch_to_melee()186 static bool _autoswitch_to_melee()
187 {
188     bool penance;
189     if (is_melee_weapon(*you.weapon())
190         && !needs_handle_warning(*you.weapon(), OPER_ATTACK, penance))
191     {
192         return false;
193     }
194 
195     int item_slot;
196     if (you.equip[EQ_WEAPON] == letter_to_index('a'))
197         item_slot = letter_to_index('b');
198     else if (you.equip[EQ_WEAPON] == letter_to_index('b'))
199         item_slot = letter_to_index('a');
200     else
201         return false;
202 
203     if (!is_melee_weapon(you.inv[item_slot]))
204         return false;
205 
206     return wield_weapon(true, item_slot);
207 }
208 
209 /**
210  * Handle melee combat between attacker and defender.
211  *
212  * Works using the new fight rewrite. For a monster attacking, this method
213  * loops through all their available attacks, instantiating a new melee_attack
214  * for each attack. Combat effects should not go here, if at all possible. This
215  * is merely a wrapper function which is used to start combat.
216  *
217  * @param[in] attacker,defender The (non-null) participants in the attack.
218  *                              Either may be killed as a result of the attack.
219  * @param[out] did_hit If non-null, receives true if the attack hit the
220  *                     defender, and false otherwise.
221  * @param simu Is this a simulated attack?  Disables a few problematic
222  *             effects such as blood spatter and distortion teleports.
223  *
224  * @return Whether the attack took time (i.e. wasn't cancelled).
225  */
fight_melee(actor * attacker,actor * defender,bool * did_hit,bool simu)226 bool fight_melee(actor *attacker, actor *defender, bool *did_hit, bool simu)
227 {
228     ASSERT(attacker); // XXX: change to actor &attacker
229     ASSERT(defender); // XXX: change to actor &defender
230 
231     // A dead defender would result in us returning true without actually
232     // taking an action.
233     ASSERT(defender->alive());
234 
235     if (defender->is_player())
236     {
237         ASSERT(!crawl_state.game_is_arena());
238         // Friendly and good neutral monsters won't attack unless confused.
239         if (attacker->as_monster()->wont_attack()
240             && !mons_is_confused(*attacker->as_monster())
241             && !attacker->as_monster()->has_ench(ENCH_INSANE))
242         {
243             return false;
244         }
245 
246         // In case the monster hasn't noticed you, bumping into it will
247         // change that.
248         behaviour_event(attacker->as_monster(), ME_ALERT, defender);
249     }
250     else if (attacker->is_player())
251     {
252         ASSERT(!crawl_state.game_is_arena());
253         // Can't damage orbs this way.
254         if (mons_is_projectile(defender->type) && !you.confused())
255         {
256             you.turn_is_over = false;
257             return false;
258         }
259 
260         if (!simu && Options.auto_switch
261             && you.weapon()
262             && _autoswitch_to_melee())
263         {
264             return true; // Is this right? We did take time, but we didn't melee
265         }
266 
267         melee_attack attk(&you, defender);
268 
269         if (simu)
270             attk.simu = true;
271 
272         // We're trying to hit a monster, break out of travel/explore now.
273         interrupt_activity(activity_interrupt::hit_monster,
274                            defender->as_monster());
275 
276         // Check if the player is fighting with something unsuitable,
277         // or someone unsuitable.
278         if (you.can_see(*defender) && !simu
279             && !wielded_weapon_check(attk.weapon))
280         {
281             you.turn_is_over = false;
282             return false;
283         }
284 
285         if (!attk.attack())
286         {
287             // Attack was cancelled or unsuccessful...
288             if (attk.cancel_attack)
289                 you.turn_is_over = false;
290             return !attk.cancel_attack;
291         }
292 
293         if (did_hit)
294             *did_hit = attk.did_hit;
295 
296         if (!simu && will_have_passive(passive_t::shadow_attacks))
297             dithmenos_shadow_melee(defender);
298 
299         return true;
300     }
301 
302     // If execution gets here, attacker != Player, so we can safely continue
303     // with processing the number of attacks a monster has without worrying
304     // about unpredictable or weird results from players.
305 
306     const int nrounds = attacker->as_monster()->has_hydra_multi_attack()
307         ? attacker->heads() + MAX_NUM_ATTACKS - 1
308         : MAX_NUM_ATTACKS;
309     coord_def pos = defender->pos();
310 
311     // Melee combat, tell attacker to wield its melee weapon.
312     attacker->as_monster()->wield_melee_weapon();
313 
314     int effective_attack_number = 0;
315     int attack_number;
316     for (attack_number = 0; attack_number < nrounds && attacker->alive();
317          ++attack_number, ++effective_attack_number)
318     {
319         if (!attacker->alive())
320             return false;
321 
322         // Monster went away?
323         if (!defender->alive()
324             || defender->pos() != pos
325             || defender->is_banished())
326         {
327             if (attacker == defender
328                || !attacker->as_monster()->has_multitargeting())
329             {
330                 break;
331             }
332 
333             // Hydras can try and pick up a new monster to attack to
334             // finish out their round. -cao
335             bool end = true;
336             for (adjacent_iterator i(attacker->pos()); i; ++i)
337             {
338                 if (*i == you.pos()
339                     && !mons_aligned(attacker, &you))
340                 {
341                     attacker->as_monster()->foe = MHITYOU;
342                     attacker->as_monster()->target = you.pos();
343                     defender = &you;
344                     end = false;
345                     break;
346                 }
347 
348                 monster* mons = monster_at(*i);
349                 if (mons && !mons_aligned(attacker, mons))
350                 {
351                     defender = mons;
352                     end = false;
353                     pos = mons->pos();
354                     break;
355                 }
356             }
357 
358             // No adjacent hostiles.
359             if (end)
360                 break;
361         }
362 
363         if (!simu && attacker->is_monster()
364             && mons_attack_spec(*attacker->as_monster(), attack_number, true)
365                    .flavour == AF_KITE
366             && attacker->as_monster()->foe_distance() == 1
367             && attacker->reach_range() == REACH_TWO
368             && x_chance_in_y(3, 5))
369         {
370             monster* mons = attacker->as_monster();
371             coord_def foepos = mons->get_foe()->pos();
372             coord_def hopspot = mons->pos() - (foepos - mons->pos()).sgn();
373 
374             bool found = false;
375             if (!monster_habitable_grid(mons, env.grid(hopspot)) ||
376                 actor_at(hopspot))
377             {
378                 for (adjacent_iterator ai(mons->pos()); ai; ++ai)
379                 {
380                     if (ai->distance_from(foepos) != 2)
381                         continue;
382                     else
383                     {
384                         if (monster_habitable_grid(mons, env.grid(*ai))
385                             && !actor_at(*ai))
386                         {
387                             hopspot = *ai;
388                             found = true;
389                             break;
390                         }
391                     }
392                 }
393             }
394             else
395                 found = true;
396 
397             if (found)
398             {
399                 const bool could_see = you.can_see(*mons);
400                 if (mons->move_to_pos(hopspot))
401                 {
402                     if (could_see || you.can_see(*mons))
403                     {
404                         mprf("%s hops backward while attacking.",
405                              mons->name(DESC_THE, true).c_str());
406                     }
407                     mons->speed_increment -= 2; // Add a small extra delay
408                 }
409             }
410         }
411 
412         melee_attack melee_attk(attacker, defender, attack_number,
413                                 effective_attack_number);
414 
415         if (simu)
416             melee_attk.simu = true;
417 
418         // If the attack fails out, keep effective_attack_number up to
419         // date so that we don't cause excess energy loss in monsters
420         if (!melee_attk.attack())
421             effective_attack_number = melee_attk.effective_attack_number;
422         else if (did_hit && !(*did_hit))
423             *did_hit = melee_attk.did_hit;
424 
425         fire_final_effects();
426     }
427 
428     return true;
429 }
430 
431 /**
432  * If the given attacker attacks the given defender right now, what kind of
433  * extra-damage "stab" attack can the attacker perform, if any?
434  *
435  * @param attacker  The attacker; may be null.
436  * @param defender  The defender.
437  * @param actual    True if we're actually committing to a stab, false if we're
438  *                  just checking for display purposes.
439  * @return          The best (most damaging) kind of stab available to the
440  *                  attacker against this defender, or STAB_NO_STAB.
441  */
find_stab_type(const actor * attacker,const actor & defender,bool actual)442 stab_type find_stab_type(const actor *attacker,
443                          const actor &defender,
444                          bool actual)
445 {
446     const monster* def = defender.as_monster();
447 
448     // Stabbing monsters is unchivalric, and disabled under TSO!
449     // When just checking for display purposes, still indicate when monsters
450     // are sleeping/paralysed etc.
451     if (actual && attacker && attacker->is_player()
452         && def && have_passive(passive_t::no_stabbing))
453     {
454         return STAB_NO_STAB;
455     }
456 
457     // No stabbing monsters that cannot fight (e.g. plants) or monsters
458     // the attacker can't see (either due to invisibility or being behind
459     // opaque clouds).
460     if (def && mons_is_firewood(*def))
461         return STAB_NO_STAB;
462 
463     if (attacker && !attacker->can_see(defender))
464         return STAB_NO_STAB;
465 
466     // sleeping
467     if (defender.asleep())
468         return STAB_SLEEPING;
469 
470     // paralysed
471     if (defender.paralysed())
472         return STAB_PARALYSED;
473 
474     // petrified
475     if (defender.petrified())
476         return STAB_PETRIFIED;
477 
478     // petrifying
479     if (def && def->petrifying())
480         return STAB_PETRIFYING;
481 
482     // held in a net
483     if (def && def->caught())
484         return STAB_HELD_IN_NET;
485 
486     // invisible
487     if (attacker && !attacker->visible_to(&defender))
488         return STAB_INVISIBLE;
489 
490     // fleeing
491     if (def && mons_is_fleeing(*def))
492         return STAB_FLEEING;
493 
494     // allies
495     if (def && def->friendly())
496         return STAB_ALLY;
497 
498     // confused (but not perma-confused)
499     if (def && mons_is_confused(*def, false))
500         return STAB_CONFUSED;
501 
502     // Distracted (but not batty); this only applies to players.
503     if (attacker && attacker->is_player()
504         && def && def->foe != MHITYOU && !mons_is_batty(*def))
505     {
506         return STAB_DISTRACTED;
507     }
508 
509     return STAB_NO_STAB;
510 }
511 
512 /**
513  * What bonus does this type of stab give the player when attacking?
514  *
515  * @param   The type of stab in question; e.g. STAB_SLEEPING.
516  * @return  The bonus the stab gives. Note that this is used as a divisor for
517  *          damage, so the larger the value we return here, the less bonus
518  *          damage will be done.
519  */
stab_bonus_denom(stab_type stab)520 int stab_bonus_denom(stab_type stab)
521 {
522     // XXX: if we don't get rid of this logic, turn it into a static array.
523     switch (stab)
524     {
525         case STAB_NO_STAB:
526         case NUM_STABS:
527             return 0;
528         case STAB_SLEEPING:
529         case STAB_PARALYSED:
530         case STAB_PETRIFIED:
531             return 1;
532         default:
533             return 4;
534     }
535 }
536 
is_boolean_resist(beam_type flavour)537 static bool is_boolean_resist(beam_type flavour)
538 {
539     switch (flavour)
540     {
541     case BEAM_ELECTRICITY:
542     case BEAM_MIASMA:
543     case BEAM_STICKY_FLAME:
544     case BEAM_WATER:  // water asphyxiation damage,
545                       // bypassed by being water inhabitant.
546     case BEAM_POISON:
547     case BEAM_POISON_ARROW:
548         return true;
549     default:
550         return false;
551     }
552 }
553 
554 // Gets the percentage of the total damage of this damage flavour that can
555 // be resisted.
get_resistible_fraction(beam_type flavour)556 static inline int get_resistible_fraction(beam_type flavour)
557 {
558     switch (flavour)
559     {
560     // Drowning damage from water is resistible by being a water thing, or
561     // otherwise asphyx resistant.
562     case BEAM_WATER:
563         return 40;
564 
565     // Assume ice storm and throw icicle are mostly solid.
566     case BEAM_ICE:
567         return 40;
568 
569     // 50/50 split of elec and sonic damage.
570     case BEAM_THUNDER:
571         return 50;
572 
573     case BEAM_LAVA:
574         return 55;
575 
576     case BEAM_POISON_ARROW:
577         return 70;
578 
579     default:
580         return 100;
581     }
582 }
583 
_beam_to_resist(const actor * defender,beam_type flavour)584 static int _beam_to_resist(const actor* defender, beam_type flavour)
585 {
586     switch (flavour)
587     {
588         case BEAM_FIRE:
589         case BEAM_LAVA:
590             return defender->res_fire();
591         case BEAM_DAMNATION:
592             return defender->res_damnation();
593         case BEAM_STEAM:
594             return defender->res_steam();
595         case BEAM_COLD:
596         case BEAM_ICE:
597             return defender->res_cold();
598         case BEAM_WATER:
599             return defender->res_water_drowning();
600         case BEAM_ELECTRICITY:
601         case BEAM_THUNDER:
602         case BEAM_STUN_BOLT:
603             return defender->res_elec();
604         case BEAM_NEG:
605         case BEAM_PAIN:
606         case BEAM_MALIGN_OFFERING:
607         case BEAM_VAMPIRIC_DRAINING:
608             return defender->res_negative_energy();
609         case BEAM_ACID:
610             return defender->res_acid();
611         case BEAM_POISON:
612         case BEAM_POISON_ARROW:
613             return defender->res_poison();
614         case BEAM_HOLY:
615             return defender->res_holy_energy();
616         default:
617             return 0;
618     }
619 }
620 
621 
622 /**
623  * Adjusts damage for elemental resists, electricity and poison.
624  *
625  * For players, damage is reduced to 1/2, 1/3, or 1/5 if res has values 1, 2,
626  * or 3, respectively. "Boolean" resists (rElec, rPois) reduce damage to 1/3.
627  * rN is a special case that reduces damage to 1/2, 1/4, 0 instead.
628  *
629  * For monsters, damage is reduced to 1/2, 1/5, and 0 for 1/2/3 resistance.
630  * "Boolean" resists give 1/3, 1/6, 0 instead.
631  *
632  * @param defender      The victim of the attack.
633  * @param flavour       The type of attack having its damage adjusted.
634  *                      (Does not necessarily imply the attack is a beam.)
635  * @param rawdamage     The base damage, to be adjusted by resistance.
636  * @return              The amount of damage done, after resists are applied.
637  */
resist_adjust_damage(const actor * defender,beam_type flavour,int rawdamage)638 int resist_adjust_damage(const actor* defender, beam_type flavour, int rawdamage)
639 {
640     const int res = _beam_to_resist(defender, flavour);
641     if (!res)
642         return rawdamage;
643 
644     const bool is_mon = defender->is_monster();
645 
646     const int resistible_fraction = get_resistible_fraction(flavour);
647 
648     int resistible = rawdamage * resistible_fraction / 100;
649     const int irresistible = rawdamage - resistible;
650 
651     if (res > 0)
652     {
653         const bool immune_at_3_res = is_mon
654                                      || flavour == BEAM_NEG
655                                      || flavour == BEAM_PAIN
656                                      || flavour == BEAM_MALIGN_OFFERING
657                                      || flavour == BEAM_VAMPIRIC_DRAINING
658                                      || flavour == BEAM_HOLY
659                                      || flavour == BEAM_POISON
660                                      // just the resistible part
661                                      || flavour == BEAM_POISON_ARROW;
662 
663         if (immune_at_3_res && res >= 3 || res > 3)
664             resistible = 0;
665         else
666         {
667             // Is this a resist that claims to be boolean for damage purposes?
668             const int bonus_res = (is_boolean_resist(flavour) ? 1 : 0);
669 
670             // Monster resistances are stronger than player versions.
671             if (is_mon)
672                 resistible /= 1 + bonus_res + res * res;
673             else if (flavour == BEAM_NEG
674                      || flavour == BEAM_PAIN
675                      || flavour == BEAM_MALIGN_OFFERING
676                      || flavour == BEAM_VAMPIRIC_DRAINING)
677             {
678                 resistible /= res * 2;
679             }
680             else
681                 resistible /= (3 * res + 1) / 2 + bonus_res;
682         }
683     }
684     else if (res < 0)
685         resistible = resistible * 15 / 10;
686 
687     return max(resistible + irresistible, 0);
688 }
689 
690 // Reduce damage by AC.
691 // In most cases, we want AC to mostly stop weak attacks completely but affect
692 // strong ones less, but the regular formula is too hard to apply well to cases
693 // when damage is spread into many small chunks.
694 //
695 // Every point of damage is processed independently. Every point of AC has
696 // an independent 1/81 chance of blocking that damage.
697 //
698 // AC 20 stops 22% of damage, AC 40 -- 39%, AC 80 -- 63%.
apply_chunked_AC(int dam,int ac)699 int apply_chunked_AC(int dam, int ac)
700 {
701     double chance = pow(80.0/81, ac);
702     uint64_t cr = chance * (((uint64_t)1) << 32);
703 
704     int hurt = 0;
705     for (int i = 0; i < dam; i++)
706         if (rng::get_uint32() < cr)
707             hurt++;
708 
709     return hurt;
710 }
711 
712 ///////////////////////////////////////////////////////////////////////////
713 
wielded_weapon_check(const item_def * weapon,string attack_verb)714 bool wielded_weapon_check(const item_def *weapon, string attack_verb)
715 {
716     bool penance = false;
717     if (you.received_weapon_warning
718         || (weapon
719             && !needs_handle_warning(*weapon, OPER_ATTACK, penance)
720             && is_melee_weapon(*weapon))
721         || you.confused())
722     {
723         return true;
724     }
725 
726     // Don't pester the player if they're using UC, in treeform,
727     // or if they don't have any melee weapons yet.
728     if (!weapon
729         && (you.skill(SK_UNARMED_COMBAT) > 0
730             || you.form == transformation::tree
731             || !any_of(you.inv.begin(), you.inv.end(),
732                        [](item_def &it)
733                        { return is_melee_weapon(it) && can_wield(&it); })))
734     {
735         return true;
736     }
737 
738     string prompt;
739     prompt = make_stringf("Really %s while wielding %s?",
740         attack_verb.size() ? attack_verb.c_str() : "attack",
741         weapon ? weapon->name(DESC_YOUR).c_str() : "nothing");
742     if (penance)
743         prompt += " This could place you under penance!";
744 
745     const bool result = yesno(prompt.c_str(), true, 'n');
746 
747     if (!result)
748         canned_msg(MSG_OK);
749 
750     learned_something_new(HINT_WIELD_WEAPON); // for hints mode Rangers
751 
752     // Don't warn again if you decide to continue your attack.
753     if (result)
754         you.received_weapon_warning = true;
755 
756     return result;
757 }
758 
759 /**
760  * Should the given attacker cleave into the given victim with an axe or axe-
761  * like weapon?
762  *
763  * @param attacker  The creature doing the cleaving.
764  * @param defender  The potential cleave-ee.
765  * @return          True if the defender is an enemy of the defender; false
766  *                  otherwise.
767  */
_dont_harm(const actor & attacker,const actor & defender)768 static bool _dont_harm(const actor &attacker, const actor &defender)
769 {
770     if (mons_aligned(&attacker, &defender))
771         return true;
772 
773     if (defender.is_player())
774         return attacker.wont_attack();
775 
776     if (attacker.is_player())
777     {
778         return defender.wont_attack()
779                || mons_attitude(*defender.as_monster()) == ATT_NEUTRAL;
780     }
781 
782     return false;
783 }
784 
785 /**
786  * Force cleave attacks. Used for melee actions that don't have targets, e.g.
787  * attacking empty space (otherwise, cleaving is handled in melee_attack).
788  *
789  * @param target the nominal target of the original attack.
790  * @return whether there were cleave targets relative to the player and `target`.
791  */
force_player_cleave(coord_def target)792 bool force_player_cleave(coord_def target)
793 {
794     list<actor*> cleave_targets;
795     get_cleave_targets(you, target, cleave_targets);
796 
797     if (!cleave_targets.empty())
798     {
799         targeter_cleave hitfunc(&you, target);
800         if (stop_attack_prompt(hitfunc, "attack"))
801             return true;
802 
803         if (!you.fumbles_attack())
804             attack_cleave_targets(you, cleave_targets);
805         return true;
806     }
807 
808     return false;
809 }
810 
attack_cleaves(const actor & attacker,int which_attack)811 bool attack_cleaves(const actor &attacker, int which_attack)
812 {
813     const item_def* weap = attacker.weapon(which_attack);
814 
815     return weap && item_attack_skill(*weap) == SK_AXES
816         || attacker.is_player()
817             && (you.form == transformation::storm
818                 || you.duration[DUR_CLEAVE]);
819 }
820 
821 /**
822  * List potential cleave targets (adjacent hostile creatures), including the
823  * defender itself.
824  *
825  * @param attacker[in]   The attacking creature.
826  * @param def[in]        The location of the targeted defender.
827  * @param targets[out]   A list to be populated with targets.
828  * @param which_attack   The attack_number (default -1, which uses the default weapon).
829  */
get_cleave_targets(const actor & attacker,const coord_def & def,list<actor * > & targets,int which_attack)830 void get_cleave_targets(const actor &attacker, const coord_def& def,
831                         list<actor*> &targets, int which_attack)
832 {
833     // Prevent scanning invalid coordinates if the attacker dies partway through
834     // a cleave (due to hitting explosive creatures, or perhaps other things)
835     if (!attacker.alive())
836         return;
837 
838     if (actor_at(def))
839         targets.push_back(actor_at(def));
840 
841     if (attack_cleaves(attacker, which_attack))
842     {
843         const coord_def atk = attacker.pos();
844         coord_def atk_vector = def - atk;
845         const int dir = random_choose(-1, 1);
846 
847         for (int i = 0; i < 7; ++i)
848         {
849             atk_vector = rotate_adjacent(atk_vector, dir);
850 
851             actor *target = actor_at(atk + atk_vector);
852             if (target && !_dont_harm(attacker, *target))
853                 targets.push_back(target);
854         }
855     }
856 
857     // fake cleaving: gyre and gimble's extra attacks are implemented as
858     // cleaving attacks on enemies already in `targets`
859     const item_def* weap = attacker.weapon(which_attack);
860     if (weap && is_unrandom_artefact(*weap, UNRAND_GYRE))
861     {
862         list<actor*> new_targets;
863         for (actor* targ : targets)
864         {
865             new_targets.push_back(targ);
866             new_targets.push_back(targ);
867         }
868         targets = new_targets;
869     }
870 }
871 
872 /**
873  * Attack a provided list of cleave targets.
874  *
875  * @param attacker                  The attacking creature.
876  * @param targets                   The targets to cleave.
877  * @param attack_number             ?
878  * @param effective_attack_number   ?
879  */
attack_cleave_targets(actor & attacker,list<actor * > & targets,int attack_number,int effective_attack_number,wu_jian_attack_type wu_jian_attack,bool is_projected)880 void attack_cleave_targets(actor &attacker, list<actor*> &targets,
881                            int attack_number, int effective_attack_number,
882                            wu_jian_attack_type wu_jian_attack,
883                            bool is_projected)
884 {
885     if (attacker.is_player())
886     {
887         const item_def* weap = attacker.weapon(attack_number);
888 
889         if ((wu_jian_attack == WU_JIAN_ATTACK_WHIRLWIND
890              || wu_jian_attack == WU_JIAN_ATTACK_WALL_JUMP
891              || wu_jian_attack == WU_JIAN_ATTACK_TRIGGERED_AUX)
892             && !(weap && is_unrandom_artefact(*weap, UNRAND_GYRE)))
893         {
894             return; // WJC AOE attacks don't cleave, but G&G use cleaving
895             // XXX: If a player under Xom wrath gets cleaving while using G&G and
896             // worshiping Wu they'll be able to cleave their Wu attacks.
897         }
898     }
899 
900     while (attacker.alive() && !targets.empty())
901     {
902         actor* def = targets.front();
903 
904         if (def && def->alive() && !_dont_harm(attacker, *def)
905             && (is_projected || adjacent(attacker.pos(), def->pos())))
906         {
907             melee_attack attck(&attacker, def, attack_number,
908                                ++effective_attack_number, true);
909 
910             attck.wu_jian_attack = wu_jian_attack;
911             attck.is_projected = is_projected;
912             attck.attack();
913         }
914         targets.pop_front();
915     }
916 }
917 
918 /**
919  * What skill is required to reach mindelay with a weapon? May be >27.
920  * @param weapon The weapon to be considered.
921  * @returns The level of the relevant skill you must reach.
922  */
weapon_min_delay_skill(const item_def & weapon)923 int weapon_min_delay_skill(const item_def &weapon)
924 {
925     const int speed = property(weapon, PWPN_SPEED);
926     const int mindelay = weapon_min_delay(weapon, false);
927     return (speed - mindelay) * 2;
928 }
929 
930 /**
931  * How fast will this weapon get from your skill training?
932  *
933  * @param weapon the weapon to be considered.
934  * @param check_speed whether to take it into account if the weapon has the
935  *                    speed brand.
936  * @return How many aut the fastest possible attack with this weapon would take.
937  */
weapon_min_delay(const item_def & weapon,bool check_speed)938 int weapon_min_delay(const item_def &weapon, bool check_speed)
939 {
940     const int base = property(weapon, PWPN_SPEED);
941     int min_delay = base/2;
942 
943     // Short blades can get up to at least unarmed speed.
944     if (item_attack_skill(weapon) == SK_SHORT_BLADES && min_delay > 5)
945         min_delay = 5;
946 
947     // All weapons have min delay 7 or better
948     if (min_delay > 7)
949         min_delay = 7;
950 
951     // ...except crossbows...
952     if (item_attack_skill(weapon) == SK_CROSSBOWS && min_delay < 10)
953         min_delay = 10;
954 
955     // ... and unless it would take more than skill 27 to get there.
956     // Round up the reduction from skill, so that min delay is rounded down.
957     min_delay = max(min_delay, base - (MAX_SKILL_LEVEL + 1)/2);
958 
959     if (check_speed && get_weapon_brand(weapon) == SPWPN_SPEED)
960     {
961         min_delay *= 2;
962         min_delay /= 3;
963     }
964 
965     // never go faster than speed 3 (ie 3.33 attacks per round)
966     if (min_delay < 3)
967         min_delay = 3;
968 
969     return min_delay;
970 }
971 
mons_weapon_damage_rating(const item_def & launcher)972 int mons_weapon_damage_rating(const item_def &launcher)
973 {
974     return property(launcher, PWPN_DAMAGE) + launcher.plus;
975 }
976 
977 // Returns a rough estimate of damage from firing/throwing missile.
mons_missile_damage(monster * mons,const item_def * launch,const item_def * missile)978 int mons_missile_damage(monster* mons, const item_def *launch,
979                         const item_def *missile)
980 {
981     if (!missile || (!launch && !is_throwable(mons, *missile)))
982         return 0;
983 
984     const int missile_damage = property(*missile, PWPN_DAMAGE) / 2 + 1;
985     const int launch_damage  = launch? property(*launch, PWPN_DAMAGE) : 0;
986     return max(0, launch_damage + missile_damage);
987 }
988 
mons_usable_missile(monster * mons,item_def ** launcher)989 int mons_usable_missile(monster* mons, item_def **launcher)
990 {
991     *launcher = nullptr;
992     item_def *launch = nullptr;
993     for (int i = MSLOT_WEAPON; i <= MSLOT_ALT_WEAPON; ++i)
994     {
995         if (item_def *item = mons->mslot_item(static_cast<mon_inv_type>(i)))
996         {
997             if (is_range_weapon(*item))
998                 launch = item;
999         }
1000     }
1001 
1002     const item_def *missiles = mons->missiles();
1003     if (launch && missiles && !missiles->launched_by(*launch))
1004         launch = nullptr;
1005 
1006     const int fdam = mons_missile_damage(mons, launch, missiles);
1007 
1008     if (!fdam)
1009         return NON_ITEM;
1010     else
1011     {
1012         *launcher = launch;
1013         return missiles->index();
1014     }
1015 }
1016 
bad_attack(const monster * mon,string & adj,string & suffix,bool & would_cause_penance,coord_def attack_pos)1017 bool bad_attack(const monster *mon, string& adj, string& suffix,
1018                 bool& would_cause_penance, coord_def attack_pos)
1019 {
1020     ASSERT(mon); // XXX: change to const monster &mon
1021     ASSERT(!crawl_state.game_is_arena());
1022 
1023     if (!you.can_see(*mon))
1024         return false;
1025 
1026     if (attack_pos == coord_def(0, 0))
1027         attack_pos = you.pos();
1028 
1029     adj.clear();
1030     suffix.clear();
1031     would_cause_penance = false;
1032 
1033     if (is_sanctuary(mon->pos()) || is_sanctuary(attack_pos))
1034         suffix = ", despite your sanctuary";
1035 
1036     if (you.duration[DUR_LIFESAVING]
1037         && mon->holiness() & (MH_NATURAL | MH_PLANT))
1038     {
1039         suffix = " while asking for your life to be spared";
1040         would_cause_penance = true;
1041     }
1042 
1043     if (you_worship(GOD_JIYVA) && mons_is_slime(*mon)
1044         && !(mon->is_shapeshifter() && (mon->flags & MF_KNOWN_SHIFTER)))
1045     {
1046         would_cause_penance = true;
1047         return true;
1048     }
1049 
1050     if (mon->friendly())
1051     {
1052         if (god_hates_attacking_friend(you.religion, *mon))
1053         {
1054             adj = "your ally ";
1055 
1056             monster_info mi(mon, MILEV_NAME);
1057             if (!mi.is(MB_NAME_UNQUALIFIED))
1058                 adj += "the ";
1059 
1060             would_cause_penance = true;
1061 
1062         }
1063         else
1064         {
1065             adj = "your ";
1066 
1067             monster_info mi(mon, MILEV_NAME);
1068             if (mi.is(MB_NAME_UNQUALIFIED))
1069                 adj += "ally ";
1070         }
1071 
1072         return true;
1073     }
1074 
1075     if (mon->neutral() && is_good_god(you.religion))
1076     {
1077         adj += "neutral ";
1078         if (you_worship(GOD_SHINING_ONE) || you_worship(GOD_ELYVILON))
1079             would_cause_penance = true;
1080     }
1081     else if (mon->wont_attack())
1082     {
1083         adj += "non-hostile ";
1084         if (you_worship(GOD_SHINING_ONE) || you_worship(GOD_ELYVILON))
1085             would_cause_penance = true;
1086     }
1087 
1088     return !adj.empty() || !suffix.empty();
1089 }
1090 
stop_attack_prompt(const monster * mon,bool beam_attack,coord_def beam_target,bool * prompted,coord_def attack_pos)1091 bool stop_attack_prompt(const monster* mon, bool beam_attack,
1092                         coord_def beam_target, bool *prompted,
1093                         coord_def attack_pos)
1094 {
1095     ASSERT(mon); // XXX: change to const monster &mon
1096     bool penance = false;
1097 
1098     if (prompted)
1099         *prompted = false;
1100 
1101     if (crawl_state.disables[DIS_CONFIRMATIONS])
1102         return false;
1103 
1104     if (you.confused() || !you.can_see(*mon))
1105         return false;
1106 
1107     string adj, suffix;
1108     if (!bad_attack(mon, adj, suffix, penance, attack_pos))
1109         return false;
1110 
1111     // Listed in the form: "your rat", "Blork the orc".
1112     string mon_name = mon->name(DESC_PLAIN);
1113     if (starts_with(mon_name, "the ")) // no "your the Royal Jelly" nor "the the RJ"
1114         mon_name = mon_name.substr(4); // strlen("the ")
1115     if (!starts_with(adj, "your"))
1116         adj = "the " + adj;
1117     mon_name = adj + mon_name;
1118     string verb;
1119     if (beam_attack)
1120     {
1121         verb = "fire ";
1122         if (beam_target == mon->pos())
1123             verb += "at ";
1124         else
1125         {
1126             verb += "in " + apostrophise(mon_name) + " direction";
1127             mon_name = "";
1128         }
1129     }
1130     else
1131         verb = "attack ";
1132 
1133     const string prompt = make_stringf("Really %s%s%s?%s",
1134              verb.c_str(), mon_name.c_str(), suffix.c_str(),
1135              penance ? " This attack would place you under penance!" : "");
1136 
1137     if (prompted)
1138         *prompted = true;
1139 
1140     if (yesno(prompt.c_str(), false, 'n'))
1141         return false;
1142     else
1143     {
1144         canned_msg(MSG_OK);
1145         return true;
1146     }
1147 }
1148 
stop_attack_prompt(targeter & hitfunc,const char * verb,function<bool (const actor * victim)> affects,bool * prompted,const monster * defender)1149 bool stop_attack_prompt(targeter &hitfunc, const char* verb,
1150                         function<bool(const actor *victim)> affects,
1151                         bool *prompted, const monster *defender)
1152 {
1153     if (crawl_state.disables[DIS_CONFIRMATIONS])
1154         return false;
1155 
1156     if (crawl_state.which_god_acting() == GOD_XOM)
1157         return false;
1158 
1159     if (you.confused())
1160         return false;
1161 
1162     string adj, suffix;
1163     bool penance = false;
1164     bool defender_ok = true;
1165     counted_monster_list victims;
1166     for (distance_iterator di(hitfunc.origin, false, true, LOS_RADIUS); di; ++di)
1167     {
1168         if (hitfunc.is_affected(*di) <= AFF_NO)
1169             continue;
1170 
1171         const monster* mon = monster_at(*di);
1172         if (!mon || !you.can_see(*mon))
1173             continue;
1174 
1175         if (affects && !affects(mon))
1176             continue;
1177 
1178         string adjn, suffixn;
1179         bool penancen = false;
1180         if (bad_attack(mon, adjn, suffixn, penancen))
1181         {
1182             // record the adjectives for the first listed, or
1183             // first that would cause penance
1184             if (victims.empty() || penancen && !penance)
1185                 adj = adjn, suffix = suffixn, penance = penancen;
1186 
1187             victims.add(mon);
1188 
1189             if (defender && defender == mon)
1190                 defender_ok = false;
1191         }
1192     }
1193 
1194     if (victims.empty())
1195         return false;
1196 
1197     // Listed in the form: "your rat", "Blork the orc".
1198     string mon_name = victims.describe(DESC_PLAIN);
1199     if (starts_with(mon_name, "the ")) // no "your the Royal Jelly" nor "the the RJ"
1200         mon_name = mon_name.substr(4); // strlen("the ")
1201     if (!starts_with(adj, "your"))
1202         adj = "the " + adj;
1203     mon_name = adj + mon_name;
1204 
1205     const string prompt = make_stringf("Really %s%s %s%s?%s",
1206              verb, defender_ok ? " near" : "", mon_name.c_str(),
1207              suffix.c_str(),
1208              penance ? " This attack would place you under penance!" : "");
1209 
1210     if (prompted)
1211         *prompted = true;
1212 
1213     if (yesno(prompt.c_str(), false, 'n'))
1214         return false;
1215     else
1216     {
1217         canned_msg(MSG_OK);
1218         return true;
1219     }
1220 }
1221 
rude_stop_summoning_reason()1222 string rude_stop_summoning_reason()
1223 {
1224     if (you.duration[DUR_TOXIC_RADIANCE])
1225         return "toxic aura";
1226 
1227     if (you.duration[DUR_NOXIOUS_BOG])
1228         return "noxious bog";
1229 
1230     if (you.duration[DUR_VORTEX])
1231         return "polar vortex";
1232 
1233     return "";
1234 }
1235 
1236 /**
1237  * Does the player have a hostile duration up that would/could cause
1238  * a summon to be abjured? If so, prompt the player as to whether they
1239  * want to continue to create their summon. Note that this prompt is never a
1240  * penance prompt, because we don't cause penance when monsters enter line of
1241  * sight when OTR is active, regardless of how they entered LOS.
1242  *
1243  * @param verb    The verb to be used in the prompt. Defaults to "summon".
1244  * @return        True if the player wants to abort.
1245  */
rude_stop_summoning_prompt(string verb)1246 bool rude_stop_summoning_prompt(string verb)
1247 {
1248     string which = rude_stop_summoning_reason();
1249 
1250     if (which.empty())
1251         return false;
1252 
1253     if (crawl_state.disables[DIS_CONFIRMATIONS])
1254         return false;
1255 
1256     if (crawl_state.which_god_acting() == GOD_XOM)
1257         return false;
1258 
1259     string prompt = make_stringf("Really %s while emitting a %s?",
1260                                  verb.c_str(), which.c_str());
1261 
1262     if (yesno(prompt.c_str(), false, 'n'))
1263         return false;
1264     else
1265     {
1266         canned_msg(MSG_OK);
1267         return true;
1268     }
1269 }
1270 
can_reach_attack_between(coord_def source,coord_def target)1271 bool can_reach_attack_between(coord_def source, coord_def target)
1272 {
1273     const coord_def delta(target - source);
1274     const int grid_distance(delta.rdist());
1275     const coord_def first_middle(source + delta / 2);
1276     const coord_def second_middle(target - delta / 2);
1277 
1278     return grid_distance == 2
1279         // And with no dungeon furniture in the way of the reaching
1280         // attack;
1281         && (feat_is_reachable_past(env.grid(first_middle))
1282             || feat_is_reachable_past(env.grid(second_middle)))
1283         // The foe should be on the map (not stepped from time).
1284         && in_bounds(target);
1285 }
1286