1 /**
2 * @file
3 * @brief Functions for handling player mutations.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "mutation.h"
9
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <sstream>
16
17 #include "ability.h"
18 #include "areas.h"
19 #include "cio.h"
20 #include "coordit.h"
21 #include "dactions.h"
22 #include "delay.h"
23 #include "describe.h"
24 #include "english.h"
25 #include "env.h"
26 #include "god-abil.h"
27 #include "god-passive.h"
28 #include "hints.h"
29 #include "item-prop.h"
30 #include "items.h"
31 #include "libutil.h"
32 #include "menu.h"
33 #include "message.h"
34 #include "mon-place.h"
35 #include "notes.h"
36 #include "output.h"
37 #include "player-stats.h"
38 #include "religion.h"
39 #include "skills.h"
40 #include "state.h"
41 #include "stringutil.h"
42 #include "tag-version.h"
43 #include "terrain.h"
44 #include "transform.h"
45 #include "unicode.h"
46 #include "xom.h"
47
48 using namespace ui;
49
50 static bool _delete_single_mutation_level(mutation_type mutat, const string &reason, bool transient);
51
52 struct body_facet_def
53 {
54 equipment_type eq;
55 mutation_type mut;
56 };
57
58 struct facet_def
59 {
60 int tier;
61 mutation_type muts[3];
62 int when[3];
63 };
64
65 struct demon_mutation_info
66 {
67 mutation_type mut;
68 int when;
69 int facet;
70
demon_mutation_infodemon_mutation_info71 demon_mutation_info(mutation_type m, int w, int f)
72 : mut(m), when(w), facet(f) { }
73 };
74
75 enum class mutflag
76 {
77 good = 1 << 0, // used by benemut etc
78 bad = 1 << 1, // used by malmut etc
79 jiyva = 1 << 2, // jiyva-only muts
80 qazlal = 1 << 3, // qazlal wrath
81 xom = 1 << 4, // xom being xom
82
83 last = xom
84 };
85 DEF_BITFIELD(mutflags, mutflag, 4);
86 COMPILE_CHECK(mutflags::exponent(mutflags::last_exponent) == mutflag::last);
87
88 #include "mutation-data.h"
89
90 static const body_facet_def _body_facets[] =
91 {
92 //{ EQ_NONE, MUT_FANGS },
93 { EQ_HELMET, MUT_HORNS },
94 { EQ_HELMET, MUT_ANTENNAE },
95 //{ EQ_HELMET, MUT_BEAK },
96 { EQ_GLOVES, MUT_CLAWS },
97 { EQ_BOOTS, MUT_HOOVES },
98 { EQ_BOOTS, MUT_TALONS }
99 };
100
101 static vector<mutation_type> removed_mutations =
102 {
103 #if TAG_MAJOR_VERSION == 34
104 MUT_ROUGH_BLACK_SCALES,
105 MUT_BREATHE_FLAMES,
106 MUT_BREATHE_POISON,
107 MUT_CARNIVOROUS,
108 MUT_CLING,
109 MUT_CONSERVE_POTIONS,
110 MUT_CONSERVE_SCROLLS,
111 MUT_EXOSKELETON,
112 MUT_FAST_METABOLISM,
113 MUT_FLEXIBLE_WEAK,
114 MUT_FOOD_JELLY,
115 MUT_FUMES,
116 MUT_HERBIVOROUS,
117 MUT_JUMP,
118 MUT_SAPROVOROUS,
119 MUT_SLOW_METABOLISM,
120 MUT_STRONG_STIFF,
121 MUT_SUSTAIN_ATTRIBUTES,
122 MUT_TELEPORT_CONTROL,
123 MUT_TRAMPLE_RESISTANCE,
124 MUT_MUMMY_RESTORATION,
125 MUT_NO_CHARM_MAGIC,
126 MUT_MIASMA_IMMUNITY,
127 MUT_BLURRY_VISION,
128 MUT_BLINK,
129 MUT_UNBREATHING,
130 MUT_GOURMAND,
131 #endif
132 };
133
get_removed_mutations()134 vector<mutation_type> get_removed_mutations()
135 {
136 return removed_mutations;
137 }
138
139 /**
140 * Conflicting mutation pairs. Entries are symmetric (so if A conflicts
141 * with B, B conflicts with A in the same way).
142 *
143 * The third value in each entry means:
144 * 0: If the new mutation is forced, remove all levels of the old
145 * mutation. Either way, keep scanning for more conflicts and
146 * do what they say (accepting the mutation if there are no
147 * further conflicts).
148 *
149 * -1: If the new mutation is forced, remove all levels of the old
150 * mutation and scan for more conflicts. If it is not forced,
151 * fail at giving the new mutation.
152 *
153 * 1: If the new mutation is temporary, just allow the conflict.
154 * Otherwise, trade off: delete one level of the old mutation,
155 * don't give the new mutation, and consider it a success.
156 *
157 * It makes sense to have two entries for the same pair, one with value 0
158 * and one with 1: that would replace all levels of the old mutation if
159 * forced, or a single level if not forced. However, the 0 entry must
160 * precede the 1 entry; so if you re-order this list, keep all the 0s
161 * before all the 1s.
162 */
163 static const int conflict[][3] =
164 {
165 #if TAG_MAJOR_VERSION == 34
166 { MUT_REGENERATION, MUT_SLOW_METABOLISM, 0},
167 #endif
168 { MUT_REGENERATION, MUT_INHIBITED_REGENERATION, 0},
169 { MUT_FAST, MUT_SLOW, 0},
170 #if TAG_MAJOR_VERSION == 34
171 { MUT_STRONG_STIFF, MUT_FLEXIBLE_WEAK, 1},
172 #endif
173 { MUT_STRONG, MUT_WEAK, 1},
174 { MUT_CLEVER, MUT_DOPEY, 1},
175 { MUT_AGILE, MUT_CLUMSY, 1},
176 { MUT_ROBUST, MUT_FRAIL, 1},
177 { MUT_HIGH_MAGIC, MUT_LOW_MAGIC, 1},
178 { MUT_WILD_MAGIC, MUT_SUBDUED_MAGIC, 1},
179 #if TAG_MAJOR_VERSION == 34
180 { MUT_CARNIVOROUS, MUT_HERBIVOROUS, 1},
181 { MUT_SLOW_METABOLISM, MUT_FAST_METABOLISM, 1},
182 #endif
183 { MUT_REGENERATION, MUT_INHIBITED_REGENERATION, 1},
184 { MUT_BERSERK, MUT_CLARITY, 1},
185 { MUT_FAST, MUT_SLOW, 1},
186 { MUT_FANGS, MUT_BEAK, -1},
187 { MUT_ANTENNAE, MUT_HORNS, -1}, // currently overridden by physiology_mutation_conflict
188 { MUT_HOOVES, MUT_TALONS, -1}, // currently overridden by physiology_mutation_conflict
189 { MUT_TRANSLUCENT_SKIN, MUT_CAMOUFLAGE, -1},
190 { MUT_MUTATION_RESISTANCE, MUT_EVOLUTION, -1},
191 { MUT_ANTIMAGIC_BITE, MUT_ACIDIC_BITE, -1},
192 { MUT_HEAT_RESISTANCE, MUT_HEAT_VULNERABILITY, -1},
193 { MUT_COLD_RESISTANCE, MUT_COLD_VULNERABILITY, -1},
194 { MUT_SHOCK_RESISTANCE, MUT_SHOCK_VULNERABILITY, -1},
195 { MUT_STRONG_WILLED, MUT_WEAK_WILLED, -1},
196 { MUT_NO_REGENERATION, MUT_INHIBITED_REGENERATION, -1},
197 { MUT_NO_REGENERATION, MUT_REGENERATION, -1},
198 { MUT_HP_CASTING, MUT_HIGH_MAGIC, -1},
199 { MUT_HP_CASTING, MUT_LOW_MAGIC, -1},
200 };
201
_mut_has_use(const mutation_def & mut,mutflag use)202 static bool _mut_has_use(const mutation_def &mut, mutflag use)
203 {
204 return bool(mut.uses & use);
205 }
206
207 #define MUT_BAD(mut) _mut_has_use((mut), mutflag::bad)
208 #define MUT_GOOD(mut) _mut_has_use((mut), mutflag::good)
209
_mut_weight(const mutation_def & mut,mutflag use)210 static int _mut_weight(const mutation_def &mut, mutflag use)
211 {
212 switch (use)
213 {
214 case mutflag::jiyva:
215 case mutflag::qazlal:
216 case mutflag::xom:
217 return 1;
218 case mutflag::good:
219 case mutflag::bad:
220 default:
221 return mut.weight;
222 }
223 }
224
225 static int mut_index[NUM_MUTATIONS];
226 static int category_mut_index[MUT_NON_MUTATION - CATEGORY_MUTATIONS];
227 static map<mutflag, int> total_weight;
228
init_mut_index()229 void init_mut_index()
230 {
231 total_weight.clear();
232 for (int i = 0; i < NUM_MUTATIONS; ++i)
233 mut_index[i] = -1;
234
235 for (unsigned int i = 0; i < ARRAYSZ(mut_data); ++i)
236 {
237 const mutation_type mut = mut_data[i].mutation;
238 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
239 ASSERT(mut_index[mut] == -1);
240 mut_index[mut] = i;
241 for (const auto flag : mutflags::range())
242 {
243 if (_mut_has_use(mut_data[i], flag))
244 total_weight[flag] += _mut_weight(mut_data[i], flag);
245 }
246 }
247
248 // this is all a bit silly but ok
249 for (int i = 0; i < MUT_NON_MUTATION - CATEGORY_MUTATIONS; ++i)
250 category_mut_index[i] = -1;
251
252 for (unsigned int i = 0; i < ARRAYSZ(category_mut_data); ++i)
253 {
254 const mutation_type mut = category_mut_data[i].mutation;
255 ASSERT_RANGE(mut, CATEGORY_MUTATIONS, MUT_NON_MUTATION);
256 ASSERT(category_mut_index[mut-CATEGORY_MUTATIONS] == -1);
257 category_mut_index[mut-CATEGORY_MUTATIONS] = i;
258 }
259 }
260
_get_mutation_def(mutation_type mut)261 static const mutation_def& _get_mutation_def(mutation_type mut)
262 {
263 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
264 ASSERT(mut_index[mut] != -1);
265 return mut_data[mut_index[mut]];
266 }
267
268 /*
269 * Get the max number of possible levels for mutation `mut`. This is typically 1 or 3.
270 *
271 * @return the mutation cap.
272 */
get_mutation_cap(mutation_type mut)273 int get_mutation_cap(mutation_type mut)
274 {
275 return _get_mutation_def(mut).levels;
276 }
277
_get_category_mutation_def(mutation_type mut)278 static const mutation_category_def& _get_category_mutation_def(mutation_type mut)
279 {
280 ASSERT_RANGE(mut, CATEGORY_MUTATIONS, MUT_NON_MUTATION);
281 ASSERT(category_mut_index[mut-CATEGORY_MUTATIONS] != -1);
282 return category_mut_data[category_mut_index[mut-CATEGORY_MUTATIONS]];
283 }
284
_is_valid_mutation(mutation_type mut)285 static bool _is_valid_mutation(mutation_type mut)
286 {
287 return mut >= 0 && mut < NUM_MUTATIONS && mut_index[mut] != -1;
288 }
289
290 static const mutation_type _ds_scales[] =
291 {
292 MUT_DISTORTION_FIELD, MUT_ICY_BLUE_SCALES,
293 MUT_LARGE_BONE_PLATES, MUT_MOLTEN_SCALES,
294 MUT_RUGGED_BROWN_SCALES, MUT_SLIMY_GREEN_SCALES,
295 MUT_THIN_METALLIC_SCALES, MUT_THIN_SKELETAL_STRUCTURE,
296 MUT_YELLOW_SCALES, MUT_STURDY_FRAME,
297 MUT_SANGUINE_ARMOUR, MUT_BIG_BRAIN,
298 MUT_SHARP_SCALES,
299 };
300
_is_demonspawn_scale(mutation_type mut)301 static bool _is_demonspawn_scale(mutation_type mut)
302 {
303 return find(begin(_ds_scales), end(_ds_scales), mut) != end(_ds_scales);
304 }
305
is_body_facet(mutation_type mut)306 bool is_body_facet(mutation_type mut)
307 {
308 return any_of(begin(_body_facets), end(_body_facets),
309 [=](const body_facet_def &facet)
310 { return facet.mut == mut; });
311 }
312
313 /*
314 * The degree to which `mut` is suppressed by the current form.
315 *
316 * @param mut the mutation to check.
317 *
318 * @return mutation_activity_type::FULL: completely available.
319 * mutation_activity_type::PARTIAL: partially suppressed.
320 * mutation_activity_type::INACTIVE: completely suppressed.
321 */
mutation_activity_level(mutation_type mut)322 mutation_activity_type mutation_activity_level(mutation_type mut)
323 {
324 // First make sure the player's form permits the mutation.
325 if (!form_keeps_mutations())
326 {
327 if (you.form == transformation::dragon)
328 {
329 monster_type drag = species::dragon_form(you.species);
330 if (mut == MUT_SHOCK_RESISTANCE && drag == MONS_STORM_DRAGON)
331 return mutation_activity_type::FULL;
332 if ((mut == MUT_ACIDIC_BITE || mut == MUT_ACID_RESISTANCE)
333 && drag == MONS_GOLDEN_DRAGON)
334 {
335 return mutation_activity_type::FULL;
336 }
337 if (mut == MUT_STINGER && drag == MONS_SWAMP_DRAGON)
338 return mutation_activity_type::FULL;
339 if (mut == MUT_STEAM_RESISTANCE && drag == MONS_STEAM_DRAGON)
340 return mutation_activity_type::FULL;
341 }
342 // Vampire bats keep their fangs.
343 if (you.form == transformation::bat
344 && you.has_innate_mutation(MUT_VAMPIRISM)
345 && mut == MUT_FANGS)
346 {
347 return mutation_activity_type::FULL;
348 }
349 // Dex and HP changes are kept in all forms.
350 #if TAG_MAJOR_VERSION == 34
351 if (mut == MUT_ROUGH_BLACK_SCALES)
352 return mutation_activity_type::PARTIAL;
353 #endif
354 if (mut == MUT_RUGGED_BROWN_SCALES)
355 return mutation_activity_type::PARTIAL;
356 else if (_get_mutation_def(mut).form_based)
357 return mutation_activity_type::INACTIVE;
358 }
359
360 if (you.form == transformation::statue)
361 {
362 // Statues get all but the AC benefit from scales, but are not affected
363 // by other changes in body material or speed.
364 switch (mut)
365 {
366 case MUT_GELATINOUS_BODY:
367 case MUT_TOUGH_SKIN:
368 case MUT_SHAGGY_FUR:
369 case MUT_FAST:
370 case MUT_SLOW:
371 case MUT_IRIDESCENT_SCALES:
372 return mutation_activity_type::INACTIVE;
373 #if TAG_MAJOR_VERSION == 34
374 case MUT_ROUGH_BLACK_SCALES:
375 #endif
376 case MUT_RUGGED_BROWN_SCALES:
377 case MUT_SHARP_SCALES:
378 return mutation_activity_type::PARTIAL;
379 case MUT_YELLOW_SCALES:
380 case MUT_ICY_BLUE_SCALES:
381 case MUT_MOLTEN_SCALES:
382 case MUT_SLIMY_GREEN_SCALES:
383 case MUT_THIN_METALLIC_SCALES:
384 return you.get_base_mutation_level(mut) > 2 ? mutation_activity_type::PARTIAL :
385 mutation_activity_type::INACTIVE;
386 default:
387 break;
388 }
389 }
390
391 //XXX: Should this make claws inactive too?
392 if (you.form == transformation::blade_hands && mut == MUT_PAWS)
393 return mutation_activity_type::INACTIVE;
394
395 if (you.form == transformation::tree && mut == MUT_TELEPORT)
396 return mutation_activity_type::INACTIVE;
397 #if TAG_MAJOR_VERSION == 34
398 if ((you_worship(GOD_PAKELLAS) || player_under_penance(GOD_PAKELLAS))
399 && (mut == MUT_MANA_LINK || mut == MUT_MANA_REGENERATION))
400 {
401 return mutation_activity_type::INACTIVE;
402 }
403 #endif
404
405 if (mut == MUT_BERSERK && you.is_lifeless_undead())
406 return mutation_activity_type::INACTIVE;
407
408 if (!form_can_bleed(you.form) && mut == MUT_SANGUINE_ARMOUR)
409 return mutation_activity_type::INACTIVE;
410
411 if (mut == MUT_DEMONIC_GUARDIAN && you.get_mutation_level(MUT_NO_LOVE))
412 return mutation_activity_type::INACTIVE;
413
414 if (mut == MUT_NIMBLE_SWIMMER)
415 {
416 if (feat_is_water(env.grid(you.pos())))
417 return mutation_activity_type::FULL;
418 else
419 return mutation_activity_type::INACTIVE;
420 }
421
422 return mutation_activity_type::FULL;
423 }
424
425 // Counts of various statuses/types of mutations from the current/most
426 // recent call to describe_mutations. TODO: eliminate
427 static int _num_full_suppressed = 0;
428 static int _num_part_suppressed = 0;
429 static int _num_transient = 0;
430
_suppressedmut(string desc,bool terse=false)431 static string _suppressedmut(string desc, bool terse=false)
432 {
433 return terse ? "(" + desc + ")" : "<darkgrey>((" + desc + "))</darkgrey>";
434 }
435
_innatemut(string desc,bool terse=false)436 static string _innatemut(string desc, bool terse=false)
437 {
438 return terse ? desc : "<lightblue>" + desc + "</lightblue>";
439 }
440
_formmut(string desc,bool terse=false)441 static string _formmut(string desc, bool terse=false)
442 {
443 return terse ? desc : "<green>" + desc + "</green>";
444 }
445
_badmut(string desc,bool terse=false)446 static string _badmut(string desc, bool terse=false)
447 {
448 return terse ? desc : "<lightred>" + desc + "</lightred>";
449 }
450
_annotate_form_based(string desc,bool suppressed,bool terse=false)451 static string _annotate_form_based(string desc, bool suppressed, bool terse=false)
452 {
453 if (suppressed)
454 {
455 return _suppressedmut(desc, terse);
456 ++_num_full_suppressed;
457 }
458 else
459 return _innatemut(desc, terse);
460 }
461
_dragon_abil(string desc,bool terse=false)462 static string _dragon_abil(string desc, bool terse=false)
463 {
464 const bool supp = form_changed_physiology()
465 && you.form != transformation::dragon;
466 return _annotate_form_based(desc, supp, terse);
467 }
468
469 /*
470 * Does the player have mutation `mut` with at least one temporary level?
471 *
472 * Reminder: temporary mutations can coexist with innate or normal mutations.
473 */
has_temporary_mutation(mutation_type mut) const474 bool player::has_temporary_mutation(mutation_type mut) const
475 {
476 return you.temp_mutation[mut] > 0;
477 }
478
479 /*
480 * Does the player have mutation `mut` with at least one innate level?
481 *
482 * Reminder: innate mutations can coexist with temporary or normal mutations.
483 */
has_innate_mutation(mutation_type mut) const484 bool player::has_innate_mutation(mutation_type mut) const
485 {
486 return you.innate_mutation[mut] > 0;
487 }
488
489 /*
490 * How much of mutation `mut` does the player have? This ignores form changes.
491 * If all three bool arguments are false, this should always return 0.
492 *
493 * @param temp include temporary mutation levels. defaults to true.
494 * @param innate include innate mutation levels. defaults to true.
495 * @param normal include normal (non-temp, non-innate) mutation levels. defaults to true.
496 *
497 * @return the total levels of the mutation.
498 */
get_base_mutation_level(mutation_type mut,bool innate,bool temp,bool normal) const499 int player::get_base_mutation_level(mutation_type mut, bool innate, bool temp, bool normal) const
500 {
501 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
502 // you.mutation stores the total levels of all mutations
503 int level = you.mutation[mut];
504 if (!temp)
505 level -= you.temp_mutation[mut];
506 if (!innate)
507 level -= you.innate_mutation[mut];
508 if (!normal)
509 level -= (you.mutation[mut] - (you.temp_mutation[mut] + you.innate_mutation[mut]));
510 ASSERT(level >= 0);
511 return level;
512 }
513
514 /*
515 * How much of mutation `mut` does the player have innately?
516 *
517 */
get_innate_mutation_level(mutation_type mut) const518 int player::get_innate_mutation_level(mutation_type mut) const
519 {
520 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
521 return you.innate_mutation[mut];
522 }
523
524 /*
525 * How much of mutation `mut` does the player have temporarily?
526 *
527 */
get_temp_mutation_level(mutation_type mut) const528 int player::get_temp_mutation_level(mutation_type mut) const
529 {
530 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
531 return you.temp_mutation[mut];
532 }
533
534 /*
535 * Get the current player mutation level for `mut`, possibly incorporating information about forms.
536 * See the other version of this function for the canonical usage of `minact`; some forms such as scale mutations
537 * have different thresholds depending on the purpose and form and so will call this directly (e.g. ac
538 * but not resistances are suppressed in statueform.)
539 *
540 * @param mut the mutation to check
541 * @param minact the minimum activity level needed for the mutation to count as non-suppressed.
542 *
543 * @return a mutation level, 0 if the mutation doesn't exist or is suppressed.
544 */
get_mutation_level(mutation_type mut,mutation_activity_type minact) const545 int player::get_mutation_level(mutation_type mut, mutation_activity_type minact) const
546 {
547 ASSERT_RANGE(mut, 0, NUM_MUTATIONS);
548 if (mutation_activity_level(mut) < minact)
549 return 0;
550 return get_base_mutation_level(mut, true, true);
551 }
552
553 /*
554 * Get the current player mutation level for `mut`, possibly incorporating information about forms.
555 *
556 * @param mut the mutation to check
557 * @param check_form whether to incorporate suppression from forms. Defaults to true.
558 *
559 * @return a mutation level, 0 if the mutation doesn't exist or is suppressed.
560 */
get_mutation_level(mutation_type mut,bool check_form) const561 int player::get_mutation_level(mutation_type mut, bool check_form) const
562 {
563 return get_mutation_level(mut, check_form ? mutation_activity_type::PARTIAL :
564 mutation_activity_type::INACTIVE);
565 }
566
567 /*
568 * Does the player have mutation `mut` in some form?
569 */
has_mutation(mutation_type mut,bool check_form) const570 bool player::has_mutation(mutation_type mut, bool check_form) const
571 {
572 return get_mutation_level(mut, check_form) > 0;
573 }
574
575 /*
576 * Test the validity of the player mutation structures, using ASSERTs.
577 * Will crash on a failure.
578 *
579 * @debug_msg whether to output diagnostic `dprf`s in the process.
580 */
validate_mutations(bool debug_msg)581 void validate_mutations(bool debug_msg)
582 {
583 if (debug_msg)
584 dprf("Validating player mutations");
585 int total_temp = 0;
586
587 for (int i = 0; i < NUM_MUTATIONS; i++)
588 {
589 mutation_type mut = static_cast<mutation_type>(i);
590 if (debug_msg && you.mutation[mut] > 0)
591 {
592 dprf("mutation %s: total %d innate %d temp %d",
593 mutation_name(mut), you.mutation[mut],
594 you.innate_mutation[mut], you.temp_mutation[mut]);
595 }
596 ASSERT(you.get_base_mutation_level(mut) == you.mutation[mut]);
597 ASSERT(you.mutation[i] >= you.innate_mutation[mut] + you.temp_mutation[mut]);
598 total_temp += you.temp_mutation[mut];
599
600 const mutation_def& mdef = _get_mutation_def(mut);
601 ASSERT(you.mutation[mut] <= mdef.levels);
602
603 // reconstruct what the innate mutations should be based on Ds mutation schedule
604 // TODO generalize to all innate muts
605 if (you.species == SP_DEMONSPAWN)
606 {
607 bool is_trait = false;
608 int trait_level = 0;
609 // If the player has sacrificed xp, use the pre-sac xl; sac xp
610 // doesn't remove Ds mutations.
611 // You can still trick wizmode into crashing here.
612 const int check_xl = (you.get_mutation_level(MUT_INEXPERIENCED)
613 && you.max_level <= you.get_experience_level() + 2)
614 ? you.max_level
615 : you.get_experience_level();
616 for (player::demon_trait trait : you.demonic_traits)
617 {
618 if (trait.mutation == mut)
619 {
620 is_trait = true;
621 if (check_xl >= trait.level_gained)
622 trait_level += 1;
623 }
624 }
625
626 if (debug_msg && is_trait)
627 {
628 dprf("scheduled innate for %s: %d, actual %d", mutation_name(mut),
629 trait_level, you.innate_mutation[mut]);
630 }
631 if (is_trait)
632 ASSERT(you.innate_mutation[mut] == trait_level);
633 }
634 }
635 ASSERT(total_temp == you.attribute[ATTR_TEMP_MUTATIONS]);
636 }
637
_terse_mut_name(mutation_type mut)638 static string _terse_mut_name(mutation_type mut)
639 {
640 const int current_level = you.get_mutation_level(mut);
641 const int base_level = you.get_base_mutation_level(mut);
642 const bool lowered = current_level < base_level;
643 const int temp_levels = you.get_base_mutation_level(mut, false, true, false); // only temp levels
644 const int ordinary_levels = you.get_base_mutation_level(mut, true, false, true); // excluding temp levels
645
646 const int max_levels = mutation_max_levels(mut);
647
648 string current = mutation_name(mut);
649
650 if (max_levels > 1)
651 {
652 // add on any numeric levels
653 ostringstream ostr;
654 ostr << " ";
655 if (ordinary_levels == 0) // only temporary levels are present
656 ostr << temp_levels;
657 else
658 {
659 // at least some non-temporary levels
660 ostr << ordinary_levels;
661 if (temp_levels)
662 ostr << "[+" << temp_levels << "]";
663 }
664 current += ostr.str();
665 }
666
667 // bracket the whole thing
668 if (ordinary_levels == 0)
669 current = "[" + current + "]";
670
671 if (!current.empty())
672 {
673 if (current_level == 0) // suppressed by form
674 current = "(" + current + ")";
675 if (lowered)
676 current = "<darkgrey>" + current + "</darkgrey>";
677 }
678 return current;
679 }
680
681 // TODO: reimplement other form quirks as mutations, generalize this idea?
_is_appendage_mutation(mutation_type mut)682 static bool _is_appendage_mutation(mutation_type mut)
683 {
684 for (auto app : you.props[APPENDAGE_KEY].get_vector())
685 if (mut == static_cast<mutation_type>(app.get_int()))
686 return true;
687 return false;
688 }
689
_get_mutations(bool terse)690 static vector<string> _get_mutations(bool terse)
691 {
692 vector<string> result;
693
694 bool pois_printed = false;
695
696 // XX sort good and bad non-permanent mutations better? Comes up mostly for
697 // vampires
698
699 // non-permanent and form-based stuff
700
701 if (you.form != transformation::none)
702 {
703 const auto *form = get_form(you.form);
704 ASSERT(form);
705 // we could add form->get_long_name() here for `terse`, but the line in
706 // % is shown right below a line which includes the form name.
707 if (!terse)
708 result.push_back(_formmut(form->get_description()));
709 else if (you.form == transformation::appendage)
710 {
711 // terse mode: these mutations are skipped later, so add the short
712 // forms here. The appendage description covers the long form case.
713 for (auto app : you.props[APPENDAGE_KEY].get_vector())
714 {
715 result.push_back(_terse_mut_name(
716 static_cast<mutation_type>(app.get_int())));
717 }
718 }
719
720 for (const auto &p : form->get_fakemuts(terse))
721 if (!p.empty())
722 result.push_back(_formmut(p, terse));
723
724 if (you.form == transformation::dragon)
725 {
726 if (!species::is_draconian(you.species)
727 || you.species == SP_BASE_DRACONIAN) // ugh
728 {
729 result.push_back(terse
730 ? "breathe fire" : _formmut("You can breathe fire."));
731 }
732 else if (!terse
733 && species::draconian_breath(you.species) != ABIL_NON_ABILITY)
734 {
735 result.push_back(
736 _formmut("Your breath weapon is enhanced in this form."));
737 }
738 }
739
740 if (form_base_movespeed(you.form) < 10)
741 result.push_back(terse ? "fast" : _formmut("You move quickly."));
742
743 // form-based flying can't be stopped, so don't print amphibiousness
744 if (form->player_can_fly())
745 result.push_back(terse ? "flying" : _formmut("You are flying."));
746 else if (form->player_can_swim() && !you.can_swim(true)) // n.b. this could cause issues for non-dragon giant forms if they exist
747 result.push_back(terse ? "amphibious" : _formmut("You are amphibious."));
748
749 if (form->hp_mod > 10)
750 {
751 result.push_back(terse ? "boosted hp"
752 : _formmut(make_stringf("Your maximum health is %sincreased.",
753 form->hp_mod < 13 ? "" : "greatly ")));
754 }
755 else if (form->hp_mod < 10)
756 result.push_back(terse ? "reduced hp" : _badmut("Your maximum health is decreased."));
757
758 // immunity comes from form
759 if (!terse && player_res_poison(false, true, false) == 3
760 && !player_res_poison(false, false, false))
761 {
762 pois_printed = true;
763 // wispform has a fakemut that prints something more general
764 if (you.form != transformation::wisp)
765 result.push_back(_formmut("You are immune to poison."));
766 }
767
768 // bad stuff
769 if (!terse
770 && (form->spellcasting_penalty > 0
771 || you.form == transformation::shadow)) // hard-coded effect
772 {
773 result.push_back(_badmut("Your spellcasting is less reliable in this form."));
774 }
775
776 // XX say something about AC? Best would be to compare it to AC without
777 // the form, but I'm not sure if that's possible
778
779 // XX better synchronizing with various base armour/eq possibilities
780 if (!terse && !you.has_mutation(MUT_NO_ARMOUR))
781 {
782 const string melding_desc = form->melding_description();
783 if (!melding_desc.empty())
784 result.push_back(_badmut(melding_desc));
785 }
786 if (!terse && !form->can_wield() && !you.has_mutation(MUT_NO_GRASPING))
787 {
788 // same as MUT_NO_GRASPING
789 result.push_back(_badmut(
790 "You are incapable of wielding weapons or throwing items."));
791 }
792
793 if (!form->can_cast)
794 result.push_back(terse ? "no casting" : _badmut("You cannot cast spells."));
795
796 }
797
798 // This gets DUR_NO_POTIONS as well as necromutation, is that good?
799 if (!you.can_drink(true) && you.can_drink(false))
800 result.push_back(terse ? "no potions" : _badmut("You cannot drink.")); // same as MUT_NO_DRINK
801
802 //pseudo-forms that come from species
803
804 if (you.has_mutation(MUT_VAMPIRISM))
805 {
806 if (you.vampire_alive)
807 {
808 result.push_back(terse ? "alive" :
809 _formmut("Your natural rate of healing is accelerated."));
810 }
811 else if (terse)
812 result.push_back("bloodless");
813 else
814 {
815 result.push_back(
816 _formmut("You do not regenerate when monsters are visible."));
817 result.push_back(
818 _formmut("You are frail without blood (-20% HP)."));
819 result.push_back(
820 _formmut("You can heal yourself when you bite living creatures."));
821 // XX automatically color this green somehow? Handled below more
822 // generally for non-vampires
823 if (!pois_printed)
824 result.push_back(_formmut("You are immune to poison."));
825 pois_printed = true;
826 }
827 }
828
829 if (you.can_water_walk())
830 {
831 if (terse)
832 result.push_back("walk on water");
833 else
834 {
835 if (have_passive(passive_t::water_walk))
836 result.push_back(_formmut("You can walk on water."));
837 else
838 result.push_back(_formmut("You can walk on water until reaching land."));
839 }
840 }
841
842 if (have_passive(passive_t::frail)
843 || player_under_penance(GOD_HEPLIAKLQANA))
844 {
845 if (terse)
846 result.push_back("reduced essence");
847 else
848 {
849 // XX message is probably wrong for penance?
850 result.push_back(_badmut(
851 "Your life essence is reduced to manifest your ancestor. (-10% HP)"));
852 }
853 }
854
855 // Innate abilities which haven't been implemented as mutations yet.
856 for (const string& str : species::fake_mutations(you.species, terse))
857 {
858 if (species::is_draconian(you.species))
859 result.push_back(_dragon_abil(str, terse));
860 else
861 result.push_back(_innatemut(str, terse));
862 }
863
864 if (you.racial_ac(false) > 0)
865 {
866 const int ac = you.racial_ac(false) / 100;
867 if (terse)
868 result.push_back("AC +" + to_string(ac));
869 else
870 {
871 // XX generalize this code somehow?
872 const string scale_clause = string(species::scale_type(you.species))
873 + " scales are "
874 + (you.species == SP_GREY_DRACONIAN ? "very " : "") + "hard";
875
876 result.push_back(_annotate_form_based(
877 make_stringf("Your %s. (AC +%d)", you.species == SP_NAGA
878 ? "serpentine skin is tough"
879 : you.species == SP_GARGOYLE
880 ? "stone body is resilient"
881 : scale_clause.c_str(),
882 ac),
883 player_is_shapechanged()
884 && !(species::is_draconian(you.species)
885 && you.form == transformation::dragon)));
886 }
887 }
888
889 // player::can_swim includes other cases, e.g. extra-balanced species that
890 // are not truly amphibious. Mertail has its own description that implies
891 // amphibiousness.
892 if (species::can_swim(you.species) && !you.has_innate_mutation(MUT_MERTAIL))
893 {
894 result.push_back(_annotate_form_based(
895 terse ? "amphibious" : "You are amphibious.",
896 !form_likes_water(), terse));
897 }
898
899 if (species::arm_count(you.species) > 2)
900 {
901 const bool rings_melded = !get_form()->slot_available(EQ_RING_EIGHT);
902 const int arms = you.arm_count();
903 if (terse)
904 {
905 result.push_back(_annotate_form_based(
906 make_stringf("%d rings", arms), rings_melded, true));
907 }
908 else
909 {
910 result.push_back(_annotate_form_based(
911 make_stringf("You can wear up to %s rings at the same time.",
912 number_in_words(arms).c_str()), rings_melded));
913 }
914 }
915
916 // in the terse list, this adj + a minimal size-derived desc covers the
917 // same ground as the detailed size-derived desc; so no need for the size
918 // itself in the long form.
919 if (terse)
920 {
921 const char* size_adjective = get_size_adj(you.body_size(PSIZE_BODY), true);
922 if (size_adjective)
923 result.emplace_back(size_adjective);
924 }
925
926 // XX is there a cleaner approach?
927 string armour_mut;
928 string weapon_mut;
929
930 switch (you.body_size(PSIZE_TORSO, true))
931 {
932 case SIZE_LITTLE:
933 armour_mut = terse ? "unfitting armour"
934 : "You are too small for most types of armour.";
935 weapon_mut = terse ? "no large weapons"
936 : "You are very small and have problems with some larger weapons.";
937 break;
938 case SIZE_SMALL:
939 weapon_mut = terse ? "no large weapons"
940 : "You are small and have problems with some larger weapons.";
941 break;
942 case SIZE_LARGE:
943 armour_mut = terse ? "unfitting armour"
944 : "You are too large for most types of armour.";
945 break;
946 default: // no giant species
947 break;
948 }
949 // Could move this into species-data, but then the hack that assumes
950 // _dragon_abil should get called on all draconian fake muts would break.
951 if (species::is_draconian(you.species))
952 {
953 armour_mut = terse ? "unfitting armour"
954 : "You cannot fit into any form of body armour.";
955 }
956 if (!weapon_mut.empty() && !you.has_mutation(MUT_NO_GRASPING))
957 result.push_back(_innatemut(weapon_mut, terse));
958 if (!armour_mut.empty() && !you.has_mutation(MUT_NO_ARMOUR))
959 result.push_back(_innatemut(armour_mut, terse));
960
961 if (!terse && species::get_stat_gain_multiplier(you.species) > 1)
962 result.push_back(_innatemut("Your attributes grow dramatically as you level up."));
963
964 // vampire, form cases handled above
965 if (!terse && player_res_poison(false, false, false) == 3 && !pois_printed)
966 result.push_back(_innatemut("You are immune to poison."));
967
968 // First add (non-removable) inborn abilities and demon powers.
969 for (int i = 0; i < NUM_MUTATIONS; i++)
970 {
971 mutation_type mut_type = static_cast<mutation_type>(i);
972 if (_is_appendage_mutation(mut_type))
973 continue;
974 if (you.has_innate_mutation(mut_type))
975 {
976 result.push_back(terse ? _terse_mut_name(mut_type)
977 : mutation_desc(mut_type, -1, true,
978 ((you.sacrifices[i] != 0) ? true : false)));
979 }
980 }
981
982 // Now add removable mutations.
983 for (int i = 0; i < NUM_MUTATIONS; i++)
984 {
985 mutation_type mut_type = static_cast<mutation_type>(i);
986 if (_is_appendage_mutation(mut_type))
987 continue;
988 if (you.get_base_mutation_level(mut_type, false, false, true) > 0
989 && !you.has_innate_mutation(mut_type)
990 && !you.has_temporary_mutation(mut_type))
991 {
992 result.push_back(terse ? _terse_mut_name(mut_type)
993 : mutation_desc(mut_type, -1, true));
994 }
995 }
996
997 //Finally, temporary mutations.
998 for (int i = 0; i < NUM_MUTATIONS; i++)
999 {
1000 mutation_type mut_type = static_cast<mutation_type>(i);
1001 if (you.has_temporary_mutation(mut_type))
1002 {
1003 result.push_back(terse ? _terse_mut_name(mut_type)
1004 : mutation_desc(mut_type, -1, true));
1005 }
1006 }
1007
1008 return result;
1009 }
1010
terse_mutation_list()1011 string terse_mutation_list()
1012 {
1013 const vector<string> mutations = _get_mutations(true);
1014
1015 if (mutations.empty())
1016 return "no striking features";
1017 else
1018 {
1019 return comma_separated_line(mutations.begin(), mutations.end(),
1020 ", ", ", ");
1021 }
1022 }
1023
describe_mutations(bool drop_title)1024 string describe_mutations(bool drop_title)
1025 {
1026 #ifdef DEBUG
1027 validate_mutations(true);
1028 #endif
1029 string result;
1030
1031 _num_full_suppressed = _num_part_suppressed = 0;
1032 _num_transient = 0;
1033
1034 if (!drop_title)
1035 {
1036 result += "<white>";
1037 result += "Innate Abilities, Weirdness & Mutations";
1038 result += "</white>\n\n";
1039 }
1040
1041 const vector<string> mutations = _get_mutations(false);
1042
1043 if (mutations.empty())
1044 result += "You are rather mundane.\n";
1045 else
1046 result += join_strings(mutations.begin(), mutations.end(), "\n");
1047
1048 return result;
1049 }
1050
_vampire_Ascreen_footer(bool first_page)1051 static formatted_string _vampire_Ascreen_footer(bool first_page)
1052 {
1053 const char *text = first_page ? "<w>Mutations</w>|Blood properties"
1054 : "Mutations|<w>Blood properties</w>";
1055 const string fmt = make_stringf("[<w>!</w>/<w>^</w>"
1056 #ifdef USE_TILE_LOCAL
1057 "|<w>Right-click</w>"
1058 #endif
1059 "]: %s", text);
1060 return formatted_string::parse_string(fmt);
1061 }
1062
_display_vampire_attributes()1063 static string _display_vampire_attributes()
1064 {
1065 ASSERT(you.has_mutation(MUT_VAMPIRISM));
1066
1067 string result;
1068
1069 const int lines = 13;
1070 string column[lines][3] =
1071 {
1072 {" ", "<green>Alive</green> ", "<lightred>Bloodless</lightred>"},
1073 //Full Bloodless
1074 {"Regeneration ", "fast ", "none with monsters in sight"},
1075
1076 {"HP modifier ", "none ", "-20%"},
1077
1078 {"Stealth boost ", "none ", "major "},
1079
1080 {"Heal on bite ", "no ", "yes "},
1081
1082 {"\n<w>Resistances</w>\n"
1083 "Poison resistance ", " ", "immune"},
1084
1085 {"Cold resistance ", " ", "++ "},
1086
1087 {"Negative resistance ", " ", "+++ "},
1088
1089 {"Miasma resistance ", " ", "immune"},
1090
1091 {"Torment resistance ", " ", "immune"},
1092
1093 {"\n<w>Transformations</w>\n"
1094 "Bat form (XL 3+) ", "no ", "yes "},
1095
1096 {"Other forms ", "yes ", "no "},
1097
1098 {"Berserk ", "yes ", "no "}
1099 };
1100
1101 const int highlight_col = you.vampire_alive ? 1 : 2;
1102
1103 for (int y = 0; y < lines; y++) // lines (properties)
1104 {
1105 for (int x = 0; x < 3; x++) // columns (states)
1106 {
1107 if (y > 0 && x == highlight_col)
1108 result += "<w>";
1109 result += column[y][x];
1110 if (y > 0 && x == highlight_col)
1111 result += "</w>";
1112 }
1113 result += "\n";
1114 }
1115
1116 trim_string_right(result);
1117 return result;
1118 }
1119
display_mutations()1120 void display_mutations()
1121 {
1122 string mutation_s = describe_mutations(true);
1123
1124 string extra = "";
1125 if (_num_part_suppressed)
1126 extra += "<brown>()</brown> : Partially suppressed.\n";
1127 if (_num_full_suppressed)
1128 extra += "<darkgrey>(())</darkgrey>: Completely suppressed.\n";
1129 if (_num_transient)
1130 extra += "<magenta>[]</magenta> : Transient mutations.";
1131
1132 if (!extra.empty())
1133 {
1134 mutation_s += "\n\n\n\n";
1135 mutation_s += extra;
1136 }
1137 trim_string_right(mutation_s);
1138
1139 auto vbox = make_shared<Box>(Widget::VERT);
1140 vbox->set_cross_alignment(Widget::STRETCH);
1141
1142 const char *title_text = "Innate Abilities, Weirdness & Mutations";
1143 auto title = make_shared<Text>(formatted_string(title_text, WHITE));
1144 auto title_hbox = make_shared<Box>(Widget::HORZ);
1145 title_hbox->add_child(move(title));
1146 title_hbox->set_main_alignment(Widget::CENTER);
1147 vbox->add_child(move(title_hbox));
1148
1149 auto switcher = make_shared<Switcher>();
1150
1151 const string vamp_s = you.has_mutation(MUT_VAMPIRISM)
1152 ?_display_vampire_attributes()
1153 : "N/A";
1154 const string descs[3] = { mutation_s, vamp_s };
1155 for (int i = 0; i < 2; i++)
1156 {
1157 auto scroller = make_shared<Scroller>();
1158 auto text = make_shared<Text>(formatted_string::parse_string(
1159 descs[static_cast<int>(i)]));
1160 text->set_wrap_text(true);
1161 scroller->set_child(text);
1162 switcher->add_child(move(scroller));
1163 }
1164
1165 switcher->current() = 0;
1166 switcher->set_margin_for_sdl(20, 0, 0, 0);
1167 switcher->set_margin_for_crt(1, 0, 0, 0);
1168 switcher->expand_h = false;
1169 switcher->align_x = Widget::STRETCH;
1170 #ifdef USE_TILE_LOCAL
1171 switcher->max_size().width = tiles.get_crt_font()->char_width()*80;
1172 #endif
1173 vbox->add_child(switcher);
1174
1175 auto bottom = make_shared<Text>(_vampire_Ascreen_footer(true));
1176 bottom->set_margin_for_sdl(20, 0, 0, 0);
1177 bottom->set_margin_for_crt(1, 0, 0, 0);
1178 if (you.has_mutation(MUT_VAMPIRISM))
1179 vbox->add_child(bottom);
1180
1181 auto popup = make_shared<ui::Popup>(vbox);
1182
1183 bool done = false;
1184 int lastch;
1185 popup->on_keydown_event([&](const KeyEvent& ev) {
1186 lastch = ev.key();
1187 if (you.has_mutation(MUT_VAMPIRISM)
1188 && (lastch == '!' || lastch == CK_MOUSE_CMD || lastch == '^'))
1189 {
1190 int& c = switcher->current();
1191
1192 bottom->set_text(_vampire_Ascreen_footer(c));
1193
1194 c = 1 - c;
1195 #ifdef USE_TILE_WEB
1196 tiles.json_open_object();
1197 tiles.json_write_int("pane", c);
1198 tiles.ui_state_change("mutations", 0);
1199 #endif
1200 }
1201 else
1202 done = !switcher->current_widget()->on_event(ev);
1203 return true;
1204 });
1205
1206 #ifdef USE_TILE_WEB
1207 tiles.json_open_object();
1208 tiles.json_write_string("mutations", mutation_s);
1209 if (you.has_mutation(MUT_VAMPIRISM))
1210 tiles.json_write_bool("vampire_alive", you.vampire_alive);
1211 tiles.push_ui_layout("mutations", 1);
1212 popup->on_layout_pop([](){ tiles.pop_ui_layout(); });
1213 #endif
1214
1215 ui::run_layout(move(popup), done);
1216 }
1217
_calc_mutation_amusement_value(mutation_type which_mutation)1218 static int _calc_mutation_amusement_value(mutation_type which_mutation)
1219 {
1220 int amusement = 12 * (11 - _get_mutation_def(which_mutation).weight);
1221
1222 if (MUT_GOOD(mut_data[which_mutation]))
1223 amusement /= 2;
1224 else if (MUT_BAD(mut_data[which_mutation]))
1225 amusement *= 2;
1226 // currently is only ever one of these, but maybe that'll change?
1227
1228 return amusement;
1229 }
1230
_accept_mutation(mutation_type mutat,bool ignore_weight=false)1231 static bool _accept_mutation(mutation_type mutat, bool ignore_weight = false)
1232 {
1233 if (!_is_valid_mutation(mutat))
1234 return false;
1235
1236 if (physiology_mutation_conflict(mutat))
1237 return false;
1238
1239 const mutation_def& mdef = _get_mutation_def(mutat);
1240
1241 if (you.get_base_mutation_level(mutat) >= mdef.levels)
1242 return false;
1243
1244 if (ignore_weight)
1245 return true;
1246
1247 if (mdef.weight == 0)
1248 return false;
1249
1250 // bias towards adding (non-innate) levels to existing innate mutations.
1251 const int weight = mdef.weight + you.get_innate_mutation_level(mutat);
1252
1253 // Low weight means unlikely to choose it.
1254 return x_chance_in_y(weight, 10);
1255 }
1256
_get_mut_with_use(mutflag mt)1257 static mutation_type _get_mut_with_use(mutflag mt)
1258 {
1259 const int tweight = lookup(total_weight, mt, 0);
1260 ASSERT(tweight);
1261
1262 int cweight = random2(tweight);
1263 for (const mutation_def &mutdef : mut_data)
1264 {
1265 if (!_mut_has_use(mutdef, mt))
1266 continue;
1267
1268 cweight -= _mut_weight(mutdef, mt);
1269 if (cweight >= 0)
1270 continue;
1271
1272 return mutdef.mutation;
1273 }
1274
1275 die("Error while selecting mutations");
1276 }
1277
_get_random_slime_mutation()1278 static mutation_type _get_random_slime_mutation()
1279 {
1280 return _get_mut_with_use(mutflag::jiyva);
1281 }
1282
_delete_random_slime_mutation()1283 static mutation_type _delete_random_slime_mutation()
1284 {
1285 mutation_type mutat;
1286
1287 while (true)
1288 {
1289 mutat = _get_random_slime_mutation();
1290
1291 if (you.get_base_mutation_level(mutat) > 0)
1292 break;
1293
1294 if (one_chance_in(500))
1295 {
1296 mutat = NUM_MUTATIONS;
1297 break;
1298 }
1299 }
1300
1301 return mutat;
1302 }
1303
is_slime_mutation(mutation_type mut)1304 bool is_slime_mutation(mutation_type mut)
1305 {
1306 return _mut_has_use(mut_data[mut_index[mut]], mutflag::jiyva);
1307 }
1308
_get_random_xom_mutation()1309 static mutation_type _get_random_xom_mutation()
1310 {
1311 mutation_type mutat = NUM_MUTATIONS;
1312
1313 do
1314 {
1315 mutat = static_cast<mutation_type>(random2(NUM_MUTATIONS));
1316
1317 if (one_chance_in(1000))
1318 return NUM_MUTATIONS;
1319 else if (one_chance_in(5))
1320 mutat = _get_mut_with_use(mutflag::xom);
1321 }
1322 while (!_accept_mutation(mutat, false));
1323
1324 return mutat;
1325 }
1326
_get_random_qazlal_mutation()1327 static mutation_type _get_random_qazlal_mutation()
1328 {
1329 return _get_mut_with_use(mutflag::qazlal);
1330 }
1331
_get_random_mutation(mutation_type mutclass)1332 static mutation_type _get_random_mutation(mutation_type mutclass)
1333 {
1334 mutflag mt;
1335 switch (mutclass)
1336 {
1337 case RANDOM_MUTATION:
1338 // maintain an arbitrary ratio of good to bad muts to allow easier
1339 // weight changes within categories - 60% good seems to be about
1340 // where things are right now
1341 mt = x_chance_in_y(3, 5) ? mutflag::good : mutflag::bad;
1342 break;
1343 case RANDOM_BAD_MUTATION:
1344 case RANDOM_CORRUPT_MUTATION:
1345 mt = mutflag::bad;
1346 break;
1347 case RANDOM_GOOD_MUTATION:
1348 mt = mutflag::good;
1349 break;
1350 default:
1351 die("invalid mutation class: %d", mutclass);
1352 }
1353
1354 for (int attempt = 0; attempt < 100; ++attempt)
1355 {
1356 mutation_type mut = _get_mut_with_use(mt);
1357 if (_accept_mutation(mut, true))
1358 return mut;
1359 }
1360
1361 return NUM_MUTATIONS;
1362 }
1363
1364 /**
1365 * Does the player have a mutation that conflicts with the given mutation?
1366 *
1367 * @param mut A mutation. (E.g. MUT_INHIBITED_REGENERATION, ...)
1368 * @param innate_only Whether to only check innate mutations (from e.g. race)
1369 * @return The level of the conflicting mutation.
1370 * E.g., if MUT_INHIBITED_REGENERATION is passed in and the
1371 * player has 2 levels of MUT_REGENERATION, 2 will be
1372 * returned.
1373 *
1374 * No guarantee is offered on ordering if there are
1375 * multiple conflicting mutations with different levels.
1376 */
mut_check_conflict(mutation_type mut,bool innate_only)1377 int mut_check_conflict(mutation_type mut, bool innate_only)
1378 {
1379 for (const int (&confl)[3] : conflict)
1380 {
1381 if (confl[0] != mut && confl[1] != mut)
1382 continue;
1383
1384 const mutation_type confl_mut
1385 = static_cast<mutation_type>(confl[0] == mut ? confl[1] : confl[0]);
1386
1387 const int level = you.get_base_mutation_level(confl_mut, true, !innate_only, !innate_only);
1388 if (level)
1389 return level;
1390 }
1391
1392 return 0;
1393 }
1394
1395 // Tries to give you the mutation by deleting a conflicting
1396 // one, or clears out conflicting mutations if we should give
1397 // you the mutation anyway.
1398 // Return:
1399 // 1 if we should stop processing (success);
1400 // 0 if we should continue processing;
1401 // -1 if we should stop processing (failure).
_handle_conflicting_mutations(mutation_type mutation,bool override,const string & reason,bool temp=false)1402 static int _handle_conflicting_mutations(mutation_type mutation,
1403 bool override,
1404 const string &reason,
1405 bool temp = false)
1406 {
1407 // If we have one of the pair, delete all levels of the other,
1408 // and continue processing.
1409 for (const int (&confl)[3] : conflict)
1410 {
1411 for (int j = 0; j <= 1; ++j)
1412 {
1413 const mutation_type a = (mutation_type)confl[j];
1414 const mutation_type b = (mutation_type)confl[1-j];
1415
1416 if (mutation == a && you.get_base_mutation_level(b) > 0)
1417 {
1418 // can never delete innate mutations. For case -1 and 0, fail if there are any, otherwise,
1419 // make sure there is a non-innate instance to delete.
1420 if (you.has_innate_mutation(b) &&
1421 (confl[2] != 1
1422 || you.get_base_mutation_level(b, true, false, false) == you.get_base_mutation_level(b)))
1423 {
1424 dprf("Delete mutation failed: have innate mutation %d at level %d, you.mutation at level %d", b,
1425 you.get_innate_mutation_level(b), you.get_base_mutation_level(b));
1426 return -1;
1427 }
1428
1429 // at least one level of this mutation is temporary
1430 const bool temp_b = you.has_temporary_mutation(b);
1431
1432 // confl[2] indicates how the mutation resolution should proceed (see `conflict` a the beginning of this file):
1433 switch (confl[2])
1434 {
1435 case -1:
1436 // Fail if not forced, otherwise override.
1437 if (!override)
1438 return -1;
1439 case 0:
1440 // Ignore if not forced, otherwise override.
1441 // All cases but regen:slowmeta will currently trade off.
1442 if (override)
1443 {
1444 while (_delete_single_mutation_level(b, reason, true))
1445 ;
1446 }
1447 break;
1448 case 1:
1449 // If we have one of the pair, delete a level of the
1450 // other, and that's it.
1451 //
1452 // Temporary mutations can co-exist with things they would
1453 // ordinarily conflict with. But if both a and b are temporary,
1454 // mark b for deletion.
1455 if ((temp || temp_b) && !(temp && temp_b))
1456 return 0; // Allow conflicting transient mutations
1457 else
1458 {
1459 _delete_single_mutation_level(b, reason, true);
1460 return 1; // Nothing more to do.
1461 }
1462
1463 default:
1464 die("bad mutation conflict resulution");
1465 }
1466 }
1467 }
1468 }
1469
1470 return 0;
1471 }
1472
physiology_mutation_conflict(mutation_type mutat)1473 bool physiology_mutation_conflict(mutation_type mutat)
1474 {
1475 if (mutat == MUT_IRIDESCENT_SCALES)
1476 {
1477 // No extra scales for most demonspawn, but monstrous demonspawn who
1478 // wouldn't usually get scales can get regular ones randomly.
1479 if (you.species == SP_DEMONSPAWN)
1480 {
1481 return any_of(begin(you.demonic_traits), end(you.demonic_traits),
1482 [=](const player::demon_trait &t) {
1483 return _is_demonspawn_scale(t.mutation);});
1484 }
1485
1486 // No extra scales for draconians.
1487 if (species::is_draconian(you.species))
1488 return true;
1489 }
1490
1491 // Only species that already have tails can get this one. For merfolk it
1492 // would only work in the water, so skip it.
1493 if ((!you.has_tail(false) || you.has_innate_mutation(MUT_MERTAIL))
1494 && mutat == MUT_STINGER)
1495 {
1496 return true;
1497 }
1498
1499 // Need tentacles to grow something on them.
1500 if (!you.has_innate_mutation(MUT_TENTACLE_ARMS)
1501 && mutat == MUT_TENTACLE_SPIKE)
1502 {
1503 return true;
1504 }
1505
1506 // No bones for thin skeletal structure or horns.
1507 if (!species::has_bones(you.species)
1508 && (mutat == MUT_THIN_SKELETAL_STRUCTURE || mutat == MUT_HORNS))
1509 {
1510 return true;
1511 }
1512
1513 // No feet.
1514 if (!player_has_feet(false, false)
1515 && (mutat == MUT_HOOVES || mutat == MUT_TALONS))
1516 {
1517 return true;
1518 }
1519
1520 // To get upgraded spit poison, you must have it innately
1521 if (!you.has_innate_mutation(MUT_SPIT_POISON) && mutat == MUT_SPIT_POISON)
1522 return true;
1523
1524 // Only Palentonga can go on a roll.
1525 if (!you.has_innate_mutation(MUT_ROLL) && mutat == MUT_ROLL)
1526 return true;
1527
1528 // Only Draconians (and gargoyles) can get wings.
1529 if (!species::is_draconian(you.species) && you.species != SP_GARGOYLE
1530 && mutat == MUT_BIG_WINGS)
1531 {
1532 return true;
1533 }
1534
1535 // Vampires' healing rates depend on their blood level.
1536 if (you.has_mutation(MUT_VAMPIRISM)
1537 && (mutat == MUT_REGENERATION || mutat == MUT_INHIBITED_REGENERATION))
1538 {
1539 return true;
1540 }
1541
1542 // Felid paws cap MUT_CLAWS at level 1. And octopodes have no hands.
1543 if ((you.has_innate_mutation(MUT_PAWS)
1544 || you.has_innate_mutation(MUT_TENTACLE_ARMS))
1545 && mutat == MUT_CLAWS)
1546 {
1547 return true;
1548 }
1549
1550 // Merfolk have no feet in the natural form, and we never allow mutations
1551 // that show up only in a certain transformation.
1552 if (you.has_innate_mutation(MUT_MERTAIL)
1553 && (mutat == MUT_TALONS || mutat == MUT_HOOVES))
1554 {
1555 return true;
1556 }
1557
1558 // Formicids have stasis and so prevent mutations that would do nothing.
1559 if (you.stasis() && (mutat == MUT_BERSERK || mutat == MUT_TELEPORT))
1560 return true;
1561
1562 if (you.innate_sinv() && mutat == MUT_ACUTE_VISION)
1563 return true;
1564
1565 // Already immune.
1566 if (you.is_nonliving(false) && mutat == MUT_POISON_RESISTANCE)
1567 return true;
1568
1569 // We can't use is_useless_skill() here, since species that can still wear
1570 // body armour can sacrifice armour skill with Ru.
1571 if (species_apt(SK_ARMOUR) == UNUSABLE_SKILL
1572 && (mutat == MUT_DEFORMED || mutat == MUT_STURDY_FRAME))
1573 {
1574 return true;
1575 }
1576
1577 equipment_type eq_type = EQ_NONE;
1578
1579 // Mutations of the same slot conflict
1580 if (is_body_facet(mutat))
1581 {
1582 // Find equipment slot of attempted mutation
1583 for (const body_facet_def &facet : _body_facets)
1584 if (mutat == facet.mut)
1585 eq_type = facet.eq;
1586
1587 if (eq_type != EQ_NONE)
1588 {
1589 for (const body_facet_def &facet : _body_facets)
1590 {
1591 if (eq_type == facet.eq
1592 && mutat != facet.mut
1593 && you.get_base_mutation_level(facet.mut))
1594 {
1595 return true;
1596 }
1597 }
1598 }
1599 }
1600
1601 return false;
1602 }
1603
_stat_mut_desc(mutation_type mut,bool gain)1604 static const char* _stat_mut_desc(mutation_type mut, bool gain)
1605 {
1606 stat_type stat = STAT_STR;
1607 bool positive = gain;
1608 switch (mut)
1609 {
1610 case MUT_WEAK:
1611 positive = !positive;
1612 case MUT_STRONG:
1613 stat = STAT_STR;
1614 break;
1615
1616 case MUT_DOPEY:
1617 positive = !positive;
1618 case MUT_CLEVER:
1619 stat = STAT_INT;
1620 break;
1621
1622 case MUT_CLUMSY:
1623 positive = !positive;
1624 case MUT_AGILE:
1625 stat = STAT_DEX;
1626 break;
1627
1628 default:
1629 die("invalid stat mutation: %d", mut);
1630 }
1631 return stat_desc(stat, positive ? SD_INCREASE : SD_DECREASE);
1632 }
1633
1634 /**
1635 * Do a resistance check for the given mutation permanence class.
1636 * Does not include divine intervention!
1637 *
1638 * @param mutclass The type of mutation that is checking resistance
1639 * @param beneficial Is the mutation beneficial?
1640 *
1641 * @return True if a mutation is successfully resisted, false otherwise.
1642 **/
_resist_mutation(mutation_permanence_class mutclass,bool beneficial)1643 static bool _resist_mutation(mutation_permanence_class mutclass,
1644 bool beneficial)
1645 {
1646 if (you.get_mutation_level(MUT_MUTATION_RESISTANCE) == 3)
1647 return true;
1648
1649 const int mut_resist_chance = mutclass == MUTCLASS_TEMPORARY ? 2 : 3;
1650 if (you.get_mutation_level(MUT_MUTATION_RESISTANCE)
1651 && !one_chance_in(mut_resist_chance))
1652 {
1653 return true;
1654 }
1655
1656 // To be nice, beneficial mutations go through removable sources of rMut.
1657 if (you.rmut_from_item() && !beneficial
1658 && !one_chance_in(mut_resist_chance))
1659 {
1660 return true;
1661 }
1662
1663 return false;
1664 }
1665
1666 /*
1667 * Does the player rot instead of mutating?
1668 * Right now this is coextensive with whether the player is unable to mutate.
1669 * For most undead, they will never mutate and always rot instead; vampires always mutate and never rot.
1670 *
1671 * @return true if so.
1672 */
undead_mutation_rot()1673 bool undead_mutation_rot()
1674 {
1675 return !you.can_safely_mutate();
1676 }
1677
1678 /*
1679 * Try to mutate the player, along with associated bookkeeping. This accepts mutation categories as well as particular mutations.
1680 *
1681 * In many cases this will produce only 1 level of mutation at a time, but it may mutate more than one level if the mutation category is corrupt or qazlal.
1682 *
1683 * If the player is at the mutation cap, this may fail.
1684 * 1. If mutclass is innate, this will attempt to replace temporary and normal mutations (in that order) and will fail if this isn't possible (e.g. there are only innate levels).
1685 * 2. Otherwise, this will fail. This means that a temporary mutation can block a permanent mutation of the same type in some circumstances.
1686 *
1687 * If the mutation conflicts with an existing one it may fail. See `_handle_conflicting_mutations`.
1688 *
1689 * If the player is undead, this may stat drain instead. Stat draincounts as
1690 * success.
1691 *
1692 * @param which_mutation the mutation to use.
1693 * @param reason the explanation for how the player got mutated.
1694 * @param failMsg whether to do any messaging if this fails.
1695 * @param force_mutation whether to override mutation protection and the like.
1696 * @param god_gift is this a god gift? Entails overriding mutation resistance if not forced.
1697 * @param mutclass is the mutation temporary, regular, or permanent (innate)? permanent entails force_mutation.
1698 *
1699 * @return whether the mutation succeeded.
1700 */
mutate(mutation_type which_mutation,const string & reason,bool failMsg,bool force_mutation,bool god_gift,bool beneficial,mutation_permanence_class mutclass)1701 bool mutate(mutation_type which_mutation, const string &reason, bool failMsg,
1702 bool force_mutation, bool god_gift, bool beneficial,
1703 mutation_permanence_class mutclass)
1704 {
1705 if (which_mutation == RANDOM_BAD_MUTATION
1706 && mutclass == MUTCLASS_NORMAL
1707 && crawl_state.disables[DIS_AFFLICTIONS])
1708 {
1709 return true; // no fallbacks
1710 }
1711
1712 god_gift |= crawl_state.is_god_acting();
1713
1714 if (mutclass == MUTCLASS_INNATE)
1715 force_mutation = true;
1716
1717 mutation_type mutat = which_mutation;
1718
1719 if (!force_mutation)
1720 {
1721 // God gifts override all sources of mutation resistance other
1722 // than divine protection.
1723 if (!god_gift && _resist_mutation(mutclass, beneficial))
1724 {
1725 if (failMsg)
1726 mprf(MSGCH_MUTATION, "You feel odd for a moment.");
1727 return false;
1728 }
1729
1730 // Zin's protection.
1731 if (have_passive(passive_t::resist_mutation)
1732 && x_chance_in_y(you.piety, piety_breakpoint(5)))
1733 {
1734 simple_god_message(" protects your body from mutation!");
1735 return false;
1736 }
1737 }
1738
1739 // Undead bodies don't mutate, they fall apart. -- bwr
1740 if (undead_mutation_rot())
1741 {
1742 switch (mutclass)
1743 {
1744 case MUTCLASS_TEMPORARY:
1745 if (coinflip())
1746 return false;
1747 // fallthrough to normal mut
1748 case MUTCLASS_NORMAL:
1749 mprf(MSGCH_MUTATION, "Your body decomposes!");
1750 lose_stat(STAT_RANDOM, 1);
1751 return true;
1752 case MUTCLASS_INNATE:
1753 // You can't miss out on innate mutations just because you're
1754 // temporarily undead.
1755 break;
1756 default:
1757 die("bad fall through");
1758 return false;
1759 }
1760 }
1761
1762 if (mutclass == MUTCLASS_NORMAL
1763 && (which_mutation == RANDOM_MUTATION
1764 || which_mutation == RANDOM_XOM_MUTATION)
1765 && x_chance_in_y(you.how_mutated(false, true), 15))
1766 {
1767 // God gifts override mutation loss due to being heavily
1768 // mutated.
1769 if (!one_chance_in(3) && !god_gift && !force_mutation)
1770 return false;
1771 else
1772 return delete_mutation(RANDOM_MUTATION, reason, failMsg,
1773 force_mutation, false);
1774 }
1775
1776 switch (which_mutation)
1777 {
1778 case RANDOM_MUTATION:
1779 case RANDOM_GOOD_MUTATION:
1780 case RANDOM_BAD_MUTATION:
1781 case RANDOM_CORRUPT_MUTATION:
1782 mutat = _get_random_mutation(which_mutation);
1783 break;
1784 case RANDOM_XOM_MUTATION:
1785 mutat = _get_random_xom_mutation();
1786 break;
1787 case RANDOM_SLIME_MUTATION:
1788 mutat = _get_random_slime_mutation();
1789 break;
1790 case RANDOM_QAZLAL_MUTATION:
1791 mutat = _get_random_qazlal_mutation();
1792 break;
1793 default:
1794 break;
1795 }
1796
1797
1798 if (!_is_valid_mutation(mutat))
1799 return false;
1800
1801 // [Cha] don't allow teleportitis in sprint
1802 if (mutat == MUT_TELEPORT && crawl_state.game_is_sprint())
1803 return false;
1804
1805 if (physiology_mutation_conflict(mutat))
1806 return false;
1807
1808 const mutation_def& mdef = _get_mutation_def(mutat);
1809
1810 bool gain_msg = true;
1811
1812 if (mutclass == MUTCLASS_INNATE)
1813 {
1814 // are there any non-innate instances to replace? Prioritize temporary mutations over normal.
1815 // Temporarily decrement the mutation value so it can be silently regained in the while loop below.
1816 if (you.mutation[mutat] > you.innate_mutation[mutat])
1817 {
1818 if (you.temp_mutation[mutat] > 0)
1819 {
1820 you.temp_mutation[mutat]--;
1821 you.attribute[ATTR_TEMP_MUTATIONS]--;
1822 if (you.attribute[ATTR_TEMP_MUTATIONS] == 0)
1823 you.attribute[ATTR_TEMP_MUT_XP] = 0;
1824 }
1825 you.mutation[mutat]--;
1826 mprf(MSGCH_MUTATION, "Your mutations feel more permanent.");
1827 take_note(Note(NOTE_PERM_MUTATION, mutat,
1828 you.get_base_mutation_level(mutat), reason.c_str()));
1829 gain_msg = false;
1830 }
1831 }
1832 if (you.mutation[mutat] >= mdef.levels)
1833 return false;
1834
1835 // God gifts and forced mutations clear away conflicting mutations.
1836 int rc = _handle_conflicting_mutations(mutat, god_gift || force_mutation,
1837 reason,
1838 mutclass == MUTCLASS_TEMPORARY);
1839 if (rc == 1)
1840 return true;
1841 if (rc == -1)
1842 return false;
1843
1844 ASSERT(rc == 0);
1845
1846 #ifdef USE_TILE_LOCAL
1847 const unsigned int old_talents = your_talents(false).size();
1848 #endif
1849
1850 const int levels = (which_mutation == RANDOM_CORRUPT_MUTATION
1851 || which_mutation == RANDOM_QAZLAL_MUTATION)
1852 ? min(2, mdef.levels - you.get_base_mutation_level(mutat))
1853 : 1;
1854 ASSERT(levels > 0); //TODO: is > too strong?
1855
1856 int count = levels;
1857
1858 while (count-- > 0)
1859 {
1860 // no fail condition past this point, so it is safe to do bookkeeping
1861 you.mutation[mutat]++;
1862 if (mutclass == MUTCLASS_TEMPORARY)
1863 {
1864 // do book-keeping for temporary mutations
1865 you.temp_mutation[mutat]++;
1866 you.attribute[ATTR_TEMP_MUTATIONS]++;
1867 }
1868 else if (mutclass == MUTCLASS_INNATE)
1869 you.innate_mutation[mutat]++;
1870
1871 const int cur_base_level = you.get_base_mutation_level(mutat);
1872
1873 // More than three messages, need to give them by hand.
1874 switch (mutat)
1875 {
1876 case MUT_STRONG: case MUT_AGILE: case MUT_CLEVER:
1877 case MUT_WEAK: case MUT_CLUMSY: case MUT_DOPEY:
1878 mprf(MSGCH_MUTATION, "You feel %s.", _stat_mut_desc(mutat, true));
1879 gain_msg = false;
1880 break;
1881
1882 case MUT_LARGE_BONE_PLATES:
1883 {
1884 const string arms = pluralise(species::arm_name(you.species));
1885 mprf(MSGCH_MUTATION, "%s",
1886 replace_all(mdef.gain[cur_base_level - 1], "arms",
1887 arms).c_str());
1888 gain_msg = false;
1889 }
1890 break;
1891
1892 case MUT_MISSING_HAND:
1893 {
1894 // n.b. we cannot use the built in pluralisation, because at
1895 // this point the mut has already applied, and hand_name takes
1896 // it into account.
1897 const string hands = pluralise(you.hand_name(false));
1898 mprf(MSGCH_MUTATION, "%s",
1899 replace_all(mdef.gain[cur_base_level - 1], "hands",
1900 hands).c_str());
1901 gain_msg = false;
1902 }
1903 break;
1904
1905 case MUT_SPIT_POISON:
1906 // Breathe poison replaces spit poison (so it takes the slot).
1907 if (cur_base_level >= 2)
1908 for (int i = 0; i < 52; ++i)
1909 if (you.ability_letter_table[i] == ABIL_SPIT_POISON)
1910 you.ability_letter_table[i] = ABIL_BREATHE_POISON;
1911 break;
1912
1913 default:
1914 break;
1915 }
1916
1917 // For all those scale mutations.
1918 you.redraw_armour_class = true;
1919
1920 notify_stat_change();
1921
1922 if (gain_msg)
1923 mprf(MSGCH_MUTATION, "%s", mdef.gain[cur_base_level - 1]);
1924
1925 // Do post-mutation effects.
1926 switch (mutat)
1927 {
1928 case MUT_FRAIL:
1929 case MUT_ROBUST:
1930 case MUT_RUGGED_BROWN_SCALES:
1931 calc_hp();
1932 break;
1933
1934 case MUT_LOW_MAGIC:
1935 case MUT_HIGH_MAGIC:
1936 calc_mp();
1937 break;
1938
1939 case MUT_PASSIVE_MAPPING:
1940 add_daction(DACT_REAUTOMAP);
1941 break;
1942
1943 case MUT_HOOVES:
1944 case MUT_TALONS:
1945 // Hooves and talons force boots off at 3.
1946 if (cur_base_level >= 3 && !you.melded[EQ_BOOTS]
1947 && !you.wear_barding())
1948 {
1949 remove_one_equip(EQ_BOOTS, false, true);
1950 }
1951 // Recheck Ashenzari bondage in case our available slots changed.
1952 ash_check_bondage();
1953 break;
1954
1955 case MUT_CLAWS:
1956 // Claws force gloves off at 3.
1957 if (cur_base_level >= 3 && !you.melded[EQ_GLOVES])
1958 remove_one_equip(EQ_GLOVES, false, true);
1959 // Recheck Ashenzari bondage in case our available slots changed.
1960 ash_check_bondage();
1961 break;
1962
1963 case MUT_HORNS:
1964 case MUT_ANTENNAE:
1965 // Horns & Antennae 3 removes all headgear. Same algorithm as with
1966 // glove removal.
1967
1968 if (cur_base_level >= 3 && !you.melded[EQ_HELMET])
1969 remove_one_equip(EQ_HELMET, false, true);
1970 // Intentional fall-through
1971 case MUT_BEAK:
1972 // Horns, beaks, and antennae force hard helmets off.
1973 if (you.equip[EQ_HELMET] != -1
1974 && is_hard_helmet(you.inv[you.equip[EQ_HELMET]])
1975 && !you.melded[EQ_HELMET])
1976 {
1977 remove_one_equip(EQ_HELMET, false, true);
1978 }
1979 // Recheck Ashenzari bondage in case our available slots changed.
1980 ash_check_bondage();
1981 break;
1982
1983 case MUT_ACUTE_VISION:
1984 // We might have to turn autopickup back on again.
1985 autotoggle_autopickup(false);
1986 break;
1987
1988 case MUT_NIGHTSTALKER:
1989 update_vision_range();
1990 break;
1991
1992 case MUT_BIG_WINGS:
1993 #ifdef USE_TILE
1994 init_player_doll();
1995 #endif
1996 break;
1997
1998 case MUT_SILENCE_AURA:
1999 invalidate_agrid(true);
2000 break;
2001
2002 default:
2003 break;
2004 }
2005
2006 xom_is_stimulated(_calc_mutation_amusement_value(mutat));
2007
2008 if (mutclass != MUTCLASS_TEMPORARY)
2009 {
2010 take_note(Note(NOTE_GET_MUTATION, mutat, cur_base_level,
2011 reason.c_str()));
2012 }
2013 else
2014 {
2015 // only do this once regardless of how many levels got added
2016 you.attribute[ATTR_TEMP_MUT_XP] = temp_mutation_roll();
2017 }
2018
2019 if (you.hp <= 0)
2020 {
2021 ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
2022 make_stringf("gaining the %s mutation",
2023 mutation_name(mutat)).c_str());
2024 }
2025 }
2026
2027 #ifdef USE_TILE_LOCAL
2028 if (your_talents(false).size() != old_talents)
2029 {
2030 tiles.layout_statcol();
2031 redraw_screen();
2032 update_screen();
2033 }
2034 #endif
2035 #ifdef DEBUG
2036 if (mutclass != MUTCLASS_INNATE) // taken care of in perma_mutate. Skipping this here avoids validation issues in doing repairs.
2037 validate_mutations(false);
2038 #endif
2039 return true;
2040 }
2041
2042 /*
2043 * Delete a single mutation level of fixed type `mutat`.
2044 * If `transient` is set, allow deleting temporary mutations, and prioritize them.
2045 * Note that if `transient` is true and there are no temporary mutations, this can delete non-temp mutations.
2046 * If `transient` is false, and there are only temp mutations, this will fail; otherwise it will delete a non-temp mutation.
2047 *
2048 * @mutat the mutation to delete
2049 * @reason why is it being deleted
2050 * @transient whether to allow (and prioritize) deletion of temporary mutations
2051 *
2052 * @return whether a mutation was deleted.
2053 */
_delete_single_mutation_level(mutation_type mutat,const string & reason,bool transient)2054 static bool _delete_single_mutation_level(mutation_type mutat,
2055 const string &reason,
2056 bool transient)
2057 {
2058 // are there some non-innate mutations to delete?
2059 if (you.get_base_mutation_level(mutat, false, true, true) == 0)
2060 return false;
2061
2062 bool was_transient = false;
2063 if (you.has_temporary_mutation(mutat))
2064 {
2065 if (transient)
2066 was_transient = true;
2067 else if (you.get_base_mutation_level(mutat, false, false, true) == 0) // there are only temporary mutations to delete
2068 return false;
2069
2070 // fall through: there is a non-temporary mutation level that can be deleted.
2071 }
2072
2073 const mutation_def& mdef = _get_mutation_def(mutat);
2074
2075 bool lose_msg = true;
2076
2077 you.mutation[mutat]--;
2078
2079 switch (mutat)
2080 {
2081 case MUT_STRONG: case MUT_AGILE: case MUT_CLEVER:
2082 case MUT_WEAK: case MUT_CLUMSY: case MUT_DOPEY:
2083 mprf(MSGCH_MUTATION, "You feel %s.", _stat_mut_desc(mutat, false));
2084 lose_msg = false;
2085 break;
2086
2087 case MUT_SPIT_POISON:
2088 // Breathe poison replaces spit poison (so it takes the slot).
2089 if (you.mutation[mutat] < 2)
2090 for (int i = 0; i < 52; ++i)
2091 if (you.ability_letter_table[i] == ABIL_SPIT_POISON)
2092 you.ability_letter_table[i] = ABIL_BREATHE_POISON;
2093 break;
2094
2095 case MUT_NIGHTSTALKER:
2096 update_vision_range();
2097 break;
2098
2099 case MUT_BIG_WINGS:
2100 land_player();
2101 break;
2102
2103 case MUT_HORNS:
2104 case MUT_ANTENNAE:
2105 case MUT_BEAK:
2106 case MUT_CLAWS:
2107 case MUT_HOOVES:
2108 case MUT_TALONS:
2109 // Recheck Ashenzari bondage in case our available slots changed.
2110 ash_check_bondage();
2111 break;
2112
2113 case MUT_SILENCE_AURA:
2114 invalidate_agrid(true);
2115 break;
2116
2117 default:
2118 break;
2119 }
2120
2121 // For all those scale mutations.
2122 you.redraw_armour_class = true;
2123
2124 notify_stat_change();
2125
2126 if (lose_msg)
2127 mprf(MSGCH_MUTATION, "%s", mdef.lose[you.mutation[mutat]]);
2128
2129 // Do post-mutation effects.
2130 if (mutat == MUT_FRAIL || mutat == MUT_ROBUST
2131 || mutat == MUT_RUGGED_BROWN_SCALES)
2132 {
2133 calc_hp();
2134 }
2135 if (mutat == MUT_LOW_MAGIC || mutat == MUT_HIGH_MAGIC)
2136 calc_mp();
2137
2138 if (was_transient)
2139 {
2140 --you.temp_mutation[mutat];
2141 --you.attribute[ATTR_TEMP_MUTATIONS];
2142 }
2143 else
2144 take_note(Note(NOTE_LOSE_MUTATION, mutat, you.mutation[mutat], reason));
2145
2146 if (you.hp <= 0)
2147 {
2148 ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
2149 make_stringf("losing the %s mutation", mutation_name(mutat)).c_str());
2150 }
2151
2152 return true;
2153 }
2154
2155 /*
2156 * Delete a mutation level, accepting random mutation types and checking mutation resistance.
2157 * This will not delete temporary or innate mutations.
2158 *
2159 * @param which_mutation a mutation, including random
2160 * @param reason the reason for deletion
2161 * @param failMsg whether to message the player on failure
2162 * @param force_mutation whether to try to override certain cases where the mutation would otherwise fail
2163 * @param god_gift is the mutation a god gift? Will also override certain cases.
2164 * @param disallow_mismatch for random mutations, do we override good/bad designations in `which_mutation`? (??)
2165 *
2166 * @return true iff a mutation was applied.
2167 */
delete_mutation(mutation_type which_mutation,const string & reason,bool failMsg,bool force_mutation,bool god_gift,bool disallow_mismatch)2168 bool delete_mutation(mutation_type which_mutation, const string &reason,
2169 bool failMsg,
2170 bool force_mutation, bool god_gift,
2171 bool disallow_mismatch)
2172 {
2173 god_gift |= crawl_state.is_god_acting();
2174
2175 mutation_type mutat = which_mutation;
2176
2177 if (!force_mutation)
2178 {
2179 if (!god_gift)
2180 {
2181 if (you.get_mutation_level(MUT_MUTATION_RESISTANCE) > 1
2182 && (you.get_mutation_level(MUT_MUTATION_RESISTANCE) == 3
2183 || coinflip()))
2184 {
2185 if (failMsg)
2186 mprf(MSGCH_MUTATION, "You feel rather odd for a moment.");
2187 return false;
2188 }
2189 }
2190
2191 if (undead_mutation_rot())
2192 return false;
2193 }
2194
2195 if (which_mutation == RANDOM_MUTATION
2196 || which_mutation == RANDOM_XOM_MUTATION
2197 || which_mutation == RANDOM_GOOD_MUTATION
2198 || which_mutation == RANDOM_BAD_MUTATION
2199 || which_mutation == RANDOM_NON_SLIME_MUTATION
2200 || which_mutation == RANDOM_CORRUPT_MUTATION
2201 || which_mutation == RANDOM_QAZLAL_MUTATION)
2202 {
2203 while (true)
2204 {
2205 if (one_chance_in(1000))
2206 return false;
2207
2208 mutat = static_cast<mutation_type>(random2(NUM_MUTATIONS));
2209
2210 if (you.mutation[mutat] == 0
2211 && mutat != MUT_STRONG
2212 && mutat != MUT_CLEVER
2213 && mutat != MUT_AGILE
2214 && mutat != MUT_WEAK
2215 && mutat != MUT_DOPEY
2216 && mutat != MUT_CLUMSY)
2217 {
2218 continue;
2219 }
2220
2221 if (which_mutation == RANDOM_NON_SLIME_MUTATION
2222 && is_slime_mutation(mutat))
2223 {
2224 continue;
2225 }
2226
2227 // Check whether there is a non-innate level of `mutat` to delete
2228 if (you.get_base_mutation_level(mutat, false, true, true) == 0)
2229 continue;
2230
2231 // MUT_ANTENNAE is 0, and you.attribute[] is initialized to 0.
2232 if (mutat && _is_appendage_mutation(mutat))
2233 continue;
2234
2235 const mutation_def& mdef = _get_mutation_def(mutat);
2236
2237 if (random2(10) >= mdef.weight && !is_slime_mutation(mutat))
2238 continue;
2239
2240 const bool mismatch =
2241 (which_mutation == RANDOM_GOOD_MUTATION
2242 && MUT_BAD(mdef))
2243 || (which_mutation == RANDOM_BAD_MUTATION
2244 && MUT_GOOD(mdef));
2245
2246 if (mismatch && (disallow_mismatch || !one_chance_in(10)))
2247 continue;
2248
2249 if (you.get_base_mutation_level(mutat, true, false, true) == 0)
2250 continue; // No non-transient mutations in this category to cure
2251
2252 break;
2253 }
2254 }
2255 else if (which_mutation == RANDOM_SLIME_MUTATION)
2256 {
2257 mutat = _delete_random_slime_mutation();
2258
2259 if (mutat == NUM_MUTATIONS)
2260 return false;
2261 }
2262
2263 return _delete_single_mutation_level(mutat, reason, false); // won't delete temp mutations
2264 }
2265
2266 /*
2267 * Delete all (non-innate) mutations.
2268 *
2269 * If you really need to delete innate mutations as well, have a look at `change_species_to` in species.cc.
2270 * Changing species to human, for example, is a safe way to clear innate mutations entirely. For a
2271 * demonspawn, you could also use wizmode code to set the level to 1.
2272 *
2273 * @return Whether the function found mutations to delete.
2274 */
delete_all_mutations(const string & reason)2275 bool delete_all_mutations(const string &reason)
2276 {
2277 for (int i = 0; i < NUM_MUTATIONS; ++i)
2278 {
2279 while (_delete_single_mutation_level(static_cast<mutation_type>(i), reason, true))
2280 ;
2281 }
2282 ASSERT(you.attribute[ATTR_TEMP_MUTATIONS] == 0);
2283 ASSERT(you.how_mutated(false, true, false) == 0);
2284 you.attribute[ATTR_TEMP_MUT_XP] = 0;
2285
2286 return !you.how_mutated();
2287 }
2288
2289 /*
2290 * Delete all temporary mutations.
2291 *
2292 * @return Whether the function found mutations to delete.
2293 */
delete_all_temp_mutations(const string & reason)2294 bool delete_all_temp_mutations(const string &reason)
2295 {
2296 bool found = false;
2297 for (int i = 0; i < NUM_MUTATIONS; ++i)
2298 {
2299 while (you.has_temporary_mutation(static_cast<mutation_type>(i)))
2300 if (_delete_single_mutation_level(static_cast<mutation_type>(i), reason, true))
2301 found = true;
2302 }
2303 // the rest of the bookkeeping is handled in _delete_single_mutation_level
2304 you.attribute[ATTR_TEMP_MUT_XP] = 0;
2305 return found;
2306 }
2307
2308 /*
2309 * Delete a single level of a random temporary mutation.
2310 * This function does not itself do XP-related bookkeeping; see `temp_mutation_wanes()`.
2311 *
2312 * @return Whether the function found a mutation to delete.
2313 */
delete_temp_mutation()2314 bool delete_temp_mutation()
2315 {
2316 if (you.attribute[ATTR_TEMP_MUTATIONS] > 0)
2317 {
2318 mutation_type mutat = NUM_MUTATIONS;
2319
2320 int count = 0;
2321 for (int i = 0; i < NUM_MUTATIONS; i++)
2322 if (you.has_temporary_mutation(static_cast<mutation_type>(i)) && one_chance_in(++count))
2323 mutat = static_cast<mutation_type>(i);
2324
2325 #if TAG_MAJOR_VERSION == 34
2326 // We had a brief period (between 0.14-a0-1589-g48c4fed and
2327 // 0.14-a0-1604-g40af2d8) where we corrupted attributes in transferred
2328 // games.
2329 if (mutat == NUM_MUTATIONS)
2330 {
2331 mprf(MSGCH_ERROR, "Found no temp mutations, clearing.");
2332 you.attribute[ATTR_TEMP_MUTATIONS] = 0;
2333 return false;
2334 }
2335 #else
2336 ASSERTM(mutat != NUM_MUTATIONS, "Found no temp mutations, expected %d",
2337 you.attribute[ATTR_TEMP_MUTATIONS]);
2338 #endif
2339
2340 if (_delete_single_mutation_level(mutat, "temp mutation expiry", true))
2341 return true;
2342 }
2343
2344 return false;
2345 }
2346
mutation_name(mutation_type mut,bool allow_category)2347 const char* mutation_name(mutation_type mut, bool allow_category)
2348 {
2349 if (allow_category && mut >= CATEGORY_MUTATIONS && mut < MUT_NON_MUTATION)
2350 return _get_category_mutation_def(mut).short_desc;
2351
2352 // note -- this can produce crashes if fed invalid mutations, e.g. if allow_category is false and mut is a category mutation
2353 if (!_is_valid_mutation(mut))
2354 return nullptr;
2355
2356 return _get_mutation_def(mut).short_desc;
2357 }
2358
category_mutation_name(mutation_type mut)2359 const char* category_mutation_name(mutation_type mut)
2360 {
2361 if (mut < CATEGORY_MUTATIONS || mut >= MUT_NON_MUTATION)
2362 return nullptr;
2363 return _get_category_mutation_def(mut).short_desc;
2364 }
2365
2366 /*
2367 * Given some name, return a mutation type. Tries to match the short description as found in `mutation-data.h`.
2368 * If `partial_matches` is set, it will fill the vector with any partial matches it finds. If there is exactly one,
2369 * will return this mutation, otherwise, will fail.
2370 *
2371 * @param allow_category whether to include category mutation types (e.g. RANDOM_GOOD)
2372 * @param partial_matches an optional pointer to a vector, in case the consumer wants to do something
2373 * with the partial match results (e.g. show them to the user). If this is `nullptr`,
2374 * will accept only exact matches.
2375 *
2376 * @return the mutation type if succesful, otherwise NUM_MUTATIONS if it can't find a single match.
2377 */
mutation_from_name(string name,bool allow_category,vector<mutation_type> * partial_matches)2378 mutation_type mutation_from_name(string name, bool allow_category, vector<mutation_type> *partial_matches)
2379 {
2380 mutation_type mutat = NUM_MUTATIONS;
2381
2382 string spec = lowercase_string(name);
2383
2384 if (allow_category)
2385 {
2386 for (int i = CATEGORY_MUTATIONS; i < MUT_NON_MUTATION; ++i)
2387 {
2388 mutation_type mut = static_cast<mutation_type>(i);
2389 const char* mut_name_c = category_mutation_name(mut);
2390 if (!mut_name_c)
2391 continue;
2392 const string mut_name = lowercase_string(mut_name_c);
2393
2394 if (spec == mut_name)
2395 return mut; // note, won't fully populate partial_matches
2396
2397 if (partial_matches && strstr(mut_name.c_str(), spec.c_str()))
2398 partial_matches->push_back(mut);
2399 }
2400 }
2401
2402 for (int i = 0; i < NUM_MUTATIONS; ++i)
2403 {
2404 mutation_type mut = static_cast<mutation_type>(i);
2405 const char *mut_name_c = mutation_name(mut);
2406 if (!mut_name_c)
2407 continue;
2408 const string mut_name = lowercase_string(mut_name_c);
2409
2410 if (spec == mut_name)
2411 {
2412 mutat = mut;
2413 break;
2414 }
2415
2416 if (partial_matches && strstr(mut_name.c_str(), spec.c_str()))
2417 partial_matches->push_back(mut);
2418 }
2419
2420 // If only one matching mutation, use that.
2421 if (partial_matches && mutat == NUM_MUTATIONS && partial_matches->size() == 1)
2422 mutat = (*partial_matches)[0];
2423 return mutat;
2424 }
2425
2426 /**
2427 * A summary of what the next level of a mutation does.
2428 *
2429 * @param mut The mutation_type in question; e.g. MUT_FRAIL.
2430 * @return The mutation's description, helpfully trimmed.
2431 * e.g. "you are frail (-10% HP)".
2432 */
mut_upgrade_summary(mutation_type mut)2433 string mut_upgrade_summary(mutation_type mut)
2434 {
2435 if (!_is_valid_mutation(mut))
2436 return nullptr;
2437
2438 string mut_desc =
2439 lowercase_first(mutation_desc(mut, you.mutation[mut] + 1));
2440 strip_suffix(mut_desc, ".");
2441 return mut_desc;
2442 }
2443
mutation_max_levels(mutation_type mut)2444 int mutation_max_levels(mutation_type mut)
2445 {
2446 if (!_is_valid_mutation(mut))
2447 return 0;
2448
2449 return _get_mutation_def(mut).levels;
2450 }
2451
2452 // Return a string describing the mutation.
2453 // If colour is true, also add the colour annotation.
mutation_desc(mutation_type mut,int level,bool colour,bool is_sacrifice)2454 string mutation_desc(mutation_type mut, int level, bool colour,
2455 bool is_sacrifice)
2456 {
2457 // Ignore the player's forms, etc.
2458 const bool ignore_player = (level != -1);
2459
2460 const mutation_activity_type active = mutation_activity_level(mut);
2461 const bool partially_active = (active == mutation_activity_type::PARTIAL);
2462 const bool fully_inactive = (active == mutation_activity_type::INACTIVE);
2463
2464 const bool temporary = you.has_temporary_mutation(mut);
2465
2466 // level == -1 means default action of current level
2467 if (level == -1)
2468 {
2469 if (!fully_inactive)
2470 level = you.get_mutation_level(mut);
2471 else // give description of fully active mutation
2472 level = you.get_base_mutation_level(mut);
2473 }
2474
2475 string result;
2476
2477 const mutation_def& mdef = _get_mutation_def(mut);
2478
2479 if (mut == MUT_STRONG || mut == MUT_CLEVER
2480 || mut == MUT_AGILE || mut == MUT_WEAK
2481 || mut == MUT_DOPEY || mut == MUT_CLUMSY)
2482 {
2483 level = min(level, 2);
2484 }
2485 if (mut == MUT_ICEMAIL)
2486 {
2487 ostringstream ostr;
2488 ostr << mdef.have[0] << player_icemail_armour_class() << ")";
2489 result = ostr.str();
2490 }
2491 else if (mut == MUT_CONDENSATION_SHIELD)
2492 {
2493 ostringstream ostr;
2494 ostr << mdef.have[0] << player_condensation_shield_class() << ")";
2495 result = ostr.str();
2496 }
2497 else if (mut == MUT_SANGUINE_ARMOUR)
2498 {
2499 ostringstream ostr;
2500 ostr << mdef.have[level - 1] << sanguine_armour_bonus() / 100 << ")";
2501 result = ostr.str();
2502 }
2503 else if (mut == MUT_MP_WANDS && you.has_mutation(MUT_HP_CASTING))
2504 result = "You expend health (3 HP) to strengthen your wands.";
2505 else if (!ignore_player && mut == MUT_TENTACLE_ARMS)
2506 {
2507 const string num_tentacles = number_in_words(you.has_tentacles(false));
2508 result = make_stringf(
2509 "You have tentacles for arms and can constrict up to %s enemies at once.",
2510 num_tentacles.c_str());
2511 }
2512 else if (!ignore_player && you.has_innate_mutation(MUT_PAWS) && mut == MUT_CLAWS)
2513 result = "You have sharp claws."; // XX ugly override
2514 else if (have_passive(passive_t::no_mp_regen) && mut == MUT_ANTIMAGIC_BITE)
2515 result = "Your bite disrupts the magic of your enemies.";
2516 else if (result.empty() && level > 0)
2517 result = mdef.have[level - 1];
2518
2519 if (!ignore_player)
2520 {
2521 if (fully_inactive)
2522 {
2523 result = "((" + result + "))";
2524 ++_num_full_suppressed;
2525 }
2526 else if (partially_active)
2527 {
2528 result = "(" + result + ")";
2529 ++_num_part_suppressed;
2530 }
2531 }
2532
2533 if (temporary)
2534 {
2535 result = "[" + result + "]";
2536 ++_num_transient;
2537 }
2538
2539 if (colour)
2540 {
2541 const char* colourname = (MUT_BAD(mdef) ? "red" : "lightgrey");
2542 const bool permanent = you.has_innate_mutation(mut);
2543
2544 if (permanent)
2545 {
2546 const bool demonspawn = (you.species == SP_DEMONSPAWN);
2547 const bool extra = you.get_base_mutation_level(mut, false, true, true) > 0;
2548
2549 if (fully_inactive || (mut == MUT_COLD_BLOODED && player_res_cold(false) > 0))
2550 colourname = "darkgrey";
2551 else if (is_sacrifice)
2552 colourname = "lightred";
2553 else if (partially_active)
2554 colourname = demonspawn ? "yellow" : "blue";
2555 else if (extra)
2556 colourname = demonspawn ? "lightcyan" : "cyan";
2557 else
2558 colourname = demonspawn ? "cyan" : "lightblue";
2559 }
2560 else if (fully_inactive)
2561 colourname = "darkgrey";
2562 else if (partially_active)
2563 colourname = "brown";
2564 else if (_is_appendage_mutation(mut) && you.form == transformation::appendage)
2565 colourname = "green";
2566 else if (is_slime_mutation(mut))
2567 colourname = "lightgreen";
2568 else if (temporary)
2569 colourname = (you.get_base_mutation_level(mut, true, false, true) > 0) ?
2570 "lightmagenta" : "magenta";
2571
2572 // Build the result
2573 ostringstream ostr;
2574 ostr << '<' << colourname << '>' << result
2575 << "</" << colourname << '>';
2576 result = ostr.str();
2577 }
2578
2579 return result;
2580 }
2581
2582 // The "when" numbers indicate the range of times in which the mutation tries
2583 // to place itself; it will be approximately placed between when% and
2584 // (when + 100)% of the way through the mutations. For example, you should
2585 // usually get all your body slot mutations in the first 2/3 of your
2586 // mutations and you should usually only start your tier 3 facet in the second
2587 // half of your mutations. See _order_ds_mutations() for details.
2588 static const facet_def _demon_facets[] =
2589 {
2590 // Body Slot facets
2591 { 0, { MUT_CLAWS, MUT_CLAWS, MUT_CLAWS },
2592 { -33, -33, -33 } },
2593 { 0, { MUT_HORNS, MUT_HORNS, MUT_HORNS },
2594 { -33, -33, -33 } },
2595 { 0, { MUT_ANTENNAE, MUT_ANTENNAE, MUT_ANTENNAE },
2596 { -33, -33, -33 } },
2597 { 0, { MUT_HOOVES, MUT_HOOVES, MUT_HOOVES },
2598 { -33, -33, -33 } },
2599 { 0, { MUT_TALONS, MUT_TALONS, MUT_TALONS },
2600 { -33, -33, -33 } },
2601 // Scale mutations
2602 { 1, { MUT_DISTORTION_FIELD, MUT_DISTORTION_FIELD, MUT_DISTORTION_FIELD },
2603 { -33, -33, 0 } },
2604 { 1, { MUT_ICY_BLUE_SCALES, MUT_ICY_BLUE_SCALES, MUT_ICY_BLUE_SCALES },
2605 { -33, -33, 0 } },
2606 { 1, { MUT_LARGE_BONE_PLATES, MUT_LARGE_BONE_PLATES, MUT_LARGE_BONE_PLATES },
2607 { -33, -33, 0 } },
2608 { 1, { MUT_MOLTEN_SCALES, MUT_MOLTEN_SCALES, MUT_MOLTEN_SCALES },
2609 { -33, -33, 0 } },
2610 { 1, { MUT_RUGGED_BROWN_SCALES, MUT_RUGGED_BROWN_SCALES,
2611 MUT_RUGGED_BROWN_SCALES },
2612 { -33, -33, 0 } },
2613 { 1, { MUT_SLIMY_GREEN_SCALES, MUT_SLIMY_GREEN_SCALES, MUT_SLIMY_GREEN_SCALES },
2614 { -33, -33, 0 } },
2615 { 1, { MUT_THIN_METALLIC_SCALES, MUT_THIN_METALLIC_SCALES,
2616 MUT_THIN_METALLIC_SCALES },
2617 { -33, -33, 0 } },
2618 { 1, { MUT_THIN_SKELETAL_STRUCTURE, MUT_THIN_SKELETAL_STRUCTURE,
2619 MUT_THIN_SKELETAL_STRUCTURE },
2620 { -33, -33, 0 } },
2621 { 1, { MUT_YELLOW_SCALES, MUT_YELLOW_SCALES, MUT_YELLOW_SCALES },
2622 { -33, -33, 0 } },
2623 { 1, { MUT_STURDY_FRAME, MUT_STURDY_FRAME, MUT_STURDY_FRAME },
2624 { -33, -33, 0 } },
2625 { 1, { MUT_SANGUINE_ARMOUR, MUT_SANGUINE_ARMOUR, MUT_SANGUINE_ARMOUR },
2626 { -33, -33, 0 } },
2627 { 1, { MUT_BIG_BRAIN, MUT_BIG_BRAIN, MUT_BIG_BRAIN },
2628 { -33, -33, 0 } },
2629 { 1, { MUT_SHARP_SCALES, MUT_SHARP_SCALES, MUT_SHARP_SCALES },
2630 { -33, -33, 0 } },
2631 // Tier 2 facets
2632 { 2, { MUT_IGNITE_BLOOD, MUT_IGNITE_BLOOD, MUT_IGNITE_BLOOD },
2633 { -33, 0, 0 } },
2634 { 2, { MUT_CONDENSATION_SHIELD, MUT_ICEMAIL, MUT_ICEMAIL },
2635 { -33, 0, 0 } },
2636 { 2, { MUT_DEMONIC_MAGIC, MUT_DEMONIC_MAGIC, MUT_DEMONIC_MAGIC },
2637 { -33, 0, 0 } },
2638 { 2, { MUT_POWERED_BY_DEATH, MUT_POWERED_BY_DEATH, MUT_POWERED_BY_DEATH },
2639 { -33, 0, 0 } },
2640 { 2, { MUT_DEMONIC_GUARDIAN, MUT_DEMONIC_GUARDIAN, MUT_DEMONIC_GUARDIAN },
2641 { -33, 0, 0 } },
2642 { 2, { MUT_SPINY, MUT_SPINY, MUT_SPINY },
2643 { -33, 0, 0 } },
2644 { 2, { MUT_POWERED_BY_PAIN, MUT_POWERED_BY_PAIN, MUT_POWERED_BY_PAIN },
2645 { -33, 0, 0 } },
2646 { 2, { MUT_FOUL_STENCH, MUT_FOUL_STENCH, MUT_FOUL_STENCH },
2647 { -33, 0, 0 } },
2648 { 2, { MUT_MANA_REGENERATION, MUT_MANA_SHIELD, MUT_MANA_LINK },
2649 { -33, 0, 0 } },
2650 // Tier 3 facets
2651 { 3, { MUT_DEMONIC_WILL, MUT_TORMENT_RESISTANCE, MUT_HURL_DAMNATION },
2652 { 50, 50, 50 } },
2653 { 3, { MUT_ROBUST, MUT_ROBUST, MUT_ROBUST },
2654 { 50, 50, 50 } },
2655 { 3, { MUT_HEX_ENHANCER, MUT_BLACK_MARK, MUT_SILENCE_AURA },
2656 { 50, 50, 50 } },
2657 { 3, { MUT_AUGMENTATION, MUT_AUGMENTATION, MUT_AUGMENTATION },
2658 { 50, 50, 50 } },
2659 { 3, { MUT_CORRUPTING_PRESENCE, MUT_CORRUPTING_PRESENCE, MUT_WORD_OF_CHAOS },
2660 { 50, 50, 50 } },
2661 };
2662
_works_at_tier(const facet_def & facet,int tier)2663 static bool _works_at_tier(const facet_def& facet, int tier)
2664 {
2665 return facet.tier == tier;
2666 }
2667
2668 typedef decltype(facet_def().muts) mut_array_t;
_slot_is_unique(const mut_array_t & mut,set<const facet_def * > facets_used)2669 static bool _slot_is_unique(const mut_array_t &mut,
2670 set<const facet_def *> facets_used)
2671 {
2672 set<equipment_type> eq;
2673
2674 // find the equipment slot(s) used by mut
2675 for (const body_facet_def &facet : _body_facets)
2676 {
2677 for (mutation_type slotmut : mut)
2678 if (facet.mut == slotmut)
2679 eq.insert(facet.eq);
2680 }
2681
2682 if (eq.empty())
2683 return true;
2684
2685 for (const facet_def *used : facets_used)
2686 {
2687 for (const body_facet_def &facet : _body_facets)
2688 if (facet.mut == used->muts[0] && eq.count(facet.eq))
2689 return false;
2690 }
2691
2692 return true;
2693 }
2694
_select_ds_mutations()2695 static vector<demon_mutation_info> _select_ds_mutations()
2696 {
2697 int ct_of_tier[] = { 1, 1, 2, 1 };
2698 // 1 in 10 chance to create a monstrous set
2699 if (one_chance_in(10))
2700 {
2701 ct_of_tier[0] = 3;
2702 ct_of_tier[1] = 0;
2703 }
2704
2705 try_again:
2706 vector<demon_mutation_info> ret;
2707
2708 ret.clear();
2709 int absfacet = 0;
2710 int elemental = 0;
2711 int cloud_producing = 0;
2712
2713 set<const facet_def *> facets_used;
2714
2715 for (int tier = ARRAYSZ(ct_of_tier) - 1; tier >= 0; --tier)
2716 {
2717 for (int nfacet = 0; nfacet < ct_of_tier[tier]; ++nfacet)
2718 {
2719 const facet_def* next_facet;
2720
2721 do
2722 {
2723 next_facet = &RANDOM_ELEMENT(_demon_facets);
2724 }
2725 while (!_works_at_tier(*next_facet, tier)
2726 || facets_used.count(next_facet)
2727 || !_slot_is_unique(next_facet->muts, facets_used));
2728
2729 facets_used.insert(next_facet);
2730
2731 for (int i = 0; i < 3; ++i)
2732 {
2733 mutation_type m = next_facet->muts[i];
2734
2735 ret.emplace_back(m, next_facet->when[i], absfacet);
2736
2737 if (i==0)
2738 {
2739 if (m == MUT_CONDENSATION_SHIELD || m == MUT_IGNITE_BLOOD)
2740 elemental++;
2741
2742 if (m == MUT_FOUL_STENCH || m == MUT_IGNITE_BLOOD)
2743 cloud_producing++;
2744 }
2745 }
2746
2747 ++absfacet;
2748 }
2749 }
2750
2751 if (elemental > 1)
2752 goto try_again;
2753
2754 if (cloud_producing > 1)
2755 goto try_again;
2756
2757 return ret;
2758 }
2759
2760 static vector<mutation_type>
_order_ds_mutations(vector<demon_mutation_info> muts)2761 _order_ds_mutations(vector<demon_mutation_info> muts)
2762 {
2763 vector<mutation_type> out;
2764 vector<int> times;
2765 FixedVector<int, 1000> time_slots;
2766 time_slots.init(-1);
2767 for (unsigned int i = 0; i < muts.size(); i++)
2768 {
2769 int first = max(0, muts[i].when);
2770 int last = min(100, muts[i].when + 100);
2771 int k;
2772 do
2773 {
2774 k = 10 * first + random2(10 * (last - first));
2775 }
2776 while (time_slots[k] >= 0);
2777 time_slots[k] = i;
2778 times.push_back(k);
2779
2780 // Don't reorder mutations within a facet.
2781 for (unsigned int j = i; j > 0; j--)
2782 {
2783 if (muts[j].facet == muts[j-1].facet && times[j] < times[j-1])
2784 {
2785 int earlier = times[j];
2786 int later = times[j-1];
2787 time_slots[earlier] = j-1;
2788 time_slots[later] = j;
2789 times[j-1] = earlier;
2790 times[j] = later;
2791 }
2792 else
2793 break;
2794 }
2795 }
2796
2797 for (int time = 0; time < 1000; time++)
2798 if (time_slots[time] >= 0)
2799 out.push_back(muts[time_slots[time]].mut);
2800
2801 return out;
2802 }
2803
2804 static vector<player::demon_trait>
_schedule_ds_mutations(vector<mutation_type> muts)2805 _schedule_ds_mutations(vector<mutation_type> muts)
2806 {
2807 list<mutation_type> muts_left(muts.begin(), muts.end());
2808
2809 list<int> slots_left;
2810
2811 vector<player::demon_trait> out;
2812
2813 for (int level = 2; level <= 27; ++level)
2814 slots_left.push_back(level);
2815
2816 while (!muts_left.empty())
2817 {
2818 if (out.empty() // always give a mutation at XL 2
2819 || x_chance_in_y(muts_left.size(), slots_left.size()))
2820 {
2821 player::demon_trait dt;
2822
2823 dt.level_gained = slots_left.front();
2824 dt.mutation = muts_left.front();
2825
2826 dprf("Demonspawn will gain %s at level %d",
2827 _get_mutation_def(dt.mutation).short_desc, dt.level_gained);
2828
2829 out.push_back(dt);
2830
2831 muts_left.pop_front();
2832 }
2833 slots_left.pop_front();
2834 }
2835
2836 return out;
2837 }
2838
roll_demonspawn_mutations()2839 void roll_demonspawn_mutations()
2840 {
2841 // intentionally create the subgenerator either way, so that this has the
2842 // same impact on the current main rng for all chars.
2843 rng::subgenerator ds_rng;
2844
2845 if (you.species != SP_DEMONSPAWN)
2846 return;
2847 you.demonic_traits = _schedule_ds_mutations(
2848 _order_ds_mutations(
2849 _select_ds_mutations()));
2850 }
2851
perma_mutate(mutation_type which_mut,int how_much,const string & reason)2852 bool perma_mutate(mutation_type which_mut, int how_much, const string &reason)
2853 {
2854 ASSERT(_is_valid_mutation(which_mut));
2855
2856 int cap = get_mutation_cap(which_mut);
2857 how_much = min(how_much, cap);
2858
2859 int rc = 1;
2860 // clear out conflicting mutations
2861 int count = 0;
2862 while (rc == 1 && ++count < 100)
2863 rc = _handle_conflicting_mutations(which_mut, true, reason);
2864 ASSERT(rc == 0);
2865
2866 int levels = 0;
2867 while (how_much-- > 0)
2868 {
2869 dprf("Perma Mutate %s: cap %d, total %d, innate %d", mutation_name(which_mut), cap,
2870 you.get_base_mutation_level(which_mut), you.get_innate_mutation_level(which_mut));
2871 if (you.get_base_mutation_level(which_mut, true, false, false) < cap
2872 && !mutate(which_mut, reason, false, true, false, false, MUTCLASS_INNATE))
2873 {
2874 dprf("Innate mutation failed.");
2875 break;
2876 }
2877 levels++;
2878 }
2879
2880 #ifdef DEBUG
2881 // don't validate permamutate directly on level regain; this is so that wizmode level change
2882 // functions can work correctly.
2883 if (you.experience_level >= you.max_level)
2884 validate_mutations(false);
2885 #endif
2886 return levels > 0;
2887 }
2888
temp_mutate(mutation_type which_mut,const string & reason)2889 bool temp_mutate(mutation_type which_mut, const string &reason)
2890 {
2891 return mutate(which_mut, reason, false, false, false, false, MUTCLASS_TEMPORARY);
2892 }
2893
temp_mutation_roll()2894 int temp_mutation_roll()
2895 {
2896 return min(you.experience_level, 17) * (500 + roll_dice(5, 500)) / 17;
2897 }
2898
temp_mutation_wanes()2899 bool temp_mutation_wanes()
2900 {
2901 const int starting_tmuts = you.attribute[ATTR_TEMP_MUTATIONS];
2902 if (starting_tmuts == 0)
2903 return false;
2904
2905 int num_remove = min(starting_tmuts,
2906 max(starting_tmuts * 5 / 12 - random2(3),
2907 1 + random2(3)));
2908
2909 mprf(MSGCH_DURATION, "You feel the corruption within you wane %s.",
2910 (num_remove >= starting_tmuts ? "completely" : "somewhat"));
2911
2912 for (int i = 0; i < num_remove; ++i)
2913 delete_temp_mutation(); // chooses randomly
2914
2915 if (you.attribute[ATTR_TEMP_MUTATIONS] > 0)
2916 you.attribute[ATTR_TEMP_MUT_XP] += temp_mutation_roll();
2917 else
2918 you.attribute[ATTR_TEMP_MUT_XP] = 0;
2919 ASSERT(you.attribute[ATTR_TEMP_MUTATIONS] < starting_tmuts);
2920 return true;
2921 }
2922
2923 /**
2924 * How mutated is the player?
2925 *
2926 * @param innate Whether to count innate mutations (default false).
2927 * @param levels Whether to add up mutation levels, as opposed to just counting number of mutations (default false).
2928 * @param temp Whether to count temporary mutations (default true).
2929 * @return Either the number of matching mutations, or the sum of their
2930 * levels, depending on \c levels
2931 */
how_mutated(bool innate,bool levels,bool temp) const2932 int player::how_mutated(bool innate, bool levels, bool temp) const
2933 {
2934 int result = 0;
2935
2936 for (int i = 0; i < NUM_MUTATIONS; ++i)
2937 {
2938 if (you.mutation[i])
2939 {
2940 const int mut_level = get_base_mutation_level(static_cast<mutation_type>(i), innate, temp);
2941
2942 if (levels)
2943 result += mut_level;
2944 else if (mut_level > 0)
2945 result++;
2946 }
2947 if (you.species == SP_DEMONSPAWN
2948 && you.props.exists("num_sacrifice_muts"))
2949 {
2950 result -= you.props["num_sacrifice_muts"].get_int();
2951 }
2952 }
2953
2954 return result;
2955 }
2956
2957 // Primary function to handle demonic guardians.
2958 // Guardian tier is partially based on player experience level. This should
2959 // allow players to get the mutation early without it going totally out of
2960 // control.
check_demonic_guardian()2961 void check_demonic_guardian()
2962 {
2963 // Players hated by all monsters don't get guardians, so that they aren't
2964 // swarmed by hostile executioners whenever things get rough.
2965 if (you.get_mutation_level(MUT_NO_LOVE))
2966 return;
2967
2968 const int mutlevel = you.get_mutation_level(MUT_DEMONIC_GUARDIAN);
2969
2970 if (you.duration[DUR_DEMONIC_GUARDIAN] == 0)
2971 {
2972 monster_type mt;
2973 int guardian_str = mutlevel + div_rand_round(you.experience_level - 9, 9);
2974
2975 switch (guardian_str)
2976 {
2977 case 1:
2978 mt = random_choose(MONS_QUASIT, MONS_WHITE_IMP, MONS_UFETUBUS,
2979 MONS_IRON_IMP, MONS_SHADOW_IMP);
2980 break;
2981 case 2:
2982 mt = random_choose(MONS_ORANGE_DEMON, MONS_ICE_DEVIL,
2983 MONS_RUST_DEVIL, MONS_HELLWING);
2984 break;
2985 case 3:
2986 mt = random_choose(MONS_SOUL_EATER, MONS_SMOKE_DEMON,
2987 MONS_SIXFIRHY, MONS_SUN_DEMON);
2988 break;
2989 case 4:
2990 mt = random_choose(MONS_BALRUG, MONS_REAPER,
2991 MONS_LOROCYPROCA, MONS_CACODEMON,
2992 MONS_HELL_BEAST);
2993 break;
2994 case 5:
2995 mt = random_choose(MONS_EXECUTIONER, MONS_HELL_SENTINEL,
2996 MONS_BRIMSTONE_FIEND);
2997 break;
2998 default:
2999 die("Invalid demonic guardian level: %d", mutlevel);
3000 }
3001
3002 monster *guardian = create_monster(
3003 mgen_data(mt, BEH_FRIENDLY, you.pos(), MHITYOU,
3004 MG_FORCE_BEH | MG_AUTOFOE).set_summoned(&you, 2, 0));
3005
3006 if (!guardian)
3007 return;
3008
3009 guardian->flags |= MF_NO_REWARD;
3010 guardian->flags |= MF_DEMONIC_GUARDIAN;
3011
3012 guardian->add_ench(ENCH_LIFE_TIMER);
3013
3014 // no more guardians for mutlevel+1 to mutlevel+20 turns
3015 you.duration[DUR_DEMONIC_GUARDIAN] = 10*(mutlevel + random2(20));
3016
3017 mpr("A demonic guardian appears!");
3018 }
3019 }
3020
3021 /**
3022 * Update the map knowledge based on any monster detection sources the player
3023 * has.
3024 */
check_monster_detect()3025 void check_monster_detect()
3026 {
3027 int radius = player_monster_detect_radius();
3028 if (radius <= 0)
3029 return;
3030
3031 for (radius_iterator ri(you.pos(), radius, C_SQUARE); ri; ++ri)
3032 {
3033 monster* mon = monster_at(*ri);
3034 map_cell& cell = env.map_knowledge(*ri);
3035 if (!mon)
3036 {
3037 if (cell.detected_monster())
3038 cell.clear_monster();
3039 continue;
3040 }
3041 if (mons_is_firewood(*mon))
3042 continue;
3043
3044 // [ds] If the PC remembers the correct monster at this
3045 // square, don't trample it with MONS_SENSED. Forgetting
3046 // legitimate monster memory affects travel, which can
3047 // path around mimics correctly only if it can actually
3048 // *see* them in monster memory -- overwriting the mimic
3049 // with MONS_SENSED causes travel to bounce back and
3050 // forth, since every time it leaves LOS of the mimic, the
3051 // mimic is forgotten (replaced by MONS_SENSED).
3052 // XXX: since mimics were changed, is this safe to remove now?
3053 const monster_type remembered_monster = cell.monster();
3054 if (remembered_monster == mon->type)
3055 continue;
3056
3057 const monster_type mc = mon->friendly() ? MONS_SENSED_FRIENDLY
3058 : have_passive(passive_t::detect_montier)
3059 ? ash_monster_tier(mon)
3060 : MONS_SENSED;
3061
3062 env.map_knowledge(*ri).set_detected_monster(mc);
3063
3064 // Don't bother warning the player (or interrupting autoexplore) about
3065 // friendly monsters or those known to be easy, or those recently
3066 // warned about
3067 if (mc == MONS_SENSED_TRIVIAL || mc == MONS_SENSED_EASY
3068 || mc == MONS_SENSED_FRIENDLY || mon->wont_attack()
3069 || testbits(mon->flags, MF_SENSED))
3070 {
3071 continue;
3072 }
3073
3074 for (radius_iterator ri2(mon->pos(), 2, C_SQUARE); ri2; ++ri2)
3075 {
3076 if (you.see_cell(*ri2))
3077 {
3078 mon->flags |= MF_SENSED;
3079 interrupt_activity(activity_interrupt::sense_monster);
3080 break;
3081 }
3082 }
3083 }
3084 }
3085
augmentation_amount()3086 int augmentation_amount()
3087 {
3088 int amount = 0;
3089 const int level = you.get_mutation_level(MUT_AUGMENTATION);
3090
3091 for (int i = 0; i < level; ++i)
3092 {
3093 if (you.hp >= ((i + level) * you.hp_max) / (2 * level))
3094 amount++;
3095 }
3096
3097 return amount;
3098 }
3099
reset_powered_by_death_duration()3100 void reset_powered_by_death_duration()
3101 {
3102 const int pbd_dur = random_range(2, 5);
3103 you.set_duration(DUR_POWERED_BY_DEATH, pbd_dur);
3104 }
3105