1 /**
2  * @file
3  * @brief Functions related to special abilities.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "ability.h"
9 
10 #include <cctype>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstring>
14 #include <iomanip>
15 #include <sstream>
16 
17 #include "abyss.h"
18 #include "act-iter.h"
19 #include "areas.h"
20 #include "art-enum.h"
21 #include "branch.h"
22 #include "chardump.h"
23 #include "cleansing-flame-source-type.h"
24 #include "cloud.h"
25 #include "coordit.h"
26 #include "database.h"
27 #include "decks.h"
28 #include "delay.h"
29 #include "describe.h"
30 #include "directn.h"
31 #include "dungeon.h"
32 #include "evoke.h"
33 #include "exercise.h"
34 #include "fight.h"
35 #include "god-abil.h"
36 #include "god-companions.h"
37 #include "god-conduct.h"
38 #include "hints.h"
39 #include "invent.h"
40 #include "item-prop.h"
41 #include "items.h"
42 #include "item-use.h"
43 #include "level-state-type.h"
44 #include "libutil.h"
45 #include "macro.h"
46 #include "maps.h"
47 #include "menu.h"
48 #include "message.h"
49 #include "mon-place.h"
50 #include "mon-util.h"
51 #include "movement.h"
52 #include "mutation.h"
53 #include "notes.h"
54 #include "options.h"
55 #include "output.h"
56 #include "player-stats.h"
57 #include "potion.h"
58 #include "prompt.h"
59 #include "religion.h"
60 #include "rltiles/tiledef-icons.h"
61 #include "skills.h"
62 #include "spl-book.h"
63 #include "spl-cast.h"
64 #include "spl-clouds.h"
65 #include "spl-damage.h"
66 #include "spl-goditem.h"
67 #include "spl-miscast.h"
68 #include "spl-other.h"
69 #include "spl-selfench.h"
70 #include "spl-summoning.h"
71 #include "spl-transloc.h"
72 #include "stairs.h"
73 #include "state.h"
74 #include "stepdown.h"
75 #include "stringutil.h"
76 #include "tag-version.h"
77 #include "target.h"
78 #include "terrain.h"
79 #include "tilepick.h"
80 #include "transform.h"
81 #include "traps.h"
82 #include "uncancel.h"
83 #include "unicode.h"
84 #include "view.h"
85 
86 enum class abflag
87 {
88     none                = 0x00000000,
89     breath              = 0x00000001, // ability uses DUR_BREATH_WEAPON
90     delay               = 0x00000002, // ability has its own delay
91     pain                = 0x00000004, // ability must hurt player (ie torment)
92     piety               = 0x00000008, // ability has its own piety cost
93     exhaustion          = 0x00000010, // fails if you.exhausted
94     instant             = 0x00000020, // doesn't take time to use
95     conf_ok             = 0x00000040, // can use even if confused
96     variable_mp         = 0x00000080, // costs a variable amount of MP
97     curse               = 0x00000100, // Destroys a cursed item
98     max_hp_drain        = 0x00000200, // drains max hit points
99     gold                = 0x00000400, // costs gold
100     sacrifice           = 0x00000800, // sacrifice (Ru)
101     hostile             = 0x00001000, // failure summons a hostile (Makhleb)
102     berserk_ok          = 0x00002000, // can use even if berserk
103     card                = 0x00004000, // deck drawing (Nemelex)
104 };
105 DEF_BITFIELD(ability_flags, abflag);
106 
107 struct generic_cost
108 {
109     int base, add, rolls;
110 
generic_costgeneric_cost111     generic_cost(int num)
112         : base(num), add(num == 0 ? 0 : (num + 1) / 2 + 1), rolls(1)
113     {
114     }
generic_costgeneric_cost115     generic_cost(int num, int _add, int _rolls = 1)
116         : base(num), add(_add), rolls(_rolls)
117     {
118     }
fixedgeneric_cost119     static generic_cost fixed(int fixed)
120     {
121         return generic_cost(fixed, 0, 1);
122     }
rangegeneric_cost123     static generic_cost range(int low, int high, int _rolls = 1)
124     {
125         return generic_cost(low, high - low + 1, _rolls);
126     }
127 
128     int cost() const PURE;
129 
operator boolgeneric_cost130     operator bool () const { return base > 0 || add > 0; }
131 };
132 
133 struct scaling_cost
134 {
135     int value;
136 
scaling_costscaling_cost137     scaling_cost(int permille) : value(permille) {}
138 
fixedscaling_cost139     static scaling_cost fixed(int fixed)
140     {
141         return scaling_cost(-fixed);
142     }
143 
144     int cost(int max) const;
145 
operator boolscaling_cost146     operator bool () const { return value != 0; }
147 };
148 
149 /// What affects the failure chance of the ability?
150 enum class fail_basis
151 {
152     xl,
153     evo,
154     invo,
155 };
156 
157 /**
158  * What skill is used to determine the player's god's invocations' failure
159  * chance?
160  *
161  * XXX: deduplicate this with the similar code for divine titles, etc
162  * (skills.cc:skill_title_by_rank)
163  *
164  * IMPORTANT NOTE: functions that depend on this will be wrong if you aren't
165  * currently worshipping a god that grants the given ability (e.g. in ?/A)!
166  *
167  * @return      The appropriate skill type; e.g. SK_INVOCATIONS.
168  */
invo_skill(god_type god)169 skill_type invo_skill(god_type god)
170 {
171     switch (god)
172     {
173         case GOD_KIKUBAAQUDGHA:
174             return SK_NECROMANCY;
175 
176 #if TAG_MAJOR_VERSION == 34
177         case GOD_PAKELLAS:
178             return SK_EVOCATIONS;
179 #endif
180         case GOD_ASHENZARI:
181         case GOD_JIYVA:
182         case GOD_GOZAG:
183         case GOD_RU:
184         case GOD_TROG:
185         case GOD_WU_JIAN:
186         case GOD_VEHUMET:
187         case GOD_XOM:
188             return SK_NONE; // ugh
189         default:
190             return SK_INVOCATIONS;
191     }
192 }
193 
194 /// How to determine the odds of the ability failing?
195 struct failure_info
196 {
197     /// what determines the variable portion of failure: e.g. xl, evo, invo
198     fail_basis basis;
199     /// base failure chance
200     int base_chance;
201     /// multiplier to skill/xl; subtracted from base fail chance
202     int variable_fail_mult;
203     /// denominator to piety; subtracted from base fail chance if invo
204     int piety_fail_denom;
205 
206     /**
207      * What's the chance of the ability failing if the player tries to use it
208      * right now?
209      *
210      * See spl-cast.cc:_get_true_fail_rate() for details on what this 'chance'
211      * actually means.
212      *
213      * @return  A failure chance; may be outside the 0-100 range.
214      */
chancefailure_info215     int chance() const
216     {
217         switch (basis)
218         {
219         case fail_basis::xl:
220             return base_chance - you.experience_level * variable_fail_mult;
221         case fail_basis::evo:
222             return base_chance - you.skill(SK_EVOCATIONS, variable_fail_mult);
223         case fail_basis::invo:
224         {
225             const int sk_mod = invo_skill() == SK_NONE ? 0 :
226                                  you.skill(invo_skill(), variable_fail_mult);
227             const int piety_mod
228                 = piety_fail_denom ? you.piety / piety_fail_denom : 0;
229             return base_chance - sk_mod - piety_mod;
230         }
231         default:
232             die("unknown failure basis %d!", (int)basis);
233         }
234     }
235 
236     /// What skill governs the use of this ability, if any?
skillfailure_info237     skill_type skill() const
238     {
239         switch (basis)
240         {
241         case fail_basis::evo:
242             return SK_EVOCATIONS;
243         case fail_basis::invo:
244             return invo_skill();
245         case fail_basis::xl:
246         default:
247             return SK_NONE;
248         }
249     }
250 };
251 
252 // Structure for representing an ability:
253 struct ability_def
254 {
255     ability_type        ability;
256     const char *        name;
257     unsigned int        mp_cost;        // magic cost of ability
258     scaling_cost        hp_cost;        // hit point cost of ability
259     generic_cost        piety_cost;     // + random2((piety_cost + 1) / 2 + 1)
260     failure_info        failure;        // calculator for failure odds
261     ability_flags       flags;          // used for additional cost notices
262 
get_mp_costability_def263     int get_mp_cost() const
264     {
265         if (you.has_mutation(MUT_HP_CASTING))
266             return 0;
267         return mp_cost;
268     }
269 
get_hp_costability_def270     int get_hp_cost() const
271     {
272         int cost = hp_cost.cost(you.hp_max);
273         if (you.has_mutation(MUT_HP_CASTING))
274             return cost + mp_cost;
275         return cost;
276     }
277 };
278 
279 static int _lookup_ability_slot(ability_type abil);
280 static spret _do_ability(const ability_def& abil, bool fail, dist *target=nullptr);
281 static void _pay_ability_costs(const ability_def& abil);
282 static int _scale_piety_cost(ability_type abil, int original_cost);
283 
_get_ability_list()284 static vector<ability_def> &_get_ability_list()
285 {
286     // construct on initialization v2:
287     // https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2
288 
289     // The description screen was way out of date with the actual costs.
290     // This table puts all the information in one place... -- bwr
291     //
292     // The three numerical fields are: MP, HP, and piety.
293     // Note:  piety_cost = val + random2((val + 1) / 2 + 1);
294     //        hp cost is in per-mil of maxhp (i.e. 20 = 2% of hp, rounded up)
295     static vector<ability_def> Ability_List =
296     {
297         // NON_ABILITY should always come first
298         { ABIL_NON_ABILITY, "No ability", 0, 0, 0, {}, abflag::none },
299         { ABIL_SPIT_POISON, "Spit Poison",
300             0, 0, 0, {fail_basis::xl, 20, 1}, abflag::breath },
301 
302         { ABIL_BREATHE_FIRE, "Breathe Fire",
303             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
304         { ABIL_BREATHE_FROST, "Breathe Frost",
305             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
306         { ABIL_BREATHE_POISON, "Breathe Poison Gas",
307             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
308         { ABIL_BREATHE_MEPHITIC, "Breathe Noxious Fumes",
309             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
310         { ABIL_BREATHE_LIGHTNING, "Breathe Lightning",
311             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
312         { ABIL_BREATHE_POWER, "Breathe Dispelling Energy",
313             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
314         { ABIL_BREATHE_STEAM, "Breathe Steam",
315             0, 0, 0, {fail_basis::xl, 20, 1}, abflag::breath },
316         { ABIL_BREATHE_ACID, "Breathe Acid",
317             0, 0, 0, {fail_basis::xl, 30, 1}, abflag::breath },
318 
319         { ABIL_TRAN_BAT, "Bat Form",
320             2, 0, 0, {fail_basis::xl, 45, 2}, abflag::none },
321         { ABIL_EXSANGUINATE, "Exsanguinate",
322             0, 0, 0, {}, abflag::delay},
323         { ABIL_REVIVIFY, "Revivify",
324             0, 0, 0, {}, abflag::delay},
325     #if TAG_MAJOR_VERSION == 34
326         { ABIL_FLY, "Fly", 3, 0, 0, {fail_basis::xl, 42, 3}, abflag::none },
327         { ABIL_STOP_FLYING, "Stop Flying", 0, 0, 0, {}, abflag::none },
328     #endif
329         { ABIL_DAMNATION, "Hurl Damnation",
330             0, 150, 0, {fail_basis::xl, 50, 1}, abflag::none },
331         { ABIL_WORD_OF_CHAOS, "Word of Chaos",
332             6, 0, 0, {fail_basis::xl, 50, 1}, abflag::max_hp_drain },
333 
334         { ABIL_DIG, "Dig", 0, 0, 0, {}, abflag::instant | abflag::none },
335         { ABIL_SHAFT_SELF, "Shaft Self", 0, 0, 0, {}, abflag::delay },
336 
337         { ABIL_HOP, "Hop", 0, 0, 0, {}, abflag::none },
338 
339         { ABIL_ROLLING_CHARGE, "Rolling Charge", 0, 0, 0, {}, abflag::none },
340         { ABIL_BLINKBOLT, "Blinkbolt", 0, 0, 0, {}, abflag::none },
341 
342         // EVOKE abilities use Evocations and come from items.
343         // Teleportation and Blink can also come from mutations
344         // so we have to distinguish them (see above). The off items
345         // below are labeled EVOKE because they only work now if the
346         // player has an item with the evocable power (not just because
347         // you used a wand, potion, or miscast effect). I didn't see
348         // any reason to label them as "Evoke" in the text, they don't
349         // use or train Evocations (the others do).  -- bwr
350         { ABIL_EVOKE_BLINK, "Evoke Blink",
351             1, 0, 0, {fail_basis::evo, 40, 2}, abflag::none },
352         { ABIL_HEAL_WOUNDS, "Heal Wounds",
353             0, 0, 0, {fail_basis::xl, 45, 2}, abflag::none },
354         { ABIL_EVOKE_BERSERK, "Evoke Berserk Rage",
355             0, 0, 0, {fail_basis::evo, 50, 2}, abflag::none },
356 
357         { ABIL_EVOKE_TURN_INVISIBLE, "Evoke Invisibility",
358             2, 0, 0, {fail_basis::evo, 60, 2}, abflag::max_hp_drain },
359     #if TAG_MAJOR_VERSION == 34
360         { ABIL_EVOKE_FLIGHT, "Evoke Flight",
361             1, 0, 0, {fail_basis::evo, 40, 2}, abflag::none },
362     #endif
363         { ABIL_EVOKE_THUNDER, "Evoke Thunderclouds",
364             5, 0, 0, {fail_basis::evo, 60, 2}, abflag::none },
365 
366 
367         { ABIL_END_TRANSFORMATION, "End Transformation",
368             0, 0, 0, {}, abflag::none },
369 
370         // INVOCATIONS:
371         // Zin
372         { ABIL_ZIN_RECITE, "Recite",
373             0, 0, 0, {fail_basis::invo, 30, 6, 20}, abflag::none },
374         { ABIL_ZIN_VITALISATION, "Vitalisation",
375             2, 0, 1, {fail_basis::invo, 40, 5, 20}, abflag::none },
376         { ABIL_ZIN_IMPRISON, "Imprison",
377             5, 0, 4, {fail_basis::invo, 60, 5, 20}, abflag::none },
378         { ABIL_ZIN_SANCTUARY, "Sanctuary",
379             7, 0, 15, {fail_basis::invo, 80, 4, 25}, abflag::none },
380         { ABIL_ZIN_DONATE_GOLD, "Donate Gold",
381             0, 0, 0, {fail_basis::invo}, abflag::none },
382 
383         // The Shining One
384         { ABIL_TSO_DIVINE_SHIELD, "Divine Shield",
385             3, 0, 2, {fail_basis::invo, 40, 5, 20}, abflag::none },
386         { ABIL_TSO_CLEANSING_FLAME, "Cleansing Flame",
387             5, 0, 2, {fail_basis::invo, 70, 4, 25}, abflag::none },
388         { ABIL_TSO_SUMMON_DIVINE_WARRIOR, "Summon Divine Warrior",
389             8, 0, 5, {fail_basis::invo, 80, 4, 25}, abflag::none },
390         { ABIL_TSO_BLESS_WEAPON, "Brand Weapon With Holy Wrath", 0, 0, 0,
391             {fail_basis::invo}, abflag::none },
392 
393         // Kikubaaqudgha
394         { ABIL_KIKU_RECEIVE_CORPSES, "Receive Corpses",
395             3, 0, 2, {fail_basis::invo, 40, 5, 20}, abflag::none },
396         { ABIL_KIKU_TORMENT, "Torment",
397             4, 0, 8, {fail_basis::invo, 60, 5, 20}, abflag::none },
398         { ABIL_KIKU_GIFT_CAPSTONE_SPELLS, "Receive Forbidden Knowledge", 0, 0, 0,
399             {fail_basis::invo}, abflag::none },
400         { ABIL_KIKU_BLESS_WEAPON, "Brand Weapon With Pain", 0, 0, 0,
401             {fail_basis::invo}, abflag::pain },
402 
403         // Yredelemnul
404         { ABIL_YRED_INJURY_MIRROR, "Injury Mirror",
405             0, 0, 0, {fail_basis::invo, 40, 4, 20}, abflag::piety },
406         { ABIL_YRED_ANIMATE_REMAINS, "Animate Remains",
407             2, 0, 0, {fail_basis::invo, 40, 4, 20}, abflag::none },
408         { ABIL_YRED_RECALL_UNDEAD_SLAVES, "Recall Undead Slaves",
409             2, 0, 0, {fail_basis::invo, 50, 4, 20}, abflag::none },
410         { ABIL_YRED_ANIMATE_DEAD, "Animate Dead",
411             2, 0, 0, {fail_basis::invo, 40, 4, 20}, abflag::none },
412         { ABIL_YRED_DRAIN_LIFE, "Drain Life",
413             6, 0, 2, {fail_basis::invo, 60, 4, 25}, abflag::none },
414         { ABIL_YRED_ENSLAVE_SOUL, "Enslave Soul",
415             8, 0, 4, {fail_basis::invo, 80, 4, 25}, abflag::none },
416 
417         // Okawaru
418         { ABIL_OKAWARU_HEROISM, "Heroism",
419             2, 0, 1, {fail_basis::invo, 30, 6, 20}, abflag::none },
420         { ABIL_OKAWARU_FINESSE, "Finesse",
421             5, 0, 3, {fail_basis::invo, 60, 4, 25}, abflag::none },
422 
423         // Makhleb
424         { ABIL_MAKHLEB_MINOR_DESTRUCTION, "Minor Destruction",
425             0, scaling_cost::fixed(1), 0, {fail_basis::invo, 40, 5, 20}, abflag::none },
426         { ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB, "Lesser Servant of Makhleb",
427             0, scaling_cost::fixed(4), 2, {fail_basis::invo, 40, 5, 20}, abflag::hostile },
428         { ABIL_MAKHLEB_MAJOR_DESTRUCTION, "Major Destruction",
429             0, scaling_cost::fixed(6), generic_cost::range(0, 1),
430             {fail_basis::invo, 60, 4, 25}, abflag::none },
431         { ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB, "Greater Servant of Makhleb",
432             0, scaling_cost::fixed(10), 5,
433             {fail_basis::invo, 90, 2, 5}, abflag::hostile },
434 
435         // Sif Muna
436         { ABIL_SIF_MUNA_CHANNEL_ENERGY, "Channel Magic",
437             0, 0, 2, {fail_basis::invo, 60, 4, 25}, abflag::none },
438         { ABIL_SIF_MUNA_FORGET_SPELL, "Forget Spell",
439             0, 0, 8, {fail_basis::invo}, abflag::none },
440         { ABIL_SIF_MUNA_DIVINE_EXEGESIS, "Divine Exegesis",
441             0, 0, 12, {fail_basis::invo, 80, 4, 25}, abflag::none },
442 
443         // Trog
444         { ABIL_TROG_BERSERK, "Berserk",
445             0, 0, 0, {fail_basis::invo, 45, 0, 2}, abflag::none },
446         { ABIL_TROG_HAND, "Trog's Hand",
447             0, 0, 2, {fail_basis::invo, piety_breakpoint(2), 0, 1}, abflag::none },
448         { ABIL_TROG_BROTHERS_IN_ARMS, "Brothers in Arms",
449             0, 0, generic_cost::range(5, 6),
450             {fail_basis::invo, piety_breakpoint(5), 0, 1}, abflag::none },
451 
452         // Elyvilon
453         { ABIL_ELYVILON_LIFESAVING, "Divine Protection",
454             0, 0, 0, {fail_basis::invo}, abflag::piety },
455         { ABIL_ELYVILON_LESSER_HEALING, "Lesser Healing", 1, 0,
456             generic_cost::range(0, 1), {fail_basis::invo, 30, 6, 20}, abflag::none },
457         { ABIL_ELYVILON_HEAL_OTHER, "Heal Other",
458             2, 0, 2, {fail_basis::invo, 40, 5, 20}, abflag::none },
459         { ABIL_ELYVILON_PURIFICATION, "Purification",
460             3, 0, 3, {fail_basis::invo, 20, 5, 20}, abflag::conf_ok },
461         { ABIL_ELYVILON_GREATER_HEALING, "Greater Healing",
462             2, 0, 3, {fail_basis::invo, 40, 5, 20}, abflag::none },
463         { ABIL_ELYVILON_DIVINE_VIGOUR, "Divine Vigour",
464             0, 0, 6, {fail_basis::invo, 80, 4, 25}, abflag::none },
465 
466         // Lugonu
467         { ABIL_LUGONU_ABYSS_EXIT, "Depart the Abyss",
468             1, 0, 10, {fail_basis::invo, 30, 6, 20}, abflag::none },
469         { ABIL_LUGONU_BEND_SPACE, "Bend Space",
470             1, scaling_cost::fixed(2), 0, {fail_basis::invo, 40, 5, 20}, abflag::none },
471         { ABIL_LUGONU_BANISH, "Banish", 4, 0, generic_cost::range(3, 4),
472             {fail_basis::invo, 85, 7, 20}, abflag::none },
473         { ABIL_LUGONU_CORRUPT, "Corrupt", 7, scaling_cost::fixed(5), 10,
474             {fail_basis::invo, 70, 4, 25}, abflag::none },
475         { ABIL_LUGONU_ABYSS_ENTER, "Enter the Abyss", 10, 0, 28,
476             {fail_basis::invo, 80, 4, 25}, abflag::pain },
477         { ABIL_LUGONU_BLESS_WEAPON, "Brand Weapon With Distortion", 0, 0, 0,
478             {fail_basis::invo}, abflag::none },
479 
480         // Nemelex
481         { ABIL_NEMELEX_DRAW_DESTRUCTION, "Draw Destruction",
482             0, 0, 0, {fail_basis::invo}, abflag::card },
483         { ABIL_NEMELEX_DRAW_ESCAPE, "Draw Escape",
484             0, 0, 0, {fail_basis::invo}, abflag::card },
485         { ABIL_NEMELEX_DRAW_SUMMONING, "Draw Summoning",
486             0, 0, 0, {fail_basis::invo}, abflag::card },
487         { ABIL_NEMELEX_DRAW_STACK, "Draw Stack",
488             0, 0, 0, {fail_basis::invo}, abflag::card },
489         { ABIL_NEMELEX_TRIPLE_DRAW, "Triple Draw",
490             2, 0, 6, {fail_basis::invo, 60, 5, 20}, abflag::none },
491         { ABIL_NEMELEX_DEAL_FOUR, "Deal Four",
492             8, 0, 4, {fail_basis::invo, -1}, abflag::none }, // failure special-cased
493         { ABIL_NEMELEX_STACK_FIVE, "Stack Five",
494             5, 0, 10, {fail_basis::invo, 80, 4, 25}, abflag::none },
495 
496         // Beogh
497         { ABIL_BEOGH_SMITING, "Smiting",
498             3, 0, generic_cost::fixed(3), {fail_basis::invo, 40, 5, 20}, abflag::none },
499         { ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS, "Recall Orcish Followers",
500             2, 0, 0, {fail_basis::invo, 30, 6, 20}, abflag::none },
501         { ABIL_BEOGH_GIFT_ITEM, "Give Item to Named Follower",
502             0, 0, 0, {fail_basis::invo}, abflag::none },
503         { ABIL_BEOGH_RESURRECTION, "Resurrection",
504             0, 0, 28, {fail_basis::invo}, abflag::none },
505 
506         // Jiyva
507         { ABIL_JIYVA_CALL_JELLY, "Request Jelly",
508             2, 0, 1, {fail_basis::invo}, abflag::none },
509         { ABIL_JIYVA_SLIMIFY, "Slimify",
510             4, 0, 8, {fail_basis::invo, 90, 0, 2}, abflag::none },
511         { ABIL_JIYVA_CURE_BAD_MUTATION, "Cure Bad Mutation",
512             0, 0, 15, {fail_basis::invo}, abflag::none },
513 
514         // Fedhas
515         { ABIL_FEDHAS_WALL_OF_BRIARS, "Wall of Briars",
516             3, 0, 2, {fail_basis::invo, 30, 6, 20}, abflag::none},
517         { ABIL_FEDHAS_GROW_BALLISTOMYCETE, "Grow Ballistomycete",
518             4, 0, 4, {fail_basis::invo, 60, 4, 25}, abflag::none },
519         { ABIL_FEDHAS_OVERGROW, "Overgrow",
520             8, 0, 12, {fail_basis::invo, 70, 5, 20}, abflag::none},
521         { ABIL_FEDHAS_GROW_OKLOB, "Grow Oklob",
522             6, 0, 6, {fail_basis::invo, 80, 4, 25}, abflag::none },
523 
524         // Cheibriados
525         { ABIL_CHEIBRIADOS_TIME_BEND, "Bend Time",
526             3, 0, 1, {fail_basis::invo, 40, 4, 20}, abflag::none },
527         { ABIL_CHEIBRIADOS_DISTORTION, "Temporal Distortion",
528             4, 0, 3, {fail_basis::invo, 60, 5, 20}, abflag::instant },
529         { ABIL_CHEIBRIADOS_SLOUCH, "Slouch",
530             5, 0, 8, {fail_basis::invo, 60, 4, 25}, abflag::none },
531         { ABIL_CHEIBRIADOS_TIME_STEP, "Step From Time",
532             10, 0, 10, {fail_basis::invo, 80, 4, 25}, abflag::none },
533 
534         // Ashenzari
535         { ABIL_ASHENZARI_CURSE, "Curse Item",
536             0, 0, 0, {fail_basis::invo}, abflag::none },
537         { ABIL_ASHENZARI_UNCURSE, "Shatter the Chains",
538             0, 0, 0, {fail_basis::invo}, abflag::curse },
539 
540         // Dithmenos
541         { ABIL_DITHMENOS_SHADOW_STEP, "Shadow Step",
542             4, 80, 5, {fail_basis::invo, 30, 6, 20}, abflag::none },
543         { ABIL_DITHMENOS_SHADOW_FORM, "Shadow Form",
544             9, 0, 12, {fail_basis::invo, 80, 4, 25}, abflag::max_hp_drain },
545 
546         // Ru
547         { ABIL_RU_DRAW_OUT_POWER, "Draw Out Power", 0, 0, 0,
548             {fail_basis::invo}, abflag::exhaustion|abflag::max_hp_drain|abflag::conf_ok },
549         { ABIL_RU_POWER_LEAP, "Power Leap",
550             5, 0, 0, {fail_basis::invo}, abflag::exhaustion },
551         { ABIL_RU_APOCALYPSE, "Apocalypse",
552             8, 0, 0, {fail_basis::invo}, abflag::exhaustion|abflag::max_hp_drain },
553 
554         { ABIL_RU_SACRIFICE_PURITY, "Sacrifice Purity",
555             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
556         { ABIL_RU_SACRIFICE_WORDS, "Sacrifice Words",
557             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
558         { ABIL_RU_SACRIFICE_DRINK, "Sacrifice Drink",
559             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
560         { ABIL_RU_SACRIFICE_ESSENCE, "Sacrifice Essence",
561             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
562         { ABIL_RU_SACRIFICE_HEALTH, "Sacrifice Health",
563             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
564         { ABIL_RU_SACRIFICE_STEALTH, "Sacrifice Stealth",
565             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
566         { ABIL_RU_SACRIFICE_ARTIFICE, "Sacrifice Artifice",
567             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
568         { ABIL_RU_SACRIFICE_LOVE, "Sacrifice Love",
569             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
570         { ABIL_RU_SACRIFICE_COURAGE, "Sacrifice Courage",
571             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
572         { ABIL_RU_SACRIFICE_ARCANA, "Sacrifice Arcana",
573             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
574         { ABIL_RU_SACRIFICE_NIMBLENESS, "Sacrifice Nimbleness",
575             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
576         { ABIL_RU_SACRIFICE_DURABILITY, "Sacrifice Durability",
577             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
578         { ABIL_RU_SACRIFICE_HAND, "Sacrifice a Hand",
579             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
580         { ABIL_RU_SACRIFICE_EXPERIENCE, "Sacrifice Experience",
581             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
582         { ABIL_RU_SACRIFICE_SKILL, "Sacrifice Skill",
583             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
584         { ABIL_RU_SACRIFICE_EYE, "Sacrifice an Eye",
585             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
586         { ABIL_RU_SACRIFICE_RESISTANCE, "Sacrifice Resistance",
587             0, 0, 0, {fail_basis::invo}, abflag::sacrifice },
588         { ABIL_RU_REJECT_SACRIFICES, "Reject Sacrifices",
589             0, 0, 0, {fail_basis::invo}, abflag::none },
590 
591         // Gozag
592         { ABIL_GOZAG_POTION_PETITION, "Potion Petition",
593             0, 0, 0, {fail_basis::invo}, abflag::gold },
594         { ABIL_GOZAG_CALL_MERCHANT, "Call Merchant",
595             0, 0, 0, {fail_basis::invo}, abflag::gold|abflag::none },
596         { ABIL_GOZAG_BRIBE_BRANCH, "Bribe Branch",
597             0, 0, 0, {fail_basis::invo}, abflag::gold },
598 
599         // Qazlal
600         { ABIL_QAZLAL_UPHEAVAL, "Upheaval",
601             4, 0, 3, {fail_basis::invo, 40, 5, 20}, abflag::none },
602         { ABIL_QAZLAL_ELEMENTAL_FORCE, "Elemental Force",
603             6, 0, 6, {fail_basis::invo, 60, 5, 20}, abflag::none },
604         { ABIL_QAZLAL_DISASTER_AREA, "Disaster Area",
605             7, 0, 10, {fail_basis::invo, 70, 4, 25}, abflag::none },
606 
607         // Uskayaw
608         { ABIL_USKAYAW_STOMP, "Stomp",
609             3, 0, generic_cost::fixed(20), {fail_basis::invo}, abflag::none },
610         { ABIL_USKAYAW_LINE_PASS, "Line Pass",
611             4, 0, generic_cost::fixed(20), {fail_basis::invo}, abflag::none},
612         { ABIL_USKAYAW_GRAND_FINALE, "Grand Finale",
613             8, 0, generic_cost::fixed(0),
614             {fail_basis::invo, 120 + piety_breakpoint(4), 5, 1}, abflag::none},
615 
616         // Hepliaklqana
617         { ABIL_HEPLIAKLQANA_RECALL, "Recall Ancestor",
618             2, 0, 0, {fail_basis::invo}, abflag::none },
619         { ABIL_HEPLIAKLQANA_TRANSFERENCE, "Transference",
620             2, 0, 3, {fail_basis::invo, 40, 5, 20},
621             abflag::none },
622         { ABIL_HEPLIAKLQANA_IDEALISE, "Idealise",
623             4, 0, 4, {fail_basis::invo, 60, 4, 25},
624             abflag::none },
625 
626         { ABIL_HEPLIAKLQANA_TYPE_KNIGHT,       "Ancestor Life: Knight",
627             0, 0, 0, {fail_basis::invo}, abflag::none },
628         { ABIL_HEPLIAKLQANA_TYPE_BATTLEMAGE,   "Ancestor Life: Battlemage",
629             0, 0, 0, {fail_basis::invo}, abflag::none },
630         { ABIL_HEPLIAKLQANA_TYPE_HEXER,        "Ancestor Life: Hexer",
631             0, 0, 0, {fail_basis::invo}, abflag::none },
632 
633         { ABIL_HEPLIAKLQANA_IDENTITY,  "Ancestor Identity",
634             0, 0, 0, {fail_basis::invo}, abflag::instant },
635 
636         // Wu Jian
637         { ABIL_WU_JIAN_SERPENTS_LASH, "Serpent's Lash",
638             0, 0, 2, {fail_basis::invo}, abflag::exhaustion | abflag::instant },
639         { ABIL_WU_JIAN_HEAVENLY_STORM, "Heavenly Storm",
640             0, 0, 20, {fail_basis::invo, piety_breakpoint(5), 0, 1}, abflag::none },
641         // Lunge and Whirlwind abilities aren't menu abilities but currently need
642         // to exist for action counting, hence need enums/entries.
643         { ABIL_WU_JIAN_LUNGE, "Lunge", 0, 0, 0, {}, abflag::berserk_ok },
644         { ABIL_WU_JIAN_WHIRLWIND, "Whirlwind", 0, 0, 0, {}, abflag::berserk_ok },
645         { ABIL_WU_JIAN_WALLJUMP, "Wall Jump",
646             0, 0, 0, {}, abflag::berserk_ok },
647 
648         { ABIL_STOP_RECALL, "Stop Recall", 0, 0, 0, {fail_basis::invo}, abflag::none },
649         { ABIL_RENOUNCE_RELIGION, "Renounce Religion",
650             0, 0, 0, {fail_basis::invo}, abflag::none },
651         { ABIL_CONVERT_TO_BEOGH, "Convert to Beogh",
652             0, 0, 0, {fail_basis::invo}, abflag::none },
653     };
654     return Ability_List;
655 }
656 
get_ability_def(ability_type abil)657 static const ability_def& get_ability_def(ability_type abil)
658 {
659     for (const ability_def &ab_def : _get_ability_list())
660         if (ab_def.ability == abil)
661             return ab_def;
662 
663     return _get_ability_list()[0];
664 }
665 
get_defined_abilities()666 vector<ability_type> get_defined_abilities()
667 {
668     vector<ability_type> r;
669     for (const ability_def &ab_def : _get_ability_list())
670         r.push_back(ab_def.ability);
671     return r;
672 }
673 
ability_mp_cost(ability_type abil)674 unsigned int ability_mp_cost(ability_type abil)
675 {
676     return get_ability_def(abil).get_mp_cost();
677 }
678 
679 /**
680  * Is there a valid ability with a name matching that given?
681  *
682  * @param key   The name in question. (Not case sensitive.)
683  * @return      true if such an ability exists; false if not.
684  */
string_matches_ability_name(const string & key)685 bool string_matches_ability_name(const string& key)
686 {
687     return ability_by_name(key) != ABIL_NON_ABILITY;
688 }
689 
_invis_causes_drain()690 static bool _invis_causes_drain()
691 {
692     return !player_equip_unrand(UNRAND_INVISIBILITY);
693 }
694 
695 /**
696  * Find an ability whose name matches the given key.
697  *
698  * @param name      The name in question. (Not case sensitive.)
699  * @return          The enum of the relevant ability, if there was one; else
700  *                  ABIL_NON_ABILITY.
701  */
ability_by_name(const string & key)702 ability_type ability_by_name(const string &key)
703 {
704     for (const auto &abil : _get_ability_list())
705     {
706         if (abil.ability == ABIL_NON_ABILITY)
707             continue;
708 
709         const string name = lowercase_string(ability_name(abil.ability));
710         if (name == lowercase_string(key))
711             return abil.ability;
712     }
713 
714     return ABIL_NON_ABILITY;
715 }
716 
print_abilities()717 string print_abilities()
718 {
719     string text = "\n<w>a:</w> ";
720 
721     const vector<talent> talents = your_talents(false);
722 
723     if (talents.empty())
724         text += "no special abilities";
725     else
726     {
727         for (unsigned int i = 0; i < talents.size(); ++i)
728         {
729             if (i)
730                 text += ", ";
731             text += ability_name(talents[i].which);
732         }
733     }
734 
735     return text;
736 }
737 
get_gold_cost(ability_type ability)738 int get_gold_cost(ability_type ability)
739 {
740     switch (ability)
741     {
742     case ABIL_GOZAG_CALL_MERCHANT:
743         return gozag_price_for_shop(true);
744     case ABIL_GOZAG_POTION_PETITION:
745         return GOZAG_POTION_PETITION_AMOUNT;
746     case ABIL_GOZAG_BRIBE_BRANCH:
747         return GOZAG_BRIBE_AMOUNT;
748     default:
749         return 0;
750     }
751 }
752 
nemelex_card_text(ability_type ability)753 string nemelex_card_text(ability_type ability)
754 {
755     int cards = deck_cards(ability_deck(ability));
756 
757     if (ability == ABIL_NEMELEX_DRAW_STACK)
758         return make_stringf("(next: %s)", stack_top().c_str());
759     else
760         return make_stringf("(%d in deck)", cards);
761 }
762 
763 static const int VAMPIRE_BAT_FORM_STAT_DRAIN = 2;
764 
_ashenzari_curse_text()765 static string _ashenzari_curse_text()
766 {
767     const CrawlVector& curses = you.props[CURSE_KNOWLEDGE_KEY].get_vector();
768     return "(Boost: "
769            + comma_separated_fn(curses.begin(), curses.end(),
770                                 curse_abbr, "/", "/")
771            + ")";
772 }
773 
make_cost_description(ability_type ability)774 const string make_cost_description(ability_type ability)
775 {
776     const ability_def& abil = get_ability_def(ability);
777     string ret;
778     if (abil.get_mp_cost())
779         ret += make_stringf(", %d MP", abil.get_mp_cost());
780 
781     if (abil.flags & abflag::variable_mp)
782         ret += ", MP";
783 
784     if (ability == ABIL_HEAL_WOUNDS)
785         ret += make_stringf(", Permanent MP (%d left)", get_real_mp(false));
786 
787     if (ability == ABIL_TRAN_BAT)
788     {
789         ret += make_stringf(", Stat Drain (%d each)",
790                             VAMPIRE_BAT_FORM_STAT_DRAIN);
791     }
792 
793     if (ability == ABIL_REVIVIFY)
794         ret += ", Frailty";
795 
796     if (ability == ABIL_ASHENZARI_CURSE
797         && !you.props[CURSE_KNOWLEDGE_KEY].get_vector().empty())
798     {
799         ret += ", ";
800         ret += _ashenzari_curse_text();
801     }
802 
803     const int hp_cost = abil.get_hp_cost();
804     if (hp_cost)
805         ret += make_stringf(", %d HP", hp_cost);
806 
807     if (abil.piety_cost || abil.flags & abflag::piety)
808         ret += ", Piety"; // randomised and exact amount hidden from player
809 
810     if (abil.flags & abflag::breath)
811         ret += ", Breath";
812 
813     if (abil.flags & abflag::delay)
814         ret += ", Delay";
815 
816     if (abil.flags & abflag::pain)
817         ret += ", Pain";
818 
819     if (abil.flags & abflag::exhaustion)
820         ret += ", Exhaustion";
821 
822     if (abil.flags & abflag::instant)
823         ret += ", Instant"; // not really a cost, more of a bonus - bwr
824 
825     if (abil.flags & abflag::max_hp_drain
826         && (ability != ABIL_EVOKE_TURN_INVISIBLE || _invis_causes_drain()))
827     {
828         ret += ", Max HP drain";
829     }
830 
831     if (abil.flags & abflag::curse)
832         ret += ", Cursed item";
833 
834     if (abil.flags & abflag::gold)
835     {
836         const int amount = get_gold_cost(ability);
837         if (amount)
838             ret += make_stringf(", %d Gold", amount);
839         else if (ability == ABIL_GOZAG_POTION_PETITION)
840             ret += ", Free";
841         else
842             ret += ", Gold";
843     }
844 
845     if (abil.flags & abflag::sacrifice)
846     {
847         ret += ", ";
848         const string prefix = "Sacrifice ";
849         ret += string(ability_name(ability)).substr(prefix.size());
850         ret += ru_sac_text(ability);
851     }
852 
853     if (abil.flags & abflag::card)
854     {
855         ret += ", ";
856         ret += "A Card ";
857         ret += nemelex_card_text(ability);
858     }
859 
860     // If we haven't output anything so far, then the effect has no cost
861     if (ret.empty())
862         return "None";
863 
864     ret.erase(0, 2);
865     return ret;
866 }
867 
_get_piety_amount_str(int value)868 static string _get_piety_amount_str(int value)
869 {
870     return value > 15 ? "extremely large" :
871            value > 10 ? "large" :
872            value > 5  ? "moderate" :
873                         "small";
874 }
875 
_detailed_cost_description(ability_type ability)876 static const string _detailed_cost_description(ability_type ability)
877 {
878     const ability_def& abil = get_ability_def(ability);
879     ostringstream ret;
880 
881     bool have_cost = false;
882     ret << "This ability costs: ";
883 
884     if (abil.get_mp_cost())
885     {
886         have_cost = true;
887         ret << "\nMP     : ";
888         ret << abil.get_mp_cost();
889     }
890     if (abil.get_hp_cost())
891     {
892         have_cost = true;
893         ret << "\nHP     : ";
894         ret << abil.get_hp_cost();
895     }
896 
897     if (abil.piety_cost || abil.flags & abflag::piety)
898     {
899         have_cost = true;
900         ret << "\nPiety  : ";
901         if (abil.flags & abflag::piety)
902             ret << "variable";
903         else
904         {
905             int avgcost = abil.piety_cost.base + abil.piety_cost.add / 2;
906             ret << _get_piety_amount_str(avgcost);
907         }
908     }
909 
910     if (abil.flags & abflag::gold)
911     {
912         have_cost = true;
913         ret << "\nGold   : ";
914         int gold_amount = get_gold_cost(ability);
915         if (gold_amount)
916             ret << gold_amount;
917         else if (ability == ABIL_GOZAG_POTION_PETITION)
918             ret << "free";
919         else
920             ret << "variable";
921     }
922 
923     if (abil.flags & abflag::curse)
924     {
925         have_cost = true;
926         ret << "\nOne cursed item";
927     }
928 
929     if (!have_cost)
930         ret << "nothing.";
931 
932     if (abil.flags & abflag::breath)
933         ret << "\nYou must catch your breath between uses of this ability.";
934 
935     if (abil.flags & abflag::delay)
936         ret << "\nThis ability takes some time before being effective.";
937 
938     if (abil.flags & abflag::pain)
939         ret << "\nUsing this ability will hurt you.";
940 
941     if (abil.flags & abflag::exhaustion)
942         ret << "\nThis ability causes exhaustion, and cannot be used when exhausted.";
943 
944     if (abil.flags & abflag::instant)
945         ret << "\nThis ability is instantaneous.";
946 
947     if (abil.flags & abflag::conf_ok)
948         ret << "\nYou can use this ability even if confused.";
949 
950     if (abil.flags & abflag::max_hp_drain
951         && (ability != ABIL_EVOKE_TURN_INVISIBLE || _invis_causes_drain()))
952     {
953         ret << "\nThis ability will temporarily drain your maximum hit points when used";
954         if (ability == ABIL_EVOKE_TURN_INVISIBLE)
955             ret << ", even unsuccessfully";
956         ret << ".";
957     }
958 
959     if (abil.ability == ABIL_HEAL_WOUNDS)
960     {
961         ASSERT(!have_cost); // validate just in case this ever changes
962         return "This ability has a chance of reducing your maximum magic "
963                "capacity when used.";
964     }
965 
966     return ret.str();
967 }
968 
969 // TODO: consolidate with player_has_ability?
fixup_ability(ability_type ability)970 ability_type fixup_ability(ability_type ability)
971 {
972     switch (ability)
973     {
974     case ABIL_YRED_ANIMATE_REMAINS:
975         // suppress animate remains once animate dead is unlocked (ugh)
976         if (in_good_standing(GOD_YREDELEMNUL, 2))
977             return ABIL_NON_ABILITY;
978         return ability;
979 
980     case ABIL_YRED_RECALL_UNDEAD_SLAVES:
981     case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS:
982         if (!you.recall_list.empty())
983             return ABIL_STOP_RECALL;
984         return ability;
985 
986     case ABIL_EVOKE_BERSERK:
987     case ABIL_TROG_BERSERK:
988         if (you.is_lifeless_undead() || you.stasis())
989             return ABIL_NON_ABILITY;
990         return ability;
991 
992     case ABIL_EVOKE_BLINK:
993         if (you.stasis())
994             return ABIL_NON_ABILITY;
995         else
996             return ability;
997 
998     case ABIL_LUGONU_ABYSS_EXIT:
999     case ABIL_LUGONU_ABYSS_ENTER:
1000         if (brdepth[BRANCH_ABYSS] == -1)
1001             return ABIL_NON_ABILITY;
1002         else
1003             return ability;
1004 
1005     case ABIL_TSO_BLESS_WEAPON:
1006     case ABIL_KIKU_BLESS_WEAPON:
1007     case ABIL_LUGONU_BLESS_WEAPON:
1008         if (you.has_mutation(MUT_NO_GRASPING))
1009             return ABIL_NON_ABILITY;
1010         else
1011             return ability;
1012 
1013     case ABIL_ELYVILON_HEAL_OTHER:
1014     case ABIL_TSO_SUMMON_DIVINE_WARRIOR:
1015     case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
1016     case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
1017     case ABIL_TROG_BROTHERS_IN_ARMS:
1018     case ABIL_GOZAG_BRIBE_BRANCH:
1019     case ABIL_QAZLAL_ELEMENTAL_FORCE:
1020         if (you.get_mutation_level(MUT_NO_LOVE))
1021             return ABIL_NON_ABILITY;
1022         else
1023             return ability;
1024 
1025     case ABIL_SIF_MUNA_CHANNEL_ENERGY:
1026         if (you.get_mutation_level(MUT_HP_CASTING))
1027             return ABIL_NON_ABILITY;
1028         return ability;
1029 
1030     case ABIL_SIF_MUNA_FORGET_SPELL:
1031         if (you.get_mutation_level(MUT_INNATE_CASTER))
1032             return ABIL_NON_ABILITY;
1033         return ability;
1034 
1035     default:
1036         return ability;
1037     }
1038 }
1039 
1040 /// Handle special cases for ability failure chances.
_adjusted_failure_chance(ability_type ability,int base_chance)1041 static int _adjusted_failure_chance(ability_type ability, int base_chance)
1042 {
1043     switch (ability)
1044     {
1045     case ABIL_BREATHE_FIRE:
1046     case ABIL_BREATHE_FROST:
1047     case ABIL_BREATHE_ACID:
1048     case ABIL_BREATHE_LIGHTNING:
1049     case ABIL_BREATHE_POWER:
1050     case ABIL_BREATHE_MEPHITIC:
1051     case ABIL_BREATHE_STEAM:
1052         if (you.form == transformation::dragon)
1053             return base_chance - 20;
1054         return base_chance;
1055 
1056     case ABIL_NEMELEX_DEAL_FOUR:
1057         return 70 - (you.piety * 2 / 45) - you.skill(SK_INVOCATIONS, 9) / 2;
1058 
1059     default:
1060         return base_chance;
1061     }
1062 }
1063 
get_talent(ability_type ability,bool check_confused)1064 talent get_talent(ability_type ability, bool check_confused)
1065 {
1066     ASSERT(ability != ABIL_NON_ABILITY);
1067 
1068     // Placeholder handling, part 1: The ability we have might be a
1069     // placeholder, so convert it into its corresponding ability before
1070     // doing anything else, so that we'll handle its flags properly.
1071     talent result { fixup_ability(ability), 0, 0, false };
1072     const ability_def &abil = get_ability_def(result.which);
1073 
1074     if (check_confused && you.confused()
1075         && !testbits(abil.flags, abflag::conf_ok))
1076     {
1077         result.which = ABIL_NON_ABILITY;
1078         return result;
1079     }
1080 
1081     // Look through the table to see if there's a preference, else find
1082     // a new empty slot for this ability. - bwr
1083     const int index = find_ability_slot(abil.ability);
1084     result.hotkey = index >= 0 ? index_to_letter(index) : 0;
1085 
1086     const int base_chance = abil.failure.chance();
1087     const int failure = _adjusted_failure_chance(ability, base_chance);
1088     result.fail = max(0, min(100, failure));
1089 
1090     result.is_invocation = abil.failure.basis == fail_basis::invo;
1091 
1092     return result;
1093 }
1094 
ability_name(ability_type ability)1095 const char* ability_name(ability_type ability)
1096 {
1097     return get_ability_def(ability).name;
1098 }
1099 
get_ability_names()1100 vector<const char*> get_ability_names()
1101 {
1102     vector<const char*> result;
1103     for (const talent &tal : your_talents(false))
1104         result.push_back(ability_name(tal.which));
1105     return result;
1106 }
1107 
_curse_desc()1108 static string _curse_desc()
1109 {
1110     if (!you.props.exists(CURSE_KNOWLEDGE_KEY))
1111         return "";
1112 
1113     const CrawlVector& curses = you.props[CURSE_KNOWLEDGE_KEY].get_vector();
1114 
1115     if (curses.empty())
1116         return "";
1117 
1118     return "\nIf you bind an item with this curse Ashenzari will enhance "
1119            "the following skills:\n"
1120            + comma_separated_fn(curses.begin(), curses.end(), desc_curse_skills,
1121                                 ".\n", ".\n") + ".";
1122 }
1123 
_desc_sac_mut(const CrawlStoreValue & mut_store)1124 static string _desc_sac_mut(const CrawlStoreValue &mut_store)
1125 {
1126     return mut_upgrade_summary(static_cast<mutation_type>(mut_store.get_int()));
1127 }
1128 
_sacrifice_desc(const ability_type ability)1129 static string _sacrifice_desc(const ability_type ability)
1130 {
1131     const string boilerplate =
1132         "\nIf you make this sacrifice, your powers granted by Ru "
1133         "will become stronger in proportion to the value of the "
1134         "sacrifice, and you may gain new powers as well.\n\n"
1135         "Sacrifices cannot be taken back.\n";
1136     const string piety_info = ru_sacrifice_description(ability);
1137     const string desc = boilerplate + piety_info;
1138 
1139     if (!you_worship(GOD_RU))
1140         return desc;
1141 
1142     const string sac_vec_key = ru_sacrifice_vector(ability);
1143     if (sac_vec_key.empty())
1144         return desc;
1145 
1146     ASSERT(you.props.exists(sac_vec_key));
1147     const CrawlVector &sacrifice_muts = you.props[sac_vec_key].get_vector();
1148     return "\nAfter this sacrifice, you will find that "
1149             + comma_separated_fn(sacrifice_muts.begin(), sacrifice_muts.end(),
1150                                  _desc_sac_mut)
1151             + ".\n" + desc;
1152 }
1153 
_nemelex_desc(ability_type ability)1154 static string _nemelex_desc(ability_type ability)
1155 {
1156     ostringstream desc;
1157     deck_type deck = ability_deck(ability);
1158 
1159     desc << "Draw a card from " << (deck == DECK_STACK ? "your " : "the ");
1160     desc << deck_name(deck) << "; " << lowercase_first(deck_description(deck));
1161 
1162     return desc.str();
1163 }
1164 
1165 // XXX: should this be in describe.cc?
get_ability_desc(const ability_type ability,bool need_title)1166 string get_ability_desc(const ability_type ability, bool need_title)
1167 {
1168     const string& name = ability_name(ability);
1169 
1170     string lookup;
1171 
1172     if (testbits(get_ability_def(ability).flags, abflag::card))
1173         lookup = _nemelex_desc(ability);
1174     else
1175         lookup = getLongDescription(name + " ability");
1176 
1177     if (lookup.empty()) // Nothing found?
1178         lookup = "No description found.\n";
1179 
1180     if (ability == ABIL_ASHENZARI_CURSE)
1181         lookup += _curse_desc();
1182 
1183     if (testbits(get_ability_def(ability).flags, abflag::sacrifice))
1184         lookup += _sacrifice_desc(ability);
1185 
1186     if (god_hates_ability(ability, you.religion))
1187     {
1188         lookup += uppercase_first(god_name(you.religion))
1189                   + " frowns upon the use of this ability.\n";
1190     }
1191 
1192     ostringstream res;
1193     if (need_title)
1194         res << name << "\n\n";
1195     res << lookup << "\n" << _detailed_cost_description(ability);
1196 
1197     const string quote = getQuoteString(name + " ability");
1198     if (!quote.empty())
1199         res << "\n\n" << quote;
1200 
1201     return res.str();
1202 }
1203 
_print_talent_description(const talent & tal)1204 static void _print_talent_description(const talent& tal)
1205 {
1206     describe_ability(tal.which);
1207 }
1208 
no_ability_msg()1209 void no_ability_msg()
1210 {
1211     // Give messages if the character cannot use innate talents right now.
1212     // * Vampires can't turn into bats when full of blood.
1213     // * Tengu can't start to fly if already flying.
1214     if (you.get_mutation_level(MUT_VAMPIRISM) >= 2)
1215     {
1216         if (you.transform_uncancellable)
1217             mpr("You can't untransform!");
1218         else
1219         {
1220             ASSERT(you.vampire_alive);
1221             mpr("Sorry, you cannot become a bat while alive.");
1222         }
1223     }
1224     else if (you.get_mutation_level(MUT_TENGU_FLIGHT)
1225              || you.get_mutation_level(MUT_BIG_WINGS))
1226     {
1227         if (you.airborne())
1228             mpr("You're already flying!");
1229     }
1230     else
1231         mpr("Sorry, you're not good enough to have a special ability.");
1232 }
1233 
1234 // Prompts the user for an ability to use, first checking the lua hook
1235 // c_choose_ability
activate_ability()1236 bool activate_ability()
1237 {
1238     vector<talent> talents = your_talents(false);
1239 
1240     if (talents.empty())
1241     {
1242         no_ability_msg();
1243         crawl_state.zero_turns_taken();
1244         return false;
1245     }
1246 
1247     int selected = -1;
1248 
1249     string luachoice;
1250 
1251     if (!clua.callfn("c_choose_ability", ">s", &luachoice))
1252     {
1253         if (!clua.error.empty())
1254             mprf(MSGCH_ERROR, "Lua error: %s", clua.error.c_str());
1255     }
1256     else if (!luachoice.empty())
1257     {
1258         bool valid = false;
1259         // Sanity check
1260         for (unsigned int i = 0; i < talents.size(); ++i)
1261         {
1262             if (talents[i].hotkey == luachoice[0])
1263             {
1264                 selected = static_cast<int>(i);
1265                 valid = true;
1266                 break;
1267             }
1268         }
1269 
1270         // Lua gave us garbage, defer to the user
1271         if (!valid)
1272             selected = -1;
1273     }
1274 
1275 #ifndef TOUCH_UI
1276     if (Options.ability_menu && selected == -1)
1277 #else
1278     if (selected == -1)
1279 #endif
1280     {
1281         selected = choose_ability_menu(talents);
1282         if (selected == -1)
1283         {
1284             canned_msg(MSG_OK);
1285             crawl_state.zero_turns_taken();
1286             return false;
1287         }
1288     }
1289 #ifndef TOUCH_UI
1290     else
1291     {
1292         while (selected < 0)
1293         {
1294             msg::streams(MSGCH_PROMPT) << "Use which ability? (? or * to list) "
1295                                        << endl;
1296 
1297             const int keyin = get_ch();
1298 
1299             if (keyin == '?' || keyin == '*')
1300             {
1301                 selected = choose_ability_menu(talents);
1302                 if (selected == -1)
1303                 {
1304                     canned_msg(MSG_OK);
1305                     crawl_state.zero_turns_taken();
1306                     return false;
1307                 }
1308             }
1309             else if (key_is_escape(keyin) || keyin == ' ' || keyin == '\r'
1310                      || keyin == '\n')
1311             {
1312                 canned_msg(MSG_OK);
1313                 crawl_state.zero_turns_taken();
1314                 return false;
1315             }
1316             else if (isaalpha(keyin))
1317             {
1318                 // Try to find the hotkey.
1319                 for (unsigned int i = 0; i < talents.size(); ++i)
1320                 {
1321                     if (talents[i].hotkey == keyin)
1322                     {
1323                         selected = static_cast<int>(i);
1324                         break;
1325                     }
1326                 }
1327 
1328                 // If we can't, cancel out.
1329                 if (selected < 0)
1330                 {
1331                     mpr("You can't do that.");
1332                     crawl_state.zero_turns_taken();
1333                     return false;
1334                 }
1335             }
1336         }
1337     }
1338 #endif
1339     return activate_talent(talents[selected]);
1340 }
1341 
_can_movement_ability(bool quiet)1342 static bool _can_movement_ability(bool quiet)
1343 {
1344     if (you.attribute[ATTR_HELD])
1345     {
1346         if (!quiet)
1347             mprf("You cannot do that while %s.", held_status());
1348         return false;
1349     }
1350     else if (you.is_stationary())
1351     {
1352         if (!quiet)
1353             canned_msg(MSG_CANNOT_MOVE);
1354         return false;
1355     }
1356     return true;
1357 }
1358 
_can_hop(bool quiet)1359 static bool _can_hop(bool quiet)
1360 {
1361     if (you.duration[DUR_NO_HOP])
1362     {
1363         if (!quiet)
1364             mpr("Your legs are too worn out to hop.");
1365         return false;
1366     }
1367     return _can_movement_ability(quiet);
1368 }
1369 
_can_blinkbolt(bool quiet)1370 static bool _can_blinkbolt(bool quiet)
1371 {
1372     if (you.duration[DUR_BLINKBOLT_COOLDOWN])
1373     {
1374         if (!quiet)
1375             mpr("You aren't ready to blinkbolt again yet.");
1376         return false;
1377     }
1378     return true;
1379 }
1380 
1381 // Check prerequisites for a number of abilities.
1382 // Abort any attempt if these cannot be met, without losing the turn.
1383 // TODO: Many more cases need to be added!
_check_ability_possible(const ability_def & abil,bool quiet=false)1384 static bool _check_ability_possible(const ability_def& abil, bool quiet = false)
1385 {
1386     if (you.berserk() && !testbits(abil.flags, abflag::berserk_ok))
1387     {
1388         if (!quiet)
1389             canned_msg(MSG_TOO_BERSERK);
1390         return false;
1391     }
1392 
1393     // Doing these would outright kill the player.
1394     // (or, in the case of the stat-zeros, they'd at least be extremely
1395     // dangerous.)
1396     if (abil.ability == ABIL_END_TRANSFORMATION)
1397     {
1398         if (feat_dangerous_for_form(transformation::none, env.grid(you.pos()))
1399             && !you.duration[DUR_FLIGHT])
1400         {
1401             if (!quiet)
1402             {
1403                 mprf("Turning back right now would cause you to %s!",
1404                     env.grid(you.pos()) == DNGN_LAVA ? "burn" : "drown");
1405             }
1406 
1407             return false;
1408         }
1409     }
1410     else if ((abil.ability == ABIL_EXSANGUINATE
1411               || abil.ability == ABIL_REVIVIFY)
1412             && you.form != transformation::none)
1413     {
1414         if (feat_dangerous_for_form(transformation::none, env.grid(you.pos())))
1415         {
1416             if (!quiet)
1417             {
1418                 mprf("Becoming %s right now would cause you to %s!",
1419                     abil.ability == ABIL_EXSANGUINATE ? "bloodless" : "alive",
1420                     env.grid(you.pos()) == DNGN_LAVA ? "burn" : "drown");
1421             }
1422 
1423             return false;
1424         }
1425     }
1426 
1427     if ((abil.ability == ABIL_EVOKE_BERSERK
1428          || abil.ability == ABIL_TROG_BERSERK)
1429         && !you.can_go_berserk(true, false, quiet))
1430     {
1431         return false;
1432     }
1433 
1434     if (you.confused() && !testbits(abil.flags, abflag::conf_ok))
1435     {
1436         if (!quiet)
1437             canned_msg(MSG_TOO_CONFUSED);
1438         return false;
1439     }
1440 
1441     // Silence and water elementals
1442     if (silenced(you.pos())
1443         || you.duration[DUR_WATER_HOLD] && !you.res_water_drowning())
1444     {
1445         talent tal = get_talent(abil.ability, false);
1446         if (tal.is_invocation && abil.ability != ABIL_RENOUNCE_RELIGION)
1447         {
1448             if (!quiet)
1449             {
1450                 mprf("You cannot call out to %s while %s.",
1451                      god_name(you.religion).c_str(),
1452                      you.duration[DUR_WATER_HOLD] ? "unable to breathe"
1453                                                   : "silenced");
1454             }
1455             return false;
1456         }
1457         if (abil.ability == ABIL_WORD_OF_CHAOS)
1458         {
1459             if (!quiet)
1460             {
1461                 mprf("You cannot speak a word of chaos while %s.",
1462                      you.duration[DUR_WATER_HOLD] ? "unable to breathe"
1463                                                   : "silenced");
1464             }
1465             return false;
1466         }
1467     }
1468 
1469     const god_power* god_power = god_power_from_ability(abil.ability);
1470     if (god_power && !god_power_usable(*god_power))
1471     {
1472         if (!quiet)
1473             canned_msg(MSG_GOD_DECLINES);
1474         return false;
1475     }
1476 
1477     if (testbits(abil.flags, abflag::card) && !deck_cards(ability_deck(abil.ability)))
1478     {
1479         if (!quiet)
1480             mpr("That deck is empty!");
1481         return false;
1482     }
1483 
1484     if (!quiet)
1485     {
1486         vector<text_pattern> &actions = Options.confirm_action;
1487         if (!actions.empty())
1488         {
1489             const char* name = ability_name(abil.ability);
1490             for (const text_pattern &action : actions)
1491             {
1492                 if (action.matches(name))
1493                 {
1494                     string prompt = "Really use " + string(name) + "?";
1495                     if (!yesno(prompt.c_str(), false, 'n'))
1496                     {
1497                         canned_msg(MSG_OK);
1498                         return false;
1499                     }
1500                     break;
1501                 }
1502             }
1503         }
1504     }
1505 
1506     // Check that we can afford to pay the costs.
1507     // Note that mutation shenanigans might leave us with negative MP,
1508     // so don't fail in that case if there's no MP cost.
1509     if (abil.get_mp_cost() > 0 && !enough_mp(abil.get_mp_cost(), quiet, true))
1510         return false;
1511 
1512     const int hpcost = abil.get_hp_cost();
1513     if (hpcost > 0 && !enough_hp(hpcost, quiet))
1514         return false;
1515 
1516     switch (abil.ability)
1517     {
1518     case ABIL_ZIN_RECITE:
1519     {
1520         if (!zin_check_able_to_recite(quiet))
1521             return false;
1522 
1523         int result = zin_check_recite_to_monsters(quiet);
1524         if (result != 1)
1525         {
1526             if (!quiet)
1527             {
1528                 if (result == 0)
1529                     mpr("There's no appreciative audience!");
1530                 else if (result == -1)
1531                     mpr("You are not zealous enough to affect this audience!");
1532             }
1533             return false;
1534         }
1535         return true;
1536     }
1537 
1538     case ABIL_ZIN_SANCTUARY:
1539         if (env.sanctuary_time)
1540         {
1541             if (!quiet)
1542                 mpr("There's already a sanctuary in place on this level.");
1543             return false;
1544         }
1545         return true;
1546 
1547     case ABIL_ZIN_DONATE_GOLD:
1548         if (!you.gold)
1549         {
1550             if (!quiet)
1551                 mpr("You have nothing to donate!");
1552             return false;
1553         }
1554         return true;
1555 
1556     case ABIL_ELYVILON_PURIFICATION:
1557         if (!you.duration[DUR_SICKNESS]
1558             && !you.duration[DUR_POISONING]
1559             && !you.duration[DUR_CONF] && !you.duration[DUR_SLOW]
1560             && !you.petrifying()
1561             && you.strength(false) == you.max_strength()
1562             && you.intel(false) == you.max_intel()
1563             && you.dex(false) == you.max_dex()
1564             && !player_drained()
1565             && !you.duration[DUR_WEAK])
1566         {
1567             if (!quiet)
1568                 mpr("Nothing ails you!");
1569             return false;
1570         }
1571         return true;
1572 
1573     case ABIL_LUGONU_ABYSS_EXIT:
1574         if (!player_in_branch(BRANCH_ABYSS))
1575         {
1576             if (!quiet)
1577                 mpr("You aren't in the Abyss!");
1578             return false;
1579         }
1580         return true;
1581 
1582     case ABIL_LUGONU_CORRUPT:
1583         return !is_level_incorruptible(quiet);
1584 
1585     case ABIL_LUGONU_ABYSS_ENTER:
1586         if (player_in_branch(BRANCH_ABYSS))
1587         {
1588             if (!quiet)
1589                 mpr("You're already here!");
1590             return false;
1591         }
1592         return true;
1593 
1594     case ABIL_SIF_MUNA_FORGET_SPELL:
1595         if (you.spell_no == 0)
1596         {
1597             if (!quiet)
1598                 canned_msg(MSG_NO_SPELLS);
1599             return false;
1600         }
1601         return true;
1602 
1603     case ABIL_SIF_MUNA_DIVINE_EXEGESIS:
1604         return can_cast_spells(quiet, true);
1605 
1606     case ABIL_SPIT_POISON:
1607     case ABIL_BREATHE_FIRE:
1608     case ABIL_BREATHE_FROST:
1609     case ABIL_BREATHE_POISON:
1610     case ABIL_BREATHE_LIGHTNING:
1611     case ABIL_BREATHE_ACID:
1612     case ABIL_BREATHE_POWER:
1613     case ABIL_BREATHE_STEAM:
1614     case ABIL_BREATHE_MEPHITIC:
1615         if (you.duration[DUR_BREATH_WEAPON])
1616         {
1617             if (!quiet)
1618                 canned_msg(MSG_CANNOT_DO_YET);
1619             return false;
1620         }
1621         return true;
1622 
1623     case ABIL_HEAL_WOUNDS:
1624         if (you.hp == you.hp_max)
1625         {
1626             if (!quiet)
1627                 canned_msg(MSG_FULL_HEALTH);
1628             return false;
1629         }
1630         if (get_real_mp(false) < 1)
1631         {
1632             if (!quiet)
1633                 mpr("You don't have enough innate magic capacity.");
1634             return false;
1635         }
1636         return true;
1637 
1638     case ABIL_SHAFT_SELF:
1639         return you.can_do_shaft_ability(quiet);
1640 
1641     case ABIL_HOP:
1642         return _can_hop(quiet);
1643 
1644     case ABIL_ROLLING_CHARGE:
1645         return _can_movement_ability(quiet) &&
1646                                 palentonga_charge_possible(quiet, true);
1647 
1648     case ABIL_WORD_OF_CHAOS:
1649         if (you.duration[DUR_WORD_OF_CHAOS_COOLDOWN])
1650         {
1651             if (!quiet)
1652                 canned_msg(MSG_CANNOT_DO_YET);
1653             return false;
1654         }
1655         return true;
1656 
1657     case ABIL_EVOKE_BLINK:
1658     case ABIL_BLINKBOLT:
1659     {
1660         const string no_tele_reason = you.no_tele_reason(false, true);
1661         if (no_tele_reason.empty())
1662             return true;
1663 
1664         if (!quiet)
1665              mpr(no_tele_reason);
1666         return false;
1667     }
1668 
1669     case ABIL_EVOKE_BERSERK:
1670     case ABIL_TROG_BERSERK:
1671         return you.can_go_berserk(true, false, true)
1672                && (quiet || berserk_check_wielded_weapon());
1673 
1674     case ABIL_EVOKE_TURN_INVISIBLE:
1675         if (you.duration[DUR_INVIS])
1676         {
1677             if (!quiet)
1678                 mpr("You are already invisible!");
1679             return false;
1680         }
1681         return true;
1682 
1683     case ABIL_GOZAG_POTION_PETITION:
1684         return gozag_setup_potion_petition(quiet);
1685 
1686     case ABIL_GOZAG_CALL_MERCHANT:
1687         return gozag_setup_call_merchant(quiet);
1688 
1689     case ABIL_GOZAG_BRIBE_BRANCH:
1690         return gozag_check_bribe_branch(quiet);
1691 
1692     case ABIL_RU_SACRIFICE_EXPERIENCE:
1693         if (you.experience_level <= RU_SAC_XP_LEVELS)
1694         {
1695             if (!quiet)
1696                 mpr("You don't have enough experience to sacrifice.");
1697             return false;
1698         }
1699         return true;
1700 
1701         // only available while your ancestor is alive.
1702     case ABIL_HEPLIAKLQANA_IDEALISE:
1703     case ABIL_HEPLIAKLQANA_RECALL:
1704     case ABIL_HEPLIAKLQANA_TRANSFERENCE:
1705         if (hepliaklqana_ancestor() == MID_NOBODY)
1706         {
1707             if (!quiet)
1708             {
1709                 mprf("%s is still trapped in memory!",
1710                      hepliaklqana_ally_name().c_str());
1711             }
1712             return false;
1713         }
1714         return true;
1715 
1716     case ABIL_WU_JIAN_WALLJUMP:
1717     {
1718         // TODO: Add check for whether there is any valid landing spot
1719         if (you.is_nervous())
1720         {
1721             if (!quiet)
1722                 mpr("You are too terrified to wall jump!");
1723             return false;
1724         }
1725         if (you.attribute[ATTR_HELD])
1726         {
1727             if (!quiet)
1728             {
1729                 mprf("You cannot wall jump while caught in a %s.",
1730                      get_trapping_net(you.pos()) == NON_ITEM ? "web" : "net");
1731             }
1732             return false;
1733         }
1734         // Is there a valid place to wall jump?
1735         bool has_targets = false;
1736         for (adjacent_iterator ai(you.pos()); ai; ++ai)
1737             if (feat_can_wall_jump_against(env.grid(*ai)))
1738             {
1739                 has_targets = true;
1740                 break;
1741             }
1742 
1743         if (!has_targets)
1744         {
1745             if (!quiet)
1746                 mpr("There is nothing to wall jump against here.");
1747             return false;
1748         }
1749         return true;
1750     }
1751 
1752     default:
1753         return true;
1754     }
1755 }
1756 
_check_ability_dangerous(const ability_type ability,bool quiet=false)1757 static bool _check_ability_dangerous(const ability_type ability,
1758                                      bool quiet = false)
1759 {
1760     if (ability == ABIL_TRAN_BAT)
1761         return !check_form_stat_safety(transformation::bat, quiet);
1762     else if (ability == ABIL_END_TRANSFORMATION
1763              && !feat_dangerous_for_form(transformation::none,
1764                                          env.grid(you.pos())))
1765     {
1766         return !check_form_stat_safety(transformation::bat, quiet);
1767     }
1768     else
1769         return false;
1770 }
1771 
check_ability_possible(const ability_type ability,bool quiet)1772 bool check_ability_possible(const ability_type ability, bool quiet)
1773 {
1774     return _check_ability_possible(get_ability_def(ability), quiet);
1775 }
1776 
activate_talent(const talent & tal,dist * target)1777 bool activate_talent(const talent& tal, dist *target)
1778 {
1779     const ability_def& abil = get_ability_def(tal.which);
1780 
1781     if (_check_ability_dangerous(abil.ability) || !_check_ability_possible(abil))
1782     {
1783         crawl_state.zero_turns_taken();
1784         return false;
1785     }
1786 
1787     bool fail = random2avg(100, 3) < tal.fail;
1788 
1789     const spret ability_result = _do_ability(abil, fail, target);
1790     switch (ability_result)
1791     {
1792         case spret::success:
1793             ASSERT(!fail || testbits(abil.flags, abflag::hostile));
1794             practise_using_ability(abil.ability);
1795             _pay_ability_costs(abil);
1796             count_action(tal.is_invocation ? CACT_INVOKE : CACT_ABIL, abil.ability);
1797             return true;
1798         case spret::fail:
1799             mpr("You fail to use your ability.");
1800             you.turn_is_over = true;
1801             return false;
1802         case spret::abort:
1803             crawl_state.zero_turns_taken();
1804             return false;
1805         case spret::none:
1806         default:
1807             die("Weird ability return type");
1808             return false;
1809     }
1810 }
1811 
_calc_breath_ability_range(ability_type ability)1812 static int _calc_breath_ability_range(ability_type ability)
1813 {
1814     int range = 0;
1815 
1816     switch (ability)
1817     {
1818     case ABIL_BREATHE_ACID:
1819         range = 3;
1820         break;
1821     case ABIL_BREATHE_FIRE:
1822     case ABIL_BREATHE_FROST:
1823     case ABIL_SPIT_POISON:
1824         range = 5;
1825         break;
1826     case ABIL_BREATHE_MEPHITIC:
1827     case ABIL_BREATHE_STEAM:
1828     case ABIL_BREATHE_POISON:
1829         range = 6;
1830         break;
1831     case ABIL_BREATHE_LIGHTNING:
1832     case ABIL_BREATHE_POWER:
1833         range = LOS_MAX_RANGE;
1834         break;
1835     default:
1836         die("Bad breath type!");
1837         break;
1838     }
1839 
1840     return min((int)you.current_vision, range);
1841 }
1842 
_acid_breath_can_hit(const actor * act)1843 static bool _acid_breath_can_hit(const actor *act)
1844 {
1845     if (act->is_monster())
1846     {
1847         const monster* mons = act->as_monster();
1848         bolt testbeam;
1849         testbeam.thrower = KILL_YOU;
1850         zappy(ZAP_BREATHE_ACID, 100, false, testbeam);
1851 
1852         return !testbeam.ignores_monster(mons);
1853     }
1854     else
1855         return false;
1856 }
1857 
1858 /// If the player is stationary, print 'You cannot move.' and return true.
_abort_if_stationary()1859 static bool _abort_if_stationary()
1860 {
1861     if (!you.is_stationary())
1862         return false;
1863 
1864     canned_msg(MSG_CANNOT_MOVE);
1865     return true;
1866 }
1867 
_cleansing_flame_affects(const actor * act)1868 static bool _cleansing_flame_affects(const actor *act)
1869 {
1870     return act->res_holy_energy() < 3;
1871 }
1872 
_vampire_str_int_info_blurb(string stats_affected)1873 static string _vampire_str_int_info_blurb(string stats_affected)
1874 {
1875     return make_stringf("This will reduce your %s to zero. ",
1876                         stats_affected.c_str());
1877 }
1878 
1879 /*
1880  * Create a string which informs the player of the consequences of bat form.
1881  *
1882  * @param str_affected Whether the player will cause strength stat zero by
1883  * Bat Form's stat drain ability cost.
1884  * @param dex_affected Whether the player will cause dexterity stat zero by
1885  * Bat Form's stat drain ability cost, disregarding Bat Form's dexterity boost.
1886  * @param int_affected Whether the player will cause intelligence stat zero by
1887  * Bat Form's stat drain ability cost.
1888  * @returns The string prompt to give the player.
1889  */
_vampire_bat_transform_prompt(bool str_affected,bool dex_affected,bool intel_affected)1890 static string _vampire_bat_transform_prompt(bool str_affected, bool dex_affected,
1891                                             bool intel_affected)
1892 {
1893     string prompt = "";
1894 
1895     if (str_affected && intel_affected)
1896         prompt += _vampire_str_int_info_blurb("strength and intelligence");
1897     else if (str_affected)
1898         prompt += _vampire_str_int_info_blurb("strength");
1899     else if (intel_affected)
1900         prompt += _vampire_str_int_info_blurb("intelligence");
1901 
1902     // Bat form's dexterity boost will keep a vampire's dexterity above zero until
1903     // they untransform.
1904     if (dex_affected)
1905         prompt += "This will reduce your dexterity to zero once you untransform. ";
1906 
1907     prompt += "Continue?";
1908 
1909     return prompt;
1910 }
1911 
_stat_affected_by_bat_form_stat_drain(int stat_value)1912 static bool _stat_affected_by_bat_form_stat_drain(int stat_value)
1913 {
1914     // We check whether the stat is greater than zero to avoid prompting if a
1915     // stat is already zero.
1916     return 0 < stat_value && stat_value <= VAMPIRE_BAT_FORM_STAT_DRAIN;
1917 }
1918 
1919 /*
1920  * Give the player a chance to cancel a bat form transformation which could
1921  * cause their stats to be drained to zero.
1922  *
1923  * @returns Whether the player canceled the transformation.
1924  */
_player_cancels_vampire_bat_transformation()1925 static bool _player_cancels_vampire_bat_transformation()
1926 {
1927 
1928     bool str_affected = _stat_affected_by_bat_form_stat_drain(you.strength());
1929     bool dex_affected = _stat_affected_by_bat_form_stat_drain(you.dex());
1930     bool intel_affected = _stat_affected_by_bat_form_stat_drain(you.intel());
1931 
1932     // Don't prompt if there's no risk of stat-zero
1933     if (!str_affected && !dex_affected && !intel_affected)
1934         return false;
1935 
1936     string prompt = _vampire_bat_transform_prompt(str_affected, dex_affected,
1937                                                   intel_affected);
1938 
1939     bool proceed_with_transformation = yesno(prompt.c_str(), false, 'n');
1940 
1941     if (!proceed_with_transformation)
1942         canned_msg(MSG_OK);
1943 
1944     return !proceed_with_transformation;
1945 }
1946 
_cause_vampire_bat_form_stat_drain()1947 static void _cause_vampire_bat_form_stat_drain()
1948 {
1949     lose_stat(STAT_STR, VAMPIRE_BAT_FORM_STAT_DRAIN);
1950     lose_stat(STAT_INT, VAMPIRE_BAT_FORM_STAT_DRAIN);
1951     lose_stat(STAT_DEX, VAMPIRE_BAT_FORM_STAT_DRAIN);
1952 }
1953 
1954 /*
1955  * Use an ability.
1956  *
1957  * @param abil The actual ability used.
1958  * @param fail If true, the ability is doomed to fail, and spret::fail will
1959  * be returned if the ability is not spret::aborted.
1960  * @returns Whether the spell succeeded (spret::success), failed (spret::fail),
1961  *  or was canceled (spret::abort). Never returns spret::none.
1962  */
_do_ability(const ability_def & abil,bool fail,dist * target)1963 static spret _do_ability(const ability_def& abil, bool fail, dist *target)
1964 {
1965     dist target_local;
1966     if (!target)
1967         target = &target_local;
1968 
1969     bolt beam;
1970 
1971     // Note: the costs will not be applied until after this switch
1972     // statement... it's assumed that only failures have returned! - bwr
1973     switch (abil.ability)
1974     {
1975     case ABIL_HEAL_WOUNDS:
1976         fail_check();
1977         if (one_chance_in(4))
1978         {
1979             mpr("Your magical essence is drained by the effort!");
1980             rot_mp(1);
1981         }
1982         potionlike_effect(POT_HEAL_WOUNDS, 40);
1983         break;
1984 
1985     case ABIL_DIG:
1986         fail_check();
1987         if (!you.digging)
1988         {
1989             you.digging = true;
1990             mpr("You extend your mandibles.");
1991         }
1992         else
1993         {
1994             you.digging = false;
1995             mpr("You retract your mandibles.");
1996         }
1997         break;
1998 
1999     case ABIL_SHAFT_SELF:
2000         fail_check();
2001         if (you.can_do_shaft_ability(false))
2002         {
2003             if (cancel_harmful_move())
2004                 return spret::abort;
2005 
2006             if (yesno("Are you sure you want to shaft yourself?", true, 'n'))
2007                 start_delay<ShaftSelfDelay>(1);
2008             else
2009                 return spret::abort;
2010         }
2011         else
2012             return spret::abort;
2013         break;
2014 
2015     case ABIL_HOP:
2016         if (_can_hop(false))
2017             return frog_hop(fail, target);
2018         else
2019             return spret::abort;
2020 
2021     case ABIL_ROLLING_CHARGE:
2022         if (_can_movement_ability(false))
2023             return palentonga_charge(fail, target);
2024         else
2025             return spret::abort;
2026 
2027 
2028     case ABIL_BLINKBOLT:
2029         {
2030             if (_can_blinkbolt(false))
2031             {
2032                 int power = 0;
2033                 if (you.props.exists(AIRFORM_POWER_KEY))
2034                     power = you.props[AIRFORM_POWER_KEY].get_int();
2035                 else
2036                     return spret::abort;
2037                 return your_spells(SPELL_BLINKBOLT, power, false, nullptr, target);
2038             }
2039             else
2040                 return spret::abort;
2041         }
2042 
2043 
2044     case ABIL_SPIT_POISON:      // Naga poison spit
2045     {
2046         int power = 10 + you.experience_level;
2047         beam.range = _calc_breath_ability_range(abil.ability);
2048 
2049         if (!spell_direction(*target, beam)
2050             || !player_tracer(ZAP_SPIT_POISON, power, beam))
2051         {
2052             return spret::abort;
2053         }
2054         else
2055         {
2056             fail_check();
2057             zapping(ZAP_SPIT_POISON, power, beam);
2058             you.set_duration(DUR_BREATH_WEAPON, 3 + random2(5));
2059         }
2060         break;
2061     }
2062 
2063     case ABIL_BREATHE_ACID:       // Draconian acid splash
2064     {
2065         beam.range = _calc_breath_ability_range(abil.ability);
2066         targeter_splash hitfunc(&you, beam.range);
2067         direction_chooser_args args;
2068         args.mode = TARG_HOSTILE;
2069         args.hitfunc = &hitfunc;
2070         if (!spell_direction(*target, beam, &args))
2071             return spret::abort;
2072 
2073         if (stop_attack_prompt(hitfunc, "spit at", _acid_breath_can_hit))
2074             return spret::abort;
2075 
2076         fail_check();
2077         zapping(ZAP_BREATHE_ACID, (you.form == transformation::dragon) ?
2078                 2 * you.experience_level : you.experience_level,
2079                 beam, false, "You spit a glob of acid.");
2080 
2081         you.increase_duration(DUR_BREATH_WEAPON,
2082                           3 + random2(10) + random2(30 - you.experience_level));
2083         break;
2084     }
2085 
2086     case ABIL_BREATHE_FIRE:
2087     case ABIL_BREATHE_FROST:
2088     case ABIL_BREATHE_POISON:
2089     case ABIL_BREATHE_POWER:
2090     case ABIL_BREATHE_STEAM:
2091     case ABIL_BREATHE_MEPHITIC:
2092         beam.range = _calc_breath_ability_range(abil.ability);
2093         if (!spell_direction(*target, beam))
2094             return spret::abort;
2095 
2096         // fallthrough to ABIL_BREATHE_LIGHTNING
2097 
2098     case ABIL_BREATHE_LIGHTNING: // not targeted
2099         fail_check();
2100 
2101         // TODO: refactor this to use only one call to zapping(), don't
2102         // duplicate its fail_check(), split out breathe_lightning, etc
2103 
2104         switch (abil.ability)
2105         {
2106         case ABIL_BREATHE_FIRE:
2107         {
2108             int power = you.experience_level;
2109 
2110             if (you.form == transformation::dragon)
2111                 power += 12;
2112 
2113             string msg = "You breathe a blast of fire";
2114             msg += (power < 15) ? '.' : '!';
2115 
2116             if (zapping(ZAP_BREATHE_FIRE, power, beam, true, msg.c_str())
2117                 == spret::abort)
2118             {
2119                 return spret::abort;
2120             }
2121             break;
2122         }
2123 
2124         case ABIL_BREATHE_FROST:
2125             if (zapping(ZAP_BREATHE_FROST,
2126                         you.form == transformation::dragon
2127                             ? 2 * you.experience_level : you.experience_level,
2128                         beam, true, "You exhale a wave of freezing cold.")
2129                 == spret::abort)
2130             {
2131                 return spret::abort;
2132             }
2133             break;
2134 
2135         case ABIL_BREATHE_POISON:
2136             if (zapping(ZAP_BREATHE_POISON, you.experience_level, beam, true,
2137                         "You exhale a blast of poison gas.")
2138                 == spret::abort)
2139             {
2140                 return spret::abort;
2141             }
2142             break;
2143 
2144         case ABIL_BREATHE_LIGHTNING:
2145             mpr("You breathe a wild blast of lightning!");
2146             black_drac_breath();
2147             break;
2148 
2149         case ABIL_BREATHE_ACID:
2150             if (zapping(ZAP_BREATHE_ACID,
2151                         you.form == transformation::dragon
2152                             ? 2 * you.experience_level : you.experience_level,
2153                         beam, true, "You spit a glob of acid.")
2154                 == spret::abort)
2155             {
2156                 return spret::abort;
2157             }
2158             break;
2159 
2160         case ABIL_BREATHE_POWER:
2161             if (zapping(ZAP_BREATHE_POWER,
2162                         you.form == transformation::dragon
2163                             ? 2 * you.experience_level : you.experience_level,
2164                         beam, true, "You breathe a bolt of dispelling energy.")
2165                 == spret::abort)
2166             {
2167                 return spret::abort;
2168             }
2169             break;
2170 
2171         case ABIL_BREATHE_STEAM:
2172             if (zapping(ZAP_BREATHE_STEAM,
2173                         you.form == transformation::dragon
2174                             ? 2 * you.experience_level : you.experience_level,
2175                         beam, true, "You exhale a blast of scalding steam.")
2176                 == spret::abort)
2177             {
2178                 return spret::abort;
2179             }
2180             break;
2181 
2182         case ABIL_BREATHE_MEPHITIC:
2183             if (zapping(ZAP_BREATHE_MEPHITIC,
2184                         you.form == transformation::dragon
2185                             ? 2 * you.experience_level : you.experience_level,
2186                         beam, true, "You exhale a blast of noxious fumes.")
2187                 == spret::abort)
2188             {
2189                 return spret::abort;
2190             }
2191             break;
2192 
2193         default:
2194             break;
2195         }
2196 
2197         you.increase_duration(DUR_BREATH_WEAPON,
2198                       3 + random2(10) + random2(30 - you.experience_level));
2199 
2200         if (abil.ability == ABIL_BREATHE_STEAM)
2201             you.duration[DUR_BREATH_WEAPON] /= 2;
2202 
2203         break;
2204 
2205     case ABIL_EVOKE_BLINK:      // randarts
2206         fail_check();
2207         return cast_blink(fail);
2208         break;
2209 
2210     case ABIL_EVOKE_BERSERK:    // randarts
2211         fail_check();
2212         you.go_berserk(true);
2213         break;
2214 
2215     // DEMONIC POWERS:
2216     case ABIL_DAMNATION:
2217         fail_check();
2218         if (your_spells(SPELL_HURL_DAMNATION,
2219                         40 + you.experience_level * 6,
2220                         false, nullptr, target) == spret::abort)
2221         {
2222             return spret::abort;
2223         }
2224         break;
2225 
2226     case ABIL_WORD_OF_CHAOS:
2227         return word_of_chaos(40 + you.experience_level * 6, fail);
2228 
2229     case ABIL_EVOKE_TURN_INVISIBLE:     // cloaks, randarts
2230         if (!invis_allowed())
2231             return spret::abort;
2232         if (_invis_causes_drain())
2233             drain_player(40, false, true); // yes, before the fail check!
2234         fail_check();
2235         potionlike_effect(POT_INVISIBILITY,
2236                           player_adjust_evoc_power(
2237                               you.skill(SK_EVOCATIONS, 2) + 5));
2238         contaminate_player(1000 + random2(2000), true);
2239         break;
2240 
2241     case ABIL_EVOKE_THUNDER: // robe of Clouds
2242         fail_check();
2243         mpr("The folds of your robe billow into a mighty storm.");
2244 
2245         for (radius_iterator ri(you.pos(), 2, C_SQUARE); ri; ++ri)
2246             if (!cell_is_solid(*ri))
2247                 place_cloud(CLOUD_STORM, *ri, 8 + random2avg(8,2), &you);
2248 
2249         break;
2250 
2251     case ABIL_END_TRANSFORMATION:
2252         fail_check();
2253         untransform();
2254         break;
2255 
2256     // INVOCATIONS:
2257     case ABIL_ZIN_RECITE:
2258     {
2259         fail_check();
2260         if (zin_check_recite_to_monsters() == 1)
2261         {
2262             you.attribute[ATTR_RECITE_TYPE] = (recite_type) random2(NUM_RECITE_TYPES); // This is just flavor
2263             you.attribute[ATTR_RECITE_SEED] = random2(2187); // 3^7
2264             you.duration[DUR_RECITE] = 3 * BASELINE_DELAY;
2265             mprf("You clear your throat and prepare to recite.");
2266         }
2267         else
2268         {
2269             canned_msg(MSG_OK);
2270             return spret::abort;
2271         }
2272         break;
2273     }
2274     case ABIL_ZIN_VITALISATION:
2275         fail_check();
2276         zin_vitalisation();
2277         break;
2278 
2279     case ABIL_ZIN_IMPRISON:
2280     {
2281         beam.range = LOS_MAX_RANGE;
2282         direction_chooser_args args;
2283         args.restricts = DIR_TARGET;
2284         args.mode = TARG_HOSTILE;
2285         args.needs_path = false;
2286         if (!spell_direction(*target, beam, &args))
2287             return spret::abort;
2288 
2289         if (beam.target == you.pos())
2290         {
2291             mpr("You cannot imprison yourself!");
2292             return spret::abort;
2293         }
2294 
2295         monster* mons = monster_at(beam.target);
2296 
2297         if (mons == nullptr || !you.can_see(*mons))
2298         {
2299             mpr("There is no monster there to imprison!");
2300             return spret::abort;
2301         }
2302 
2303         if (mons_is_firewood(*mons) || mons_is_conjured(mons->type))
2304         {
2305             mpr("You cannot imprison that!");
2306             return spret::abort;
2307         }
2308 
2309         if (mons->friendly() || mons->good_neutral())
2310         {
2311             mpr("You cannot imprison a law-abiding creature!");
2312             return spret::abort;
2313         }
2314 
2315         fail_check();
2316 
2317         int power = 3 + (roll_dice(5, you.skill(SK_INVOCATIONS, 5) + 12) / 26);
2318 
2319         if (!cast_imprison(power, mons, -GOD_ZIN))
2320             return spret::abort;
2321         break;
2322     }
2323 
2324     case ABIL_ZIN_SANCTUARY:
2325         fail_check();
2326         zin_sanctuary();
2327         break;
2328 
2329     case ABIL_ZIN_DONATE_GOLD:
2330         fail_check();
2331         zin_donate_gold();
2332         break;
2333 
2334     case ABIL_TSO_DIVINE_SHIELD:
2335         fail_check();
2336         tso_divine_shield();
2337         break;
2338 
2339     case ABIL_TSO_CLEANSING_FLAME:
2340     {
2341         targeter_radius hitfunc(&you, LOS_SOLID, 2);
2342         {
2343             if (stop_attack_prompt(hitfunc, "harm", _cleansing_flame_affects))
2344                 return spret::abort;
2345         }
2346         fail_check();
2347         cleansing_flame(10 + you.skill_rdiv(SK_INVOCATIONS, 7, 6),
2348                         cleansing_flame_source::invocation, you.pos(), &you);
2349         break;
2350     }
2351 
2352     case ABIL_TSO_SUMMON_DIVINE_WARRIOR:
2353         fail_check();
2354         summon_holy_warrior(you.skill(SK_INVOCATIONS, 4), false);
2355         break;
2356 
2357     case ABIL_TSO_BLESS_WEAPON:
2358         fail_check();
2359         simple_god_message(" will bless one of your weapons.");
2360         // included in default force_more_message
2361         if (!bless_weapon(GOD_SHINING_ONE, SPWPN_HOLY_WRATH, YELLOW))
2362             return spret::abort;
2363         break;
2364 
2365     case ABIL_KIKU_RECEIVE_CORPSES:
2366         fail_check();
2367         kiku_receive_corpses(you.skill(SK_NECROMANCY, 4));
2368         break;
2369 
2370     case ABIL_KIKU_TORMENT:
2371         fail_check();
2372         if (!kiku_take_corpse())
2373         {
2374             mpr("There are no corpses to sacrifice!");
2375             return spret::abort;
2376         }
2377         simple_god_message(" torments the living!");
2378         torment(&you, TORMENT_KIKUBAAQUDGHA, you.pos());
2379         break;
2380 
2381     case ABIL_KIKU_BLESS_WEAPON:
2382         fail_check();
2383         simple_god_message(" will bloody one of your weapons with pain.");
2384         // included in default force_more_message
2385         if (!bless_weapon(GOD_KIKUBAAQUDGHA, SPWPN_PAIN, RED))
2386             return spret::abort;
2387         break;
2388 
2389     case ABIL_KIKU_GIFT_CAPSTONE_SPELLS:
2390     {
2391         fail_check();
2392         if (!kiku_gift_capstone_spells())
2393             return spret::abort;
2394         break;
2395     }
2396 
2397     case ABIL_YRED_INJURY_MIRROR:
2398         fail_check();
2399         if (yred_injury_mirror())
2400             mpr("Another wave of unholy energy enters you.");
2401         else
2402         {
2403             mprf("You offer yourself to %s, and are filled with unholy energy.",
2404                  god_name(you.religion).c_str());
2405         }
2406         you.duration[DUR_MIRROR_DAMAGE] = 9 * BASELINE_DELAY
2407                      + random2avg(you.piety * BASELINE_DELAY, 2) / 10;
2408         break;
2409 
2410     case ABIL_YRED_ANIMATE_REMAINS:
2411         fail_check();
2412         canned_msg(MSG_ANIMATE_REMAINS);
2413         if (animate_remains(you.pos(), CORPSE_BODY, BEH_FRIENDLY, 0,
2414                             MHITYOU, &you, "", GOD_YREDELEMNUL) < 0)
2415         {
2416             mpr("There are no remains here to animate!");
2417             return spret::abort;
2418         }
2419         break;
2420 
2421     case ABIL_YRED_ANIMATE_DEAD:
2422         fail_check();
2423         canned_msg(MSG_CALL_DEAD);
2424         if (!animate_dead(&you, you.skill_rdiv(SK_INVOCATIONS) + 1,
2425                          BEH_FRIENDLY, MHITYOU, &you, "", GOD_YREDELEMNUL))
2426         {
2427             mpr("There are no remains here to animate!");
2428             return spret::abort;
2429         }
2430 
2431         break;
2432 
2433     case ABIL_YRED_RECALL_UNDEAD_SLAVES:
2434         fail_check();
2435         start_recall(recall_t::yred);
2436         break;
2437 
2438     case ABIL_YRED_DRAIN_LIFE:
2439     {
2440         int damage = 0;
2441         const spret result =
2442             fire_los_attack_spell(SPELL_DRAIN_LIFE,
2443                                   you.skill_rdiv(SK_INVOCATIONS),
2444                                   &you, fail, &damage);
2445         if (result != spret::success)
2446             return result;
2447 
2448         if (damage > 0)
2449         {
2450             mpr("You feel life flooding into your body.");
2451             inc_hp(damage);
2452         }
2453         break;
2454     }
2455 
2456     case ABIL_YRED_ENSLAVE_SOUL:
2457     {
2458         god_acting gdact;
2459         beam.range = LOS_MAX_RANGE;
2460         direction_chooser_args args;
2461         args.restricts = DIR_TARGET;
2462         args.mode = TARG_HOSTILE;
2463         args.needs_path = false;
2464 
2465         if (!spell_direction(*target, beam, &args))
2466             return spret::abort;
2467 
2468         if (beam.target == you.pos())
2469         {
2470             mpr("Your soul already belongs to Yredelemnul.");
2471             return spret::abort;
2472         }
2473 
2474         monster* mons = monster_at(beam.target);
2475 
2476         if (mons && you.can_see(*mons) && mons->is_illusion())
2477         {
2478             fail_check();
2479             simple_monster_message(*mons, "'s clone doesn't have a soul to enslave!");
2480             // Still costs a turn to gain the information.
2481             return spret::success;
2482         }
2483 
2484         if (mons == nullptr || !you.can_see(*mons)
2485             || !yred_can_enslave_soul(mons))
2486         {
2487             mpr("You see nothing there you can enslave the soul of!");
2488             return spret::abort;
2489         }
2490 
2491         // The monster can be no more than lightly wounded/damaged.
2492         if (mons_get_damage_level(*mons) > MDAM_LIGHTLY_DAMAGED)
2493         {
2494             simple_monster_message(*mons, "'s soul is too badly injured.");
2495             return spret::abort;
2496         }
2497         fail_check();
2498 
2499         const int duration = you.skill_rdiv(SK_INVOCATIONS, 3, 4) + 2;
2500         mons->add_ench(mon_enchant(ENCH_SOUL_RIPE, 0, &you,
2501                                    duration * BASELINE_DELAY));
2502         simple_monster_message(*mons, "'s soul is now ripe for the taking.");
2503         break;
2504     }
2505 
2506     case ABIL_OKAWARU_HEROISM:
2507         fail_check();
2508         mprf(MSGCH_DURATION, you.duration[DUR_HEROISM]
2509              ? "You feel more confident with your borrowed prowess."
2510              : "You gain the combat prowess of a mighty hero.");
2511 
2512         you.increase_duration(DUR_HEROISM,
2513                               10 + random2avg(you.skill(SK_INVOCATIONS, 6), 2),
2514                               100);
2515         you.redraw_evasion      = true;
2516         you.redraw_armour_class = true;
2517         break;
2518 
2519     case ABIL_OKAWARU_FINESSE:
2520         fail_check();
2521         if (you.duration[DUR_FINESSE])
2522         {
2523             // "Your [hand(s)] get{s} new energy."
2524             mprf(MSGCH_DURATION, "%s",
2525                  you.hands_act("get", "new energy.").c_str());
2526         }
2527         else
2528             mprf(MSGCH_DURATION, "You can now deal lightning-fast blows.");
2529 
2530         you.increase_duration(DUR_FINESSE,
2531                               10 + random2avg(you.skill(SK_INVOCATIONS, 6), 2),
2532                               100);
2533 
2534         did_god_conduct(DID_HASTY, 8); // Currently irrelevant.
2535         break;
2536 
2537     case ABIL_MAKHLEB_MINOR_DESTRUCTION:
2538     {
2539         // TODO: range check duplicated for UI/messaging purposes in quiver.cc,
2540         // _ability_quiver_range_check
2541         beam.range = min((int)you.current_vision, 5);
2542 
2543         if (!spell_direction(*target, beam))
2544             return spret::abort;
2545 
2546         int power = you.skill(SK_INVOCATIONS, 1)
2547                     + random2(1 + you.skill(SK_INVOCATIONS, 1))
2548                     + random2(1 + you.skill(SK_INVOCATIONS, 1));
2549 
2550         // Since the actual beam is random, check with BEAM_MMISSILE.
2551         if (!player_tracer(ZAP_DEBUGGING_RAY, power, beam, beam.range))
2552             return spret::abort;
2553 
2554         fail_check();
2555         beam.origin_spell = SPELL_NO_SPELL; // let zapping reset this
2556 
2557         switch (random2(5))
2558         {
2559         case 0: zapping(ZAP_THROW_FLAME, power, beam); break;
2560         case 1: zapping(ZAP_PAIN, power, beam); break;
2561         case 2: zapping(ZAP_STONE_ARROW, power, beam); break;
2562         case 3: zapping(ZAP_SHOCK, power, beam); break;
2563         case 4: zapping(ZAP_BREATHE_ACID, power / 7, beam); break;
2564         }
2565         break;
2566     }
2567 
2568     case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB:
2569         summon_demon_type(random_choose(MONS_HELLWING, MONS_NEQOXEC,
2570                                         MONS_ORANGE_DEMON, MONS_SMOKE_DEMON,
2571                                         MONS_YNOXINUL),
2572                           20 + you.skill(SK_INVOCATIONS, 3),
2573                           GOD_MAKHLEB, 0, !fail);
2574         break;
2575 
2576     case ABIL_MAKHLEB_MAJOR_DESTRUCTION:
2577     {
2578         beam.range = you.current_vision;
2579 
2580         if (!spell_direction(*target, beam))
2581             return spret::abort;
2582 
2583         int power = you.skill(SK_INVOCATIONS, 2)
2584                     + random2(1 + you.skill(SK_INVOCATIONS, 2))
2585                     + random2(1 + you.skill(SK_INVOCATIONS, 2));
2586 
2587         // Since the actual beam is random, check with BEAM_MMISSILE.
2588         if (!player_tracer(ZAP_DEBUGGING_RAY, power, beam, beam.range))
2589             return spret::abort;
2590 
2591         fail_check();
2592         {
2593             beam.origin_spell = SPELL_NO_SPELL; // let zapping reset this
2594             zap_type ztype =
2595                 random_choose(ZAP_BOLT_OF_FIRE,
2596                               ZAP_LIGHTNING_BOLT,
2597                               ZAP_BOLT_OF_MAGMA,
2598                               ZAP_BOLT_OF_DRAINING,
2599                               ZAP_CORROSIVE_BOLT);
2600             zapping(ztype, power, beam);
2601         }
2602         break;
2603     }
2604 
2605     case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB:
2606         summon_demon_type(random_choose(MONS_EXECUTIONER, MONS_GREEN_DEATH,
2607                                         MONS_BLIZZARD_DEMON, MONS_BALRUG,
2608                                         MONS_CACODEMON),
2609                           20 + you.skill(SK_INVOCATIONS, 3),
2610                           GOD_MAKHLEB, 0, !fail);
2611         break;
2612 
2613     case ABIL_TROG_BERSERK:
2614         fail_check();
2615         // Trog abilities don't use or train invocations.
2616         you.go_berserk(true);
2617         break;
2618 
2619     case ABIL_TROG_HAND:
2620         fail_check();
2621         // Trog abilities don't use or train invocations.
2622         trog_do_trogs_hand(you.piety / 2);
2623         break;
2624 
2625     case ABIL_TROG_BROTHERS_IN_ARMS:
2626         fail_check();
2627         // Trog abilities don't use or train invocations.
2628         summon_berserker(you.piety +
2629                          random2(you.piety/4) - random2(you.piety/4),
2630                          &you);
2631         break;
2632 
2633     case ABIL_SIF_MUNA_FORGET_SPELL:
2634         fail_check();
2635         if (cast_selective_amnesia() <= 0)
2636         {
2637             canned_msg(MSG_OK);
2638             return spret::abort;
2639         }
2640         break;
2641 
2642     case ABIL_SIF_MUNA_CHANNEL_ENERGY:
2643     {
2644         fail_check();
2645         you.increase_duration(DUR_CHANNEL_ENERGY,
2646             4 + random2avg(you.skill_rdiv(SK_INVOCATIONS, 2, 3), 2), 100);
2647         break;
2648     }
2649 
2650     case ABIL_SIF_MUNA_DIVINE_EXEGESIS:
2651         return divine_exegesis(fail);
2652 
2653     case ABIL_ELYVILON_LIFESAVING:
2654         fail_check();
2655         if (you.duration[DUR_LIFESAVING])
2656             mpr("You renew your call for help.");
2657         else
2658         {
2659             mprf("You beseech %s to protect your life.",
2660                  god_name(you.religion).c_str());
2661         }
2662         // Might be a decrease, this is intentional (like Yred).
2663         you.duration[DUR_LIFESAVING] = 9 * BASELINE_DELAY
2664                      + random2avg(you.piety * BASELINE_DELAY, 2) / 10;
2665         break;
2666 
2667     case ABIL_ELYVILON_LESSER_HEALING:
2668     case ABIL_ELYVILON_GREATER_HEALING:
2669     {
2670         fail_check();
2671         int pow = 0;
2672         if (abil.ability == ABIL_ELYVILON_LESSER_HEALING)
2673             pow = 3 + you.skill_rdiv(SK_INVOCATIONS, 1, 6);
2674         else
2675             pow = 10 + you.skill_rdiv(SK_INVOCATIONS, 1, 3);
2676         pow = min(50, pow);
2677         const int healed = pow + roll_dice(2, pow) - 2;
2678         mpr("You are healed.");
2679         inc_hp(healed);
2680         break;
2681     }
2682 
2683     case ABIL_ELYVILON_PURIFICATION:
2684         fail_check();
2685         elyvilon_purification();
2686         break;
2687 
2688     case ABIL_ELYVILON_HEAL_OTHER:
2689     {
2690         int pow = 30 + you.skill(SK_INVOCATIONS, 1);
2691         return cast_healing(pow, fail);
2692     }
2693 
2694     case ABIL_ELYVILON_DIVINE_VIGOUR:
2695         fail_check();
2696         if (!elyvilon_divine_vigour())
2697             return spret::abort;
2698         break;
2699 
2700     case ABIL_LUGONU_ABYSS_EXIT:
2701         if (cancel_harmful_move(false))
2702             return spret::abort;
2703         fail_check();
2704         down_stairs(DNGN_EXIT_ABYSS);
2705         break;
2706 
2707     case ABIL_LUGONU_BEND_SPACE:
2708         if (cancel_harmful_move(false))
2709             return spret::abort;
2710         fail_check();
2711         lugonu_bend_space();
2712         break;
2713 
2714     case ABIL_LUGONU_BANISH:
2715     {
2716         beam.range = you.current_vision;
2717         const int pow = 68 + you.skill(SK_INVOCATIONS, 3);
2718 
2719         direction_chooser_args args;
2720         args.mode = TARG_HOSTILE;
2721         args.get_desc_func = bind(desc_wl_success_chance, placeholders::_1,
2722                                   zap_ench_power(ZAP_BANISHMENT, pow, false),
2723                                   nullptr);
2724         if (!spell_direction(*target, beam, &args))
2725             return spret::abort;
2726 
2727         if (beam.target == you.pos())
2728         {
2729             mpr("You cannot banish yourself!");
2730             return spret::abort;
2731         }
2732 
2733         fail_check();
2734 
2735         return zapping(ZAP_BANISHMENT, pow, beam, true, nullptr, fail);
2736     }
2737 
2738     case ABIL_LUGONU_CORRUPT:
2739         fail_check();
2740         if (!lugonu_corrupt_level(300 + you.skill(SK_INVOCATIONS, 15)))
2741             return spret::abort;
2742         break;
2743 
2744     case ABIL_LUGONU_ABYSS_ENTER:
2745     {
2746         if (cancel_harmful_move(false))
2747             return spret::abort;
2748         fail_check();
2749         // Deflate HP.
2750         dec_hp(random2avg(you.hp, 2), false);
2751 
2752         no_notes nx; // This banishment shouldn't be noted.
2753         banished();
2754         break;
2755     }
2756 
2757     case ABIL_LUGONU_BLESS_WEAPON:
2758         fail_check();
2759         simple_god_message(" will brand one of your weapons with the "
2760                            "corruption of the Abyss.");
2761         // included in default force_more_message
2762         if (!bless_weapon(GOD_LUGONU, SPWPN_DISTORTION, MAGENTA))
2763             return spret::abort;
2764         break;
2765 
2766     case ABIL_NEMELEX_DRAW_DESTRUCTION:
2767         fail_check();
2768         if (!deck_draw(DECK_OF_DESTRUCTION))
2769             return spret::abort;
2770         break;
2771     case ABIL_NEMELEX_DRAW_ESCAPE:
2772         fail_check();
2773         if (!deck_draw(DECK_OF_ESCAPE))
2774             return spret::abort;
2775         break;
2776     case ABIL_NEMELEX_DRAW_SUMMONING:
2777         fail_check();
2778         if (!deck_draw(DECK_OF_SUMMONING))
2779             return spret::abort;
2780         break;
2781     case ABIL_NEMELEX_DRAW_STACK:
2782         fail_check();
2783         if (!deck_draw(DECK_STACK))
2784             return spret::abort;
2785         break;
2786 
2787     case ABIL_NEMELEX_TRIPLE_DRAW:
2788         fail_check();
2789         if (!deck_triple_draw())
2790             return spret::abort;
2791         break;
2792 
2793     case ABIL_NEMELEX_DEAL_FOUR:
2794         fail_check();
2795         if (!deck_deal())
2796             return spret::abort;
2797         break;
2798 
2799     case ABIL_NEMELEX_STACK_FIVE:
2800         fail_check();
2801         if (!deck_stack())
2802             return spret::abort;
2803         break;
2804 
2805     case ABIL_BEOGH_SMITING:
2806         fail_check();
2807         if (your_spells(SPELL_SMITING,
2808                         12 + skill_bump(SK_INVOCATIONS, 6),
2809                         false, nullptr, target) == spret::abort)
2810         {
2811             return spret::abort;
2812         }
2813         break;
2814 
2815     case ABIL_BEOGH_GIFT_ITEM:
2816         if (!beogh_gift_item())
2817             return spret::abort;
2818         break;
2819 
2820     case ABIL_BEOGH_RESURRECTION:
2821         if (!beogh_resurrect())
2822             return spret::abort;
2823         break;
2824 
2825     case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS:
2826         fail_check();
2827         start_recall(recall_t::beogh);
2828         break;
2829 
2830     case ABIL_STOP_RECALL:
2831         fail_check();
2832         mpr("You stop recalling your allies.");
2833         end_recall();
2834         break;
2835 
2836     case ABIL_FEDHAS_WALL_OF_BRIARS:
2837         fail_check();
2838         if (!fedhas_wall_of_briars())
2839             return spret::abort;
2840         break;
2841 
2842     case ABIL_FEDHAS_GROW_BALLISTOMYCETE:
2843         return fedhas_grow_ballistomycete(fail);
2844 
2845     case ABIL_FEDHAS_OVERGROW:
2846         return fedhas_overgrow(fail);
2847 
2848     case ABIL_FEDHAS_GROW_OKLOB:
2849         return fedhas_grow_oklob(fail);
2850 
2851     case ABIL_TRAN_BAT:
2852     {
2853         if (_player_cancels_vampire_bat_transformation())
2854             return spret::abort;
2855         fail_check();
2856         if (!transform(100, transformation::bat))
2857         {
2858             crawl_state.zero_turns_taken();
2859             return spret::abort;
2860         }
2861 
2862         _cause_vampire_bat_form_stat_drain();
2863 
2864         break;
2865     }
2866 
2867     case ABIL_EXSANGUINATE:
2868         fail_check();
2869         start_delay<ExsanguinateDelay>(5);
2870         break;
2871 
2872     case ABIL_REVIVIFY:
2873         fail_check();
2874         start_delay<RevivifyDelay>(5);
2875         break;
2876 
2877     case ABIL_JIYVA_CALL_JELLY:
2878     {
2879         fail_check();
2880         mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, you.pos(),
2881                      MHITNOT, MG_NONE, GOD_JIYVA);
2882 
2883         mg.non_actor_summoner = "Jiyva";
2884 
2885         if (!create_monster(mg))
2886             return spret::abort;
2887         break;
2888     }
2889 
2890     case ABIL_JIYVA_SLIMIFY:
2891     {
2892         fail_check();
2893         const item_def* const weapon = you.weapon();
2894         const string msg = weapon ? weapon->name(DESC_YOUR)
2895                                   : ("your " + you.hand_name(true));
2896         mprf(MSGCH_DURATION, "A thick mucus forms on %s.", msg.c_str());
2897         you.increase_duration(DUR_SLIMIFY,
2898                               random2avg(you.piety / 4, 2) + 3, 100);
2899         break;
2900     }
2901 
2902     case ABIL_JIYVA_CURE_BAD_MUTATION:
2903         fail_check();
2904         jiyva_remove_bad_mutation();
2905         break;
2906 
2907     case ABIL_CHEIBRIADOS_TIME_STEP:
2908         fail_check();
2909         cheibriados_time_step(max(1, you.skill(SK_INVOCATIONS, 10)
2910                                      * you.piety / 100));
2911         break;
2912 
2913     case ABIL_CHEIBRIADOS_TIME_BEND:
2914         fail_check();
2915         cheibriados_time_bend(16 + you.skill(SK_INVOCATIONS, 8));
2916         break;
2917 
2918     case ABIL_CHEIBRIADOS_DISTORTION:
2919         fail_check();
2920         cheibriados_temporal_distortion();
2921         break;
2922 
2923     case ABIL_CHEIBRIADOS_SLOUCH:
2924         fail_check();
2925         if (!cheibriados_slouch())
2926             return spret::abort;
2927         break;
2928 
2929     case ABIL_ASHENZARI_CURSE:
2930     {
2931         fail_check();
2932         if (!ashenzari_curse_item())
2933             return spret::abort;
2934         break;
2935     }
2936 
2937     case ABIL_ASHENZARI_UNCURSE:
2938         fail_check();
2939         if (!ashenzari_uncurse_item())
2940             return spret::abort;
2941         break;
2942 
2943     case ABIL_DITHMENOS_SHADOW_STEP:
2944         if (_abort_if_stationary() || cancel_harmful_move(false))
2945             return spret::abort;
2946         fail_check();
2947         if (!dithmenos_shadow_step()) // TODO dist arg
2948         {
2949             canned_msg(MSG_OK);
2950             return spret::abort;
2951         }
2952         break;
2953 
2954     case ABIL_DITHMENOS_SHADOW_FORM:
2955         fail_check();
2956         if (!transform(you.skill(SK_INVOCATIONS, 2), transformation::shadow))
2957         {
2958             crawl_state.zero_turns_taken();
2959             return spret::abort;
2960         }
2961         break;
2962 
2963     case ABIL_GOZAG_POTION_PETITION:
2964         fail_check();
2965         run_uncancel(UNC_POTION_PETITION, 0);
2966         break;
2967 
2968     case ABIL_GOZAG_CALL_MERCHANT:
2969         fail_check();
2970         run_uncancel(UNC_CALL_MERCHANT, 0);
2971         break;
2972 
2973     case ABIL_GOZAG_BRIBE_BRANCH:
2974         fail_check();
2975         if (!gozag_bribe_branch())
2976             return spret::abort;
2977         break;
2978 
2979     case ABIL_QAZLAL_UPHEAVAL:
2980         return qazlal_upheaval(coord_def(), false, fail, target);
2981 
2982     case ABIL_QAZLAL_ELEMENTAL_FORCE:
2983         return qazlal_elemental_force(fail);
2984 
2985     case ABIL_QAZLAL_DISASTER_AREA:
2986         fail_check();
2987         if (!qazlal_disaster_area())
2988             return spret::abort;
2989         break;
2990 
2991     case ABIL_RU_SACRIFICE_PURITY:
2992     case ABIL_RU_SACRIFICE_WORDS:
2993     case ABIL_RU_SACRIFICE_DRINK:
2994     case ABIL_RU_SACRIFICE_ESSENCE:
2995     case ABIL_RU_SACRIFICE_HEALTH:
2996     case ABIL_RU_SACRIFICE_STEALTH:
2997     case ABIL_RU_SACRIFICE_ARTIFICE:
2998     case ABIL_RU_SACRIFICE_LOVE:
2999     case ABIL_RU_SACRIFICE_COURAGE:
3000     case ABIL_RU_SACRIFICE_ARCANA:
3001     case ABIL_RU_SACRIFICE_NIMBLENESS:
3002     case ABIL_RU_SACRIFICE_DURABILITY:
3003     case ABIL_RU_SACRIFICE_HAND:
3004     case ABIL_RU_SACRIFICE_EXPERIENCE:
3005     case ABIL_RU_SACRIFICE_SKILL:
3006     case ABIL_RU_SACRIFICE_EYE:
3007     case ABIL_RU_SACRIFICE_RESISTANCE:
3008         fail_check();
3009         if (!ru_do_sacrifice(abil.ability))
3010             return spret::abort;
3011         break;
3012 
3013     case ABIL_RU_REJECT_SACRIFICES:
3014         fail_check();
3015         if (!ru_reject_sacrifices())
3016             return spret::abort;
3017         break;
3018 
3019     case ABIL_RU_DRAW_OUT_POWER:
3020         fail_check();
3021         if (you.duration[DUR_EXHAUSTED])
3022         {
3023             mpr("You're too exhausted to draw out your power.");
3024             return spret::abort;
3025         }
3026         if (you.hp == you.hp_max && you.magic_points == you.max_magic_points
3027             && !you.duration[DUR_CONF]
3028             && !you.duration[DUR_SLOW]
3029             && !you.attribute[ATTR_HELD]
3030             && !you.petrifying()
3031             && !you.is_constricted())
3032         {
3033             mpr("You have no need to draw out power.");
3034             return spret::abort;
3035         }
3036         ru_draw_out_power();
3037         you.increase_duration(DUR_EXHAUSTED, 12 + random2(5));
3038         break;
3039 
3040     case ABIL_RU_POWER_LEAP:
3041         if (you.duration[DUR_EXHAUSTED])
3042         {
3043             mpr("You're too exhausted to power leap.");
3044             return spret::abort;
3045         }
3046 
3047         if (_abort_if_stationary() || cancel_harmful_move())
3048             return spret::abort;
3049 
3050         fail_check();
3051 
3052         if (!ru_power_leap()) // TODO dist arg
3053         {
3054             canned_msg(MSG_OK);
3055             return spret::abort;
3056         }
3057         you.increase_duration(DUR_EXHAUSTED, 18 + random2(8));
3058         break;
3059 
3060     case ABIL_RU_APOCALYPSE:
3061         if (you.duration[DUR_EXHAUSTED])
3062         {
3063             mpr("You're too exhausted to unleash your apocalyptic power.");
3064             return spret::abort;
3065         }
3066 
3067         fail_check();
3068 
3069         if (!ru_apocalypse())
3070             return spret::abort;
3071         you.increase_duration(DUR_EXHAUSTED, 30 + random2(20));
3072         break;
3073 
3074     case ABIL_USKAYAW_STOMP:
3075         fail_check();
3076         if (!uskayaw_stomp())
3077             return spret::abort;
3078         break;
3079 
3080     case ABIL_USKAYAW_LINE_PASS:
3081         if (_abort_if_stationary() || cancel_harmful_move())
3082             return spret::abort;
3083         fail_check();
3084         if (!uskayaw_line_pass()) // TODO dist arg
3085             return spret::abort;
3086         break;
3087 
3088     case ABIL_USKAYAW_GRAND_FINALE:
3089         if (cancel_harmful_move(false))
3090             return spret::abort;
3091         return uskayaw_grand_finale(fail); // TODO dist arg
3092 
3093     case ABIL_HEPLIAKLQANA_IDEALISE:
3094         return hepliaklqana_idealise(fail);
3095 
3096     case ABIL_HEPLIAKLQANA_RECALL:
3097         fail_check();
3098         if (try_recall(hepliaklqana_ancestor()))
3099             upgrade_hepliaklqana_ancestor(true);
3100         break;
3101 
3102     case ABIL_HEPLIAKLQANA_TRANSFERENCE:
3103         return hepliaklqana_transference(fail); // TODO: dist arg
3104 
3105     case ABIL_HEPLIAKLQANA_TYPE_KNIGHT:
3106     case ABIL_HEPLIAKLQANA_TYPE_BATTLEMAGE:
3107     case ABIL_HEPLIAKLQANA_TYPE_HEXER:
3108         if (!hepliaklqana_choose_ancestor_type(abil.ability))
3109             return spret::abort;
3110         break;
3111 
3112     case ABIL_HEPLIAKLQANA_IDENTITY:
3113         hepliaklqana_choose_identity();
3114         break;
3115 
3116     case ABIL_WU_JIAN_SERPENTS_LASH:
3117         if (you.attribute[ATTR_SERPENTS_LASH])
3118         {
3119             mpr("You are already lashing out.");
3120             return spret::abort;
3121         }
3122         if (you.duration[DUR_EXHAUSTED])
3123         {
3124             mpr("You are too exhausted to lash out.");
3125             return spret::abort;
3126         }
3127         fail_check();
3128         mprf(MSGCH_GOD, "Your muscles tense, ready for explosive movement...");
3129         you.attribute[ATTR_SERPENTS_LASH] = 2;
3130         you.redraw_status_lights = true;
3131         return spret::success;
3132 
3133     case ABIL_WU_JIAN_HEAVENLY_STORM:
3134         if (you.props.exists(WU_JIAN_HEAVENLY_STORM_KEY))
3135         {
3136             mpr("You are already engulfed in a heavenly storm!");
3137             return spret::abort;
3138         }
3139         fail_check();
3140         wu_jian_heavenly_storm();
3141         break;
3142 
3143     case ABIL_WU_JIAN_WALLJUMP:
3144         fail_check();
3145         return wu_jian_wall_jump_ability();
3146 
3147     case ABIL_RENOUNCE_RELIGION:
3148         fail_check();
3149         if (yesno("Really renounce your faith, foregoing its fabulous benefits?",
3150                   false, 'n')
3151             && yesno("Are you sure?", false, 'n'))
3152         {
3153             excommunication(true);
3154         }
3155         else
3156         {
3157             canned_msg(MSG_OK);
3158             return spret::abort;
3159         }
3160         break;
3161 
3162     case ABIL_CONVERT_TO_BEOGH:
3163         fail_check();
3164         god_pitch(GOD_BEOGH);
3165         if (you_worship(GOD_BEOGH))
3166         {
3167             spare_beogh_convert();
3168             break;
3169         }
3170         return spret::abort;
3171 
3172     case ABIL_NON_ABILITY:
3173         fail_check();
3174         mpr("Sorry, you can't do that.");
3175         break;
3176 
3177     default:
3178         die("invalid ability");
3179     }
3180 
3181     return spret::success;
3182 }
3183 
3184 // [ds] Increase piety cost for god abilities that are particularly
3185 // overpowered in Sprint. Yes, this is a hack. No, I don't care.
_scale_piety_cost(ability_type abil,int original_cost)3186 static int _scale_piety_cost(ability_type abil, int original_cost)
3187 {
3188     // Abilities that have aroused our ire earn 2.5x their classic
3189     // Crawl piety cost.
3190     return (crawl_state.game_is_sprint()
3191             && (abil == ABIL_TROG_BROTHERS_IN_ARMS
3192                 || abil == ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB))
3193            ? div_rand_round(original_cost * 5, 2)
3194            : original_cost;
3195 }
3196 
_pay_ability_costs(const ability_def & abil)3197 static void _pay_ability_costs(const ability_def& abil)
3198 {
3199     // wall jump handles its own timing, because it can be instant if
3200     // serpent's lash is activated.
3201     if (abil.flags & abflag::instant)
3202     {
3203         you.turn_is_over = false;
3204         you.elapsed_time_at_last_input = you.elapsed_time;
3205         update_turn_count();
3206     }
3207     else if (abil.ability != ABIL_WU_JIAN_WALLJUMP)
3208         you.turn_is_over = true;
3209 
3210     const int piety_cost =
3211         _scale_piety_cost(abil.ability, abil.piety_cost.cost());
3212     const int hp_cost    = abil.get_hp_cost();
3213     const int mp_cost = abil.get_mp_cost();
3214 
3215     dprf("Cost: mp=%d; hp=%d; piety=%d",
3216          mp_cost, hp_cost, piety_cost);
3217 
3218     if (mp_cost)
3219     {
3220         pay_mp(mp_cost);
3221         finalize_mp_cost();
3222     }
3223 
3224     if (hp_cost)
3225         dec_hp(hp_cost, false);
3226 
3227     if (piety_cost)
3228         lose_piety(piety_cost);
3229 }
3230 
choose_ability_menu(const vector<talent> & talents)3231 int choose_ability_menu(const vector<talent>& talents)
3232 {
3233     ToggleableMenu abil_menu(MF_SINGLESELECT | MF_ANYPRINTABLE
3234             | MF_NO_WRAP_ROWS | MF_TOGGLE_ACTION | MF_ALWAYS_SHOW_MORE);
3235 
3236     abil_menu.set_highlighter(nullptr);
3237 #ifdef USE_TILE_LOCAL
3238     {
3239         // Hack like the one in spl-cast.cc:list_spells() to align the title.
3240         ToggleableMenuEntry* me =
3241             new ToggleableMenuEntry("Ability - do what?                  "
3242                                     "Cost                            Failure",
3243                                     "Ability - describe what?            "
3244                                     "Cost                            Failure",
3245                                     MEL_ITEM);
3246         me->colour = BLUE;
3247         abil_menu.set_title(me, true, true);
3248     }
3249 #else
3250     abil_menu.set_title(
3251         new ToggleableMenuEntry("Ability - do what?                  "
3252                                 "Cost                            Failure",
3253                                 "Ability - describe what?            "
3254                                 "Cost                            Failure",
3255                                 MEL_TITLE), true, true);
3256 #endif
3257     abil_menu.set_tag("ability");
3258     abil_menu.add_toggle_key('!');
3259     abil_menu.add_toggle_key('?');
3260     abil_menu.menu_action = Menu::ACT_EXECUTE;
3261 
3262     if (crawl_state.game_is_hints())
3263     {
3264         // XXX: This could be buggy if you manage to pick up lots and
3265         // lots of abilities during hints mode.
3266         abil_menu.set_more(hints_abilities_info());
3267     }
3268     else
3269     {
3270         abil_menu.set_more(formatted_string::parse_string(
3271                            "Press '<w>!</w>' or '<w>?</w>' to toggle "
3272                            "between ability selection and description."));
3273     }
3274 
3275     int numbers[52];
3276     for (int i = 0; i < 52; ++i)
3277         numbers[i] = i;
3278 
3279     bool found_invocations = false;
3280 
3281     // First add all non-invocation abilities.
3282     for (unsigned int i = 0; i < talents.size(); ++i)
3283     {
3284         if (talents[i].is_invocation)
3285             found_invocations = true;
3286         else
3287         {
3288             ToggleableMenuEntry* me =
3289                 new ToggleableMenuEntry(describe_talent(talents[i]),
3290                                         describe_talent(talents[i]),
3291                                         MEL_ITEM, 1, talents[i].hotkey);
3292             me->data = &numbers[i];
3293             me->add_tile(tile_def(tileidx_ability(talents[i].which)));
3294             if (!check_ability_possible(talents[i].which, true))
3295             {
3296                 me->colour = COL_INAPPLICABLE;
3297                 me->add_tile(tile_def(TILEI_MESH));
3298             }
3299             else if (_check_ability_dangerous(talents[i].which, true))
3300                 me->colour = COL_DANGEROUS;
3301             // Only check this here, since your god can't hate its own abilities
3302             else if (god_hates_ability(talents[i].which, you.religion))
3303                 me->colour = COL_FORBIDDEN;
3304             abil_menu.add_entry(me);
3305         }
3306     }
3307 
3308     if (found_invocations)
3309     {
3310 #ifdef USE_TILE_LOCAL
3311         MenuEntry* subtitle = new MenuEntry(" Invocations -    ", MEL_ITEM);
3312         subtitle->colour = BLUE;
3313         abil_menu.add_entry(subtitle);
3314 #else
3315         abil_menu.add_entry(new MenuEntry(" Invocations -    ", MEL_SUBTITLE));
3316 #endif
3317         for (unsigned int i = 0; i < talents.size(); ++i)
3318         {
3319             if (talents[i].is_invocation)
3320             {
3321                 ToggleableMenuEntry* me =
3322                     new ToggleableMenuEntry(describe_talent(talents[i]),
3323                                             describe_talent(talents[i]),
3324                                             MEL_ITEM, 1, talents[i].hotkey);
3325                 me->data = &numbers[i];
3326                 me->add_tile(tile_def(tileidx_ability(talents[i].which)));
3327                 if (!check_ability_possible(talents[i].which, true))
3328                 {
3329                     me->colour = COL_INAPPLICABLE;
3330                     me->add_tile(tile_def(TILEI_MESH));
3331                 }
3332                 else if (_check_ability_dangerous(talents[i].which, true))
3333                     me->colour = COL_DANGEROUS;
3334                 abil_menu.add_entry(me);
3335             }
3336         }
3337     }
3338 
3339     int ret = -1;
3340     abil_menu.on_single_selection = [&abil_menu, &talents, &ret](const MenuEntry& sel)
3341     {
3342         ASSERT(sel.hotkeys.size() == 1);
3343         int selected = *(static_cast<int*>(sel.data));
3344 
3345         if (abil_menu.menu_action == Menu::ACT_EXAMINE)
3346             _print_talent_description(talents[selected]);
3347         else
3348             ret = *(static_cast<int*>(sel.data));
3349         return abil_menu.menu_action == Menu::ACT_EXAMINE;
3350     };
3351     abil_menu.show(false);
3352     if (!crawl_state.doing_prev_cmd_again)
3353     {
3354         redraw_screen();
3355         update_screen();
3356     }
3357     return ret;
3358 }
3359 
3360 
describe_talent(const talent & tal)3361 string describe_talent(const talent& tal)
3362 {
3363     ASSERT(tal.which != ABIL_NON_ABILITY);
3364 
3365     const string failure = failure_rate_to_string(tal.fail)
3366         + (testbits(get_ability_def(tal.which).flags, abflag::hostile)
3367            ? " hostile" : "");
3368 
3369     ostringstream desc;
3370     desc << left
3371          << chop_string(ability_name(tal.which), 32)
3372          << chop_string(make_cost_description(tal.which), 32)
3373          << chop_string(failure, 12);
3374     return trimmed_string(desc.str());
3375 }
3376 
_add_talent(vector<talent> & vec,const ability_type ability,bool check_confused)3377 static void _add_talent(vector<talent>& vec, const ability_type ability,
3378                         bool check_confused)
3379 {
3380     const talent t = get_talent(ability, check_confused);
3381     if (t.which != ABIL_NON_ABILITY)
3382         vec.push_back(t);
3383 }
3384 
is_religious_ability(ability_type abil)3385 bool is_religious_ability(ability_type abil)
3386 {
3387     // ignores abandon religion / convert to beogh
3388     return abil >= ABIL_FIRST_RELIGIOUS_ABILITY
3389         && abil <= ABIL_LAST_RELIGIOUS_ABILITY;
3390 }
3391 
is_card_ability(ability_type abil)3392 bool is_card_ability(ability_type abil)
3393 {
3394     return testbits(get_ability_def(abil).flags, abflag::card);
3395 }
3396 
player_has_ability(ability_type abil,bool include_unusable)3397 bool player_has_ability(ability_type abil, bool include_unusable)
3398 {
3399     // TODO: consolidate fixup checks into here?
3400     abil = fixup_ability(abil);
3401     if (abil == ABIL_NON_ABILITY || abil == NUM_ABILITIES)
3402         return false;
3403 
3404     if (is_religious_ability(abil))
3405     {
3406         // TODO: something less dumb than this?
3407         auto god_abils = get_god_abilities(include_unusable, false,
3408                                                include_unusable);
3409         return count(god_abils.begin(), god_abils.end(), abil);
3410     }
3411 
3412     if (species::is_draconian(you.species)
3413         && species::draconian_breath(you.species) == abil)
3414     {
3415         return !form_changed_physiology() || you.form == transformation::dragon;
3416     }
3417 
3418     switch (abil)
3419     {
3420     case ABIL_HEAL_WOUNDS:
3421         return you.species == SP_DEEP_DWARF;
3422     case ABIL_SHAFT_SELF:
3423         if (crawl_state.game_is_sprint() || brdepth[you.where_are_you] == 1)
3424             return false;
3425         // fallthrough
3426     case ABIL_DIG:
3427         return you.can_burrow()
3428                             && (form_keeps_mutations() || include_unusable);
3429     case ABIL_HOP:
3430         return you.get_mutation_level(MUT_HOP);
3431     case ABIL_ROLLING_CHARGE:
3432         return you.get_mutation_level(MUT_ROLL);
3433     case ABIL_BREATHE_POISON:
3434         return you.get_mutation_level(MUT_SPIT_POISON) >= 2;
3435     case ABIL_SPIT_POISON:
3436         return you.get_mutation_level(MUT_SPIT_POISON) == 1;
3437     case ABIL_REVIVIFY:
3438         return you.has_mutation(MUT_VAMPIRISM) && !you.vampire_alive;
3439     case ABIL_EXSANGUINATE:
3440         return you.has_mutation(MUT_VAMPIRISM) && you.vampire_alive;
3441     case ABIL_TRAN_BAT:
3442         return you.get_mutation_level(MUT_VAMPIRISM) >= 2
3443                 && !you.vampire_alive
3444                 && you.form != transformation::bat;
3445     case ABIL_BREATHE_FIRE:
3446         // red draconian handled before the switch
3447         return you.form == transformation::dragon
3448                     && species::dragon_form(you.species) == MONS_FIRE_DRAGON;
3449     case ABIL_BLINKBOLT:
3450         return you.form == transformation::storm;
3451     // mutations
3452     case ABIL_DAMNATION:
3453         return you.get_mutation_level(MUT_HURL_DAMNATION);
3454     case ABIL_WORD_OF_CHAOS:
3455         return you.get_mutation_level(MUT_WORD_OF_CHAOS)
3456                 && (!silenced(you.pos()) || include_unusable);
3457     case ABIL_END_TRANSFORMATION:
3458         return you.duration[DUR_TRANSFORMATION] && !you.transform_uncancellable;
3459     // TODO: other god abilities
3460     case ABIL_RENOUNCE_RELIGION:
3461         return !you_worship(GOD_NO_GOD);
3462     case ABIL_CONVERT_TO_BEOGH:
3463         return env.level_state & LSTATE_BEOGH && can_convert_to_beogh();
3464     // pseudo-evocations from equipped items
3465     case ABIL_EVOKE_BLINK:
3466         return you.scan_artefacts(ARTP_BLINK)
3467                                 && !you.get_mutation_level(MUT_NO_ARTIFICE);
3468     case ABIL_EVOKE_THUNDER:
3469         return player_equip_unrand(UNRAND_RCLOUDS)
3470                                 && !you.get_mutation_level(MUT_NO_ARTIFICE);
3471     case ABIL_EVOKE_BERSERK:
3472         return you.evokable_berserk()
3473                                 && !you.get_mutation_level(MUT_NO_ARTIFICE);
3474     case ABIL_EVOKE_TURN_INVISIBLE:
3475         return you.evokable_invis()
3476                                 && !you.get_mutation_level(MUT_NO_ARTIFICE);
3477     default:
3478         // removed abilities handled here
3479         return false;
3480     }
3481 }
3482 
3483 /**
3484  * Return all relevant talents that the player has.
3485  *
3486  * Currently the only abilities that are affected by include_unusable are god
3487  * abilities (affect by e.g. penance or silence).
3488  * @param check_confused If true, abilities that don't work when confused will
3489  *                       be excluded.
3490  * @param include_unusable If true, abilities that are currently unusable will
3491  *                         be excluded.
3492  * @return  A vector of talent structs.
3493  */
your_talents(bool check_confused,bool include_unusable,bool ignore_piety)3494 vector<talent> your_talents(bool check_confused, bool include_unusable, bool ignore_piety)
3495 {
3496     vector<talent> talents;
3497 
3498     // TODO: can we just iterate over ability_type?
3499     vector<ability_type> check_order =
3500         { ABIL_HEAL_WOUNDS,
3501             ABIL_DIG,
3502             ABIL_SHAFT_SELF,
3503             ABIL_HOP,
3504             ABIL_ROLLING_CHARGE,
3505             ABIL_SPIT_POISON,
3506             ABIL_BREATHE_FIRE,
3507             ABIL_BREATHE_FROST,
3508             ABIL_BREATHE_POISON,
3509             ABIL_BREATHE_LIGHTNING,
3510             ABIL_BREATHE_POWER,
3511             ABIL_BREATHE_STEAM,
3512             ABIL_BREATHE_MEPHITIC,
3513             ABIL_BREATHE_ACID,
3514             ABIL_TRAN_BAT,
3515             ABIL_REVIVIFY,
3516             ABIL_EXSANGUINATE,
3517             ABIL_DAMNATION,
3518             ABIL_WORD_OF_CHAOS,
3519             ABIL_BLINKBOLT,
3520             ABIL_END_TRANSFORMATION,
3521             ABIL_RENOUNCE_RELIGION,
3522             ABIL_CONVERT_TO_BEOGH,
3523             ABIL_EVOKE_BLINK,
3524             ABIL_EVOKE_THUNDER,
3525             ABIL_EVOKE_BERSERK,
3526             ABIL_EVOKE_TURN_INVISIBLE
3527         };
3528 
3529     for (auto a : check_order)
3530         if (player_has_ability(a, include_unusable))
3531             _add_talent(talents, a, check_confused);
3532 
3533 
3534     // player_has_ability will just brute force these anyways (TODO)
3535     for (ability_type abil : get_god_abilities(include_unusable, ignore_piety,
3536                                                include_unusable))
3537     {
3538         _add_talent(talents, abil, check_confused);
3539     }
3540 
3541     // Side effect alert!
3542     // Find hotkeys for the non-hotkeyed talents.
3543     for (talent &tal : talents)
3544     {
3545         const int index = _lookup_ability_slot(tal.which);
3546         if (index > -1)
3547         {
3548             tal.hotkey = index_to_letter(index);
3549             continue;
3550         }
3551 
3552         // Try to find a free hotkey for i, starting from Z.
3553         for (int k = 51; k >= 0; --k)
3554         {
3555             const int kkey = index_to_letter(k);
3556             bool good_key = true;
3557 
3558             // Check that it doesn't conflict with other hotkeys.
3559             for (const talent &other : talents)
3560                 if (other.hotkey == kkey)
3561                 {
3562                     good_key = false;
3563                     break;
3564                 }
3565 
3566             if (good_key)
3567             {
3568                 tal.hotkey = kkey;
3569                 you.ability_letter_table[k] = tal.which;
3570                 break;
3571             }
3572         }
3573         // In theory, we could be left with an unreachable ability
3574         // here (if you have 53 or more abilities simultaneously).
3575     }
3576 
3577     return talents;
3578 }
3579 
3580 /**
3581  * Maybe move an ability to the slot given by the ability_slot option.
3582  *
3583  * @param[in] slot current slot of the ability
3584  * @returns the new slot of the ability; may still be slot, if the ability
3585  *          was not reassigned.
3586  */
auto_assign_ability_slot(int slot)3587 int auto_assign_ability_slot(int slot)
3588 {
3589     const ability_type abil_type = you.ability_letter_table[slot];
3590     const string abilname = lowercase_string(ability_name(abil_type));
3591     bool overwrite = false;
3592     // check to see whether we've chosen an automatic label:
3593     for (auto& mapping : Options.auto_ability_letters)
3594     {
3595         if (!mapping.first.matches(abilname))
3596             continue;
3597         for (char i : mapping.second)
3598         {
3599             if (i == '+')
3600                 overwrite = true;
3601             else if (i == '-')
3602                 overwrite = false;
3603             else if (isaalpha(i))
3604             {
3605                 const int index = letter_to_index(i);
3606                 ability_type existing_ability = you.ability_letter_table[index];
3607 
3608                 if (existing_ability == ABIL_NON_ABILITY
3609                     || existing_ability == abil_type)
3610                 {
3611                     // Unassigned or already assigned to this ability.
3612                     you.ability_letter_table[index] = abil_type;
3613                     if (slot != index)
3614                         you.ability_letter_table[slot] = ABIL_NON_ABILITY;
3615                     return index;
3616                 }
3617                 else if (overwrite)
3618                 {
3619                     const string str = lowercase_string(ability_name(existing_ability));
3620                     // Don't overwrite an ability matched by the same rule.
3621                     if (mapping.first.matches(str))
3622                         continue;
3623                     you.ability_letter_table[slot] = abil_type;
3624                     swap_ability_slots(slot, index, true);
3625                     return index;
3626                 }
3627                 // else occupied, continue to the next mapping.
3628             }
3629         }
3630     }
3631     return slot;
3632 }
3633 
3634 // Returns an index (0-51) if already assigned, -1 if not.
_lookup_ability_slot(const ability_type abil)3635 static int _lookup_ability_slot(const ability_type abil)
3636 {
3637     // Placeholder handling, part 2: The ability we have might
3638     // correspond to a placeholder, in which case the ability letter
3639     // table will contain that placeholder. Convert the latter to
3640     // its corresponding ability before comparing the two, so that
3641     // we'll find the placeholder's index properly.
3642     for (int slot = 0; slot < 52; slot++)
3643         if (fixup_ability(you.ability_letter_table[slot]) == abil)
3644             return slot;
3645     return -1;
3646 }
3647 
3648 // Assign a new ability slot if necessary. Returns an index (0-51) if
3649 // successful, -1 if you should just use the next one.
find_ability_slot(const ability_type abil,char firstletter)3650 int find_ability_slot(const ability_type abil, char firstletter)
3651 {
3652     // If we were already assigned a slot, use it.
3653     int had_slot = _lookup_ability_slot(abil);
3654     if (had_slot > -1)
3655         return had_slot;
3656 
3657     // No requested slot, find new one and make it preferred.
3658 
3659     // firstletter defaults to 'f', because a-e is for invocations
3660     int first_slot = letter_to_index(firstletter);
3661 
3662     // Reserve the first non-god ability slot (f) for Draconian breath
3663     if (you.species == SP_BASE_DRACONIAN && first_slot >= letter_to_index('f'))
3664         first_slot += 1;
3665 
3666     ASSERT(first_slot < 52);
3667 
3668     switch (abil)
3669     {
3670     case ABIL_ELYVILON_LIFESAVING:
3671         first_slot = letter_to_index('p');
3672         break;
3673     case ABIL_KIKU_GIFT_CAPSTONE_SPELLS:
3674         first_slot = letter_to_index('N');
3675         break;
3676     case ABIL_TSO_BLESS_WEAPON:
3677     case ABIL_KIKU_BLESS_WEAPON:
3678     case ABIL_LUGONU_BLESS_WEAPON:
3679         first_slot = letter_to_index('W');
3680         break;
3681     case ABIL_CONVERT_TO_BEOGH:
3682         first_slot = letter_to_index('Y');
3683         break;
3684     case ABIL_RU_SACRIFICE_PURITY:
3685     case ABIL_RU_SACRIFICE_WORDS:
3686     case ABIL_RU_SACRIFICE_DRINK:
3687     case ABIL_RU_SACRIFICE_ESSENCE:
3688     case ABIL_RU_SACRIFICE_HEALTH:
3689     case ABIL_RU_SACRIFICE_STEALTH:
3690     case ABIL_RU_SACRIFICE_ARTIFICE:
3691     case ABIL_RU_SACRIFICE_LOVE:
3692     case ABIL_RU_SACRIFICE_COURAGE:
3693     case ABIL_RU_SACRIFICE_ARCANA:
3694     case ABIL_RU_SACRIFICE_NIMBLENESS:
3695     case ABIL_RU_SACRIFICE_DURABILITY:
3696     case ABIL_RU_SACRIFICE_HAND:
3697     case ABIL_RU_SACRIFICE_EXPERIENCE:
3698     case ABIL_RU_SACRIFICE_SKILL:
3699     case ABIL_RU_SACRIFICE_EYE:
3700     case ABIL_RU_SACRIFICE_RESISTANCE:
3701     case ABIL_RU_REJECT_SACRIFICES:
3702     case ABIL_HEPLIAKLQANA_TYPE_KNIGHT:
3703     case ABIL_HEPLIAKLQANA_TYPE_BATTLEMAGE:
3704     case ABIL_HEPLIAKLQANA_TYPE_HEXER:
3705     case ABIL_HEPLIAKLQANA_IDENTITY: // move this?
3706     case ABIL_ASHENZARI_CURSE:
3707     case ABIL_ASHENZARI_UNCURSE:
3708         first_slot = letter_to_index('G');
3709         break;
3710     default:
3711         break;
3712     }
3713 
3714     for (int slot = first_slot; slot < 52; ++slot)
3715     {
3716         if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
3717         {
3718             you.ability_letter_table[slot] = abil;
3719             return auto_assign_ability_slot(slot);
3720         }
3721     }
3722 
3723     // If we can't find anything else, try a-e.
3724     for (int slot = first_slot - 1; slot >= 0; --slot)
3725     {
3726         if (you.ability_letter_table[slot] == ABIL_NON_ABILITY)
3727         {
3728             you.ability_letter_table[slot] = abil;
3729             return auto_assign_ability_slot(slot);
3730         }
3731     }
3732 
3733     // All letters are assigned.
3734     return -1;
3735 }
3736 
3737 
get_god_abilities(bool ignore_silence,bool ignore_piety,bool ignore_penance)3738 vector<ability_type> get_god_abilities(bool ignore_silence, bool ignore_piety,
3739                                        bool ignore_penance)
3740 {
3741     vector<ability_type> abilities;
3742     if (you_worship(GOD_RU) && you.props.exists(AVAILABLE_SAC_KEY))
3743     {
3744         bool any_sacrifices = false;
3745         for (const auto& store : you.props[AVAILABLE_SAC_KEY].get_vector())
3746         {
3747             any_sacrifices = true;
3748             abilities.push_back(static_cast<ability_type>(store.get_int()));
3749         }
3750         if (any_sacrifices)
3751             abilities.push_back(ABIL_RU_REJECT_SACRIFICES);
3752     }
3753     if (you_worship(GOD_ASHENZARI))
3754     {
3755         if (you.props.exists(AVAILABLE_CURSE_KEY))
3756             abilities.push_back(ABIL_ASHENZARI_CURSE);
3757         if (ignore_piety || you.piety > ASHENZARI_BASE_PIETY )
3758             abilities.push_back(ABIL_ASHENZARI_UNCURSE);
3759     }
3760     // XXX: should we check ignore_piety?
3761     if (you_worship(GOD_HEPLIAKLQANA)
3762         && piety_rank() >= 2 && !you.props.exists(HEPLIAKLQANA_ALLY_TYPE_KEY))
3763     {
3764         for (int anc_type = ABIL_HEPLIAKLQANA_FIRST_TYPE;
3765              anc_type <= ABIL_HEPLIAKLQANA_LAST_TYPE;
3766              ++anc_type)
3767         {
3768             abilities.push_back(static_cast<ability_type>(anc_type));
3769         }
3770     }
3771     if (silenced(you.pos()) && you_worship(GOD_WU_JIAN) && piety_rank() >= 2)
3772         abilities.push_back(ABIL_WU_JIAN_WALLJUMP);
3773 
3774     if (!ignore_silence && silenced(you.pos()))
3775         return abilities;
3776     // Remaining abilities are unusable if silenced.
3777     if (you_worship(GOD_NEMELEX_XOBEH))
3778     {
3779         for (int deck = ABIL_NEMELEX_FIRST_DECK;
3780              deck <= ABIL_NEMELEX_LAST_DECK;
3781              ++deck)
3782         {
3783             abilities.push_back(static_cast<ability_type>(deck));
3784         }
3785         if (!you.props[NEMELEX_STACK_KEY].get_vector().empty())
3786             abilities.push_back(ABIL_NEMELEX_DRAW_STACK);
3787     }
3788 
3789     for (const auto& power : get_god_powers(you.religion))
3790     {
3791         if (god_power_usable(power, ignore_piety, ignore_penance))
3792         {
3793             const ability_type abil = fixup_ability(power.abil);
3794             ASSERT(abil != ABIL_NON_ABILITY);
3795             abilities.push_back(abil);
3796         }
3797     }
3798 
3799     return abilities;
3800 }
3801 
swap_ability_slots(int index1,int index2,bool silent)3802 void swap_ability_slots(int index1, int index2, bool silent)
3803 {
3804     // Swap references in the letter table.
3805     ability_type tmp = you.ability_letter_table[index2];
3806     you.ability_letter_table[index2] = you.ability_letter_table[index1];
3807     you.ability_letter_table[index1] = tmp;
3808 
3809     if (!silent)
3810     {
3811         mprf_nocap("%c - %s", index_to_letter(index2),
3812                    ability_name(you.ability_letter_table[index2]));
3813     }
3814 
3815 }
3816 
3817 /**
3818  * What skill affects the success chance/power of a given skill, if any?
3819  *
3820  * @param ability       The ability in question.
3821  * @return              The skill that governs the ability, or SK_NONE.
3822  */
abil_skill(ability_type ability)3823 skill_type abil_skill(ability_type ability)
3824 {
3825     ASSERT(ability != ABIL_NON_ABILITY);
3826     return get_ability_def(ability).failure.skill();
3827 }
3828 
3829 /**
3830  * How valuable is it to train the skill that governs this ability? (What
3831  * 'magnitude' does the ability have?)
3832  *
3833  * @param ability       The ability in question.
3834  * @return              A 'magnitude' for the ability, probably < 10.
3835  */
abil_skill_weight(ability_type ability)3836 int abil_skill_weight(ability_type ability)
3837 {
3838     ASSERT(ability != ABIL_NON_ABILITY);
3839     // This is very loosely modelled on a legacy model; fairly arbitrary.
3840     const int base_fail = get_ability_def(ability).failure.base_chance;
3841     const int floor = base_fail ? 1 : 0;
3842     return max(floor, div_rand_round(base_fail, 8) - 3);
3843 }
3844 
3845 
3846 ////////////////////////////////////////////////////////////////////////
3847 // generic_cost
3848 
cost() const3849 int generic_cost::cost() const
3850 {
3851     return base + (add > 0 ? random2avg(add, rolls) : 0);
3852 }
3853 
cost(int max) const3854 int scaling_cost::cost(int max) const
3855 {
3856     return (value < 0) ? (-value) : ((value * max + 500) / 1000);
3857 }
3858