add two new Ru sacrifices
[crawl.git] / crawl-ref / source / player.cc
1 /**
2  * @file
3  * @brief Player related functions.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "player.h"
9
10 #include <algorithm>
11 #include <cctype>
12 #include <cmath>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cstring>
16 #include <sstream>
17
18 #include "ability.h"
19 #include "act-iter.h"
20 #include "areas.h"
21 #include "art-enum.h"
22 #include "bloodspatter.h"
23 #include "branch.h"
24 #ifdef DGL_WHEREIS
25  #include "chardump.h"
26 #endif
27 #include "cloud.h"
28 #include "coordit.h"
29 #include "delay.h"
30 #include "dgnevent.h"
31 #include "directn.h"
32 #include "english.h"
33 #include "env.h"
34 #include "errors.h"
35 #include "exercise.h"
36 #include "food.h"
37 #include "godabil.h"
38 #include "godconduct.h"
39 #include "godpassive.h"
40 #include "godwrath.h"
41 #include "hints.h"
42 #include "hiscores.h"
43 #include "invent.h"
44 #include "itemprop.h"
45 #include "item_use.h"
46 #include "kills.h"
47 #include "libutil.h"
48 #include "macro.h"
49 #include "melee_attack.h"
50 #include "message.h"
51 #include "misc.h"
52 #include "mon-place.h"
53 #include "mutation.h"
54 #include "notes.h"
55 #include "output.h"
56 #include "player-stats.h"
57 #include "potion.h"
58 #include "prompt.h"
59 #include "religion.h"
60 #include "shout.h"
61 #include "skills.h"
62 #include "spl-damage.h"
63 #include "spl-transloc.h"
64 #include "spl-util.h"
65 #include "sprint.h"
66 #include "stairs.h"
67 #include "stash.h"
68 #include "state.h"
69 #include "status.h"
70 #include "stepdown.h"
71 #include "stringutil.h"
72 #include "terrain.h"
73 #ifdef USE_TILE
74  #include "tiledef-feat.h"
75  #include "tileview.h"
76 #endif
77 #include "transform.h"
78 #include "traps.h"
79 #include "travel.h"
80 #include "view.h"
81 #include "xom.h"
82
83 #if TAG_MAJOR_VERSION == 34
84 const int DJ_MP_RATE = 2;
85 #endif
86
87 static int _bone_armour_bonus();
88
89 static void _moveto_maybe_repel_stairs()
90 {
91     const dungeon_feature_type new_grid = env.grid(you.pos());
92     const command_type stair_dir = feat_stair_direction(new_grid);
93
94     if (stair_dir == CMD_NO_CMD
95         || new_grid == DNGN_ENTER_SHOP
96         ||  !you.duration[DUR_REPEL_STAIRS_MOVE])
97     {
98         return;
99     }
100
101     int pct = you.duration[DUR_REPEL_STAIRS_CLIMB] ? 29 : 50;
102
103     // When the effect is still strong, the chance to actually catch
104     // a stair is smaller. (Assuming the duration starts out at 1000.)
105     const int dur = max(0, you.duration[DUR_REPEL_STAIRS_MOVE] - 700);
106     pct += dur/10;
107
108     if (x_chance_in_y(pct, 100))
109     {
110         const string stair_str = feature_description_at(you.pos(), false,
111                                                         DESC_THE, false);
112         const string prep = feat_preposition(new_grid, true, &you);
113
114         if (slide_feature_over(you.pos()))
115         {
116             mprf("%s slides away as you move %s it!", stair_str.c_str(),
117                  prep.c_str());
118
119             if (player_in_a_dangerous_place() && one_chance_in(5))
120                 xom_is_stimulated(25);
121         }
122     }
123 }
124
125 bool check_moveto_cloud(const coord_def& p, const string &move_verb,
126                         bool *prompted)
127 {
128     if (you.confused())
129         return true;
130     const cloud_type ctype = cloud_type_at(p);
131     // Don't prompt if already in a cloud of the same type.
132     if (is_damaging_cloud(ctype, true, cloud_is_yours_at(p))
133         && ctype != cloud_type_at(you.pos())
134         && !crawl_state.disables[DIS_CONFIRMATIONS])
135     {
136         // Don't prompt for steam unless we're at uncomfortably low hp.
137         if (ctype == CLOUD_STEAM)
138         {
139             int threshold = 20;
140             if (player_res_steam() < 0)
141                 threshold = threshold * 3 / 2;
142             threshold = threshold * you.time_taken / BASELINE_DELAY;
143             // Do prompt if we'd lose icemail, though.
144             if (you.hp > threshold && !you.mutation[MUT_ICEMAIL])
145                 return true;
146         }
147
148         if (prompted)
149             *prompted = true;
150         string prompt = make_stringf("Really %s into that cloud of %s?",
151                                      move_verb.c_str(),
152                                      cloud_type_name(ctype).c_str());
153         learned_something_new(HINT_CLOUD_WARNING);
154
155         if (!yesno(prompt.c_str(), false, 'n'))
156         {
157             canned_msg(MSG_OK);
158             return false;
159         }
160     }
161     return true;
162 }
163
164 bool check_moveto_trap(const coord_def& p, const string &move_verb,
165                        bool *prompted)
166 {
167     // If there's no trap, let's go.
168     trap_def* trap = find_trap(p);
169     if (!trap || env.grid(p) == DNGN_UNDISCOVERED_TRAP)
170         return true;
171
172     if (trap->type == TRAP_ZOT && !crawl_state.disables[DIS_CONFIRMATIONS])
173     {
174         string msg = "Do you really want to %s into the Zot trap?";
175         string prompt = make_stringf(msg.c_str(), move_verb.c_str());
176
177         if (prompted)
178             *prompted = true;
179         if (!yes_or_no("%s", prompt.c_str()))
180         {
181             canned_msg(MSG_OK);
182             return false;
183         }
184     }
185     else if (!trap->is_safe() && !crawl_state.disables[DIS_CONFIRMATIONS])
186     {
187         string prompt;
188
189         if (prompted)
190             *prompted = true;
191         prompt = make_stringf("Really %s %s that %s?", move_verb.c_str(),
192                               (trap->type == TRAP_ALARM
193                                || trap->type == TRAP_PLATE) ? "onto"
194                               : "into",
195                               feature_description_at(p, false, DESC_BASENAME,
196                                                      false).c_str());
197         if (!yesno(prompt.c_str(), true, 'n'))
198         {
199             canned_msg(MSG_OK);
200             return false;
201         }
202     }
203     return true;
204 }
205
206 static bool _check_moveto_dangerous(const coord_def& p, const string& msg)
207 {
208     if (you.can_swim() && feat_is_water(env.grid(p))
209         || you.airborne() || !is_feat_dangerous(env.grid(p)))
210     {
211         return true;
212     }
213
214     if (msg != "")
215         mpr(msg);
216     else if (species_likes_water(you.species) && feat_is_water(env.grid(p)))
217         mpr("You cannot enter water in your current form.");
218     else if (species_likes_lava(you.species) && feat_is_lava(env.grid(p)))
219         mpr("You cannot enter lava in your current form.");
220     else
221         canned_msg(MSG_UNTHINKING_ACT);
222     return false;
223 }
224
225 bool check_moveto_terrain(const coord_def& p, const string &move_verb,
226                           const string &msg, bool *prompted)
227 {
228     if (!_check_moveto_dangerous(p, msg))
229         return false
230 ;
231     if (!need_expiration_warning() && need_expiration_warning(p)
232         && !crawl_state.disables[DIS_CONFIRMATIONS])
233     {
234         string prompt;
235
236         if (prompted)
237             *prompted = true;
238
239         if (msg != "")
240             prompt = msg + " ";
241
242         prompt += "Are you sure you want to " + move_verb;
243
244         if (you.ground_level())
245             prompt += " into ";
246         else
247             prompt += " over ";
248
249         prompt += env.grid(p) == DNGN_DEEP_WATER ? "deep water" : "lava";
250
251         prompt += need_expiration_warning(DUR_FLIGHT, p)
252             ? " while you are losing your buoyancy?"
253             : " while your transformation is expiring?";
254
255         if (!yesno(prompt.c_str(), false, 'n'))
256         {
257             canned_msg(MSG_OK);
258             return false;
259         }
260     }
261     return true;
262 }
263
264 bool check_moveto_exclusion(const coord_def& p, const string &move_verb,
265                             bool *prompted)
266 {
267     string prompt;
268
269     if (is_excluded(p)
270         && !is_stair_exclusion(p)
271         && !is_excluded(you.pos())
272         && !crawl_state.disables[DIS_CONFIRMATIONS])
273     {
274         if (prompted)
275             *prompted = true;
276         prompt = make_stringf("Really %s into a travel-excluded area?",
277                               move_verb.c_str());
278
279         if (!yesno(prompt.c_str(), false, 'n'))
280         {
281             canned_msg(MSG_OK);
282             return false;
283         }
284     }
285     return true;
286 }
287
288 bool check_moveto(const coord_def& p, const string &move_verb, const string &msg)
289 {
290     return check_moveto_terrain(p, move_verb, msg)
291            && check_moveto_cloud(p, move_verb)
292            && check_moveto_trap(p, move_verb)
293            && check_moveto_exclusion(p, move_verb);
294 }
295
296 // Returns true if this is a valid swap for this monster.  If true, then
297 // the valid location is set in loc. (Otherwise loc becomes garbage.)
298 bool swap_check(monster* mons, coord_def &loc, bool quiet)
299 {
300     loc = you.pos();
301
302     if (you.is_stationary())
303         return false;
304
305     // Don't move onto dangerous terrain.
306     if (is_feat_dangerous(grd(mons->pos())))
307     {
308         canned_msg(MSG_UNTHINKING_ACT);
309         return false;
310     }
311
312     if (mons->is_projectile())
313     {
314         if (!quiet)
315             mpr("It's unwise to walk into this.");
316         return false;
317     }
318
319     if (mons->caught())
320     {
321         if (!quiet)
322         {
323             simple_monster_message(mons,
324                 make_stringf(" is %s!", held_status(mons)).c_str());
325         }
326         return false;
327     }
328
329     if (mons->is_constricted())
330     {
331         if (!quiet)
332             simple_monster_message(mons, " is being constricted!");
333         return false;
334     }
335
336     // prompt when swapping into known zot traps
337     if (!quiet && find_trap(loc) && find_trap(loc)->type == TRAP_ZOT
338         && env.grid(loc) != DNGN_UNDISCOVERED_TRAP
339         && !yes_or_no("Do you really want to swap %s into the Zot trap?",
340                       mons->name(DESC_YOUR).c_str()))
341     {
342         return false;
343     }
344
345     // First try: move monster onto your position.
346     bool swap = !monster_at(loc) && monster_habitable_grid(mons, grd(loc));
347
348     if (monster_at(loc)
349         && monster_at(loc)->type == MONS_TOADSTOOL
350         && mons->type == MONS_WANDERING_MUSHROOM)
351     {
352         swap = monster_habitable_grid(mons, grd(loc));
353     }
354
355     // Choose an appropriate habitat square at random around the target.
356     if (!swap)
357     {
358         int num_found = 0;
359
360         for (adjacent_iterator ai(mons->pos()); ai; ++ai)
361             if (!monster_at(*ai) && monster_habitable_grid(mons, grd(*ai))
362                 && one_chance_in(++num_found))
363             {
364                 loc = *ai;
365             }
366
367         if (num_found)
368             swap = true;
369     }
370
371     if (!swap && !quiet)
372     {
373         // Might not be ideal, but it's better than insta-killing
374         // the monster... maybe try for a short blink instead? - bwr
375         simple_monster_message(mons, " cannot make way for you.");
376         // FIXME: AI_HIT_MONSTER isn't ideal.
377         interrupt_activity(AI_HIT_MONSTER, mons);
378     }
379
380     return swap;
381 }
382
383 static void _splash()
384 {
385     if (you.can_swim())
386         noisy(4, you.pos(), "Floosh!");
387     else if (!beogh_water_walk())
388         noisy(8, you.pos(), "Splash!");
389 }
390
391 void moveto_location_effects(dungeon_feature_type old_feat,
392                              bool stepped, const coord_def& old_pos)
393 {
394     const dungeon_feature_type new_grid = env.grid(you.pos());
395
396     // Terrain effects.
397     if (is_feat_dangerous(new_grid))
398         fall_into_a_pool(new_grid);
399
400     if (you.ground_level())
401     {
402         if (player_likes_lava(false))
403         {
404             if (feat_is_lava(new_grid) && !feat_is_lava(old_feat))
405             {
406                 if (!stepped)
407                     noisy(4, you.pos(), "Gloop!");
408
409                 mprf("You %s lava.",
410                      (stepped) ? "slowly immerse yourself in the" : "fall into the");
411
412                 // Extra time if you stepped in.
413                 if (stepped)
414                     you.time_taken *= 2;
415 #if TAG_MAJOR_VERSION == 34
416                 // This gets called here because otherwise you wouldn't heat
417                 // until your second turn in lava.
418                 if (temperature() < TEMP_FIRE)
419                     mpr("The lava instantly superheats you.");
420                 you.temperature = TEMP_MAX;
421 #endif
422             }
423
424             else if (!feat_is_lava(new_grid) && feat_is_lava(old_feat))
425             {
426                 mpr("You slowly pull yourself out of the lava.");
427                 you.time_taken *= 2;
428             }
429         }
430
431         if (you.species == SP_MERFOLK)
432         {
433             if (feat_is_water(new_grid) // We're entering water
434                 // We're not transformed, or with a form compatible with tail
435                 && (you.form == TRAN_NONE
436                     || you.form == TRAN_APPENDAGE
437                     || you.form == TRAN_BLADE_HANDS))
438             {
439                 merfolk_start_swimming(stepped);
440             }
441             else if (!feat_is_water(new_grid) && !is_feat_dangerous(new_grid))
442                 merfolk_stop_swimming();
443         }
444
445         if (feat_is_water(new_grid) && !stepped)
446             _splash();
447
448         if (feat_is_water(new_grid) && !you.can_swim() && !beogh_water_walk())
449         {
450             if (stepped)
451             {
452                 you.time_taken *= 13 + random2(8);
453                 you.time_taken /= 10;
454             }
455
456             if (!feat_is_water(old_feat))
457             {
458                 mprf("You %s the %s water.",
459                      stepped ? "enter" : "fall into",
460                      new_grid == DNGN_SHALLOW_WATER ? "shallow" : "deep");
461             }
462
463             if (new_grid == DNGN_DEEP_WATER && old_feat != DNGN_DEEP_WATER)
464                 mpr("You sink to the bottom.");
465
466             if (!feat_is_water(old_feat))
467             {
468                 mpr("Moving in this stuff is going to be slow.");
469                 if (you.invisible())
470                     mpr("...and don't expect to remain undetected.");
471             }
472         }
473     }
474
475     // Traps go off.
476     // (But not when losing flight - i.e., moving into the same tile)
477     trap_def* ptrap = find_trap(you.pos());
478     if (ptrap && old_pos != you.pos())
479         ptrap->trigger(you, !stepped); // blinking makes it hard to evade
480
481     if (stepped)
482         _moveto_maybe_repel_stairs();
483 }
484
485 // Use this function whenever the player enters (or lands and thus re-enters)
486 // a grid.
487 //
488 // stepped     - normal walking moves
489 void move_player_to_grid(const coord_def& p, bool stepped)
490 {
491     ASSERT(!crawl_state.game_is_arena());
492     ASSERT_IN_BOUNDS(p);
493
494     if (!stepped)
495         tornado_move(p);
496
497     // assuming that entering the same square means coming from above (flight)
498     const coord_def old_pos = you.pos();
499     const bool from_above = (old_pos == p);
500     const dungeon_feature_type old_grid =
501         (from_above) ? DNGN_FLOOR : grd(old_pos);
502
503     // Really must be clear.
504     ASSERT(you.can_pass_through_feat(grd(p)));
505
506     // Better not be an unsubmerged monster either.
507     ASSERT(!monster_at(p) || monster_at(p)->submerged()
508            || fedhas_passthrough(monster_at(p))
509            || mons_is_player_shadow(monster_at(p)));
510
511     // Move the player to new location.
512     you.moveto(p, true);
513     viewwindow();
514
515     moveto_location_effects(old_grid, stepped, old_pos);
516 }
517
518
519 /**
520  * Check if the given terrain feature is safe for the player to move into.
521  * (Or, at least, not instantly lethal.)
522  *
523  * @param grid          The type of terrain feature under consideration.
524  * @param permanently   Whether to disregard temporary effects (non-permanent
525  *                      flight, forms, etc)
526  * @param ignore_flight Whether to ignore all forms of flight (including
527  *                      permanent flight)
528  * @return              Whether the terrain is safe.
529  */
530 bool is_feat_dangerous(dungeon_feature_type grid, bool permanently,
531                        bool ignore_flight)
532 {
533     if (!ignore_flight
534         && (you.permanent_flight() || you.airborne() && !permanently))
535     {
536         return false;
537     }
538     else if (grid == DNGN_DEEP_WATER && !player_likes_water(permanently)
539              || grid == DNGN_LAVA && !player_likes_lava(permanently))
540     {
541         return true;
542     }
543     else
544         return false;
545 }
546
547 bool is_map_persistent()
548 {
549     return !testbits(env.level_flags, LFLAG_NO_MAP);
550 }
551
552 bool player_in_hell()
553 {
554     return is_hell_subbranch(you.where_are_you);
555 }
556
557 bool player_in_connected_branch()
558 {
559     return is_connected_branch(you.where_are_you);
560 }
561
562 bool player_likes_water(bool permanently)
563 {
564     return !permanently && beogh_water_walk()
565            || (species_likes_water(you.species) || !permanently)
566                && form_likes_water();
567 }
568
569 bool player_likes_lava(bool permanently)
570 {
571     return (species_likes_lava(you.species) || !permanently)
572            && form_likes_lava();
573 }
574
575 bool player_can_open_doors()
576 {
577     return you.form != TRAN_BAT;
578 }
579
580 // TODO: get rid of this.
581 bool player_genus(genus_type which_genus, species_type species)
582 {
583     if (species == SP_UNKNOWN)
584         species = you.species;
585
586     return species_genus(species) == which_genus;
587 }
588
589 // If transform is true, compare with current transformation instead
590 // of (or in addition to) underlying species.
591 // (See mon-data.h for species/genus use.)
592 bool is_player_same_genus(const monster_type mon)
593 {
594     // Genus would include necrophage and rotting hulk.
595     if (you.species == SP_GHOUL)
596         return mons_species(mon) == MONS_GHOUL;
597
598     // Note that these are currently considered to be the same genus:
599     // * humans, demigods, and demonspawn
600     // * ogres and two-headed ogres
601     // * trolls, iron trolls, and deep trolls
602     // * kobolds and big kobolds
603     // * dwarves and deep dwarves
604     // * all elf races
605     // * all orc races
606     return mons_genus(mon) == mons_genus(player_mons(false));
607 }
608
609 void update_player_symbol()
610 {
611     you.symbol = Options.show_player_species ? player_mons() : transform_mons();
612 }
613
614 monster_type player_mons(bool transform)
615 {
616     monster_type mons;
617
618     if (transform)
619     {
620         mons = transform_mons();
621         if (mons != MONS_PLAYER)
622             return mons;
623     }
624
625     mons = player_species_to_mons_species(you.species);
626
627     if (mons == MONS_ORC)
628     {
629         if (you_worship(GOD_BEOGH))
630         {
631             mons = (you.piety >= piety_breakpoint(4)) ? MONS_ORC_HIGH_PRIEST
632                                                       : MONS_ORC_PRIEST;
633         }
634     }
635     else if (mons == MONS_OGRE)
636     {
637         const skill_type sk = best_skill(SK_FIRST_SKILL, SK_LAST_SKILL);
638         if (sk >= SK_SPELLCASTING && sk < SK_INVOCATIONS)
639             mons = MONS_OGRE_MAGE;
640     }
641
642     return mons;
643 }
644
645 void update_vision_range()
646 {
647     you.normal_vision = LOS_RADIUS;
648     int nom   = 1;
649     int denom = 1;
650
651     // Nightstalker gives -1/-2/-3.
652     if (player_mutation_level(MUT_NIGHTSTALKER))
653     {
654         nom *= LOS_RADIUS - player_mutation_level(MUT_NIGHTSTALKER);
655         denom *= LOS_RADIUS;
656     }
657
658     // Lantern of shadows.
659     if (you.attribute[ATTR_SHADOWS])
660         nom *= 3, denom *= 4;
661
662     // the Darkness spell.
663     if (you.duration[DUR_DARKNESS])
664         nom *= 3, denom *= 4;
665
666     // robe of Night.
667     if (player_equip_unrand(UNRAND_NIGHT))
668         nom *= 3, denom *= 4;
669
670     you.current_vision = (you.normal_vision * nom + denom / 2) / denom;
671     ASSERT(you.current_vision > 0);
672     set_los_radius(you.current_vision);
673 }
674
675 /**
676  * Ignoring form, but not ignoring equipment, can the player use (usually wear)
677  * a given equipment slot?
678  *
679  * @param eq                The slot in question.
680  * @param special_armour    Whether to check if the player can use some subset
681  *                          of item types for a given slot (e.g. hats,
682  *                          bardings); otherwise, those return false.
683  * @return                  Whether the player can ever use the given slot.
684  */
685 bool you_can_wear(int eq, bool special_armour)
686 {
687     switch (eq)
688     {
689     case EQ_LEFT_RING:
690         return you.species != SP_OCTOPODE
691                && !player_mutation_level(MUT_MISSING_HAND);
692
693     case EQ_RIGHT_RING:
694         return you.species != SP_OCTOPODE;
695
696     case EQ_RING_ONE:
697     case EQ_RING_TWO:
698     case EQ_RING_THREE:
699     case EQ_RING_FOUR:
700     case EQ_RING_FIVE:
701     case EQ_RING_SIX:
702     case EQ_RING_SEVEN:
703         return you.species == SP_OCTOPODE;
704
705     case EQ_RING_EIGHT:
706         return you.species == SP_OCTOPODE
707                && !player_mutation_level(MUT_MISSING_HAND);
708
709     case EQ_AMULET:
710         return true;
711
712     case EQ_RING_AMULET:
713         return player_equip_unrand(UNRAND_FINGER_AMULET);
714
715     case EQ_CLOAK:
716         return you.species != SP_FELID && you.species != SP_OCTOPODE;
717
718     case EQ_GLOVES:
719         if (player_mutation_level(MUT_CLAWS, false) == 3)
720             return false;
721
722         // big & tiny & weird races can't wear gloves
723         if (you.species == SP_TROLL
724             || you.species == SP_OGRE
725             || you.species == SP_SPRIGGAN
726             || you.species == SP_FELID
727             || you.species == SP_OCTOPODE)
728         {
729             return false;
730         }
731         return true;
732
733     case EQ_BOOTS:
734         // Bardings.
735         if (you.species == SP_NAGA || you.species == SP_CENTAUR)
736             return special_armour;
737         if (player_mutation_level(MUT_HOOVES, false) == 3
738             || player_mutation_level(MUT_TALONS, false) == 3)
739         {
740             return false;
741         }
742         // big and tiny & weird races can't wear boots.
743         if (you.species == SP_TROLL
744             || you.species == SP_SPRIGGAN
745 #if TAG_MAJOR_VERSION == 34
746             || you.species == SP_DJINNI
747 #endif
748             || you.species == SP_OGRE
749             || you.species == SP_FELID
750             || you.species == SP_OCTOPODE)
751         {
752             return false;
753         }
754         return true;
755
756     case EQ_BODY_ARMOUR:
757         // weird races (& draconians) can't wear body armour
758         if (player_genus(GENPC_DRACONIAN)
759             || you.species == SP_FELID
760             || you.species == SP_OCTOPODE)
761         {
762             return false;
763         }
764         return true;
765
766     case EQ_SHIELD:
767         // no hand, no shield
768         if (player_mutation_level(MUT_MISSING_HAND) || you.species == SP_FELID)
769             return false;
770
771         /// big & tiny races can only wear some shield types.
772         if (you.species == SP_TROLL
773             || you.species == SP_SPRIGGAN
774             || you.species == SP_OGRE)
775         {
776             return special_armour;
777         }
778         return true;
779
780     case EQ_HELMET:
781         // the cat in the hat is strictly disallowed
782         if (you.species == SP_FELID)
783             return false;
784
785         // No hats with Horns 3 or Antennae 3.
786         if (player_mutation_level(MUT_HORNS, false) == 3
787             || player_mutation_level(MUT_ANTENNAE, false) == 3)
788         {
789             return false;
790         }
791
792         // Anyone else can wear hats.
793         if (special_armour)
794             return true;
795
796         // Any level of horns/beak/antennae lock out hard helmets.
797         if (player_mutation_level(MUT_HORNS, false)
798             || player_mutation_level(MUT_BEAK, false)
799             || player_mutation_level(MUT_ANTENNAE, false))
800         {
801             return false;
802         }
803
804         // big & tiny & weird races can't wear helmets (& draconians)
805         if (you.species == SP_TROLL
806             || you.species == SP_SPRIGGAN
807             || you.species == SP_OGRE
808             || you.species == SP_OCTOPODE
809             || player_genus(GENPC_DRACONIAN))
810         {
811             return false;
812         }
813         return true;
814
815     case EQ_WEAPON:
816     case EQ_STAFF:
817         return you.species != SP_FELID;
818
819     default:
820         return false;
821     }
822 }
823
824 bool player_has_feet(bool temp)
825 {
826     if (you.species == SP_NAGA
827         || you.species == SP_FELID
828         || you.species == SP_OCTOPODE
829 #if TAG_MAJOR_VERSION == 34
830         || you.species == SP_DJINNI
831 #endif
832         || you.fishtail && temp)
833     {
834         return false;
835     }
836
837     if (player_mutation_level(MUT_HOOVES, temp) == 3
838         || player_mutation_level(MUT_TALONS, temp) == 3)
839     {
840         return false;
841     }
842
843     return true;
844 }
845
846 bool player_wearing_slot(int eq)
847 {
848     ASSERT(you.equip[eq] != -1 || !you.melded[eq]);
849     return you.equip[eq] != -1 && !you.melded[eq];
850 }
851
852 bool you_tran_can_wear(const item_def &item)
853 {
854     switch (item.base_type)
855     {
856     case OBJ_WEAPONS:
857         return you_tran_can_wear(EQ_WEAPON);
858
859     case OBJ_JEWELLERY:
860         return you_tran_can_wear(jewellery_is_amulet(item) ? EQ_AMULET
861                                                            : EQ_RINGS);
862     case OBJ_ARMOUR:
863         if (item.sub_type == ARM_NAGA_BARDING)
864             return you.species == SP_NAGA && you_tran_can_wear(EQ_BOOTS);
865         else if (item.sub_type == ARM_CENTAUR_BARDING)
866             return you.species == SP_CENTAUR && you_tran_can_wear(EQ_BOOTS);
867
868         if (fit_armour_size(item, you.body_size()) != 0)
869             return false;
870
871         return you_tran_can_wear(get_armour_slot(item), true);
872
873     default:
874         return true;
875     }
876 }
877
878 /**
879  * Is the given equipment slot available to the player in their current state?
880  *
881  * @param eq                The equipment slot.
882  * @param check_mutation    Whether to consider mutations (horns, antennae)
883  *                          & mermaid fishtails.
884  * @return                  Whether the given slot is at all available. (Even
885  *                          if restricted.)
886  */
887 bool you_tran_can_wear(int eq, bool check_mutation)
888 {
889     if (eq == EQ_NONE)
890         return true;
891
892     if (!get_form(you.form)->slot_available(eq))
893         return false;
894
895     // missing hand is implemented as a mutation, but it's permanent &
896     // irrevocable, so don't care about check_mutation.
897     if (player_mutation_level(MUT_MISSING_HAND)
898         && (eq == EQ_LEFT_RING
899             || eq == EQ_SHIELD
900             || eq == EQ_RING_EIGHT))
901     {
902         return false;
903     }
904
905     // Not a transformation, but also temporary -> check first.
906     if (check_mutation)
907     {
908         if (eq == EQ_GLOVES && you.has_claws(false) == 3)
909             return false;
910
911         if (eq == EQ_HELMET && player_mutation_level(MUT_HORNS) == 3)
912             return false;
913
914         if (eq == EQ_HELMET && player_mutation_level(MUT_ANTENNAE) == 3)
915             return false;
916
917         if (eq == EQ_BOOTS
918             && (you.fishtail
919                 || player_mutation_level(MUT_HOOVES) == 3
920                 || you.has_talons(false) == 3))
921         {
922             return false;
923         }
924     }
925
926     return true;
927 }
928
929 bool player_weapon_wielded()
930 {
931     if (you.melded[EQ_WEAPON])
932         return false;
933
934     const int wpn = you.equip[EQ_WEAPON];
935
936     if (wpn == -1)
937         return false;
938
939     if (!is_weapon(you.inv[wpn]))
940         return false;
941
942     return true;
943 }
944
945 // Returns false if the player is wielding a weapon inappropriate for Berserk.
946 bool berserk_check_wielded_weapon()
947 {
948     const item_def * const wpn = you.weapon();
949     bool penance = false;
950     if (wpn && wpn->defined() && (!is_melee_weapon(*wpn)
951                                    || needs_handle_warning(*wpn,
952                                                            OPER_ATTACK,
953                                                            penance)))
954     {
955         string prompt = "Do you really want to go berserk while wielding "
956                         + wpn->name(DESC_YOUR) + "?";
957         if (penance)
958             prompt += " This could place you under penance!";
959
960         if (!yesno(prompt.c_str(), true, 'n'))
961         {
962             canned_msg(MSG_OK);
963             return false;
964         }
965     }
966
967     return true;
968 }
969
970 // Looks in equipment "slot" to see if there is an equipped "sub_type".
971 // Returns number of matches (in the case of rings, both are checked)
972 int player::wearing(equipment_type slot, int sub_type, bool calc_unid) const
973 {
974     int ret = 0;
975
976     const item_def* item;
977
978     switch (slot)
979     {
980     case EQ_WEAPON:
981         // Hands can have more than just weapons.
982         if (weapon() && weapon()->is_type(OBJ_WEAPONS, sub_type))
983             ret++;
984         break;
985
986     case EQ_STAFF:
987         // Like above, but must be magical staff.
988         if (weapon()
989             && weapon()->is_type(OBJ_STAVES, sub_type)
990             && (calc_unid || item_type_known(*weapon())))
991         {
992             ret++;
993         }
994         break;
995
996     case EQ_RINGS:
997         for (int slots = EQ_LEFT_RING; slots < NUM_EQUIP; slots++)
998         {
999             if (slots == EQ_AMULET)
1000                 continue;
1001
1002             if ((item = slot_item(static_cast<equipment_type>(slots)))
1003                 && item->sub_type == sub_type
1004                 && (calc_unid
1005                     || item_type_known(*item)))
1006             {
1007                 ret++;
1008             }
1009         }
1010         break;
1011
1012     case EQ_RINGS_PLUS:
1013         for (int slots = EQ_LEFT_RING; slots < NUM_EQUIP; slots++)
1014         {
1015             if (slots == EQ_AMULET)
1016                 continue;
1017
1018             if ((item = slot_item(static_cast<equipment_type>(slots)))
1019                 && item->sub_type == sub_type
1020                 && (calc_unid
1021                     || item_type_known(*item)))
1022             {
1023                 ret += item->plus;
1024             }
1025         }
1026         break;
1027
1028     case EQ_ALL_ARMOUR:
1029         // Doesn't make much sense here... be specific. -- bwr
1030         die("EQ_ALL_ARMOUR is not a proper slot");
1031         break;
1032
1033     default:
1034         if (! (slot > EQ_NONE && slot < NUM_EQUIP))
1035             die("invalid slot");
1036         if ((item = slot_item(slot))
1037             && item->sub_type == sub_type
1038             && (calc_unid || item_type_known(*item)))
1039         {
1040             ret++;
1041         }
1042         break;
1043     }
1044
1045     return ret;
1046 }
1047
1048 // Looks in equipment "slot" to see if equipped item has "special" ego-type
1049 // Returns number of matches (jewellery returns zero -- no ego type).
1050 // [ds] There's no equivalent of calc_unid or req_id because as of now, weapons
1051 // and armour type-id on wield/wear.
1052 int player::wearing_ego(equipment_type slot, int special, bool calc_unid) const
1053 {
1054     int ret = 0;
1055
1056     const item_def* item;
1057     switch (slot)
1058     {
1059     case EQ_WEAPON:
1060         // Hands can have more than just weapons.
1061         if ((item = slot_item(EQ_WEAPON))
1062             && item->base_type == OBJ_WEAPONS
1063             && get_weapon_brand(*item) == special)
1064         {
1065             ret++;
1066         }
1067         break;
1068
1069     case EQ_LEFT_RING:
1070     case EQ_RIGHT_RING:
1071     case EQ_AMULET:
1072     case EQ_STAFF:
1073     case EQ_RINGS:
1074     case EQ_RINGS_PLUS:
1075         // no ego types for these slots
1076         break;
1077
1078     case EQ_ALL_ARMOUR:
1079         // Check all armour slots:
1080         for (int i = EQ_MIN_ARMOUR; i <= EQ_MAX_ARMOUR; i++)
1081         {
1082             if ((item = slot_item(static_cast<equipment_type>(i)))
1083                 && get_armour_ego_type(*item) == special
1084                 && (calc_unid || item_type_known(*item)))
1085             {
1086                 ret++;
1087             }
1088         }
1089         break;
1090
1091     default:
1092         if (slot < EQ_MIN_ARMOUR || slot > EQ_MAX_ARMOUR)
1093             die("invalid slot: %d", slot);
1094         // Check a specific armour slot for an ego type:
1095         if ((item = slot_item(static_cast<equipment_type>(slot)))
1096             && get_armour_ego_type(*item) == special
1097             && (calc_unid || item_type_known(*item)))
1098         {
1099             ret++;
1100         }
1101         break;
1102     }
1103
1104     return ret;
1105 }
1106
1107 // Returns true if the indicated unrandart is equipped
1108 // [ds] There's no equivalent of calc_unid or req_id because as of now, weapons
1109 // and armour type-id on wield/wear.
1110 bool player_equip_unrand(int unrand_index)
1111 {
1112     const unrandart_entry* entry = get_unrand_entry(unrand_index);
1113     equipment_type   slot  = get_item_slot(entry->base_type,
1114                                            entry->sub_type);
1115
1116     item_def* item;
1117
1118     switch (slot)
1119     {
1120     case EQ_WEAPON:
1121         // Hands can have more than just weapons.
1122         if ((item = you.slot_item(slot))
1123             && item->base_type == OBJ_WEAPONS
1124             && is_unrandom_artefact(*item)
1125             && item->special == unrand_index)
1126         {
1127             return true;
1128         }
1129         break;
1130
1131     case EQ_RINGS:
1132         for (int slots = EQ_LEFT_RING; slots < NUM_EQUIP; ++slots)
1133         {
1134             if (slots == EQ_AMULET)
1135                 continue;
1136
1137             if ((item = you.slot_item(static_cast<equipment_type>(slots)))
1138                 && is_unrandom_artefact(*item)
1139                 && item->special == unrand_index)
1140             {
1141                 return true;
1142             }
1143         }
1144         break;
1145
1146     case EQ_NONE:
1147     case EQ_STAFF:
1148     case EQ_LEFT_RING:
1149     case EQ_RIGHT_RING:
1150     case EQ_RINGS_PLUS:
1151     case EQ_ALL_ARMOUR:
1152         // no unrandarts for these slots.
1153         break;
1154
1155     default:
1156         if (slot <= EQ_NONE || slot >= NUM_EQUIP)
1157             die("invalid slot: %d", slot);
1158         // Check a specific slot.
1159         if ((item = you.slot_item(slot))
1160             && is_unrandom_artefact(*item)
1161             && item->special == unrand_index)
1162         {
1163             return true;
1164         }
1165         break;
1166     }
1167
1168     return false;
1169 }
1170
1171 // Given an adjacent monster, returns true if the player can hit it (the
1172 // monster should not be submerged, or be submerged in shallow water if
1173 // the player has a polearm).
1174 bool player_can_hit_monster(const monster* mon)
1175 {
1176     if (!mon->submerged())
1177         return true;
1178
1179     if (grd(mon->pos()) != DNGN_SHALLOW_WATER)
1180         return false;
1181
1182     const item_def *weapon = you.weapon();
1183     return weapon && item_attack_skill(*weapon) == SK_POLEARMS;
1184 }
1185
1186 bool player_can_hear(const coord_def& p, int hear_distance)
1187 {
1188     return !silenced(p)
1189            && !silenced(you.pos())
1190            && you.pos().distance_from(p) <= hear_distance;
1191 }
1192
1193 int player_teleport(bool calc_unid)
1194 {
1195     ASSERT(!crawl_state.game_is_arena());
1196
1197     // Don't allow any form of teleportation in Sprint.
1198     if (crawl_state.game_is_sprint())
1199         return 0;
1200
1201     // Short-circuit rings of teleport to prevent spam.
1202     if (you.species == SP_FORMICID)
1203         return 0;
1204
1205     int tp = 0;
1206
1207     // rings (keep in sync with _equip_jewellery_effect)
1208     tp += 8 * you.wearing(EQ_RINGS, RING_TELEPORTATION, calc_unid);
1209
1210     // artefacts
1211     tp += you.scan_artefacts(ARTP_CAUSE_TELEPORTATION, calc_unid);
1212
1213     // mutations
1214     tp += player_mutation_level(MUT_TELEPORT) * 3;
1215
1216     return tp;
1217 }
1218
1219 // Computes bonuses to regeneration from most sources. Does not handle
1220 // slow healing, vampireness, or Trog's Hand.
1221 static int _player_bonus_regen()
1222 {
1223     int rr = 0;
1224
1225     // Trog's Hand is handled separately so that it will bypass slow healing,
1226     // and it overrides the spell.
1227     if (you.duration[DUR_REGENERATION]
1228         && !you.duration[DUR_TROGS_HAND])
1229     {
1230         rr += 100;
1231     }
1232
1233     // Jewellery.
1234     rr += REGEN_PIP * you.wearing(EQ_AMULET, AMU_REGENERATION);
1235
1236     // Artefacts
1237     rr += REGEN_PIP * you.scan_artefacts(ARTP_REGENERATION);
1238
1239     // Troll leather (except for trolls).
1240     if ((you.wearing(EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR)
1241          || you.wearing(EQ_BODY_ARMOUR, ARM_TROLL_HIDE))
1242         && you.species != SP_TROLL)
1243     {
1244         rr += REGEN_PIP;
1245     }
1246
1247     // Fast heal mutation.
1248     rr += player_mutation_level(MUT_REGENERATION) * 20;
1249
1250     // Powered By Death mutation, boosts regen by 10 per corpse in
1251     // a mutation_level * 3 (3/6/9) radius, to a maximum of 7
1252     // corpses.  If and only if the duration of the effect is
1253     // still active.
1254     if (you.duration[DUR_POWERED_BY_DEATH])
1255         rr += handle_pbd_corpses() * 100;
1256
1257     return rr;
1258 }
1259
1260 // Slow healing mutation: slows or stops regeneration when monsters are
1261 // visible at level 1 or 2 respectively, stops regeneration at level 3.
1262 static int _slow_heal_rate()
1263 {
1264     if (player_mutation_level(MUT_SLOW_HEALING) == 3)
1265         return 0;
1266
1267     for (monster_near_iterator mi(you.pos(), LOS_NO_TRANS); mi; ++mi)
1268     {
1269         if (!mons_is_firewood(*mi)
1270             && !mi->wont_attack()
1271             && !mi->neutral())
1272         {
1273             return 2 - player_mutation_level(MUT_SLOW_HEALING);
1274         }
1275     }
1276     return 2;
1277 }
1278
1279 int player_regen()
1280 {
1281     int rr = you.hp_max / 3;
1282
1283     if (rr > 20)
1284         rr = 20 + ((rr - 20) / 2);
1285
1286     // Add in miscellaneous bonuses
1287     rr += _player_bonus_regen();
1288
1289     // Before applying other effects, make sure that there's something
1290     // to heal.
1291     rr = max(1, rr);
1292
1293     // Healing depending on satiation.
1294     // The better-fed you are, the faster you heal.
1295     if (you.species == SP_VAMPIRE)
1296     {
1297         if (you.hunger_state == HS_STARVING)
1298             rr = 0;   // No regeneration for starving vampires.
1299         else if (you.hunger_state == HS_ENGORGED)
1300             rr += 20; // More bonus regeneration for engorged vampires.
1301         else if (you.hunger_state < HS_SATIATED)
1302             rr /= 2;  // Halved regeneration for hungry vampires.
1303         else if (you.hunger_state >= HS_FULL)
1304             rr += 10; // Bonus regeneration for full vampires.
1305     }
1306 #if TAG_MAJOR_VERSION == 34
1307
1308     // Compared to other races, a starting djinni would have regen of 4 (hp)
1309     // plus 17 (mp).  So let's compensate them early; they can stand getting
1310     // shafted on the total regen rates later on.
1311     if (you.species == SP_DJINNI)
1312         if (you.hp_max < 100)
1313             rr += (100 - you.hp_max) / 6;
1314 #endif
1315
1316     // Slow heal mutation.
1317     if (player_mutation_level(MUT_SLOW_HEALING) > 0)
1318     {
1319         rr *= _slow_heal_rate();
1320         rr /= 2;
1321     }
1322     if (you.stat_zero[STAT_STR])
1323         rr /= 4;
1324
1325     if (you.disease)
1326         rr = 0;
1327
1328     // Trog's Hand.  This circumvents the slow healing effect.
1329     if (you.duration[DUR_TROGS_HAND])
1330         rr += 100;
1331
1332     return rr;
1333 }
1334
1335 int player_hunger_rate(bool temp)
1336 {
1337     int hunger = 3;
1338
1339     if (temp && you.form == TRAN_BAT)
1340         return 1;
1341
1342     if (you.species == SP_TROLL)
1343         hunger += 3;            // in addition to the +3 for fast metabolism
1344
1345     if (temp
1346         && (you.duration[DUR_REGENERATION]
1347             || you.duration[DUR_TROGS_HAND])
1348         && you.hp < you.hp_max)
1349     {
1350         hunger += 4;
1351     }
1352
1353     if (temp)
1354     {
1355         if (you.duration[DUR_INVIS])
1356             hunger += 5;
1357
1358         // Berserk has its own food penalty - excluding berserk haste.
1359         // Doubling the hunger cost for haste so that the per turn hunger
1360         // is consistent now that a hasted turn causes 50% the normal hunger
1361         // -cao
1362         if (you.duration[DUR_HASTE])
1363             hunger += haste_mul(5);
1364     }
1365
1366     if (you.species == SP_VAMPIRE)
1367     {
1368         switch (you.hunger_state)
1369         {
1370         case HS_STARVING:
1371         case HS_NEAR_STARVING:
1372             hunger -= 3;
1373             break;
1374         case HS_VERY_HUNGRY:
1375             hunger -= 2;
1376             break;
1377         case HS_HUNGRY:
1378             hunger--;
1379             break;
1380         case HS_SATIATED:
1381             break;
1382         case HS_FULL:
1383             hunger++;
1384             break;
1385         case HS_VERY_FULL:
1386             hunger += 2;
1387             break;
1388         case HS_ENGORGED:
1389             hunger += 3;
1390         }
1391     }
1392     else
1393     {
1394         hunger += player_mutation_level(MUT_FAST_METABOLISM)
1395                 - player_mutation_level(MUT_SLOW_METABOLISM);
1396     }
1397
1398     if (you.hp < you.hp_max
1399         && player_mutation_level(MUT_SLOW_HEALING) < 3)
1400     {
1401         // jewellery
1402         hunger += 3 * you.wearing(EQ_AMULET, AMU_REGENERATION);
1403
1404         // troll leather
1405         if (you.species != SP_TROLL
1406             && (you.wearing(EQ_BODY_ARMOUR, ARM_TROLL_LEATHER_ARMOUR)
1407                 || you.wearing(EQ_BODY_ARMOUR, ARM_TROLL_HIDE)))
1408         {
1409             hunger += coinflip() ? 2 : 1;
1410         }
1411     }
1412
1413     // If Cheibriados has slowed your life processes, you will hunger less.
1414     if (you_worship(GOD_CHEIBRIADOS) && you.piety >= piety_breakpoint(0))
1415         hunger = hunger * 3 / 4;
1416
1417     if (hunger < 1)
1418         hunger = 1;
1419
1420     return hunger;
1421 }
1422
1423 int player_spell_levels()
1424 {
1425     int sl = you.experience_level - 1 + you.skill(SK_SPELLCASTING, 2, true);
1426
1427     bool fireball = false;
1428     bool delayed_fireball = false;
1429
1430     if (sl > 99)
1431         sl = 99;
1432
1433     for (const spell_type spell : you.spells)
1434     {
1435         if (spell == SPELL_FIREBALL)
1436             fireball = true;
1437         else if (spell == SPELL_DELAYED_FIREBALL)
1438             delayed_fireball = true;
1439
1440         if (spell != SPELL_NO_SPELL)
1441             sl -= spell_difficulty(spell);
1442     }
1443
1444     // Fireball is free for characters with delayed fireball
1445     if (fireball && delayed_fireball)
1446         sl += spell_difficulty(SPELL_FIREBALL);
1447
1448     // Note: This can happen because of level drain.  Maybe we should
1449     // force random spells out when that happens. -- bwr
1450     if (sl < 0)
1451         sl = 0;
1452
1453     return sl;
1454 }
1455
1456 int player_likes_chunks(bool permanently)
1457 {
1458     return you.gourmand(true, !permanently)
1459            ? 3 : player_mutation_level(MUT_CARNIVOROUS);
1460 }
1461
1462 // If temp is set to false, temporary sources or resistance won't be counted.
1463 int player_res_fire(bool calc_unid, bool temp, bool items)
1464 {
1465 #if TAG_MAJOR_VERSION == 34
1466     if (you.species == SP_DJINNI)
1467         return 4; // full immunity
1468
1469 #endif
1470     int rf = 0;
1471
1472     if (items)
1473     {
1474         // rings of fire resistance/fire
1475         rf += you.wearing(EQ_RINGS, RING_PROTECTION_FROM_FIRE, calc_unid);
1476         rf += you.wearing(EQ_RINGS, RING_FIRE, calc_unid);
1477
1478         // rings of ice
1479         rf -= you.wearing(EQ_RINGS, RING_ICE, calc_unid);
1480
1481         // Staves
1482         rf += you.wearing(EQ_STAFF, STAFF_FIRE, calc_unid);
1483
1484         // body armour:
1485         const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1486         if (body_armour)
1487             rf += armour_type_prop(body_armour->sub_type, ARMF_RES_FIRE);
1488
1489         // ego armours
1490         rf += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_FIRE_RESISTANCE);
1491         rf += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_RESISTANCE);
1492
1493         // randart weapons:
1494         rf += you.scan_artefacts(ARTP_FIRE, calc_unid);
1495
1496         // dragonskin cloak: 0.5 to draconic resistances
1497         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN)
1498             && coinflip())
1499         {
1500             rf++;
1501         }
1502     }
1503
1504     // species:
1505     if (you.species == SP_MUMMY)
1506         rf--;
1507
1508 #if TAG_MAJOR_VERSION == 34
1509     if (you.species == SP_LAVA_ORC)
1510     {
1511         if (temperature_effect(LORC_FIRE_RES_I))
1512             rf++;
1513         if (temperature_effect(LORC_FIRE_RES_II))
1514             rf++;
1515         if (temperature_effect(LORC_FIRE_RES_III))
1516             rf++;
1517     }
1518 #endif
1519
1520     // mutations:
1521     rf += player_mutation_level(MUT_HEAT_RESISTANCE, temp);
1522     rf -= player_mutation_level(MUT_HEAT_VULNERABILITY, temp);
1523     rf += player_mutation_level(MUT_MOLTEN_SCALES, temp) == 3 ? 1 : 0;
1524
1525     // spells:
1526     if (temp)
1527     {
1528         if (you.duration[DUR_RESISTANCE])
1529             rf++;
1530
1531         if (you.duration[DUR_FIRE_SHIELD])
1532             rf += 2;
1533
1534         if (you.duration[DUR_QAZLAL_FIRE_RES])
1535             rf++;
1536
1537         rf += get_form()->res_fire();
1538     }
1539
1540     if (rf > 3)
1541         rf = 3;
1542     if (temp && you.duration[DUR_FIRE_VULN])
1543         rf--;
1544     if (rf < -3)
1545         rf = -3;
1546
1547     return rf;
1548 }
1549
1550 int player_res_steam(bool calc_unid, bool temp, bool items)
1551 {
1552     int res = 0;
1553     const int rf = player_res_fire(calc_unid, temp, items);
1554
1555     if (you.species == SP_PALE_DRACONIAN)
1556         res += 2;
1557
1558     const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1559     if (body_armour)
1560         res += armour_type_prop(body_armour->sub_type, ARMF_RES_STEAM) * 2;
1561
1562     res += (rf < 0) ? rf
1563                     : (rf + 1) / 2;
1564
1565     if (res > 3)
1566         res = 3;
1567
1568     return res;
1569 }
1570
1571 int player_res_cold(bool calc_unid, bool temp, bool items)
1572 {
1573     int rc = 0;
1574
1575     if (temp)
1576     {
1577         if (you.duration[DUR_RESISTANCE])
1578             rc++;
1579
1580         if (you.duration[DUR_FIRE_SHIELD])
1581             rc -= 2;
1582
1583         if (you.duration[DUR_QAZLAL_COLD_RES])
1584             rc++;
1585
1586         rc += get_form()->res_cold();
1587
1588         if (you.species == SP_VAMPIRE)
1589         {
1590             if (you.hunger_state <= HS_NEAR_STARVING)
1591                 rc += 2;
1592             else if (you.hunger_state < HS_SATIATED)
1593                 rc++;
1594         }
1595
1596 #if TAG_MAJOR_VERSION == 34
1597         if (you.species == SP_LAVA_ORC && temperature_effect(LORC_COLD_VULN))
1598             rc--;
1599 #endif
1600     }
1601
1602     if (items)
1603     {
1604         // rings of cold resistance/ice
1605         rc += you.wearing(EQ_RINGS, RING_PROTECTION_FROM_COLD, calc_unid);
1606         rc += you.wearing(EQ_RINGS, RING_ICE, calc_unid);
1607
1608         // rings of fire
1609         rc -= you.wearing(EQ_RINGS, RING_FIRE, calc_unid);
1610
1611         // Staves
1612         rc += you.wearing(EQ_STAFF, STAFF_COLD, calc_unid);
1613
1614         // body armour:
1615         const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1616         if (body_armour)
1617             rc += armour_type_prop(body_armour->sub_type, ARMF_RES_COLD);
1618
1619         // ego armours
1620         rc += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_COLD_RESISTANCE);
1621         rc += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_RESISTANCE);
1622
1623         // randart weapons:
1624         rc += you.scan_artefacts(ARTP_COLD, calc_unid);
1625
1626         // dragonskin cloak: 0.5 to draconic resistances
1627         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN) && coinflip())
1628             rc++;
1629     }
1630
1631 #if TAG_MAJOR_VERSION == 34
1632     // species:
1633     if (you.species == SP_DJINNI)
1634         rc--;
1635 #endif
1636     // mutations:
1637     rc += player_mutation_level(MUT_COLD_RESISTANCE, temp);
1638     rc -= player_mutation_level(MUT_COLD_VULNERABILITY, temp);
1639     rc += player_mutation_level(MUT_ICY_BLUE_SCALES, temp) == 3 ? 1 : 0;
1640     rc += player_mutation_level(MUT_SHAGGY_FUR, temp) == 3 ? 1 : 0;
1641
1642     if (rc < -3)
1643         rc = -3;
1644     else if (rc > 3)
1645         rc = 3;
1646
1647     return rc;
1648 }
1649
1650 bool player::res_corr(bool calc_unid, bool items) const
1651 {
1652     if (religion == GOD_JIYVA && piety >= piety_breakpoint(2))
1653         return true;
1654
1655     if (get_form()->res_acid())
1656         return true;
1657
1658     if (you.duration[DUR_RESISTANCE])
1659         return true;
1660
1661     if (items)
1662     {
1663         // dragonskin cloak: 0.5 to draconic resistances
1664         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN)
1665             && coinflip())
1666         {
1667             return true;
1668         }
1669     }
1670
1671     if ((form_keeps_mutations() || form == TRAN_DRAGON)
1672         && species == SP_YELLOW_DRACONIAN)
1673     {
1674         return true;
1675     }
1676
1677     if (form_keeps_mutations()
1678         && player_mutation_level(MUT_YELLOW_SCALES) >= 3)
1679     {
1680         return true;
1681     }
1682
1683     return actor::res_corr(calc_unid, items);
1684 }
1685
1686 int player_res_acid(bool calc_unid, bool items)
1687 {
1688     return you.res_corr(calc_unid, items) ? 1 : 0;
1689 }
1690
1691 int player_res_electricity(bool calc_unid, bool temp, bool items)
1692 {
1693     int re = 0;
1694
1695     if (items)
1696     {
1697         // staff
1698         re += you.wearing(EQ_STAFF, STAFF_AIR, calc_unid);
1699
1700         // body armour:
1701         const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1702         if (body_armour)
1703             re += armour_type_prop(body_armour->sub_type, ARMF_RES_ELEC);
1704
1705         // randart weapons:
1706         re += you.scan_artefacts(ARTP_ELECTRICITY, calc_unid);
1707
1708         // dragonskin cloak: 0.5 to draconic resistances
1709         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN) && coinflip())
1710             re++;
1711     }
1712
1713     // mutations:
1714     re += player_mutation_level(MUT_THIN_METALLIC_SCALES, temp) == 3 ? 1 : 0;
1715     re += player_mutation_level(MUT_SHOCK_RESISTANCE, temp);
1716     re -= player_mutation_level(MUT_SHOCK_VULNERABILITY, temp);
1717
1718     if (temp)
1719     {
1720         if (you.attribute[ATTR_DIVINE_LIGHTNING_PROTECTION])
1721             return 3;
1722
1723         if (you.duration[DUR_RESISTANCE])
1724             re++;
1725
1726         if (you.duration[DUR_QAZLAL_ELEC_RES])
1727             re++;
1728
1729         // transformations:
1730         if (get_form()->res_elec())
1731             re++;
1732     }
1733
1734     if (re > 1)
1735         re = 1;
1736
1737     return re;
1738 }
1739
1740 bool player_control_teleport(bool temp)
1741 {
1742     return (temp && you.duration[DUR_CONTROL_TELEPORT])
1743            || crawl_state.game_is_zotdef();
1744 }
1745
1746 /**
1747  * Is the player character immune to torment?
1748  *
1749  * @param random    Whether to include unreliable effects (stochastic resist)
1750  * @param temp      Whether to include temporary effects (forms, statuses...)
1751  * @return          Whether the player resists a given instance of torment; if
1752  *                  random is passed, the result may vary from call to call.
1753  */
1754 bool player_res_torment(bool random, bool temp)
1755 {
1756     if (player_mutation_level(MUT_TORMENT_RESISTANCE))
1757         return true;
1758
1759     if (random
1760         && player_mutation_level(MUT_STOCHASTIC_TORMENT_RESISTANCE)
1761         && coinflip())
1762     {
1763         return true;
1764     }
1765
1766     if (!temp)
1767         return false;
1768
1769     return get_form()->res_neg() == 3
1770            || you.species == SP_VAMPIRE && you.hunger_state == HS_STARVING
1771            || you.petrified();
1772 }
1773
1774 // Kiku protects you from torment to a degree.
1775 bool player_kiku_res_torment()
1776 {
1777     return in_good_standing(GOD_KIKUBAAQUDGHA, 3)
1778            && !you.gift_timeout; // no protection during pain branding weapon
1779 }
1780
1781 // If temp is set to false, temporary sources or resistance won't be counted.
1782 int player_res_poison(bool calc_unid, bool temp, bool items)
1783 {
1784     switch (you.undead_state(temp))
1785     {
1786         case US_ALIVE:
1787             break;
1788         case US_HUNGRY_DEAD: //ghouls
1789         case US_UNDEAD: // mummies & lichform
1790             return 3;
1791         case US_SEMI_UNDEAD: // vampire
1792             if (you.hunger_state == HS_STARVING) // XXX: && temp?
1793                 return 3;
1794             break;
1795     }
1796
1797     if (you.is_artificial(temp)
1798         || temp && get_form()->res_pois() == 3
1799         || items && player_equip_unrand(UNRAND_OLGREB)
1800         || temp && you.duration[DUR_DIVINE_STAMINA])
1801     {
1802         return 3;
1803     }
1804
1805     int rp = 0;
1806
1807     const int artefact_rp = you.scan_artefacts(ARTP_POISON, calc_unid);
1808
1809     if (items)
1810     {
1811         // rings of poison resistance
1812         rp += you.wearing(EQ_RINGS, RING_POISON_RESISTANCE, calc_unid);
1813
1814         // Staves
1815         rp += you.wearing(EQ_STAFF, STAFF_POISON, calc_unid);
1816
1817         // ego armour:
1818         rp += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_POISON_RESISTANCE);
1819
1820         // body armour:
1821         const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1822         if (body_armour)
1823             rp += armour_type_prop(body_armour->sub_type, ARMF_RES_POISON);
1824
1825         // rPois+ artefacts
1826         if (artefact_rp > 0)
1827             rp += artefact_rp;
1828
1829         // dragonskin cloak: 0.5 to draconic resistances
1830         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN) && coinflip())
1831             rp++;
1832     }
1833
1834     // mutations:
1835     rp += player_mutation_level(MUT_POISON_RESISTANCE, temp);
1836     rp += player_mutation_level(MUT_SLIMY_GREEN_SCALES, temp) == 3 ? 1 : 0;
1837
1838     // Only thirsty vampires are naturally poison resistant.
1839     // XXX: && temp?
1840     if (you.species == SP_VAMPIRE && you.hunger_state < HS_SATIATED)
1841         rp++;
1842
1843     if (temp)
1844     {
1845         // potions/cards:
1846         if (you.duration[DUR_RESISTANCE])
1847             rp++;
1848
1849         if (get_form()->res_pois() > 0)
1850             rp++;
1851     }
1852
1853     // Cap rPois at + before vulnerability effects are applied
1854     // (so carrying multiple rPois effects is never useful)
1855     rp = min(1, rp);
1856
1857     if (temp)
1858     {
1859         if (get_form()->res_pois() < 0)
1860             rp--;
1861
1862         if (you.duration[DUR_POISON_VULN])
1863             rp--;
1864     }
1865
1866     // rPois- artefacts
1867     if (items && artefact_rp < 0)
1868         rp += artefact_rp; // actually subtracts...
1869
1870     // don't allow rPois--, etc.
1871     rp = max(-1, rp);
1872
1873     return rp;
1874 }
1875
1876 int player_res_sticky_flame(bool calc_unid, bool temp, bool items)
1877 {
1878     int rsf = 0;
1879
1880     if (you.species == SP_MOTTLED_DRACONIAN)
1881         rsf++;
1882
1883     const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
1884     if (body_armour)
1885         rsf += armour_type_prop(body_armour->sub_type, ARMF_RES_STICKY_FLAME);
1886
1887     // dragonskin cloak: 0.5 to draconic resistances
1888     if (items && calc_unid
1889         && player_equip_unrand(UNRAND_DRAGONSKIN) && coinflip())
1890     {
1891         rsf++;
1892     }
1893
1894     if (get_form()->res_sticky_flame())
1895         rsf++;
1896
1897     if (rsf > 1)
1898         rsf = 1;
1899
1900     return rsf;
1901 }
1902
1903 int player_spec_death()
1904 {
1905     int sd = 0;
1906
1907     // Staves
1908     sd += you.wearing(EQ_STAFF, STAFF_DEATH);
1909
1910     // species:
1911     if (you.species == SP_MUMMY)
1912     {
1913         if (you.experience_level >= 13)
1914             sd++;
1915         if (you.experience_level >= 26)
1916             sd++;
1917     }
1918
1919     // transformations:
1920     if (you.form == TRAN_LICH)
1921         sd++;
1922
1923     return sd;
1924 }
1925
1926 int player_spec_fire()
1927 {
1928     int sf = 0;
1929
1930     // staves:
1931     sf += you.wearing(EQ_STAFF, STAFF_FIRE);
1932
1933     // rings of fire:
1934     sf += you.wearing(EQ_RINGS, RING_FIRE);
1935
1936 #if TAG_MAJOR_VERSION == 34
1937     if (you.species == SP_LAVA_ORC && temperature_effect(LORC_FIRE_BOOST))
1938         sf++;
1939 #endif
1940
1941     if (you.duration[DUR_FIRE_SHIELD])
1942         sf++;
1943
1944     return sf;
1945 }
1946
1947 int player_spec_cold()
1948 {
1949     int sc = 0;
1950
1951     // staves:
1952     sc += you.wearing(EQ_STAFF, STAFF_COLD);
1953
1954     // rings of ice:
1955     sc += you.wearing(EQ_RINGS, RING_ICE);
1956
1957 #if TAG_MAJOR_VERSION == 34
1958     if (you.species == SP_LAVA_ORC
1959         && (temperature_effect(LORC_LAVA_BOOST)
1960             || temperature_effect(LORC_FIRE_BOOST)))
1961     {
1962         sc--;
1963     }
1964 #endif
1965
1966     return sc;
1967 }
1968
1969 int player_spec_earth()
1970 {
1971     int se = 0;
1972
1973     // Staves
1974     se += you.wearing(EQ_STAFF, STAFF_EARTH);
1975
1976     return se;
1977 }
1978
1979 int player_spec_air()
1980 {
1981     int sa = 0;
1982
1983     // Staves
1984     sa += you.wearing(EQ_STAFF, STAFF_AIR);
1985
1986     return sa;
1987 }
1988
1989 int player_spec_conj()
1990 {
1991     int sc = 0;
1992
1993     // Staves
1994     sc += you.wearing(EQ_STAFF, STAFF_CONJURATION);
1995
1996     return sc;
1997 }
1998
1999 int player_spec_hex()
2000 {
2001     return 0;
2002 }
2003
2004 int player_spec_charm()
2005 {
2006     // Nothing, for the moment.
2007     return 0;
2008 }
2009
2010 int player_spec_summ()
2011 {
2012     int ss = 0;
2013
2014     // Staves
2015     ss += you.wearing(EQ_STAFF, STAFF_SUMMONING);
2016
2017     return ss;
2018 }
2019
2020 int player_spec_poison()
2021 {
2022     int sp = 0;
2023
2024     // Staves
2025     sp += you.wearing(EQ_STAFF, STAFF_POISON);
2026
2027     if (player_equip_unrand(UNRAND_OLGREB))
2028         sp++;
2029
2030     return sp;
2031 }
2032
2033 int player_energy()
2034 {
2035     int pe = 0;
2036
2037     // Staves
2038     pe += you.wearing(EQ_STAFF, STAFF_ENERGY);
2039
2040     return pe;
2041 }
2042
2043 // If temp is set to false, temporary sources of resistance won't be
2044 // counted.
2045 int player_prot_life(bool calc_unid, bool temp, bool items)
2046 {
2047     int pl = 0;
2048
2049     // Hunger is temporary, true, but that's something you can control,
2050     // especially as life protection only increases the hungrier you
2051     // get.
2052     if (you.species == SP_VAMPIRE)
2053     {
2054         switch (you.hunger_state)
2055         {
2056         case HS_STARVING:
2057         case HS_NEAR_STARVING:
2058             pl = 3;
2059             break;
2060         case HS_VERY_HUNGRY:
2061         case HS_HUNGRY:
2062             pl = 2;
2063             break;
2064         case HS_SATIATED:
2065             pl = 1;
2066             break;
2067         default:
2068             break;
2069         }
2070     }
2071
2072     // Same here. Your piety status, and, hence, TSO's protection, is
2073     // something you can more or less control.
2074     if (you_worship(GOD_SHINING_ONE))
2075     {
2076         if (you.piety >= piety_breakpoint(1))
2077             pl++;
2078         if (you.piety >= piety_breakpoint(3))
2079             pl++;
2080         if (you.piety >= piety_breakpoint(5))
2081             pl++;
2082     }
2083
2084     if (temp)
2085     {
2086         pl += get_form()->res_neg();
2087
2088         // completely stoned, unlike statue which has some life force
2089         if (you.petrified())
2090             pl += 3;
2091     }
2092
2093     if (items)
2094     {
2095         if (you.wearing(EQ_AMULET, AMU_WARDING, calc_unid))
2096             pl++;
2097
2098         // rings
2099         pl += you.wearing(EQ_RINGS, RING_LIFE_PROTECTION, calc_unid);
2100
2101         // armour (checks body armour only)
2102         pl += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_POSITIVE_ENERGY);
2103
2104         // pearl dragon counts
2105         const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
2106         if (body_armour)
2107             pl += armour_type_prop(body_armour->sub_type, ARMF_RES_NEG);
2108
2109         // randart wpns
2110         pl += you.scan_artefacts(ARTP_NEGATIVE_ENERGY, calc_unid);
2111
2112         // dragonskin cloak: 0.5 to draconic resistances
2113         // this one is dubious (no pearl draconians)
2114         if (calc_unid && player_equip_unrand(UNRAND_DRAGONSKIN) && coinflip())
2115             pl++;
2116
2117         pl += you.wearing(EQ_STAFF, STAFF_DEATH, calc_unid);
2118     }
2119
2120     // undead/demonic power
2121     pl += player_mutation_level(MUT_NEGATIVE_ENERGY_RESISTANCE, temp);
2122
2123     pl = min(3, pl);
2124
2125     return pl;
2126 }
2127
2128 // New player movement speed system... allows for a bit more than
2129 // "player runs fast" and "player walks slow" in that the speed is
2130 // actually calculated (allowing for centaurs to get a bonus from
2131 // swiftness and other such things).  Levels of the mutation now
2132 // also have meaning (before they all just meant fast).  Most of
2133 // this isn't as fast as it used to be (6 for having anything), but
2134 // even a slight speed advantage is very good... and we certainly don't
2135 // want to go past 6 (see below). -- bwr
2136 int player_movement_speed()
2137 {
2138     int mv = 10;
2139
2140     // transformations
2141     if (you.form == TRAN_BAT)
2142         mv = 5; // but allowed minimum is six
2143     else if (you.form == TRAN_PIG)
2144         mv = 7;
2145     else if (you.form == TRAN_PORCUPINE || you.form == TRAN_WISP)
2146         mv = 8;
2147     else if (you.fishtail || you.form == TRAN_HYDRA && you.in_water())
2148         mv = 6;
2149
2150     // moving on liquefied ground takes longer
2151     if (you.liquefied_ground())
2152         mv += 3;
2153
2154     // armour
2155     if (you.run())
2156         mv -= 1;
2157
2158     mv += you.wearing_ego(EQ_ALL_ARMOUR, SPARM_PONDEROUSNESS);
2159
2160     // Cheibriados
2161     if (you_worship(GOD_CHEIBRIADOS))
2162         mv += 2 + min(div_rand_round(you.piety, 20), 8);
2163
2164     // Tengu can move slightly faster when flying.
2165     if (you.tengu_flight())
2166         mv--;
2167
2168     if (you.duration[DUR_FROZEN])
2169         mv += 4;
2170
2171     if (you.duration[DUR_GRASPING_ROOTS])
2172         mv += 3;
2173
2174     // Mutations: -2, -3, -4, unless innate and shapechanged.
2175     if (int fast = player_mutation_level(MUT_FAST))
2176         mv -= fast + 1;
2177
2178     if (int slow = player_mutation_level(MUT_SLOW))
2179     {
2180         mv *= 10 + slow * 2;
2181         mv /= 10;
2182     }
2183
2184     if (you.duration[DUR_SWIFTNESS] > 0 && !you.in_liquid())
2185     {
2186         if (you.attribute[ATTR_SWIFTNESS] > 0)
2187           mv = div_rand_round(3*mv, 4);
2188         else if (mv >= 8)
2189           mv = div_rand_round(3*mv, 2);
2190         else if (mv == 7)
2191           mv = div_rand_round(7*6, 5); // balance for the cap at 6
2192     }
2193
2194     // We'll use the old value of six as a minimum, with haste this could
2195     // end up as a speed of three, which is about as fast as we want
2196     // the player to be able to go (since 3 is 3.33x as fast and 2 is 5x,
2197     // which is a bit of a jump, and a bit too fast) -- bwr
2198     // Currently Haste takes 6 to 4, which is 2.5x as fast as delay 10
2199     // and still seems plenty fast. -- elliptic
2200     if (mv < FASTEST_PLAYER_MOVE_SPEED)
2201         mv = FASTEST_PLAYER_MOVE_SPEED;
2202
2203     return mv;
2204 }
2205
2206 // This function differs from the above in that it's used to set the
2207 // initial time_taken value for the turn.  Everything else (movement,
2208 // spellcasting, combat) applies a ratio to this value.
2209 int player_speed()
2210 {
2211     int ps = 10;
2212
2213     // When paralysed, speed is irrelevant.
2214     if (you.cannot_act())
2215         return ps;
2216
2217     for (int i = 0; i < NUM_STATS; ++i)
2218         if (you.stat_zero[i])
2219             ps *= 2;
2220
2221     if (you.duration[DUR_SLOW])
2222         ps = haste_mul(ps);
2223
2224     if (you.duration[DUR_BERSERK] && !you_worship(GOD_CHEIBRIADOS))
2225         ps = berserk_div(ps);
2226     else if (you.duration[DUR_HASTE])
2227         ps = haste_div(ps);
2228
2229     if (you.form == TRAN_STATUE || you.duration[DUR_PETRIFYING])
2230     {
2231         ps *= 15;
2232         ps /= 10;
2233     }
2234
2235     return ps;
2236 }
2237
2238 // Get level of player mutation, ignoring mutations with an activity level
2239 // less than minact.
2240 static int _mut_level(mutation_type mut, mutation_activity_type minact)
2241 {
2242     const int mlevel = you.mutation[mut];
2243
2244     const mutation_activity_type active = mutation_activity_level(mut);
2245
2246     if (active >= minact)
2247         return mlevel;
2248
2249     return 0;
2250 }
2251
2252 // Output level of player mutation.  If temp is true (the default), take into
2253 // account the suppression of mutations by changes of form.
2254 int player_mutation_level(mutation_type mut, bool temp)
2255 {
2256     return _mut_level(mut, temp ? MUTACT_PARTIAL : MUTACT_INACTIVE);
2257 }
2258
2259 static int _player_armour_beogh_bonus(const item_def& item)
2260 {
2261     if (item.base_type != OBJ_ARMOUR)
2262         return 0;
2263
2264     int bonus = 0;
2265
2266     if (in_good_standing(GOD_BEOGH))
2267     {
2268         if (you.piety >= piety_breakpoint(5))
2269             bonus = 10;
2270         else if (you.piety >= piety_breakpoint(4))
2271             bonus = 8;
2272         else if (you.piety >= piety_breakpoint(2))
2273             bonus = 6;
2274         else if (you.piety >= piety_breakpoint(0))
2275             bonus = 4;
2276         else
2277             bonus = 2;
2278     }
2279
2280     return bonus;
2281 }
2282
2283 bool is_effectively_light_armour(const item_def *item)
2284 {
2285     return !item
2286            || (abs(property(*item, PARM_EVASION)) / 10 < 5);
2287 }
2288
2289 bool player_effectively_in_light_armour()
2290 {
2291     const item_def *armour = you.slot_item(EQ_BODY_ARMOUR, false);
2292     return is_effectively_light_armour(armour);
2293 }
2294
2295 // This function returns true if the player has a radically different
2296 // shape... minor changes like blade hands don't count, also note
2297 // that lich transformation doesn't change the character's shape
2298 // (so we end up with Naga-liches, Spriggan-liches, Minotaur-liches)
2299 // it just makes the character undead (with the benefits that implies). - bwr
2300 bool player_is_shapechanged()
2301 {
2302     if (you.form == TRAN_NONE
2303         || you.form == TRAN_BLADE_HANDS
2304         || you.form == TRAN_LICH
2305         || you.form == TRAN_SHADOW
2306         || you.form == TRAN_APPENDAGE)
2307     {
2308         return false;
2309     }
2310
2311     return true;
2312 }
2313
2314 // An evasion factor based on the player's body size, smaller == higher
2315 // evasion size factor.
2316 static int _player_evasion_size_factor()
2317 {
2318     // XXX: you.body_size() implementations are incomplete, fix.
2319     const size_type size = you.body_size(PSIZE_BODY);
2320     return 2 * (SIZE_MEDIUM - size);
2321 }
2322
2323 // Determines racial shield penalties (formicids get a bonus compared to
2324 // other medium-sized races)
2325 static int _player_shield_racial_factor()
2326 {
2327     return max(1, 5 + (you.species == SP_FORMICID ? -2 // Same as trolls/centaurs/etc.
2328                                                   : _player_evasion_size_factor()));
2329 }
2330
2331 // The total EV penalty to the player for all their worn armour items
2332 // with a base EV penalty (i.e. EV penalty as a base armour property,
2333 // not as a randart property).
2334 static int _player_adjusted_evasion_penalty(const int scale)
2335 {
2336     int piece_armour_evasion_penalty = 0;
2337
2338     // Some lesser armours have small penalties now (barding).
2339     for (int i = EQ_MIN_ARMOUR; i < EQ_MAX_ARMOUR; i++)
2340     {
2341         if (i == EQ_SHIELD || !player_wearing_slot(i))
2342             continue;
2343
2344         // [ds] Evasion modifiers for armour are negatives, change
2345         // those to positive for penalty calc.
2346         const int penalty = (-property(you.inv[you.equip[i]], PARM_EVASION))/3;
2347         if (penalty > 0)
2348             piece_armour_evasion_penalty += penalty;
2349     }
2350
2351     return piece_armour_evasion_penalty * scale / 10 +
2352            you.adjusted_body_armour_penalty(scale) ;
2353 }
2354
2355 // EV bonuses that work even when helpless.
2356 static int _player_para_evasion_bonuses(ev_ignore_type evit)
2357 {
2358     int evbonus = 0;
2359
2360     if (you.duration[DUR_PHASE_SHIFT] && !(evit & EV_IGNORE_PHASESHIFT))
2361         evbonus += 8;
2362
2363     if (player_mutation_level(MUT_DISTORTION_FIELD) > 0)
2364         evbonus += player_mutation_level(MUT_DISTORTION_FIELD) + 1;
2365
2366     return evbonus;
2367 }
2368
2369 // Player EV bonuses for various effects and transformations. This
2370 // does not include tengu/merfolk EV bonuses for flight/swimming.
2371 static int _player_evasion_bonuses(ev_ignore_type evit)
2372 {
2373     int evbonus = _player_para_evasion_bonuses(evit);
2374
2375     if (you.duration[DUR_AGILITY])
2376         evbonus += AGILITY_BONUS;
2377
2378     evbonus += you.wearing(EQ_RINGS_PLUS, RING_EVASION);
2379
2380     if (you.wearing_ego(EQ_WEAPON, SPWPN_EVASION))
2381         evbonus += 5;
2382
2383     evbonus += you.scan_artefacts(ARTP_EVASION);
2384
2385     // mutations
2386     if (_mut_level(MUT_ICY_BLUE_SCALES, MUTACT_FULL) > 1)
2387         evbonus--;
2388     if (_mut_level(MUT_MOLTEN_SCALES, MUTACT_FULL) > 1)
2389         evbonus--;
2390     evbonus += max(0, player_mutation_level(MUT_GELATINOUS_BODY) - 1);
2391
2392     // transformation penalties/bonuses not covered by size alone:
2393     if (player_mutation_level(MUT_SLOW_REFLEXES))
2394         evbonus -= player_mutation_level(MUT_SLOW_REFLEXES) * 3;
2395
2396     return evbonus;
2397 }
2398
2399 // Player EV scaling for being flying tengu or swimming merfolk.
2400 static int _player_scale_evasion(int prescaled_ev, const int scale)
2401 {
2402     if (you.duration[DUR_PETRIFYING] || you.caught())
2403         prescaled_ev /= 2;
2404     else if  (you.duration[DUR_GRASPING_ROOTS])
2405         prescaled_ev = prescaled_ev * 2 / 3;
2406
2407     switch (you.species)
2408     {
2409     case SP_MERFOLK:
2410         // Merfolk get an evasion bonus in water.
2411         if (you.fishtail)
2412         {
2413             const int ev_bonus = min(9 * scale,
2414                                      max(2 * scale, prescaled_ev / 4));
2415             return prescaled_ev + ev_bonus;
2416         }
2417         break;
2418
2419     case SP_TENGU:
2420         // Flying Tengu get an evasion bonus.
2421         if (you.flight_mode())
2422         {
2423             const int ev_bonus = min(9 * scale,
2424                                      max(1 * scale, prescaled_ev / 5));
2425             return prescaled_ev + ev_bonus;
2426         }
2427         break;
2428
2429     default:
2430         break;
2431     }
2432     return prescaled_ev;
2433 }
2434
2435 /**
2436  * What is the player's bonus to EV from dodging when not paralyzed, after
2437  * accounting for size & body armour penalties?
2438  *
2439  * First, calculate base dodge bonus (linear with dodging * stepdowned dex),
2440  * and armour dodge penalty (base armour evp, increased for small races &
2441  * decreased for large, then with a magic "3" subtracted from it to make the
2442  * penalties not too harsh).
2443  *
2444  * If the player's strength is greater than the armour dodge penalty, return
2445  *      base dodge * (1 - dodge_pen / (str*2)).
2446  * E.g., if str is twice dodge penalty, return 3/4 of base dodge. If
2447  * str = dodge_pen * 4, return 7/8...
2448  *
2449  * If str is less than dodge penalty, return
2450  *      base_dodge * str / (dodge_pen * 2).
2451  * E.g., if str = dodge_pen / 2, return 1/4 of base dodge. if
2452  * str = dodge_pen / 4, return 1/8...
2453  *
2454  * For either equation, if str = dodge_pen, the result is base_dodge/2.
2455  *
2456  * @param scale     A scale to multiply the result by, to avoid precision loss.
2457  * @return          A bonus to EV, multiplied by the scale.
2458  */
2459 static int _player_armour_adjusted_dodge_bonus(int scale)
2460 {
2461     // stepdowns at 10 and 24 dex; the last two parameters are not important.
2462     const int ev_dex = stepdown_value(you.dex(), 10, 24, 72, 72);
2463
2464     const int dodge_bonus =
2465         (70 + you.skill(SK_DODGING, 10) * ev_dex) * scale
2466         / (20 - _player_evasion_size_factor()) / 10;
2467
2468     const int armour_dodge_penalty = you.unadjusted_body_armour_penalty() - 3;
2469     if (armour_dodge_penalty <= 0)
2470         return dodge_bonus;
2471
2472     const int str = max(1, you.strength());
2473     if (armour_dodge_penalty >= str)
2474         return dodge_bonus * str / (armour_dodge_penalty * 2);
2475     return dodge_bonus - dodge_bonus * armour_dodge_penalty / (str * 2);
2476 }
2477
2478 // Total EV for player using the revised 0.6 evasion model.
2479 int player_evasion(ev_ignore_type evit)
2480 {
2481     const int size_factor = _player_evasion_size_factor();
2482     // Repulsion fields and size are all that matters when paralysed or
2483     // at 0 dex.
2484     if ((you.cannot_move() || you.stat_zero[STAT_DEX] || you.form == TRAN_TREE)
2485         && !(evit & EV_IGNORE_HELPLESS))
2486     {
2487         const int paralysed_base_ev = 2 + size_factor / 2;
2488         const int repulsion_ev = _player_para_evasion_bonuses(evit);
2489         return max(1, paralysed_base_ev + repulsion_ev);
2490     }
2491
2492     const int scale = 100;
2493     const int size_base_ev = (10 + size_factor) * scale;
2494
2495     const int prestepdown_evasion =
2496         size_base_ev
2497         + _player_armour_adjusted_dodge_bonus(scale)
2498         - _player_adjusted_evasion_penalty(scale)
2499         - you.adjusted_shield_penalty(scale);
2500
2501     const int poststepdown_evasion =
2502         stepdown_value(prestepdown_evasion, 20*scale, 30*scale, 60*scale, -1);
2503
2504     const int evasion_bonuses = _player_evasion_bonuses(evit) * scale;
2505
2506     const int prescaled_evasion =
2507         poststepdown_evasion + evasion_bonuses;
2508
2509     const int final_evasion =
2510         _player_scale_evasion(prescaled_evasion, scale);
2511
2512     return unscale_round_up(final_evasion, scale);
2513 }
2514
2515 // Returns the spellcasting penalty (increase in spell failure) for the
2516 // player's worn body armour and shield.
2517 int player_armour_shield_spell_penalty()
2518 {
2519     const int scale = 100;
2520
2521     const int body_armour_penalty =
2522         max(19 * you.adjusted_body_armour_penalty(scale), 0);
2523
2524     const int total_penalty = body_armour_penalty
2525                  + 19 * you.adjusted_shield_penalty(scale);
2526
2527     return max(total_penalty, 0) / scale;
2528 }
2529
2530 /**
2531  * How many spell-success-chance-boosting ('wizardry') effects can the player
2532  * apply to the given spell?
2533  *
2534  * @param spell     The type of spell being cast.
2535  * @return          The number of relevant wizardry effects.
2536  */
2537 int player_wizardry(spell_type spell)
2538 {
2539     return you.wearing(EQ_RINGS, RING_WIZARDRY)
2540            + you.wearing(EQ_STAFF, STAFF_WIZARDRY);
2541 }
2542
2543 /**
2544  * Calculate the SH value used internally.
2545  *
2546  * Exactly twice the value displayed to players, for legacy reasons.
2547  * @return      The player's current SH value.
2548  */
2549 int player_shield_class()
2550 {
2551     int shield = 0;
2552
2553     if (you.incapacitated())
2554         return 0;
2555
2556     if (player_wearing_slot(EQ_SHIELD))
2557     {
2558         const item_def& item = you.inv[you.equip[EQ_SHIELD]];
2559         int size_factor = (you.body_size(PSIZE_TORSO) - SIZE_MEDIUM)
2560                         * (item.sub_type - ARM_LARGE_SHIELD);
2561         int base_shield = property(item, PARM_AC) * 2 + size_factor;
2562
2563         int beogh_bonus = _player_armour_beogh_bonus(item);
2564
2565         // bonus applied only to base, see above for effect:
2566         shield += base_shield * 50;
2567         shield += base_shield * you.skill(SK_SHIELDS, 5) / 2;
2568         shield += base_shield * beogh_bonus * 10 / 6;
2569
2570         shield += item.plus * 200;
2571
2572         shield += you.skill(SK_SHIELDS, 38)
2573                 + min(you.skill(SK_SHIELDS, 38), 3 * 38);
2574
2575         int stat = 0;
2576         if (item.sub_type == ARM_BUCKLER)
2577             stat = you.dex() * 38;
2578         else if (item.sub_type == ARM_LARGE_SHIELD)
2579             stat = you.dex() * 12 + you.strength() * 26;
2580         else
2581             stat = you.dex() * 19 + you.strength() * 19;
2582         stat = stat * (base_shield + 13) / 26;
2583
2584         shield += stat;
2585     }
2586     else
2587     {
2588         if (you.duration[DUR_MAGIC_SHIELD])
2589             shield += 900 + you.skill(SK_EVOCATIONS, 75);
2590
2591         if (you.duration[DUR_CONDENSATION_SHIELD])
2592             shield += 800 + you.props[CONDENSATION_SHIELD_KEY].get_int() * 15;
2593     }
2594
2595     // mutations
2596     // +2, +3, +4 (displayed values)
2597     shield += (player_mutation_level(MUT_LARGE_BONE_PLATES) > 0
2598                ? player_mutation_level(MUT_LARGE_BONE_PLATES) * 200 + 200
2599                : 0);
2600
2601     shield += qazlal_sh_boost() * 100;
2602     shield += tso_sh_boost() * 100;
2603     shield += _bone_armour_bonus() * 2;
2604
2605     return (shield + 50) / 100;
2606 }
2607
2608 /**
2609  * Calculate the SH value that should be displayed to players.
2610  *
2611  * Exactly half the internal value, for legacy reasons.
2612  * @return      The SH value to be displayed.
2613  */
2614 int player_displayed_shield_class()
2615 {
2616     return player_shield_class() / 2;
2617 }
2618
2619 /**
2620  * Does the player take halved ability damage?
2621  *
2622  * @param calc_unid     Whether to include properties of worn but unidentified
2623  *                      items in the calculation. (Probably irrelevant.)
2624  * @return              Whether the player has SustAb.
2625  */
2626 bool player_sust_abil(bool calc_unid)
2627 {
2628     return you.wearing(EQ_RINGS, RING_SUSTAIN_ABILITIES, calc_unid)
2629            || you.scan_artefacts(ARTP_SUSTAB)
2630            || player_mutation_level(MUT_SUSTAIN_ABILITIES);
2631 }
2632
2633 void forget_map(bool rot)
2634 {
2635     ASSERT(!crawl_state.game_is_arena());
2636
2637     // If forgetting was intentional, clear the travel trail.
2638     if (!rot)
2639         clear_travel_trail();
2640
2641     // Labyrinth and the Abyss use special rotting rules.
2642     const bool rot_resist = player_in_branch(BRANCH_LABYRINTH)
2643                                 && you.species == SP_MINOTAUR
2644                             || player_in_branch(BRANCH_ABYSS)
2645                                 && you_worship(GOD_LUGONU);
2646     const double geometric_chance = 0.99;
2647     const int radius = (rot_resist ? 200 : 100);
2648
2649     const int scalar = 0xFF;
2650     for (rectangle_iterator ri(0); ri; ++ri)
2651     {
2652         const coord_def &p = *ri;
2653         if (!env.map_knowledge(p).known() || you.see_cell(p))
2654             continue;
2655
2656         if (rot)
2657         {
2658             const int dist = distance2(you.pos(), p);
2659             int chance = pow(geometric_chance,
2660                              max(1, (dist - radius) / 40)) * scalar;
2661             if (x_chance_in_y(chance, scalar))
2662                 continue;
2663         }
2664
2665         if (you.see_cell(p))
2666             continue;
2667
2668         env.map_knowledge(p).clear();
2669         if (env.map_forgotten.get())
2670             (*env.map_forgotten.get())(p).clear();
2671         StashTrack.update_stash(p);
2672 #ifdef USE_TILE
2673         tile_forget_map(p);
2674 #endif
2675     }
2676
2677     ash_detect_portals(is_map_persistent());
2678 #ifdef USE_TILE
2679     tiles.update_minimap_bounds();
2680 #endif
2681 }
2682
2683 static void _remove_temp_mutation()
2684 {
2685     int num_remove = min(you.attribute[ATTR_TEMP_MUTATIONS],
2686         max(you.attribute[ATTR_TEMP_MUTATIONS] * 5 / 12 - random2(3),
2687         2 + random2(3)));
2688
2689     if (num_remove >= you.attribute[ATTR_TEMP_MUTATIONS])
2690         mprf(MSGCH_DURATION, "You feel the corruption within you wane completely.");
2691     else
2692         mprf(MSGCH_DURATION, "You feel the corruption within you wane somewhat.");
2693
2694     for (int i = 0; i < num_remove; ++i)
2695         delete_temp_mutation();
2696
2697     if (you.attribute[ATTR_TEMP_MUTATIONS] > 0)
2698     {
2699         you.attribute[ATTR_TEMP_MUT_XP] +=
2700             min(you.experience_level, 17) * (350 + roll_dice(5, 350)) / 17;
2701     }
2702 }
2703
2704 int get_exp_progress()
2705 {
2706     if (you.experience_level >= you.props[MAX_XP_KEY].get_int())
2707         return 0;
2708
2709     const int current = exp_needed(you.experience_level);
2710     const int next    = exp_needed(you.experience_level + 1);
2711     if (next == current)
2712         return 0;
2713     return (you.experience - current) * 100 / (next - current);
2714 }
2715
2716 static void _recharge_xp_evokers(int exp)
2717 {
2718     FixedVector<item_def*, NUM_MISCELLANY> evokers(nullptr);
2719     list_charging_evokers(evokers);
2720
2721     int xp_factor = max(min((int)exp_needed(you.experience_level+1, 0) * 2 / 7,
2722                              you.experience_level * 425),
2723                         you.experience_level*4 + 30)
2724                     / (3 + you.skill_rdiv(SK_EVOCATIONS, 2, 13));
2725
2726     for (int i = 0; i < NUM_MISCELLANY; ++i)
2727     {
2728         item_def* evoker = evokers[i];
2729         if (!evoker)
2730             continue;
2731
2732         int &debt = evoker_debt(evoker->sub_type);
2733         if (debt == 0)
2734             continue;
2735
2736         debt = max(0, debt - div_rand_round(exp, xp_factor));
2737         if (debt == 0)
2738             mprf("%s has recharged.", evoker->name(DESC_YOUR).c_str());
2739     }
2740 }
2741
2742 void gain_exp(unsigned int exp_gained, unsigned int* actual_gain)
2743 {
2744     if (crawl_state.game_is_arena())
2745         return;
2746
2747     if (crawl_state.game_is_zotdef())
2748     {
2749         you.zot_points += exp_gained;
2750         // All XP, for some reason Sprint speeds up only skill training,
2751         // but not levelling, Ash skill transfer, etc.
2752         exp_gained *= 2;
2753     }
2754
2755     if (player_under_penance(GOD_ASHENZARI))
2756         ash_reduce_penance(exp_gained);
2757
2758     const unsigned int old_exp = you.experience;
2759
2760     dprf("gain_exp: %d", exp_gained);
2761
2762     if (you.transfer_skill_points > 0)
2763     {
2764         // Can happen if the game got interrupted during target skill choice.
2765         if (is_invalid_skill(you.transfer_to_skill))
2766         {
2767             you.transfer_from_skill = SK_NONE;
2768             you.transfer_skill_points = 0;
2769             you.transfer_total_skill_points = 0;
2770         }
2771         else
2772         {
2773             int amount = exp_gained * 10
2774                                 / calc_skill_cost(you.skill_cost_level);
2775             if (amount >= 20 || one_chance_in(20 - amount))
2776             {
2777                 amount = max(20, amount);
2778                 transfer_skill_points(you.transfer_from_skill,
2779                                       you.transfer_to_skill, amount, false);
2780             }
2781         }
2782     }
2783
2784     if (you.experience + exp_gained > (unsigned int)MAX_EXP_TOTAL)
2785         you.experience = MAX_EXP_TOTAL;
2786     else
2787         you.experience += exp_gained;
2788
2789     you.attribute[ATTR_EVOL_XP] += exp_gained;
2790     for (int i = GOD_NO_GOD; i < NUM_GODS; ++i)
2791     {
2792         if (active_penance((god_type) i))
2793         {
2794             you.attribute[ATTR_GOD_WRATH_XP] -= exp_gained;
2795             while (you.attribute[ATTR_GOD_WRATH_XP] < 0)
2796             {
2797                 you.attribute[ATTR_GOD_WRATH_COUNT]++;
2798                 set_penance_xp_timeout();
2799             }
2800             break;
2801         }
2802     }
2803
2804     if (crawl_state.game_is_sprint())
2805         exp_gained = sprint_modify_exp(exp_gained);
2806
2807     you.exp_available += exp_gained;
2808
2809     train_skills();
2810     while (check_selected_skills()
2811            && you.exp_available >= calc_skill_cost(you.skill_cost_level))
2812     {
2813         train_skills();
2814     }
2815
2816     if (you.exp_available >= calc_skill_cost(you.skill_cost_level))
2817         you.exp_available = calc_skill_cost(you.skill_cost_level);
2818
2819     level_change();
2820
2821     if (actual_gain != nullptr)
2822         *actual_gain = you.experience - old_exp;
2823
2824     if (you.attribute[ATTR_TEMP_MUTATIONS] > 0)
2825     {
2826         you.attribute[ATTR_TEMP_MUT_XP] -= exp_gained;
2827         if (you.attribute[ATTR_TEMP_MUT_XP] <= 0)
2828             _remove_temp_mutation();
2829     }
2830
2831     _recharge_xp_evokers(exp_gained);
2832
2833     if (you.attribute[ATTR_XP_DRAIN])
2834     {
2835         int loss = div_rand_round(exp_gained * 3 / 2,
2836                                   calc_skill_cost(you.skill_cost_level));
2837
2838         // Make it easier to recover from very heavy levels of draining
2839         // (they're nasty enough as it is)
2840         loss = loss * (1 + (you.attribute[ATTR_XP_DRAIN] / 250.0f));
2841
2842         dprf("Lost %d of %d draining points", loss, you.attribute[ATTR_XP_DRAIN]);
2843
2844         you.attribute[ATTR_XP_DRAIN] -= loss;
2845         // Regaining skills may affect AC/EV.
2846         you.redraw_armour_class = true;
2847         you.redraw_evasion = true;
2848         if (you.attribute[ATTR_XP_DRAIN] <= 0)
2849         {
2850             you.attribute[ATTR_XP_DRAIN] = 0;
2851             mprf(MSGCH_RECOVERY, "Your life force feels restored.");
2852         }
2853     }
2854 }
2855
2856 static void _draconian_scale_colour_message()
2857 {
2858     switch (you.species)
2859     {
2860     case SP_RED_DRACONIAN:
2861         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a fiery red colour.");
2862         perma_mutate(MUT_HEAT_RESISTANCE, 1, "draconian maturity");
2863         break;
2864
2865     case SP_WHITE_DRACONIAN:
2866         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on an icy white colour.");
2867         perma_mutate(MUT_COLD_RESISTANCE, 1, "draconian maturity");
2868         break;
2869
2870     case SP_GREEN_DRACONIAN:
2871         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a lurid green colour.");
2872         perma_mutate(MUT_POISON_RESISTANCE, 1, "draconian maturity");
2873         break;
2874
2875     case SP_YELLOW_DRACONIAN:
2876         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a golden yellow colour.");
2877         break;
2878
2879     case SP_GREY_DRACONIAN:
2880         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a dull iron-grey colour.");
2881         perma_mutate(MUT_UNBREATHING, 1, "draconian maturity");
2882         break;
2883
2884     case SP_BLACK_DRACONIAN:
2885         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a glossy black colour.");
2886         perma_mutate(MUT_SHOCK_RESISTANCE, 1, "draconian maturity");
2887         break;
2888
2889     case SP_PURPLE_DRACONIAN:
2890         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a rich purple colour.");
2891         break;
2892
2893     case SP_MOTTLED_DRACONIAN:
2894         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start taking on a weird mottled pattern.");
2895         break;
2896
2897     case SP_PALE_DRACONIAN:
2898         mprf(MSGCH_INTRINSIC_GAIN, "Your scales start fading to a pale cyan-grey colour.");
2899         break;
2900
2901     case SP_BASE_DRACONIAN:
2902         mpr("");
2903         break;
2904
2905     default:
2906         break;
2907     }
2908 }
2909
2910 bool will_gain_life(int lev)
2911 {
2912     if (lev < you.attribute[ATTR_LIFE_GAINED] - 2)
2913         return false;
2914
2915     return you.lives + you.deaths < (lev - 1) / 3;
2916 }
2917
2918 static void _felid_extra_life()
2919 {
2920     if (will_gain_life(you.max_level)
2921         && you.lives < 2)
2922     {
2923         you.lives++;
2924         mprf(MSGCH_INTRINSIC_GAIN, "Extra life!");
2925         you.attribute[ATTR_LIFE_GAINED] = you.max_level;
2926         // Should play the 1UP sound from SMB...
2927     }
2928 }
2929
2930 /**
2931  * Handle the effects from a player's change in XL.
2932  * @param aux                     A string describing the cause of the level
2933  *                                change.
2934  * @param skip_attribute_increase If true and XL has increased, don't process
2935  *                                stat gains. Currently only used by wizmode
2936  *                                commands.
2937  */
2938 void level_change(bool skip_attribute_increase)
2939 {
2940     // necessary for the time being, as level_change() is called
2941     // directly sometimes {dlb}
2942     you.redraw_experience = true;
2943
2944     while (you.experience < exp_needed(you.experience_level))
2945         lose_level();
2946
2947     while (you.experience_level < you.props[MAX_XP_KEY].get_int()
2948            && you.experience >= exp_needed(you.experience_level + 1))
2949     {
2950         if (!skip_attribute_increase)
2951         {
2952             crawl_state.cancel_cmd_all();
2953
2954             if (is_processing_macro())
2955                 flush_input_buffer(FLUSH_ABORT_MACRO);
2956         }
2957
2958         // [ds] Make sure we increment you.experience_level and apply
2959         // any stat/hp increases only after we've cleared all prompts
2960         // for this experience level. If we do part of the work before
2961         // the prompt, and a player on telnet gets disconnected, the
2962         // SIGHUP will save Crawl in the in-between state and rob the
2963         // player of their level-up perks.
2964
2965         const int new_exp = you.experience_level + 1;
2966
2967         if (new_exp <= you.max_level)
2968         {
2969             mprf(MSGCH_INTRINSIC_GAIN,
2970                  "Welcome back to level %d!", new_exp);
2971
2972             // No more prompts for this XL past this point.
2973
2974             you.experience_level = new_exp;
2975         }
2976         else  // Character has gained a new level
2977         {
2978             // Don't want to see the dead creature at the prompt.
2979             redraw_screen();
2980             // There may be more levels left to gain.
2981             you.redraw_experience = true;
2982
2983             if (new_exp == 27)
2984                 mprf(MSGCH_INTRINSIC_GAIN, "You have reached level 27, the final one!");
2985             else if (new_exp == you.props[MAX_XP_KEY].get_int())
2986                 mprf(MSGCH_INTRINSIC_GAIN, "You have reached level %d, the highest you will ever reach!",
2987                         you.props[MAX_XP_KEY].get_int());
2988             else
2989             {
2990                 mprf(MSGCH_INTRINSIC_GAIN, "You have reached level %d!",
2991                      new_exp);
2992             }
2993
2994             const bool manual_stat_level = new_exp % 3 == 0;  // 3,6,9,12...
2995
2996             if (manual_stat_level && !skip_attribute_increase)
2997                 if (!attribute_increase())
2998                     return; // abort level gain, the xp is still there
2999
3000             crawl_state.stat_gain_prompt = false;
3001             you.experience_level = new_exp;
3002             you.max_level = you.experience_level;
3003
3004 #ifdef USE_TILE_LOCAL
3005             // In case of intrinsic ability changes.
3006             tiles.layout_statcol();
3007             redraw_screen();
3008 #endif
3009
3010             switch (you.species)
3011             {
3012             case SP_HUMAN:
3013                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3014                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3015                 break;
3016
3017             case SP_HIGH_ELF:
3018                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3019                 {
3020                     modify_stat((coinflip() ? STAT_INT
3021                                             : STAT_DEX), 1, false,
3022                                 "level gain");
3023                 }
3024                 break;
3025
3026             case SP_DEEP_ELF:
3027                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3028                     modify_stat(STAT_INT, 1, false, "level gain");
3029                 break;
3030
3031 #if TAG_MAJOR_VERSION == 34
3032             case SP_SLUDGE_ELF:
3033                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3034                 {
3035                     modify_stat((coinflip() ? STAT_INT
3036                                             : STAT_DEX), 1, false,
3037                                 "level gain");
3038                 }
3039                 break;
3040 #endif
3041
3042             case SP_DEEP_DWARF:
3043                 if (you.experience_level == 14)
3044                     perma_mutate(MUT_NEGATIVE_ENERGY_RESISTANCE, 1, "level up");
3045
3046                 if (you.experience_level == 9
3047                     || you.experience_level == 18)
3048                 {
3049                     perma_mutate(MUT_PASSIVE_MAPPING, 1, "level up");
3050                 }
3051
3052                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3053                 {
3054                     modify_stat(coinflip() ? STAT_STR
3055                                            : STAT_INT, 1, false,
3056                                 "level gain");
3057                 }
3058                 break;
3059
3060             case SP_HALFLING:
3061                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3062                     modify_stat(STAT_DEX, 1, false, "level gain");
3063                 break;
3064
3065             case SP_KOBOLD:
3066                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3067                 {
3068                     modify_stat((coinflip() ? STAT_STR
3069                                             : STAT_DEX), 1, false,
3070                                 "level gain");
3071                 }
3072                 break;
3073
3074             case SP_HILL_ORC:
3075 #if TAG_MAJOR_VERSION == 34
3076             case SP_LAVA_ORC:
3077 #endif
3078                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3079                     modify_stat(STAT_STR, 1, false, "level gain");
3080                 break;
3081
3082             case SP_MUMMY:
3083                 if (you.experience_level == 13 || you.experience_level == 26)
3084                     mprf(MSGCH_INTRINSIC_GAIN, "You feel more in touch with the powers of death.");
3085
3086                 if (you.experience_level == 13)  // level 13 for now -- bwr
3087                 {
3088                     mprf(MSGCH_INTRINSIC_GAIN, "You can now infuse your body with "
3089                                                "magic to restore decomposition.");
3090                 }
3091                 break;
3092
3093             case SP_VAMPIRE:
3094                 if (you.experience_level == 3)
3095                 {
3096                     if (you.hunger_state > HS_SATIATED)
3097                     {
3098                         mprf(MSGCH_INTRINSIC_GAIN, "If you weren't so full, "
3099                              "you could now transform into a vampire bat.");
3100                     }
3101                     else
3102                     {
3103                         mprf(MSGCH_INTRINSIC_GAIN,
3104                              "You can now transform into a vampire bat.");
3105                     }
3106                 }
3107                 break;
3108
3109             case SP_NAGA:
3110                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3111                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3112
3113                 if (!(you.experience_level % 3))
3114                 {
3115                     mprf(MSGCH_INTRINSIC_GAIN, "Your skin feels tougher.");
3116                     you.redraw_armour_class = true;
3117                 }
3118
3119                 if (you.experience_level == 13)
3120                 {
3121                     mprf(MSGCH_INTRINSIC_GAIN,
3122                          "Your tail grows strong enough to constrict your "
3123                          "enemies.");
3124                 }
3125                 break;
3126
3127             case SP_TROLL:
3128                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3129                     modify_stat(STAT_STR, 1, false, "level gain");
3130                 break;
3131
3132             case SP_OGRE:
3133                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3134                     modify_stat(STAT_STR, 1, false, "level gain");
3135                 break;
3136
3137             case SP_BASE_DRACONIAN:
3138                 if (you.experience_level >= 7)
3139                 {
3140                     you.species = random_draconian_player_species();
3141
3142                     // We just changed our aptitudes, so some skills may now
3143                     // be at the wrong level (with negative progress); if we
3144                     // print anything in this condition, we might trigger a
3145                     // --More--, a redraw, and a crash (#6376 on Mantis).
3146                     //
3147                     // Hence we first fix up our skill levels silently (passing
3148                     // do_level_up = false) but save the old values; then when
3149                     // we want the messages later, we restore the old skill
3150                     // levels and call check_skill_level_change() again, this
3151                     // time passing do_update = true.
3152
3153                     uint8_t saved_skills[NUM_SKILLS];
3154                     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
3155                     {
3156                         saved_skills[sk] = you.skills[sk];
3157                         check_skill_level_change(sk, false);
3158                     }
3159                     // The player symbol depends on species.
3160                     update_player_symbol();
3161 #ifdef USE_TILE
3162                     init_player_doll();
3163 #endif
3164                     _draconian_scale_colour_message();
3165
3166                     // Produce messages about skill increases/decreases. We
3167                     // restore one skill level at a time so that at most the
3168                     // skill being checked is at the wrong level.
3169                     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
3170                     {
3171                         you.skills[sk] = saved_skills[sk];
3172                         check_skill_level_change(sk);
3173                     }
3174
3175                     redraw_screen();
3176                 }
3177             case SP_RED_DRACONIAN:
3178             case SP_WHITE_DRACONIAN:
3179             case SP_GREEN_DRACONIAN:
3180             case SP_YELLOW_DRACONIAN:
3181             case SP_GREY_DRACONIAN:
3182             case SP_BLACK_DRACONIAN:
3183             case SP_PURPLE_DRACONIAN:
3184             case SP_MOTTLED_DRACONIAN:
3185             case SP_PALE_DRACONIAN:
3186                 if (!(you.experience_level % 3))
3187                 {
3188                     mprf(MSGCH_INTRINSIC_GAIN, "Your scales feel tougher.");
3189                     you.redraw_armour_class = true;
3190                 }
3191
3192                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3193                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3194
3195                 if (you.experience_level == 14)
3196                 {
3197                     switch (you.species)
3198                     {
3199                     case SP_GREEN_DRACONIAN:
3200                         perma_mutate(MUT_STINGER, 1, "draconian growth");
3201                         break;
3202                     case SP_YELLOW_DRACONIAN:
3203                         perma_mutate(MUT_ACIDIC_BITE, 1, "draconian growth");
3204                         break;
3205                     case SP_BLACK_DRACONIAN:
3206                         perma_mutate(MUT_BIG_WINGS, 1, "draconian growth");
3207                         mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3208                         break;
3209                     default:
3210                         break;
3211                     }
3212                 }
3213                 break;
3214
3215             case SP_CENTAUR:
3216                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3217                 {
3218                     modify_stat((coinflip() ? STAT_STR
3219                                             : STAT_DEX), 1, false,
3220                                 "level gain");
3221                 }
3222                 break;
3223
3224             case SP_DEMIGOD:
3225                 break;
3226
3227             case SP_SPRIGGAN:
3228                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3229                 {
3230                     modify_stat((coinflip() ? STAT_INT
3231                                             : STAT_DEX), 1, false,
3232                                 "level gain");
3233                 }
3234                 break;
3235
3236             case SP_MINOTAUR:
3237                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3238                 {
3239                     modify_stat((coinflip() ? STAT_STR
3240                                             : STAT_DEX), 1, false,
3241                                 "level gain");
3242                 }
3243                 break;
3244
3245             case SP_DEMONSPAWN:
3246             {
3247                 bool gave_message = false;
3248                 int level = 0;
3249                 mutation_type first_body_facet = NUM_MUTATIONS;
3250
3251                 for (const player::demon_trait trait : you.demonic_traits)
3252                 {
3253                     if (is_body_facet(trait.mutation))
3254                     {
3255                         if (first_body_facet < NUM_MUTATIONS
3256                             && trait.mutation != first_body_facet)
3257                         {
3258                             if (you.experience_level == level)
3259                             {
3260                                 mprf(MSGCH_MUTATION, "You feel monstrous as your "
3261                                      "demonic heritage exerts itself.");
3262                                 mark_milestone("monstrous", "is a "
3263                                                "monstrous demonspawn!");
3264                             }
3265                             break;
3266                         }
3267
3268                         if (first_body_facet == NUM_MUTATIONS)
3269                         {
3270                             first_body_facet = trait.mutation;
3271                             level = trait.level_gained;
3272                         }
3273                     }
3274                 }
3275
3276                 for (const player::demon_trait trait : you.demonic_traits)
3277                 {
3278                     if (trait.level_gained == you.experience_level)
3279                     {
3280                         if (!gave_message)
3281                         {
3282                             mprf(MSGCH_INTRINSIC_GAIN,
3283                                  "Your demonic ancestry asserts itself...");
3284
3285                             gave_message = true;
3286                         }
3287                         perma_mutate(trait.mutation, 1, "demonic ancestry");
3288                     }
3289                 }
3290
3291                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3292                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3293                 break;
3294             }
3295
3296             case SP_GHOUL:
3297                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3298                     modify_stat(STAT_STR, 1, false, "level gain");
3299                 break;
3300
3301             case SP_TENGU:
3302                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3303                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3304
3305                 if (you.experience_level == 5)
3306                     mprf(MSGCH_INTRINSIC_GAIN, "You have gained the ability to fly.");
3307                 else if (you.experience_level == 14)
3308                     mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3309                 break;
3310
3311             case SP_MERFOLK:
3312                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3313                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3314                 break;
3315
3316             case SP_FELID:
3317                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3318                 {
3319                     modify_stat((coinflip() ? STAT_INT
3320                                             : STAT_DEX), 1, false,
3321                                 "level gain");
3322                 }
3323
3324                 if (you.experience_level == 6 || you.experience_level == 12)
3325                     perma_mutate(MUT_SHAGGY_FUR, 1, "growing up");
3326
3327                 _felid_extra_life();
3328                 break;
3329
3330             case SP_OCTOPODE:
3331                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3332                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3333                 break;
3334
3335 #if TAG_MAJOR_VERSION == 34
3336             case SP_DJINNI:
3337                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3338                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3339                 break;
3340
3341 #endif
3342             case SP_FORMICID:
3343                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3344                 {
3345                     modify_stat((coinflip() ? STAT_STR
3346                                             : STAT_INT), 1, false,
3347                                 "level gain");
3348                 }
3349                 break;
3350
3351             case SP_GARGOYLE:
3352                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3353                 {
3354                     modify_stat((coinflip() ? STAT_STR
3355                                             : STAT_INT), 1, false,
3356                                 "level gain");
3357                 }
3358
3359                 if (you.experience_level == 14)
3360                 {
3361                     perma_mutate(MUT_BIG_WINGS, 1, "gargoyle growth");
3362                     mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3363                 }
3364                 break;
3365
3366             case SP_VINE_STALKER:
3367                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3368                 {
3369                     modify_stat((coinflip() ? STAT_STR
3370                                             : STAT_DEX), 1, false,
3371                                 "level gain");
3372                 }
3373
3374                 if (you.experience_level == 6)
3375                     perma_mutate(MUT_REGENERATION, 1, "vine stalker growth");
3376
3377                 if (you.experience_level == 8)
3378                     perma_mutate(MUT_FANGS, 1, "vine stalker growth");
3379
3380                 if (you.experience_level == 12)
3381                     perma_mutate(MUT_REGENERATION, 1, "vine stalker growth");
3382                 break;
3383
3384             default:
3385                 break;
3386             }
3387         }
3388
3389         // zot defence abilities; must also be updated in ability.cc when these levels are changed
3390         if (crawl_state.game_is_zotdef())
3391         {
3392             if (you.experience_level == 2)
3393                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob saplings.");
3394             if (you.experience_level == 3)
3395                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of arrow traps.");
3396             if (you.experience_level == 4)
3397                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of plants.");
3398             if (you.experience_level == 4)
3399                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through removing curses.");
3400             if (you.experience_level == 5)
3401                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of burning bushes.");
3402             if (you.experience_level == 6)
3403                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of altars and grenades.");
3404             if (you.experience_level == 7)
3405                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob plants.");
3406             if (you.experience_level == 8)
3407                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of net traps.");
3408             if (you.experience_level == 9)
3409                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of ice statues.");
3410             if (you.experience_level == 10)
3411                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of spear traps.");
3412             if (you.experience_level == 11)
3413                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of alarm traps.");
3414             if (you.experience_level == 12)
3415                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of mushroom circles.");
3416             if (you.experience_level == 13)
3417                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of bolt traps.");
3418             if (you.experience_level == 14)
3419                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of orange crystal statues.");
3420             if (you.experience_level == 15)
3421                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of needle traps.");
3422             if (you.experience_level == 16)
3423                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through self-teleportation.");
3424             if (you.experience_level == 17)
3425                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through making water.");
3426             if (you.experience_level == 19)
3427                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of lightning spires.");
3428             if (you.experience_level == 20)
3429                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of obsidian statues.");
3430             // gold and bazaars gained together
3431             if (you.experience_level == 21)
3432                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of bazaars.");
3433             if (you.experience_level == 21)
3434                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through acquiring gold.");
3435             if (you.experience_level == 22)
3436                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob circles.");
3437             if (you.experience_level == 24)
3438                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through acquirement.");
3439             if (you.experience_level == 25)
3440                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of blade traps.");
3441             if (you.experience_level == 26)
3442                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of curse skulls.");
3443         }
3444
3445         const int old_hp = you.hp;
3446         const int old_maxhp = you.hp_max;
3447         const int old_mp = you.magic_points;
3448         const int old_maxmp = you.max_magic_points;
3449
3450         // recalculate for game
3451         calc_hp();
3452         calc_mp();
3453
3454         set_hp(old_hp * you.hp_max / old_maxhp);
3455         set_mp(old_maxmp > 0 ? old_mp * you.max_magic_points / old_maxmp
3456                : you.max_magic_points);
3457
3458         // Get "real" values for note-taking, i.e. ignore Berserk,
3459         // transformations or equipped items.
3460         const int note_maxhp = get_real_hp(false, false);
3461         const int note_maxmp = get_real_mp(false);
3462
3463         char buf[200];
3464 #if TAG_MAJOR_VERSION == 34
3465         if (you.species == SP_DJINNI)
3466             // Djinn don't HP/MP
3467             sprintf(buf, "EP: %d/%d",
3468                     min(you.hp, note_maxhp + note_maxmp),
3469                     note_maxhp + note_maxmp);
3470         else
3471 #endif
3472             sprintf(buf, "HP: %d/%d MP: %d/%d",
3473                     min(you.hp, note_maxhp), note_maxhp,
3474                     min(you.magic_points, note_maxmp), note_maxmp);
3475         take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0, buf));
3476
3477         xom_is_stimulated(12);
3478
3479         learned_something_new(HINT_NEW_LEVEL);
3480     }
3481
3482     while (you.experience >= exp_needed(you.max_level + 1))
3483     {
3484         ASSERT(you.experience_level == you.props[MAX_XP_KEY].get_int());
3485         ASSERT(you.max_level < 127); // marshalled as an 1-byte value
3486         you.max_level++;
3487         if (you.species == SP_FELID)
3488             _felid_extra_life();
3489     }
3490
3491     you.redraw_title = true;
3492
3493 #ifdef DGL_WHEREIS
3494     whereis_record();
3495 #endif
3496
3497     // Hints mode arbitrarily ends at xp 7.
3498     if (crawl_state.game_is_hints() && you.experience_level >= 7)
3499         hints_finished();
3500 }
3501
3502 void adjust_level(int diff, bool just_xp)
3503 {
3504     ASSERT((uint64_t)you.experience <= (uint64_t)MAX_EXP_TOTAL);
3505     int max_exp_level = you.props[MAX_XP_KEY].get_int();
3506     if (you.experience_level + diff < 1)
3507         you.experience = 0;
3508     else if (you.experience_level + diff >= max_exp_level)
3509         you.experience = max(you.experience,
3510                 exp_needed(max_exp_level));
3511     else
3512     {
3513         while (diff < 0 && you.experience >=
3514                 exp_needed(max_exp_level))
3515         {
3516             // Having XP for level 53 and going back to 26 due to a single
3517             // card would mean your felid is not going to get any extra lives
3518             // in foreseable future.
3519             you.experience -= exp_needed(max_exp_level)
3520                     - exp_needed(max_exp_level - 1);
3521             diff++;
3522         }
3523         int old_min = exp_needed(you.experience_level);
3524         int old_max = exp_needed(you.experience_level + 1);
3525         int new_min = exp_needed(you.experience_level + diff);
3526         int new_max = exp_needed(you.experience_level + 1 + diff);
3527         dprf("XP before: %d\n", you.experience);
3528         dprf("%4.2f of %d..%d to %d..%d",
3529              (you.experience - old_min) * 1.0 / (old_max - old_min),
3530              old_min, old_max, new_min, new_max);
3531
3532         you.experience = ((int64_t)(new_max - new_min))
3533                        * (you.experience - old_min)
3534                        / (old_max - old_min)
3535                        + new_min;
3536         dprf("XP after: %d\n", you.experience);
3537     }
3538
3539     ASSERT((uint64_t)you.experience <= (uint64_t)MAX_EXP_TOTAL);
3540
3541     if (!just_xp)
3542         level_change();
3543 }
3544
3545 /**
3546  * Return a multiplier for dex when calculating stealth values, based on the
3547  * player's species.
3548  *
3549  * @return The