4daf9d810126c1c88e0c4c9b2b06b6bcd7fd9177
[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 >= 27)
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 < 27
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
2986             {
2987                 mprf(MSGCH_INTRINSIC_GAIN, "You have reached level %d!",
2988                      new_exp);
2989             }
2990
2991             const bool manual_stat_level = new_exp % 3 == 0;  // 3,6,9,12...
2992
2993             if (manual_stat_level && !skip_attribute_increase)
2994                 if (!attribute_increase())
2995                     return; // abort level gain, the xp is still there
2996
2997             crawl_state.stat_gain_prompt = false;
2998             you.experience_level = new_exp;
2999             you.max_level = you.experience_level;
3000
3001 #ifdef USE_TILE_LOCAL
3002             // In case of intrinsic ability changes.
3003             tiles.layout_statcol();
3004             redraw_screen();
3005 #endif
3006
3007             switch (you.species)
3008             {
3009             case SP_HUMAN:
3010                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3011                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3012                 break;
3013
3014             case SP_HIGH_ELF:
3015                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3016                 {
3017                     modify_stat((coinflip() ? STAT_INT
3018                                             : STAT_DEX), 1, false,
3019                                 "level gain");
3020                 }
3021                 break;
3022
3023             case SP_DEEP_ELF:
3024                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3025                     modify_stat(STAT_INT, 1, false, "level gain");
3026                 break;
3027
3028 #if TAG_MAJOR_VERSION == 34
3029             case SP_SLUDGE_ELF:
3030                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3031                 {
3032                     modify_stat((coinflip() ? STAT_INT
3033                                             : STAT_DEX), 1, false,
3034                                 "level gain");
3035                 }
3036                 break;
3037 #endif
3038
3039             case SP_DEEP_DWARF:
3040                 if (you.experience_level == 14)
3041                     perma_mutate(MUT_NEGATIVE_ENERGY_RESISTANCE, 1, "level up");
3042
3043                 if (you.experience_level == 9
3044                     || you.experience_level == 18)
3045                 {
3046                     perma_mutate(MUT_PASSIVE_MAPPING, 1, "level up");
3047                 }
3048
3049                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3050                 {
3051                     modify_stat(coinflip() ? STAT_STR
3052                                            : STAT_INT, 1, false,
3053                                 "level gain");
3054                 }
3055                 break;
3056
3057             case SP_HALFLING:
3058                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3059                     modify_stat(STAT_DEX, 1, false, "level gain");
3060                 break;
3061
3062             case SP_KOBOLD:
3063                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3064                 {
3065                     modify_stat((coinflip() ? STAT_STR
3066                                             : STAT_DEX), 1, false,
3067                                 "level gain");
3068                 }
3069                 break;
3070
3071             case SP_HILL_ORC:
3072 #if TAG_MAJOR_VERSION == 34
3073             case SP_LAVA_ORC:
3074 #endif
3075                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3076                     modify_stat(STAT_STR, 1, false, "level gain");
3077                 break;
3078
3079             case SP_MUMMY:
3080                 if (you.experience_level == 13 || you.experience_level == 26)
3081                     mprf(MSGCH_INTRINSIC_GAIN, "You feel more in touch with the powers of death.");
3082
3083                 if (you.experience_level == 13)  // level 13 for now -- bwr
3084                 {
3085                     mprf(MSGCH_INTRINSIC_GAIN, "You can now infuse your body with "
3086                                                "magic to restore decomposition.");
3087                 }
3088                 break;
3089
3090             case SP_VAMPIRE:
3091                 if (you.experience_level == 3)
3092                 {
3093                     if (you.hunger_state > HS_SATIATED)
3094                     {
3095                         mprf(MSGCH_INTRINSIC_GAIN, "If you weren't so full, "
3096                              "you could now transform into a vampire bat.");
3097                     }
3098                     else
3099                     {
3100                         mprf(MSGCH_INTRINSIC_GAIN,
3101                              "You can now transform into a vampire bat.");
3102                     }
3103                 }
3104                 break;
3105
3106             case SP_NAGA:
3107                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3108                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3109
3110                 if (!(you.experience_level % 3))
3111                 {
3112                     mprf(MSGCH_INTRINSIC_GAIN, "Your skin feels tougher.");
3113                     you.redraw_armour_class = true;
3114                 }
3115
3116                 if (you.experience_level == 13)
3117                 {
3118                     mprf(MSGCH_INTRINSIC_GAIN,
3119                          "Your tail grows strong enough to constrict your "
3120                          "enemies.");
3121                 }
3122                 break;
3123
3124             case SP_TROLL:
3125                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3126                     modify_stat(STAT_STR, 1, false, "level gain");
3127                 break;
3128
3129             case SP_OGRE:
3130                 if (!(you.experience_level % 3) && !skip_attribute_increase)
3131                     modify_stat(STAT_STR, 1, false, "level gain");
3132                 break;
3133
3134             case SP_BASE_DRACONIAN:
3135                 if (you.experience_level >= 7)
3136                 {
3137                     you.species = random_draconian_player_species();
3138
3139                     // We just changed our aptitudes, so some skills may now
3140                     // be at the wrong level (with negative progress); if we
3141                     // print anything in this condition, we might trigger a
3142                     // --More--, a redraw, and a crash (#6376 on Mantis).
3143                     //
3144                     // Hence we first fix up our skill levels silently (passing
3145                     // do_level_up = false) but save the old values; then when
3146                     // we want the messages later, we restore the old skill
3147                     // levels and call check_skill_level_change() again, this
3148                     // time passing do_update = true.
3149
3150                     uint8_t saved_skills[NUM_SKILLS];
3151                     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
3152                     {
3153                         saved_skills[sk] = you.skills[sk];
3154                         check_skill_level_change(sk, false);
3155                     }
3156                     // The player symbol depends on species.
3157                     update_player_symbol();
3158 #ifdef USE_TILE
3159                     init_player_doll();
3160 #endif
3161                     _draconian_scale_colour_message();
3162
3163                     // Produce messages about skill increases/decreases. We
3164                     // restore one skill level at a time so that at most the
3165                     // skill being checked is at the wrong level.
3166                     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
3167                     {
3168                         you.skills[sk] = saved_skills[sk];
3169                         check_skill_level_change(sk);
3170                     }
3171
3172                     redraw_screen();
3173                 }
3174             case SP_RED_DRACONIAN:
3175             case SP_WHITE_DRACONIAN:
3176             case SP_GREEN_DRACONIAN:
3177             case SP_YELLOW_DRACONIAN:
3178             case SP_GREY_DRACONIAN:
3179             case SP_BLACK_DRACONIAN:
3180             case SP_PURPLE_DRACONIAN:
3181             case SP_MOTTLED_DRACONIAN:
3182             case SP_PALE_DRACONIAN:
3183                 if (!(you.experience_level % 3))
3184                 {
3185                     mprf(MSGCH_INTRINSIC_GAIN, "Your scales feel tougher.");
3186                     you.redraw_armour_class = true;
3187                 }
3188
3189                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3190                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3191
3192                 if (you.experience_level == 14)
3193                 {
3194                     switch (you.species)
3195                     {
3196                     case SP_GREEN_DRACONIAN:
3197                         perma_mutate(MUT_STINGER, 1, "draconian growth");
3198                         break;
3199                     case SP_YELLOW_DRACONIAN:
3200                         perma_mutate(MUT_ACIDIC_BITE, 1, "draconian growth");
3201                         break;
3202                     case SP_BLACK_DRACONIAN:
3203                         perma_mutate(MUT_BIG_WINGS, 1, "draconian growth");
3204                         mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3205                         break;
3206                     default:
3207                         break;
3208                     }
3209                 }
3210                 break;
3211
3212             case SP_CENTAUR:
3213                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3214                 {
3215                     modify_stat((coinflip() ? STAT_STR
3216                                             : STAT_DEX), 1, false,
3217                                 "level gain");
3218                 }
3219                 break;
3220
3221             case SP_DEMIGOD:
3222                 break;
3223
3224             case SP_SPRIGGAN:
3225                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3226                 {
3227                     modify_stat((coinflip() ? STAT_INT
3228                                             : STAT_DEX), 1, false,
3229                                 "level gain");
3230                 }
3231                 break;
3232
3233             case SP_MINOTAUR:
3234                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3235                 {
3236                     modify_stat((coinflip() ? STAT_STR
3237                                             : STAT_DEX), 1, false,
3238                                 "level gain");
3239                 }
3240                 break;
3241
3242             case SP_DEMONSPAWN:
3243             {
3244                 bool gave_message = false;
3245                 int level = 0;
3246                 mutation_type first_body_facet = NUM_MUTATIONS;
3247
3248                 for (const player::demon_trait trait : you.demonic_traits)
3249                 {
3250                     if (is_body_facet(trait.mutation))
3251                     {
3252                         if (first_body_facet < NUM_MUTATIONS
3253                             && trait.mutation != first_body_facet)
3254                         {
3255                             if (you.experience_level == level)
3256                             {
3257                                 mprf(MSGCH_MUTATION, "You feel monstrous as your "
3258                                      "demonic heritage exerts itself.");
3259                                 mark_milestone("monstrous", "is a "
3260                                                "monstrous demonspawn!");
3261                             }
3262                             break;
3263                         }
3264
3265                         if (first_body_facet == NUM_MUTATIONS)
3266                         {
3267                             first_body_facet = trait.mutation;
3268                             level = trait.level_gained;
3269                         }
3270                     }
3271                 }
3272
3273                 for (const player::demon_trait trait : you.demonic_traits)
3274                 {
3275                     if (trait.level_gained == you.experience_level)
3276                     {
3277                         if (!gave_message)
3278                         {
3279                             mprf(MSGCH_INTRINSIC_GAIN,
3280                                  "Your demonic ancestry asserts itself...");
3281
3282                             gave_message = true;
3283                         }
3284                         perma_mutate(trait.mutation, 1, "demonic ancestry");
3285                     }
3286                 }
3287
3288                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3289                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3290                 break;
3291             }
3292
3293             case SP_GHOUL:
3294                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3295                     modify_stat(STAT_STR, 1, false, "level gain");
3296                 break;
3297
3298             case SP_TENGU:
3299                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3300                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3301
3302                 if (you.experience_level == 5)
3303                     mprf(MSGCH_INTRINSIC_GAIN, "You have gained the ability to fly.");
3304                 else if (you.experience_level == 14)
3305                     mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3306                 break;
3307
3308             case SP_MERFOLK:
3309                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3310                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3311                 break;
3312
3313             case SP_FELID:
3314                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3315                 {
3316                     modify_stat((coinflip() ? STAT_INT
3317                                             : STAT_DEX), 1, false,
3318                                 "level gain");
3319                 }
3320
3321                 if (you.experience_level == 6 || you.experience_level == 12)
3322                     perma_mutate(MUT_SHAGGY_FUR, 1, "growing up");
3323
3324                 _felid_extra_life();
3325                 break;
3326
3327             case SP_OCTOPODE:
3328                 if (!(you.experience_level % 5) && !skip_attribute_increase)
3329                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3330                 break;
3331
3332 #if TAG_MAJOR_VERSION == 34
3333             case SP_DJINNI:
3334                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3335                     modify_stat(STAT_RANDOM, 1, false, "level gain");
3336                 break;
3337
3338 #endif
3339             case SP_FORMICID:
3340                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3341                 {
3342                     modify_stat((coinflip() ? STAT_STR
3343                                             : STAT_INT), 1, false,
3344                                 "level gain");
3345                 }
3346                 break;
3347
3348             case SP_GARGOYLE:
3349                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3350                 {
3351                     modify_stat((coinflip() ? STAT_STR
3352                                             : STAT_INT), 1, false,
3353                                 "level gain");
3354                 }
3355
3356                 if (you.experience_level == 14)
3357                 {
3358                     perma_mutate(MUT_BIG_WINGS, 1, "gargoyle growth");
3359                     mprf(MSGCH_INTRINSIC_GAIN, "You can now fly continuously.");
3360                 }
3361                 break;
3362
3363             case SP_VINE_STALKER:
3364                 if (!(you.experience_level % 4) && !skip_attribute_increase)
3365                 {
3366                     modify_stat((coinflip() ? STAT_STR
3367                                             : STAT_DEX), 1, false,
3368                                 "level gain");
3369                 }
3370
3371                 if (you.experience_level == 6)
3372                     perma_mutate(MUT_REGENERATION, 1, "vine stalker growth");
3373
3374                 if (you.experience_level == 8)
3375                     perma_mutate(MUT_FANGS, 1, "vine stalker growth");
3376
3377                 if (you.experience_level == 12)
3378                     perma_mutate(MUT_REGENERATION, 1, "vine stalker growth");
3379                 break;
3380
3381             default:
3382                 break;
3383             }
3384         }
3385
3386         // zot defence abilities; must also be updated in ability.cc when these levels are changed
3387         if (crawl_state.game_is_zotdef())
3388         {
3389             if (you.experience_level == 2)
3390                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob saplings.");
3391             if (you.experience_level == 3)
3392                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of arrow traps.");
3393             if (you.experience_level == 4)
3394                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of plants.");
3395             if (you.experience_level == 4)
3396                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through removing curses.");
3397             if (you.experience_level == 5)
3398                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of burning bushes.");
3399             if (you.experience_level == 6)
3400                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of altars and grenades.");
3401             if (you.experience_level == 7)
3402                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob plants.");
3403             if (you.experience_level == 8)
3404                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of net traps.");
3405             if (you.experience_level == 9)
3406                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of ice statues.");
3407             if (you.experience_level == 10)
3408                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of spear traps.");
3409             if (you.experience_level == 11)
3410                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of alarm traps.");
3411             if (you.experience_level == 12)
3412                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of mushroom circles.");
3413             if (you.experience_level == 13)
3414                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of bolt traps.");
3415             if (you.experience_level == 14)
3416                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of orange crystal statues.");
3417             if (you.experience_level == 15)
3418                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of needle traps.");
3419             if (you.experience_level == 16)
3420                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through self-teleportation.");
3421             if (you.experience_level == 17)
3422                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through making water.");
3423             if (you.experience_level == 19)
3424                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of lightning spires.");
3425             if (you.experience_level == 20)
3426                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of obsidian statues.");
3427             // gold and bazaars gained together
3428             if (you.experience_level == 21)
3429                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of bazaars.");
3430             if (you.experience_level == 21)
3431                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through acquiring gold.");
3432             if (you.experience_level == 22)
3433                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of oklob circles.");
3434             if (you.experience_level == 24)
3435                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through acquirement.");
3436             if (you.experience_level == 25)
3437                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of blade traps.");
3438             if (you.experience_level == 26)
3439                 mprf(MSGCH_INTRINSIC_GAIN, "Your Zot abilities now extend through the making of curse skulls.");
3440         }
3441
3442         const int old_hp = you.hp;
3443         const int old_maxhp = you.hp_max;
3444         const int old_mp = you.magic_points;
3445         const int old_maxmp = you.max_magic_points;
3446
3447         // recalculate for game
3448         calc_hp();
3449         calc_mp();
3450
3451         set_hp(old_hp * you.hp_max / old_maxhp);
3452         set_mp(old_maxmp > 0 ? old_mp * you.max_magic_points / old_maxmp
3453                : you.max_magic_points);
3454
3455         // Get "real" values for note-taking, i.e. ignore Berserk,
3456         // transformations or equipped items.
3457         const int note_maxhp = get_real_hp(false, false);
3458         const int note_maxmp = get_real_mp(false);
3459
3460         char buf[200];
3461 #if TAG_MAJOR_VERSION == 34
3462         if (you.species == SP_DJINNI)
3463             // Djinn don't HP/MP
3464             sprintf(buf, "EP: %d/%d",
3465                     min(you.hp, note_maxhp + note_maxmp),
3466                     note_maxhp + note_maxmp);
3467         else
3468 #endif
3469             sprintf(buf, "HP: %d/%d MP: %d/%d",
3470                     min(you.hp, note_maxhp), note_maxhp,
3471                     min(you.magic_points, note_maxmp), note_maxmp);
3472         take_note(Note(NOTE_XP_LEVEL_CHANGE, you.experience_level, 0, buf));
3473
3474         xom_is_stimulated(12);
3475
3476         learned_something_new(HINT_NEW_LEVEL);
3477     }
3478
3479     while (you.experience >= exp_needed(you.max_level + 1))
3480     {
3481         ASSERT(you.experience_level == 27);
3482         ASSERT(you.max_level < 127); // marshalled as an 1-byte value
3483         you.max_level++;
3484         if (you.species == SP_FELID)
3485             _felid_extra_life();
3486     }
3487
3488     you.redraw_title = true;
3489
3490 #ifdef DGL_WHEREIS
3491     whereis_record();
3492 #endif
3493
3494     // Hints mode arbitrarily ends at xp 7.
3495     if (crawl_state.game_is_hints() && you.experience_level >= 7)
3496         hints_finished();
3497 }
3498
3499 void adjust_level(int diff, bool just_xp)
3500 {
3501     ASSERT((uint64_t)you.experience <= (uint64_t)MAX_EXP_TOTAL);
3502
3503     if (you.experience_level + diff < 1)
3504         you.experience = 0;
3505     else if (you.experience_level + diff >= 27)
3506         you.experience = max(you.experience, exp_needed(27));
3507     else
3508     {
3509         while (diff < 0 && you.experience >= exp_needed(27))
3510         {
3511             // Having XP for level 53 and going back to 26 due to a single
3512             // card would mean your felid is not going to get any extra lives
3513             // in foreseable future.
3514             you.experience -= exp_needed(27) - exp_needed(26);
3515             diff++;
3516         }
3517         int old_min = exp_needed(you.experience_level);
3518         int old_max = exp_needed(you.experience_level + 1);
3519         int new_min = exp_needed(you.experience_level + diff);
3520         int new_max = exp_needed(you.experience_level + 1 + diff);
3521         dprf("XP before: %d\n", you.experience);
3522         dprf("%4.2f of %d..%d to %d..%d",
3523              (you.experience - old_min) * 1.0 / (old_max - old_min),
3524              old_min, old_max, new_min, new_max);
3525
3526         you.experience = ((int64_t)(new_max - new_min))
3527                        * (you.experience - old_min)
3528                        / (old_max - old_min)
3529                        + new_min;
3530         dprf("XP after: %d\n", you.experience);
3531     }
3532
3533     ASSERT((uint64_t)you.experience <= (uint64_t)MAX_EXP_TOTAL);
3534
3535     if (!just_xp)
3536         level_change();
3537 }
3538
3539 /**
3540  * Return a multiplier for dex when calculating stealth values, based on the
3541  * player's species.
3542  *
3543  * @return The stealth multiplier value for the player's species.
3544  */
3545 static int _species_stealth_mod()
3546 {
3547     if (player_genus(GENPC_DRACONIAN))
3548         return 12;
3549
3550     switch (you.species)
3551     {
3552         case SP_TROLL:
3553         case SP_OGRE:
3554         case SP_CENTAUR:
3555 #if TAG_MAJOR_VERSION == 34
3556         case SP_DJINNI:
3557 #endif
3558             return 9;
3559
3560         case SP_MINOTAUR:
3561             return 12;
3562
3563         case SP_VAMPIRE:
3564             // Thirsty/bat-form vampires are (much) more stealthy
3565             if (you.hunger_state == HS_STARVING)
3566                 return 21;
3567             if (you.form == TRAN_BAT
3568                      || you.hunger_state <= HS_NEAR_STARVING)
3569             {
3570                 return 20;
3571             }
3572             if (you.hunger_state < HS_SATIATED)
3573                 return 19;
3574             return 18;
3575
3576         case SP_HALFLING:
3577         case SP_KOBOLD:
3578         case SP_SPRIGGAN:
3579         case SP_NAGA:       // not small but very good at stealth
3580         case SP_FELID:
3581         case SP_OCTOPODE:
3582             return 18;
3583
3584         default:
3585             return 15;
3586     }
3587 }
3588
3589 /**
3590  * Return a multiplier for skill when calculating stealth values, based on the
3591  * player's species & form.
3592  *
3593  * @return The player's current stealth multiplier value.
3594  */
3595 static int _stealth_mod()
3596 {
3597     const int form_stealth_mod = get_form()->get_stealth_mod();
3598
3599     if (form_stealth_mod != 0)
3600         return form_stealth_mod;
3601
3602     const int species_stealth_mod = _species_stealth_mod();
3603     if (you.form == TRAN_STATUE)
3604         return species_stealth_mod - 3;
3605     return species_stealth_mod;
3606 }
3607
3608 /**
3609  * Get the player's current stealth value.
3610  *
3611  * XXX: rename this to something more reasonable
3612
3613  *
3614  * (Keep in mind, while tweaking this function: the order in which stealth
3615  * modifiers are applied is significant!)
3616  *
3617  * @return  The player's current stealth value.
3618  */
3619 int check_stealth()
3620 {
3621     ASSERT(!crawl_state.game_is_arena());
3622     // Extreme stealthiness can be enforced by wizmode stealth setting.
3623     if (crawl_state.disables[DIS_MON_SIGHT])
3624         return 1000;
3625
3626     // lantern of shadows, berserking, "clumsy" (0-dex).
3627     if (you.attribute[ATTR_SHADOWS] || you.berserk()
3628         || you.stat_zero[STAT_DEX] || player_mutation_level(MUT_NO_STEALTH))
3629     {
3630         return 0;
3631     }
3632
3633     int stealth = you.dex() * 3;
3634
3635     if (you.form == TRAN_BLADE_HANDS && you.species == SP_FELID
3636         && !you.airborne())
3637     {
3638         stealth -= 50; // klack klack klack go the blade paws
3639         // this is an absurd special case but also it's really funny so w/e
3640     }
3641
3642     stealth += you.skill(SK_STEALTH, _stealth_mod());
3643
3644     if (you.confused())
3645         stealth /= 3;
3646
3647     const item_def *arm = you.slot_item(EQ_BODY_ARMOUR, false);
3648     const item_def *boots = you.slot_item(EQ_BOOTS, false);
3649
3650     if (arm)
3651     {
3652         // [ds] New stealth penalty formula from rob: SP = 6 * (EP^2)
3653         // Now 2 * EP^2 / 3 after EP rescaling.
3654         const int evp = you.unadjusted_body_armour_penalty();
3655         const int penalty = evp * evp * 2 / 3;
3656 #if 0
3657         dprf("Stealth penalty for armour (ep: %d): %d", ep, penalty);
3658 #endif
3659         stealth -= penalty;
3660     }
3661
3662     stealth += STEALTH_PIP * you.scan_artefacts(ARTP_STEALTH);
3663
3664     stealth += STEALTH_PIP * you.wearing(EQ_RINGS, RING_STEALTH);
3665     stealth -= STEALTH_PIP * you.wearing(EQ_RINGS, RING_LOUDNESS);
3666
3667     const item_def *body_armour = you.slot_item(EQ_BODY_ARMOUR);
3668     if (body_armour)
3669     {
3670         const int pips = armour_type_prop(body_armour->sub_type, ARMF_STEALTH);
3671         stealth += pips * STEALTH_PIP;
3672     }
3673
3674     if (you.duration[DUR_STEALTH])
3675         stealth += STEALTH_PIP * 2;
3676
3677     if (you.duration[DUR_AGILITY])
3678         stealth += STEALTH_PIP;
3679
3680     if (!you.airborne())
3681     {
3682         if (you.in_water())
3683         {
3684             // Merfolk can sneak up on monsters underwater -- bwr
3685             if (you.fishtail || you.species == SP_OCTOPODE)
3686                 stealth += STEALTH_PIP;
3687             else if (!you.can_swim() && !you.extra_balanced())
3688                 stealth /= 2;       // splashy-splashy
3689         }
3690
3691         else if (boots && get_armour_ego_type(*boots) == SPARM_STEALTH)
3692             stealth += STEALTH_PIP;
3693
3694         else if (you.has_usable_hooves())
3695             stealth -= 5 + 5 * player_mutation_level(MUT_HOOVES);
3696
3697         else if (you.species == SP_FELID && (!you.form || you.form == TRAN_APPENDAGE))
3698             stealth += 20;  // paws
3699     }
3700
3701     // Radiating silence is the negative complement of shouting all the
3702     // time... a sudden change from background noise to no noise is going
3703     // to clue anything in to the fact that something is very wrong...
3704     // a personal silence spell would naturally be different, but this
3705     // silence radiates for a distance and prevents monster spellcasting,
3706     // which pretty much gives away the stealth game.
3707     // this penalty is dependent on the actual amount of ambient noise
3708     // in the level -doy
3709     if (you.duration[DUR_SILENCE])
3710         stealth -= STEALTH_PIP + current_level_ambient_noise();
3711
3712     // Mutations.
3713     stealth += STEALTH_PIP * player_mutation_level(MUT_NIGHTSTALKER);
3714     stealth += (STEALTH_PIP / 2)
3715                 * player_mutation_level(MUT_THIN_SKELETAL_STRUCTURE);
3716     stealth += STEALTH_PIP * player_mutation_level(MUT_CAMOUFLAGE);
3717     const int how_transparent = player_mutation_level(MUT_TRANSLUCENT_SKIN);
3718     if (how_transparent)
3719         stealth += 15 * (how_transparent);
3720
3721     // it's easier to be stealthy when there's a lot of background noise
3722     stealth += 2 * current_level_ambient_noise();
3723
3724     // If you've been tagged with Corona or are Glowing, the glow
3725     // makes you extremely unstealthy.
3726     if (you.backlit())
3727         stealth = stealth * 2 / 5;
3728
3729     // On the other hand, shrouding has the reverse effect, if you know
3730     // how to make use of it:
3731     if (you.umbra())
3732     {
3733         int umbra_mul = 1, umbra_div = 1;
3734         if (you_worship(GOD_DITHMENOS) || you_worship(GOD_YREDELEMNUL))
3735         {
3736             umbra_mul = you.piety + MAX_PIETY;
3737             umbra_div = MAX_PIETY;
3738         }
3739         if (player_equip_unrand(UNRAND_SHADOWS))
3740             if (2 * umbra_mul < 3 * umbra_div)
3741             {
3742                 umbra_mul = 3;
3743                 umbra_div = 2;
3744             }
3745         stealth *= umbra_mul;
3746         stealth /= umbra_div;
3747     }
3748
3749     // If you're surrounded by a storm, you're inherently pretty conspicuous.
3750     if (in_good_standing(GOD_QAZLAL, 0))
3751     {
3752         stealth = stealth
3753                   * (MAX_PIETY - min((int)you.piety, piety_breakpoint(5)))
3754                   / (MAX_PIETY - piety_breakpoint(0));
3755     }
3756     // The shifting glow from the Orb, while too unstable to negate invis
3757     // or affect to-hit, affects stealth even more than regular glow.
3758     if (orb_haloed(you.pos()))
3759         stealth /= 3;
3760
3761     stealth = max(0, stealth);
3762
3763     return stealth;
3764 }
3765
3766 // Returns the medium duration value which is usually announced by a special
3767 // message ("XY is about to time out") or a change of colour in the
3768 // status display.
3769 // Note that these values cannot be relied on when playing since there are
3770 // random decrements precisely to avoid this.
3771 int get_expiration_threshold(duration_type dur)
3772 {
3773     switch (dur)
3774     {
3775     case DUR_PETRIFYING:
3776         return 1 * BASELINE_DELAY;
3777
3778     case DUR_QUAD_DAMAGE:
3779         return 3 * BASELINE_DELAY; // per client.qc
3780
3781     case DUR_FIRE_SHIELD:
3782     case DUR_SILENCE: // no message
3783         return 5 * BASELINE_DELAY;
3784
3785     case DUR_REGENERATION:
3786     case DUR_RESISTANCE:
3787     case DUR_SWIFTNESS:
3788     case DUR_INVIS:
3789     case DUR_HASTE:
3790     case DUR_BERSERK:
3791     case DUR_ICY_ARMOUR:
3792     case DUR_CONDENSATION_SHIELD:
3793     case DUR_PHASE_SHIFT:
3794     case DUR_CONTROL_TELEPORT:
3795     case DUR_DEATH_CHANNEL:
3796     case DUR_SHROUD_OF_GOLUBRIA:
3797     case DUR_INFUSION:
3798     case DUR_SONG_OF_SLAYING:
3799     case DUR_TROGS_HAND:
3800     case DUR_QAZLAL_FIRE_RES:
3801     case DUR_QAZLAL_COLD_RES:
3802     case DUR_QAZLAL_ELEC_RES:
3803     case DUR_QAZLAL_AC:
3804         return 6 * BASELINE_DELAY;
3805
3806     case DUR_FLIGHT:
3807     case DUR_TRANSFORMATION: // not on status
3808     case DUR_DEATHS_DOOR:    // not on status
3809     case DUR_SLIMIFY:
3810         return 10 * BASELINE_DELAY;
3811
3812     // These get no messages when they "flicker".
3813     case DUR_CONFUSING_TOUCH:
3814         return 20 * BASELINE_DELAY;
3815
3816     case DUR_ANTIMAGIC:
3817         return you.hp_max; // not so severe anymore
3818
3819     default:
3820         return 0;
3821     }
3822 }
3823
3824 // Is a given duration about to expire?
3825 bool dur_expiring(duration_type dur)
3826 {
3827     const int value = you.duration[dur];
3828     if (value <= 0)
3829         return false;
3830
3831     return value <= get_expiration_threshold(dur);
3832 }
3833
3834 static void _output_expiring_message(duration_type dur, const char* msg)
3835 {
3836     if (you.duration[dur])
3837     {
3838         const bool expires = dur_expiring(dur);
3839         mprf("%s%s", expires ? "Expiring: " : "", msg);
3840     }
3841 }
3842
3843 static void _display_char_status(int value, const char *fmt, ...)
3844 {
3845     va_list argp;
3846     va_start(argp, fmt);
3847
3848     string msg = vmake_stringf(fmt, argp);
3849
3850     if (you.wizard)
3851         mprf("%s (%d).", msg.c_str(), value);
3852     else
3853         mprf("%s.", msg.c_str());
3854
3855     va_end(argp);
3856 }
3857
3858 static void _display_vampire_status()
3859 {
3860     string msg = "At your current hunger state you ";
3861     vector<const char *> attrib;
3862
3863     switch (you.hunger_state)
3864     {
3865         case HS_STARVING:
3866             attrib.push_back("resist poison");
3867             attrib.push_back("significantly resist cold");
3868             attrib.push_back("strongly resist negative energy");
3869             attrib.push_back("resist torment");
3870             attrib.push_back("do not heal.");
3871             break;
3872         case HS_NEAR_STARVING:
3873             attrib.push_back("resist poison");
3874             attrib.push_back("significantly resist cold");
3875             attrib.push_back("strongly resist negative energy");
3876             attrib.push_back("have an extremely slow metabolism");
3877             attrib.push_back("heal slowly.");
3878             break;
3879         case HS_VERY_HUNGRY:
3880         case HS_HUNGRY:
3881             attrib.push_back("resist poison");
3882             attrib.push_back("resist cold");
3883             attrib.push_back("significantly resist negative energy");
3884             if (you.hunger_state == HS_HUNGRY)
3885                 attrib.push_back("have a slow metabolism");
3886             else
3887                 attrib.push_back("have a very slow metabolism");
3888             attrib.push_back("heal slowly.");
3889             break;
3890         case HS_SATIATED:
3891             attrib.push_back("resist negative energy.");
3892             break;
3893         case HS_FULL:
3894             attrib.push_back("have a fast metabolism");
3895             attrib.push_back("heal quickly.");
3896             break;
3897         case HS_VERY_FULL:
3898             attrib.push_back("have a very fast metabolism");
3899             attrib.push_back("heal quickly.");
3900             break;
3901         case HS_ENGORGED:
3902             attrib.push_back("have an extremely fast metabolism");
3903             attrib.push_back("heal extremely quickly.");
3904             break;
3905     }
3906
3907     if (!attrib.empty())
3908     {
3909         msg += comma_separated_line(attrib.begin(), attrib.end());
3910         mpr(msg);
3911     }
3912 }
3913
3914 static void _display_movement_speed()
3915 {
3916     const int move_cost = (player_speed() * player_movement_speed()) / 10;
3917
3918     const bool water  = you.in_liquid();
3919     const bool swim   = you.swimming();
3920
3921     const bool fly    = you.flight_mode();
3922     const bool swift  = (you.duration[DUR_SWIFTNESS] > 0
3923                          && you.attribute[ATTR_SWIFTNESS] >= 0);
3924     const bool antiswift = (you.duration[DUR_SWIFTNESS] > 0
3925                             && you.attribute[ATTR_SWIFTNESS] < 0);
3926
3927     _display_char_status(move_cost, "Your %s speed is %s%s%s",
3928           // order is important for these:
3929           (swim)    ? "swimming" :
3930           (water)   ? "wading" :
3931           (fly)     ? "flying"
3932                     : "movement",
3933
3934           (water && !swim)  ? "uncertain and " :
3935           (!water && swift) ? "aided by the wind" :
3936           (!water && antiswift) ? "hindered by the wind" : "",
3937
3938           (!water && swift) ? ((move_cost >= 10) ? ", but still "
3939                                                  : " and ") :
3940           (!water && antiswift) ? ((move_cost <= 10) ? ", but still "
3941                                                      : " and ")
3942                             : "",
3943
3944           (move_cost <   8) ? "very quick" :
3945           (move_cost <  10) ? "quick" :
3946           (move_cost == 10) ? "average" :
3947           (move_cost <  13) ? "slow"
3948                             : "very slow");
3949 }
3950
3951 static void _display_tohit()
3952 {
3953 #ifdef DEBUG_DIAGNOSTICS
3954     melee_attack attk(&you, nullptr);
3955
3956     const int to_hit = attk.calc_to_hit(false);
3957
3958     dprf("To-hit: %d", to_hit);
3959 #endif
3960 }
3961
3962 static const char* _attack_delay_desc(int attack_delay)
3963 {
3964     return (attack_delay >= 200) ? "extremely slow" :
3965            (attack_delay >= 155) ? "very slow" :
3966            (attack_delay >= 125) ? "quite slow" :
3967            (attack_delay >= 105) ? "below average" :
3968            (attack_delay >=  95) ? "average" :
3969            (attack_delay >=  75) ? "above average" :
3970            (attack_delay >=  55) ? "quite fast" :
3971            (attack_delay >=  45) ? "very fast" :
3972            (attack_delay >=  35) ? "extremely fast" :
3973                                    "blindingly fast";
3974 }
3975
3976 /**
3977  * Print a message indicating the player's attack delay with their current
3978  * weapon & quivered ammo (if applicable).
3979  *
3980  * Uses melee attack delay for ranged weapons if no appropriate ammo is
3981  * is quivered, purely for simplicity of implementation; XXX fix this
3982  */
3983 static void _display_attack_delay()
3984 {
3985     const item_def* ammo = nullptr;
3986     you.m_quiver->get_desired_item(&ammo, nullptr);
3987     const bool uses_ammo = ammo && you.weapon()
3988                            && ammo->launched_by(*you.weapon());
3989     const int delay = you.attack_delay(you.weapon(), uses_ammo ? ammo : nullptr,
3990                                        false, false);
3991
3992     const int no_shield_delay = you.attack_delay(you.weapon(),
3993                                                  uses_ammo ? ammo : nullptr,
3994                                                  false, false, false);
3995     const bool at_min_delay = you.weapon()
3996                               && weapon_min_delay(*you.weapon())
3997                                  == no_shield_delay;
3998
3999     // Scale to fit the displayed weapon base delay, i.e.,
4000     // normal speed is 100 (as in 100%).
4001     int avg = 10 * delay;
4002
4003     // Haste shouldn't be counted, but let's show finesse.
4004     if (you.duration[DUR_FINESSE])
4005         avg = max(20, avg / 2);
4006
4007     _display_char_status(avg, "Your attack speed is %s%s",
4008                          _attack_delay_desc(avg),
4009                          at_min_delay ?
4010                             " (and cannot be increased with skill)" : "");
4011 }
4012
4013 // forward declaration
4014 static string _constriction_description();
4015
4016 void display_char_status()
4017 {
4018     if (you.undead_state() == US_SEMI_UNDEAD
4019         && you.hunger_state == HS_ENGORGED)
4020     {
4021         mpr("You feel almost alive.");
4022     }
4023     else if (you.undead_state())
4024         mpr("You are undead.");
4025     else if (you.duration[DUR_DEATHS_DOOR])
4026     {
4027         _output_expiring_message(DUR_DEATHS_DOOR,
4028                                  "You are standing in death's doorway.");
4029     }
4030     else
4031         mpr("You are alive.");
4032
4033     const int halo_size = you.halo_radius2();
4034     if (halo_size >= 0)
4035     {
4036         if (halo_size > 37)
4037             mpr("You are illuminated by a large divine halo.");
4038         else if (halo_size > 10)
4039             mpr("You are illuminated by a divine halo.");
4040         else
4041             mpr("You are illuminated by a small divine halo.");
4042     }
4043     else if (you.haloed())
4044         mpr("An external divine halo illuminates you.");
4045
4046     if (you.species == SP_VAMPIRE)
4047         _display_vampire_status();
4048
4049     // A hard-coded duration/status list used to be used here. This list is no
4050     // longer hard-coded. May 2014. -reaverb
4051     status_info inf;
4052     for (unsigned i = 0; i <= STATUS_LAST_STATUS; ++i)
4053     {
4054         if (fill_status_info(i, &inf) && !inf.long_text.empty())
4055             mpr(inf.long_text);
4056     }
4057     string cinfo = _constriction_description();
4058     if (!cinfo.empty())
4059         mpr(cinfo);
4060
4061     _display_movement_speed();
4062     _display_tohit();
4063     _display_attack_delay();
4064
4065     // magic resistance
4066     _display_char_status(you.res_magic(),
4067                          "You are %s to hostile enchantments",
4068                          magic_res_adjective(player_res_magic(false)).c_str());
4069
4070     // character evaluates their ability to sneak around:
4071     _display_char_status(check_stealth(),
4072                          "You feel %s",
4073                          stealth_desc(check_stealth()).c_str());
4074 }
4075
4076 bool player::clarity(bool calc_unid, bool items) const
4077 {
4078     if (player_mutation_level(MUT_CLARITY))
4079         return true;
4080
4081     if (in_good_standing(GOD_ASHENZARI, 2))
4082         return true;
4083
4084     return actor::clarity(calc_unid, items);
4085 }
4086
4087 bool player::gourmand(bool calc_unid, bool items) const
4088 {
4089     if (player_mutation_level(MUT_GOURMAND) > 0)
4090         return true;
4091
4092     return actor::gourmand(calc_unid, items);
4093 }
4094
4095 bool player::stasis(bool calc_unid, bool items) const
4096 {
4097     if (species == SP_FORMICID)
4098         return true;
4099
4100     return actor::stasis(calc_unid, items);
4101 }
4102
4103 unsigned int exp_needed(int lev, int exp_apt)
4104 {
4105     unsigned int level = 0;
4106
4107     // Basic plan:
4108     // Section 1: levels  1- 5, second derivative goes 10-10-20-30.
4109     // Section 2: levels  6-13, second derivative is exponential/doubling.
4110     // Section 3: levels 14-27, second derivative is constant at 8470.
4111
4112     // Here's a table:
4113     //
4114     // level      xp      delta   delta2
4115     // =====   =======    =====   ======
4116     //   1           0        0       0
4117     //   2          10       10      10
4118     //   3          30       20      10
4119     //   4          70       40      20
4120     //   5         140       70      30
4121     //   6         270      130      60
4122     //   7         520      250     120
4123     //   8        1010      490     240
4124     //   9        1980      970     480
4125     //  10        3910     1930     960
4126     //  11        7760     3850    1920
4127     //  12       15450     7690    3840
4128     //  13       26895    11445    3755
4129     //  14       45585    18690    7245
4130     //  15       72745    27160    8470
4131     //  16      108375    35630    8470
4132     //  17      152475    44100    8470
4133     //  18      205045    52570    8470
4134     //  19      266085    61040    8470
4135     //  20      335595    69510    8470
4136     //  21      413575    77980    8470
4137     //  22      500025    86450    8470
4138     //  23      594945    94920    8470
4139     //  24      698335    103390   8470
4140     //  25      810195    111860   8470
4141     //  26      930525    120330   8470
4142     //  27     1059325    128800   8470
4143
4144     switch (lev)
4145     {
4146     case 1:
4147         level = 1;
4148         break;
4149     case 2:
4150         level = 10;
4151         break;
4152     case 3:
4153         level = 30;
4154         break;
4155     case 4:
4156         level = 70;
4157         break;
4158
4159     default:
4160         if (lev < 13)
4161         {
4162             lev -= 4;
4163             level = 10 + 10 * lev + (60 << lev);
4164         }
4165         else
4166         {
4167             lev -= 12;
4168             level = 16675 + 5985 * lev + 4235 * lev * lev;
4169         }
4170         break;
4171     }
4172
4173     if (exp_apt ==