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