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