1 #include "AppHdr.h"
2
3 #include "stairs.h"
4
5 #include <sstream>
6
7 #include "ability.h"
8 #include "abyss.h"
9 #include "act-iter.h"
10 #include "areas.h"
11 #include "artefact.h"
12 #include "bloodspatter.h"
13 #include "branch.h"
14 #include "chardump.h"
15 #include "colour.h"
16 #include "coordit.h"
17 #include "delay.h"
18 #include "dgn-overview.h"
19 #include "directn.h"
20 #include "env.h"
21 #include "files.h"
22 #include "god-passive.h" // passive_t::slow_abyss
23 #include "hints.h"
24 #include "hiscores.h"
25 #include "item-name.h"
26 #include "items.h"
27 #include "level-state-type.h"
28 #include "losglobal.h"
29 #include "mapmark.h"
30 #include "message.h"
31 #include "mon-death.h"
32 #include "movement.h"
33 #include "notes.h"
34 #include "orb-type.h"
35 #include "output.h"
36 #include "prompt.h"
37 #include "religion.h"
38 #include "spl-clouds.h"
39 #include "spl-damage.h"
40 #include "spl-other.h"
41 #include "state.h"
42 #include "stringutil.h"
43 #include "tag-version.h"
44 #include "terrain.h"
45 #ifdef USE_TILE_LOCAL
46 #include "tilepick.h"
47 #endif
48 #include "tiles-build-specific.h"
49 #include "timed-effects.h" // bezotted
50 #include "traps.h"
51 #include "travel.h"
52 #include "view.h"
53 #include "xom.h"
54
_annotation_exclusion_warning(level_id next_level_id)55 static string _annotation_exclusion_warning(level_id next_level_id)
56 {
57 if (level_annotation_has("!", next_level_id)
58 && next_level_id != level_id::current()
59 && is_connected_branch(next_level_id))
60 {
61 crawl_state.level_annotation_shown = true;
62 return make_stringf("Warning, next level annotated: <yellow>%s</yellow>",
63 get_level_annotation(next_level_id).c_str());
64 }
65
66 if (is_exclude_root(you.pos())
67 && feat_is_travelable_stair(env.grid(you.pos()))
68 && !strstr(get_exclusion_desc(you.pos()).c_str(), "cloud"))
69 {
70 return "This staircase is marked as excluded!";
71 }
72
73 return "";
74 }
75
_target_exclusion_warning()76 static string _target_exclusion_warning()
77 {
78 if (!feat_is_travelable_stair(env.grid(you.pos())))
79 return "";
80
81 LevelInfo *li = travel_cache.find_level_info(level_id::current());
82 if (!li)
83 return "";
84
85 const stair_info *si = li->get_stair(you.pos());
86 if (!si)
87 return "";
88
89 if (stairs_destination_is_excluded(*si))
90 return "This staircase leads to a travel-excluded area!";
91
92 return "";
93 }
94
_bezotting_warning(branch_type branch)95 static string _bezotting_warning(branch_type branch)
96 {
97 if (branch == you.where_are_you || !bezotted_in(branch))
98 return "";
99
100 const int turns = turns_until_zot_in(branch);
101 return make_stringf("You have just %d turns in %s to find a new floor before Zot consumes you.",
102 turns, branches[branch].longname);
103 }
104
check_next_floor_warning()105 bool check_next_floor_warning()
106 {
107 level_id next_level_id = level_id::get_next_level_id(you.pos());
108
109 crawl_state.level_annotation_shown = false;
110 const string annotation_warning = _annotation_exclusion_warning(next_level_id);
111
112 const string target_warning = _target_exclusion_warning();
113 const string bezotting_warning = _bezotting_warning(next_level_id.branch);
114
115 if (annotation_warning != "")
116 mprf(MSGCH_PROMPT, "%s", annotation_warning.c_str());
117 if (target_warning != "")
118 mprf(MSGCH_PROMPT, "%s", target_warning.c_str());
119 if (bezotting_warning != "")
120 mprf(MSGCH_PROMPT, "%s", bezotting_warning.c_str());
121
122 const bool might_be_dangerous = annotation_warning != ""
123 || target_warning != ""
124 || bezotting_warning != "";
125
126 if (might_be_dangerous
127 && !yesno("Enter next level anyway?", true, 'n', true, false))
128 {
129 canned_msg(MSG_OK);
130 interrupt_activity(activity_interrupt::force);
131 crawl_state.level_annotation_shown = false;
132 return false;
133 }
134 return true;
135 }
136
_player_change_level_reset()137 static void _player_change_level_reset()
138 {
139 you.prev_targ = MHITNOT;
140 if (you.pet_target != MHITYOU)
141 you.pet_target = MHITNOT;
142
143 you.prev_grd_targ.reset();
144 }
145
_player_change_level(level_id lev)146 static void _player_change_level(level_id lev)
147 {
148 you.depth = lev.depth;
149 you.where_are_you = lev.branch;
150 }
151
_maybe_destroy_shaft(const coord_def & p)152 static void _maybe_destroy_shaft(const coord_def &p)
153 {
154 trap_def* trap = trap_at(p);
155 if (trap && trap->type == TRAP_SHAFT)
156 trap->destroy(true);
157 }
158
_stair_moves_pre(dungeon_feature_type stair)159 static bool _stair_moves_pre(dungeon_feature_type stair)
160 {
161 if (crawl_state.prev_cmd == CMD_WIZARD)
162 return false;
163
164 if (stair != env.grid(you.pos()))
165 return false;
166
167 if (feat_stair_direction(stair) == CMD_NO_CMD)
168 return false;
169
170 if (!you.duration[DUR_REPEL_STAIRS_CLIMB])
171 return false;
172
173 int pct;
174 if (you.duration[DUR_REPEL_STAIRS_MOVE])
175 pct = 29;
176 else
177 pct = 50;
178
179 // When the effect is still strong, the chance to actually catch a stair
180 // is smaller. (Assuming the duration starts out at 500.)
181 const int dur = max(0, you.duration[DUR_REPEL_STAIRS_CLIMB] - 200);
182 pct += dur/20;
183
184 if (!x_chance_in_y(pct, 100))
185 return false;
186
187 // Get feature name before sliding stair over.
188 string stair_str = feature_description_at(you.pos(), false, DESC_THE);
189
190 if (!slide_feature_over(you.pos()))
191 return false;
192
193 string verb = stair_climb_verb(stair);
194
195 mprf("%s moves away as you attempt to %s it!", stair_str.c_str(),
196 verb.c_str());
197
198 you.turn_is_over = true;
199
200 return true;
201 }
202
_climb_message(dungeon_feature_type stair,bool going_up,branch_type old_branch)203 static void _climb_message(dungeon_feature_type stair, bool going_up,
204 branch_type old_branch)
205 {
206 if (!is_connected_branch(old_branch))
207 return;
208
209 if (feat_is_portal(stair))
210 mpr("The world spins around you as you enter the gateway.");
211 else if (feat_is_escape_hatch(stair))
212 {
213 if (going_up)
214 mpr("A mysterious force pulls you upwards.");
215 else
216 {
217 mprf("You %s downwards.",
218 you.airborne() ? "fly" : "slide");
219 }
220 mpr("The hatch slams shut behind you.");
221 }
222 else if (feat_is_gate(stair))
223 {
224 mprf("You %s %s through the gate.",
225 you.airborne() ? "fly" : "go",
226 going_up ? "up" : "down");
227 }
228 else
229 {
230 mprf("You %s %swards.",
231 you.airborne() ? "fly" : "climb",
232 going_up ? "up" : "down");
233 }
234 }
235
_clear_golubria_traps()236 static void _clear_golubria_traps()
237 {
238 for (auto c : find_golubria_on_level())
239 {
240 trap_def *trap = trap_at(c);
241 if (trap && trap->type == TRAP_GOLUBRIA)
242 trap->destroy();
243 }
244 }
245
_clear_prisms()246 static void _clear_prisms()
247 {
248 for (auto &mons : menv_real)
249 if (mons.type == MONS_FULMINANT_PRISM)
250 mons.reset();
251 }
252
_complete_zig()253 static void _complete_zig()
254 {
255 if (!zot_immune())
256 mpr("You have passed through the Ziggurat. Zot will hunt you nevermore.");
257 you.zigs_completed++;
258 }
259
leaving_level_now(dungeon_feature_type stair_used)260 void leaving_level_now(dungeon_feature_type stair_used)
261 {
262 if (stair_used == DNGN_EXIT_ZIGGURAT)
263 {
264 if (you.depth == 27)
265 _complete_zig();
266 mark_milestone("zig.exit", make_stringf("left a ziggurat at level %d.",
267 you.depth));
268 }
269
270 if (stair_used == DNGN_EXIT_ABYSS)
271 {
272 #ifdef DEBUG
273 auto &vault_list = you.vault_list[level_id::current()];
274 vault_list.push_back("[exit]");
275 #endif
276 }
277
278 dungeon_events.fire_position_event(DET_PLAYER_CLIMBS, you.pos());
279 dungeon_events.fire_event(DET_LEAVING_LEVEL);
280
281 _clear_golubria_traps();
282 _clear_prisms();
283
284 end_recall();
285 }
286
_update_travel_cache(const level_id & old_level,const coord_def & stair_pos)287 static void _update_travel_cache(const level_id& old_level,
288 const coord_def& stair_pos)
289 {
290 // If the old level is gone, nothing to save.
291 if (!you.save || !you.save->has_chunk(old_level.describe()))
292 return;
293
294 // Update stair information for the stairs we just ascended, and the
295 // down stairs we're currently on.
296 level_id new_level_id = level_id::current();
297
298 if (can_travel_interlevel())
299 {
300 LevelInfo &old_level_info =
301 travel_cache.get_level_info(old_level);
302 LevelInfo &new_level_info =
303 travel_cache.get_level_info(new_level_id);
304 new_level_info.update();
305
306 // First we update the old level's stair.
307 level_pos lp;
308 lp.id = new_level_id;
309 lp.pos = you.pos();
310
311 bool guess = false;
312 // Ugly hack warning:
313 // The stairs in the Vestibule of Hell exhibit special behaviour:
314 // they always lead back to the dungeon level that the player
315 // entered the Vestibule from. This means that we need to pretend
316 // we don't know where the upstairs from the Vestibule go each time
317 // we take it. If we don't, interlevel travel may try to use portals
318 // to Hell as shortcuts between dungeon levels, which won't work,
319 // and will confuse the dickens out of the player (well, it confused
320 // the dickens out of me when it happened).
321 if ((new_level_id == BRANCH_DUNGEON || new_level_id == BRANCH_DEPTHS)
322 && old_level == BRANCH_VESTIBULE)
323 {
324 old_level_info.clear_stairs(DNGN_EXIT_HELL);
325 }
326 else
327 old_level_info.update_stair(stair_pos, lp, guess);
328
329 // We *guess* that going up a staircase lands us on a downstair,
330 // and that we can descend that downstair and get back to where we
331 // came from. This assumption is guaranteed false when climbing out
332 // of one of the branches of Hell.
333 if (new_level_id != BRANCH_VESTIBULE
334 || !is_hell_subbranch(old_level.branch))
335 {
336 // Set the new level's stair, assuming arbitrarily that going
337 // downstairs will land you on the same upstairs you took to
338 // begin with (not necessarily true).
339 lp.id = old_level;
340 lp.pos = stair_pos;
341 new_level_info.update_stair(you.pos(), lp, true);
342 }
343 }
344 }
345
346 // These checks are probably unnecessary.
_check_stairs(const dungeon_feature_type ftype,bool going_up)347 static bool _check_stairs(const dungeon_feature_type ftype, bool going_up)
348 {
349 // If it's not bidirectional, check that the player is headed
350 // in the right direction.
351 if (!feat_is_bidirectional_portal(ftype))
352 {
353 if (feat_stair_direction(ftype) != (going_up ? CMD_GO_UPSTAIRS
354 : CMD_GO_DOWNSTAIRS))
355 {
356 if (ftype == DNGN_STONE_ARCH)
357 mpr("There is nothing on the other side of the stone arch.");
358 else if (ftype == DNGN_ABANDONED_SHOP)
359 mpr("This shop has been abandoned, nothing of value remains.");
360 else if (going_up)
361 mpr("You can't go up here!");
362 else
363 mpr("You can't go down here!");
364 return false;
365 }
366 }
367
368 return true;
369 }
370
_check_fall_down_stairs(const dungeon_feature_type ftype,bool going_up)371 static bool _check_fall_down_stairs(const dungeon_feature_type ftype, bool going_up)
372 {
373 if (!you.airborne()
374 && you.confused()
375 && !feat_is_escape_hatch(ftype)
376 && coinflip())
377 {
378 const char* fall_where = "down the stairs";
379 if (!feat_is_staircase(ftype))
380 fall_where = "through the gate";
381
382 mprf("In your confused state, you trip and fall %s%s.",
383 going_up ? "back " : "", fall_where);
384 if (!feat_is_staircase(ftype))
385 ouch(1, KILLED_BY_FALLING_THROUGH_GATE);
386 else
387 ouch(1, KILLED_BY_FALLING_DOWN_STAIRS);
388
389 // Note that if going downstairs, this only does damage.
390 // It doesn't cancel the level transition.
391 if (going_up)
392 {
393 you.turn_is_over = true;
394 return true;
395 }
396 }
397
398 return false;
399 }
400
_rune_effect(dungeon_feature_type ftype)401 static void _rune_effect(dungeon_feature_type ftype)
402 {
403 // Nothing even remotely flashy for Zig.
404 if (ftype != DNGN_ENTER_ZIGGURAT)
405 {
406 vector<int> runes;
407 for (int i = 0; i < NUM_RUNE_TYPES; i++)
408 if (you.runes[i])
409 runes.push_back(i);
410
411 ASSERT(runes.size() >= 1);
412 shuffle_array(runes);
413
414 // Zot is extra flashy.
415 if (ftype == DNGN_ENTER_ZOT)
416 {
417 ASSERT(runes.size() >= 3);
418
419 mprf("You insert the %s rune into the lock.", rune_type_name(runes[2]));
420 #ifdef USE_TILE_LOCAL
421 view_add_tile_overlay(you.pos(), tileidx_zap(rune_colour(runes[2])));
422 viewwindow(false);
423 update_screen();
424 #else
425 flash_view(UA_BRANCH_ENTRY, rune_colour(runes[2]));
426 #endif
427 mpr("The lock glows eerily!");
428 // included in default force_more_message
429
430 mprf("You insert the %s rune into the lock.", rune_type_name(runes[1]));
431 big_cloud(CLOUD_BLUE_SMOKE, &you, you.pos(), 20, 7 + random2(7));
432 viewwindow();
433 update_screen();
434 mpr("Heavy smoke blows from the lock!");
435 // included in default force_more_message
436 }
437
438 mprf("You insert the %s rune into the lock.", rune_type_name(runes[0]));
439
440 if (silenced(you.pos()))
441 mpr("The gate opens wide!");
442 else
443 mpr("With a soft hiss the gate opens wide!");
444 // these are included in default force_more_message
445 }
446 }
447
_gauntlet_effect()448 static void _gauntlet_effect()
449 {
450 // already doomed
451 if (you.stasis())
452 return;
453
454 mprf(MSGCH_WARN, "The nature of this place prevents you from teleporting.");
455
456 if (player_teleport(false))
457 mpr("You feel stable on this floor.");
458 }
459
_new_level_amuses_xom(dungeon_feature_type feat,dungeon_feature_type old_feat,bool shaft,int shaft_depth,bool voluntary)460 static void _new_level_amuses_xom(dungeon_feature_type feat,
461 dungeon_feature_type old_feat,
462 bool shaft, int shaft_depth, bool voluntary)
463 {
464 switch (you.where_are_you)
465 {
466 default:
467 // Xom thinks it's funny if you enter a new level via shaft
468 // or escape hatch, for shafts it's funnier the deeper you fell.
469 if (shaft || feat_is_escape_hatch(feat))
470 xom_is_stimulated(shaft_depth * 50);
471 else if (!is_connected_branch(you.where_are_you))
472 xom_is_stimulated(25);
473 else
474 xom_is_stimulated(10);
475 break;
476
477 case BRANCH_ZIGGURAT:
478 // The best way to die currently.
479 xom_is_stimulated(50);
480 break;
481
482 case BRANCH_PANDEMONIUM:
483 xom_is_stimulated(100);
484 break;
485
486 case BRANCH_ABYSS:
487 if (voluntary && old_feat == DNGN_ENTER_ABYSS)
488 xom_is_stimulated(100, XM_INTRIGUED);
489 else
490 xom_is_stimulated(200);
491 break;
492 }
493 }
494
495 /**
496 * Determine destination level.
497 *
498 * @param how How the player is trying to travel.
499 * (e.g. stairs, traps, portals, etc)
500 * @param forced True if the player is forcing the traveling attempt.
501 * (e.g. forcibly exiting the abyss, etc)
502 * @param going_up True if the player is going upstairs.
503 * @param known_shaft True if the player is intentionally shafting themself.
504 * @return The destination level, if valid. Note the default value
505 * of dest is not valid (since depth = -1) and this is
506 * generally what is returned for invalid destinations.
507 * But note the special case when failing to climb stairs
508 * when attempting to leave the dungeon, depth = 1.
509 */
_travel_destination(const dungeon_feature_type how,bool forced,bool going_up,bool known_shaft)510 static level_id _travel_destination(const dungeon_feature_type how,
511 bool forced, bool going_up,
512 bool known_shaft)
513 {
514 const bool shaft = known_shaft || how == DNGN_TRAP_SHAFT;
515 level_id shaft_dest;
516 level_id dest;
517 if (shaft)
518 {
519 if (!is_valid_shaft_level())
520 {
521 if (known_shaft)
522 mpr("The shaft disappears in a puff of logic!");
523 _maybe_destroy_shaft(you.pos());
524 return dest;
525 }
526
527 shaft_dest = you.shaft_dest();
528 }
529 // How far down you fall via a shaft or hatch.
530 const int shaft_depth = (shaft ? shaft_dest.depth - you.depth : 1);
531
532 // Only check the current position for a legal stair traverse.
533 // Check that we're going the right way (if we're not falling through
534 // a shaft or being forced).
535 if (!shaft && !forced && !_check_stairs(how, going_up))
536 return dest;
537
538 // Up and down both work for some portals.
539 // Canonicalize the direction: hell exits into the vestibule are considered
540 // going up; everything else is going down. This mostly affects which way you
541 // fall if confused.
542 if (feat_is_bidirectional_portal(how))
543 going_up = (how == DNGN_ENTER_HELL && player_in_hell(false));
544
545 if (_stair_moves_pre(how))
546 return dest;
547
548 // Falling down is checked before the transition if going upstairs, since
549 // it might prevent the transition itself.
550 if (going_up && _check_fall_down_stairs(how, true))
551 {
552 // TODO: This probably causes an obscure bug where confused players
553 // going 'down' into the vestibule are twice as likely to fall, because
554 // they have to pass a check here, and later in floor_transition
555 // Right solution is probably to use the canonicalized direction everywhere
556
557 // If player falls down the stairs trying to leave the dungeon, we set
558 // the destination depth to 1 (i.e. D:1)
559 if (how == DNGN_EXIT_DUNGEON)
560 dest.depth = 1;
561 return dest;
562 }
563
564 if (shaft)
565 {
566 if (shaft_dest == level_id::current())
567 {
568 if (known_shaft)
569 {
570 mpr("Strange, the shaft seems to lead back to this level.");
571 mpr("The strain on the space-time continuum destroys the "
572 "shaft!");
573 }
574 _maybe_destroy_shaft(you.pos());
575 return dest;
576 }
577
578 if (!known_shaft)
579 {
580 mark_milestone("shaft", "fell down a shaft to "
581 + shaft_dest.describe() + ".");
582 }
583
584 mprf("You %s into a shaft and drop %d floor%s!",
585 you.airborne() ? "are sucked" : "fall",
586 shaft_depth,
587 shaft_depth > 1 ? "s" : "");
588
589 // Shafts are one-time-use.
590 mpr("The shaft crumbles and collapses.");
591 _maybe_destroy_shaft(you.pos());
592 }
593
594 // Maybe perform the entry sequence (we check that they have enough runes
595 // in main.cc: _can_take_stairs())
596 for (branch_iterator it; it; ++it)
597 {
598 if (how != it->entry_stairs)
599 continue;
600
601 if (!you.level_visited(level_id(it->id, 1))
602 && runes_for_branch(it->id) > 0)
603 {
604 _rune_effect(how);
605 }
606
607 break;
608 }
609
610 // Markers might be deleted when removing portals.
611 const string dst = env.markers.property_at(you.pos(), MAT_ANY, "dst");
612
613 if (shaft)
614 return shaft_dest;
615 else
616 return stair_destination(how, dst, true);
617 }
618
619 /**
620 * Check to see if transition will actually move the player.
621 *
622 * @param dest The destination level (branch and depth).
623 * @param feat The dungeon feature the player is standing on.
624 * @param going_up True if the player is trying to go up stairs.
625 * @return True if the level transition should happen.
626 */
_level_transition_moves_player(level_id dest,dungeon_feature_type feat,bool going_up)627 static bool _level_transition_moves_player(level_id dest,
628 dungeon_feature_type feat,
629 bool going_up)
630 {
631 bool trying_to_exit = feat == DNGN_EXIT_DUNGEON && going_up;
632
633 // When exiting the dungeon, dest is not valid (depth = -1)
634 // So the player can transition with an invalid dest ONLY when exiting.
635 // Otherwise (i.e. not exiting) dest must be valid.
636 return dest.is_valid() != trying_to_exit;
637 }
638
639 /**
640 * Transition to a different level.
641 *
642 * @param how The type of stair/portal tile the player is being conveyed through
643 * @param whence The tile the player was on at the beginning of the transition
644 * (likely the same as how, unless forced is true)
645 * @param whither The destination level
646 * @param shaft Is the player going down a shaft?
647 */
floor_transition(dungeon_feature_type how,const dungeon_feature_type whence,level_id whither,bool forced,bool going_up,bool shaft,bool update_travel_cache)648 void floor_transition(dungeon_feature_type how,
649 const dungeon_feature_type whence, level_id whither,
650 bool forced, bool going_up, bool shaft,
651 bool update_travel_cache)
652 {
653 const level_id old_level = level_id::current();
654
655 // Clean up fake blood.
656 heal_flayed_effect(&you, true, true);
657
658 // We "stepped".
659 if (!forced)
660 apply_barbs_damage();
661
662 // Magical level changes (which currently only exist "downwards") need this.
663 clear_trapping_net();
664 end_wait_spells();
665 you.stop_constricting_all();
666 you.stop_being_constricted();
667 you.clear_beholders();
668 you.clear_fearmongers();
669 dec_frozen_ramparts(you.duration[DUR_FROZEN_RAMPARTS]);
670
671 // Fire level-leaving trigger.
672 leaving_level_now(how);
673
674 // Not entirely accurate - the player could die before
675 // reaching the Abyss.
676 if (!forced && whence == DNGN_ENTER_ABYSS)
677 {
678 mark_milestone("abyss.enter", "entered the Abyss!");
679 take_note(Note(NOTE_MESSAGE, 0, 0, "Voluntarily entered the Abyss."), true);
680 }
681 else if (!forced && whence == DNGN_EXIT_THROUGH_ABYSS)
682 {
683 mark_milestone("abyss.enter", "escaped (hah) into the Abyss!");
684 take_note(Note(NOTE_MESSAGE, 0, 0, "Took an exit into the Abyss."), true);
685 }
686 else if (how == DNGN_EXIT_ABYSS
687 && you.chapter != CHAPTER_POCKET_ABYSS)
688 {
689 mark_milestone("abyss.exit", "escaped from the Abyss!");
690 you.attribute[ATTR_BANISHMENT_IMMUNITY] = you.elapsed_time + 100
691 + random2(100);
692 you.banished_by = "";
693 you.banished_power = 0;
694 }
695
696 // Interlevel travel data.
697 const bool collect_travel_data = can_travel_interlevel();
698 if (collect_travel_data)
699 {
700 LevelInfo &old_level_info = travel_cache.get_level_info(old_level);
701 old_level_info.update();
702 }
703
704 const coord_def stair_pos = you.pos();
705
706 if (how == DNGN_EXIT_DUNGEON)
707 {
708 you.depth = 0;
709 mpr("You have escaped!");
710
711 if (player_has_orb())
712 ouch(INSTANT_DEATH, KILLED_BY_WINNING);
713
714 ouch(INSTANT_DEATH, KILLED_BY_LEAVING);
715 }
716
717 if (how == DNGN_ENTER_ZIGGURAT)
718 dungeon_terrain_changed(you.pos(), DNGN_STONE_ARCH);
719
720 if (how == DNGN_ENTER_PANDEMONIUM
721 || how == DNGN_ENTER_ABYSS
722 || feat_is_portal_entrance(how))
723 {
724 you.level_stack.push_back(level_pos::current());
725 }
726
727 // Actually change the player's branch and depth, along with some cleanup.
728 _player_change_level_reset();
729 _player_change_level(whither);
730
731 // Some branch specific messages.
732 if (old_level.branch == BRANCH_VESTIBULE
733 && !is_hell_subbranch(you.where_are_you))
734 {
735 mpr("Thank you for visiting Hell. Please come again soon.");
736 }
737
738 if (how == DNGN_EXIT_ABYSS
739 || how == DNGN_EXIT_PANDEMONIUM
740 || how == DNGN_EXIT_THROUGH_ABYSS)
741 {
742 mpr("You pass through the gate.");
743 take_note(Note(NOTE_MESSAGE, 0, 0,
744 how == DNGN_EXIT_ABYSS ? "Escaped the Abyss" :
745 how == DNGN_EXIT_PANDEMONIUM ? "Escaped Pandemonium" :
746 how == DNGN_EXIT_THROUGH_ABYSS ? "Escaped into the Abyss" :
747 "Buggered into bugdom"), true);
748
749 if (!you.wizard || !crawl_state.is_replaying_keys())
750 more();
751 }
752
753 // Fixup exits from the Hell branches.
754 if (player_in_branch(BRANCH_VESTIBULE)
755 && is_hell_subbranch(old_level.branch))
756 {
757 how = branches[old_level.branch].entry_stairs;
758 }
759
760 // Check for falling down the stairs or portal.
761 if (!going_up && !shaft && !forced)
762 _check_fall_down_stairs(how, false);
763
764 if (shaft)
765 how = DNGN_TRAP_SHAFT;
766
767 switch (you.where_are_you)
768 {
769 case BRANCH_ABYSS:
770 // There are no abyssal stairs that go up, so this whole case is only
771 // when going down.
772 you.props.erase(ABYSS_SPAWNED_XP_EXIT_KEY);
773 if (old_level.branch == BRANCH_ABYSS)
774 {
775 mprf(MSGCH_BANISHMENT, "You plunge deeper into the Abyss.");
776 if (!you.runes[RUNE_ABYSSAL] && you.depth >= ABYSSAL_RUNE_MIN_LEVEL)
777 mpr("The abyssal rune of Zot can be found at this depth.");
778 break;
779 }
780 if (!forced)
781 mpr("You enter the Abyss!");
782
783 mpr("To return, you must find a gate leading back.");
784 mpr("Killing monsters will force the Abyss to allow you passage.");
785 if (have_passive(passive_t::slow_abyss))
786 {
787 mprf(MSGCH_GOD, you.religion,
788 "You feel %s slowing down the madness of this place.",
789 god_name(you.religion).c_str());
790 }
791
792 you.props[ABYSS_STAIR_XP_KEY] = EXIT_XP_COST;
793
794 // Re-entering the Abyss halves accumulated speed.
795 you.abyss_speed /= 2;
796 learned_something_new(HINT_ABYSS);
797 break;
798
799 case BRANCH_PANDEMONIUM:
800 if (old_level.branch == BRANCH_PANDEMONIUM)
801 mpr("You pass into a different region of Pandemonium.");
802 break;
803
804 default:
805 // This hits both cases.
806 if (!shaft)
807 _climb_message(how, going_up, old_level.branch);
808 break;
809 }
810
811 // Did we enter a different branch?
812 if (!player_in_branch(old_level.branch))
813 {
814 const branch_type branch = you.where_are_you;
815 if (branch_entered(branch))
816 mprf("Welcome back to %s!", branches[branch].longname);
817 else if (how == branches[branch].entry_stairs)
818 {
819 if (branches[branch].entry_message)
820 mpr(branches[branch].entry_message);
821 else if (branch != BRANCH_ABYSS) // too many messages...
822 mprf("Welcome to %s!", branches[branch].longname);
823 }
824 const bool was_bezotted = bezotted_in(old_level.branch);
825 if (bezotted())
826 {
827 if (was_bezotted)
828 mpr("Zot already knows this place too well. Descend or flee this branch!");
829 else
830 mpr("Zot's attention fixes on you again. Descend or flee this branch!");
831 }
832 else if (was_bezotted)
833 {
834 if (branch == BRANCH_ABYSS)
835 mpr("Zot has no power in the Abyss.");
836 else
837 mpr("You feel Zot lose track of you.");
838 }
839
840 if (branch == BRANCH_GAUNTLET)
841 _gauntlet_effect();
842
843 const set<branch_type> boring_branch_exits = {
844 BRANCH_TEMPLE,
845 BRANCH_BAZAAR,
846 BRANCH_TROVE
847 };
848
849 // Did we leave a notable branch for the first time?
850 if (boring_branch_exits.count(old_level.branch) == 0
851 && !you.branches_left[old_level.branch])
852 {
853 string old_branch_string = branches[old_level.branch].longname;
854 if (starts_with(old_branch_string, "The "))
855 old_branch_string[0] = tolower_safe(old_branch_string[0]);
856 mark_milestone("br.exit", "left " + old_branch_string + ".",
857 old_level.describe());
858 you.branches_left.set(old_level.branch);
859 }
860 if (how == branches[branch].entry_stairs)
861 {
862 const string noise_desc = branch_noise_desc(branch);
863 if (!noise_desc.empty())
864 mpr(noise_desc);
865
866 const string rune_msg = branch_rune_desc(branch, true);
867 if (!rune_msg.empty())
868 mpr(rune_msg);
869 }
870
871 // Entered a branch from its parent.
872 if (parent_branch(branch) == old_level.branch)
873 enter_branch(branch, old_level);
874 }
875
876 // Warn Formicids if they cannot shaft here
877 if (player_has_ability(ABIL_SHAFT_SELF, true)
878 && !is_valid_shaft_level())
879 {
880 mpr("Beware, you cannot shaft yourself on this level.");
881 }
882
883 const bool newlevel = load_level(how, LOAD_ENTER_LEVEL, old_level);
884
885 if (newlevel)
886 {
887 _new_level_amuses_xom(how, whence, shaft,
888 (shaft ? whither.depth - old_level.depth : 1),
889 !forced);
890 }
891
892 // This should maybe go in load_level?
893 if (you.where_are_you == BRANCH_ABYSS)
894 generate_random_blood_spatter_on_level();
895
896 you.turn_is_over = true;
897
898 save_game_state();
899
900 new_level();
901
902 moveto_location_effects(whence);
903
904 trackers_init_new_level();
905
906 if (update_travel_cache && !shaft)
907 _update_travel_cache(old_level, stair_pos);
908
909 // Preventing obvious finding of stairs at your position.
910 env.map_seen.set(you.pos());
911
912 viewwindow();
913 update_screen();
914
915 // There's probably a reason for this. I don't know it.
916 if (going_up)
917 seen_monsters_react();
918 else
919 maybe_update_stashes();
920
921 autotoggle_autopickup(false);
922 request_autopickup();
923 }
924
925 /**
926 * Try to go up or down stairs.
927 *
928 * @param force_stair The type of stair/portal to take. By default,
929 * use whatever tile is under the player. But this can be overridden
930 * (e.g. passing DNGN_EXIT_ABYSS forces the player out of the abyss)
931 * @param going_up True if the player is going upstairs
932 * @param force_known_shaft True if player is shafting themselves via ability.
933 * @param update_travel_cache True if travel cache should be updated.
934 */
take_stairs(dungeon_feature_type force_stair,bool going_up,bool force_known_shaft,bool update_travel_cache)935 void take_stairs(dungeon_feature_type force_stair, bool going_up,
936 bool force_known_shaft, bool update_travel_cache)
937 {
938 const dungeon_feature_type old_feat = orig_terrain(you.pos());
939 dungeon_feature_type how = force_stair ? force_stair : old_feat;
940
941 // Taking a shaft manually (stepping on a known shaft, or using shaft ability)
942 const bool known_shaft = (!force_stair
943 && get_trap_type(you.pos()) == TRAP_SHAFT)
944 || (force_stair == DNGN_TRAP_SHAFT
945 && force_known_shaft);
946 // Latter case is falling down a shaft.
947 const bool shaft = known_shaft || force_stair == DNGN_TRAP_SHAFT;
948
949 level_id whither = _travel_destination(how, bool(force_stair), going_up,
950 known_shaft);
951
952 if (!_level_transition_moves_player(whither, old_feat, going_up))
953 return;
954
955 // The transition is "forced" for the purpose of floor_transition if
956 // a force_stair feature is specified and force_known_shaft is not set
957 // (in the latter case, the player 'moved').
958 floor_transition(how, old_feat, whither,
959 bool(force_stair) && !force_known_shaft,
960 going_up, shaft, update_travel_cache);
961 }
962
up_stairs(dungeon_feature_type force_stair,bool update_travel_cache)963 void up_stairs(dungeon_feature_type force_stair, bool update_travel_cache)
964 {
965 take_stairs(force_stair, true, false, update_travel_cache);
966 }
967
968 // Find the other end of the stair or portal at location pos on the current
969 // level. for_real is true if we are actually traversing the feature rather
970 // than merely asking what is on the other side.
stair_destination(coord_def pos,bool for_real)971 level_id stair_destination(coord_def pos, bool for_real)
972 {
973 return stair_destination(orig_terrain(pos),
974 env.markers.property_at(pos, MAT_ANY, "dst"),
975 for_real);
976 }
977
978 // Find the other end of a stair or portal on the current level. feat is the
979 // type of feature (DNGN_EXIT_ABYSS, for example), dst is the target of a
980 // portal vault entrance (and is ignored for other types of features), and
981 // for_real is true if we are actually traversing the feature rather than
982 // merely asking what is on the other side.
stair_destination(dungeon_feature_type feat,const string & dst,bool for_real)983 level_id stair_destination(dungeon_feature_type feat, const string &dst,
984 bool for_real)
985 {
986 #if TAG_MAJOR_VERSION == 34
987 if (feat == DNGN_ESCAPE_HATCH_UP && player_in_branch(BRANCH_LABYRINTH))
988 feat = DNGN_EXIT_LABYRINTH;
989 #else
990 UNUSED(dst); // see below in the switch
991 #endif
992 if (branches[you.where_are_you].exit_stairs == feat
993 && parent_branch(you.where_are_you) < NUM_BRANCHES
994 && feat != DNGN_EXIT_ZIGGURAT)
995 {
996 level_id lev = brentry[you.where_are_you];
997 if (!lev.is_valid())
998 {
999 // Wizmode, the branch wasn't generated this game.
1000 // Pick the middle of the range instead.
1001 lev = level_id(branches[you.where_are_you].parent_branch,
1002 (branches[you.where_are_you].mindepth
1003 + branches[you.where_are_you].maxdepth) / 2);
1004 ASSERT(lev.is_valid());
1005 }
1006
1007 return lev;
1008 }
1009
1010 if (feat_is_portal_exit(feat))
1011 feat = DNGN_EXIT_PANDEMONIUM;
1012
1013 switch (feat)
1014 {
1015 case DNGN_ESCAPE_HATCH_UP:
1016 case DNGN_STONE_STAIRS_UP_I:
1017 case DNGN_STONE_STAIRS_UP_II:
1018 case DNGN_STONE_STAIRS_UP_III:
1019 if (you.depth <= 1)
1020 {
1021 if (you.wizard && !for_real)
1022 return level_id();
1023 die("upstairs from top of a branch");
1024 }
1025 return level_id(you.where_are_you, you.depth - 1);
1026
1027 case DNGN_EXIT_HELL:
1028 // If set, it would be found as a branch exit.
1029 if (you.wizard)
1030 {
1031 if (for_real)
1032 {
1033 mprf(MSGCH_ERROR, "Error: no Hell exit level, how in the "
1034 "Vestibule did you get here? Let's go to D:1.");
1035 }
1036 return level_id(BRANCH_DUNGEON, 1);
1037 }
1038 else
1039 die("hell exit without return destination");
1040
1041 case DNGN_ABYSSAL_STAIR:
1042 ASSERT(player_in_branch(BRANCH_ABYSS));
1043 push_features_to_abyss();
1044 case DNGN_ESCAPE_HATCH_DOWN:
1045 case DNGN_STONE_STAIRS_DOWN_I:
1046 case DNGN_STONE_STAIRS_DOWN_II:
1047 case DNGN_STONE_STAIRS_DOWN_III:
1048 {
1049 ASSERT(!at_branch_bottom());
1050 level_id lev = level_id::current();
1051 lev.depth++;
1052 return lev;
1053 }
1054
1055 case DNGN_TRANSIT_PANDEMONIUM:
1056 return level_id(BRANCH_PANDEMONIUM);
1057
1058 case DNGN_EXIT_THROUGH_ABYSS:
1059 return level_id(BRANCH_ABYSS);
1060
1061 #if TAG_MAJOR_VERSION == 34
1062 case DNGN_ENTER_PORTAL_VAULT:
1063 if (dst.empty())
1064 {
1065 if (for_real)
1066 die("portal without a destination");
1067 else
1068 return level_id();
1069 }
1070 try
1071 {
1072 return level_id::parse_level_id(dst);
1073 }
1074 catch (const bad_level_id &err)
1075 {
1076 die("Invalid destination for portal: %s", err.what());
1077 }
1078 #endif
1079
1080 case DNGN_ENTER_HELL:
1081 if (for_real && !player_in_hell())
1082 brentry[BRANCH_VESTIBULE] = level_id::current();
1083 return level_id(BRANCH_VESTIBULE);
1084
1085 case DNGN_EXIT_ABYSS:
1086 if (you.chapter == CHAPTER_POCKET_ABYSS)
1087 return level_id(BRANCH_DUNGEON, 1);
1088 #if TAG_MAJOR_VERSION == 34
1089 case DNGN_EXIT_PORTAL_VAULT:
1090 #endif
1091 case DNGN_EXIT_PANDEMONIUM:
1092 if (you.level_stack.empty())
1093 {
1094 if (you.wizard)
1095 {
1096 if (for_real)
1097 {
1098 mprf(MSGCH_ERROR, "Error: no return path. You did create "
1099 "the exit manually, didn't you? Let's go to D:1.");
1100 }
1101 return level_id(BRANCH_DUNGEON, 1);
1102 }
1103 die("no return path from a portal (%s)",
1104 level_id::current().describe().c_str());
1105 }
1106 return you.level_stack.back().id;
1107 case DNGN_ENTER_ABYSS:
1108 push_features_to_abyss();
1109 break;
1110 default:
1111 break;
1112 }
1113
1114 // Try to find a branch stair.
1115 for (branch_iterator it; it; ++it)
1116 {
1117 if (it->entry_stairs == feat)
1118 return level_id(it->id);
1119 }
1120
1121 return level_id();
1122 }
1123
1124 // TODO(Zannick): Fully merge with up_stairs into take_stairs.
down_stairs(dungeon_feature_type force_stair,bool force_known_shaft,bool update_travel_cache)1125 void down_stairs(dungeon_feature_type force_stair, bool force_known_shaft, bool update_travel_cache)
1126 {
1127 take_stairs(force_stair, false, force_known_shaft, update_travel_cache);
1128 }
1129
_update_level_state()1130 static void _update_level_state()
1131 {
1132 env.level_state = 0;
1133
1134 vector<coord_def> golub = find_golubria_on_level();
1135 if (!golub.empty())
1136 env.level_state |= LSTATE_GOLUBRIA;
1137
1138 for (monster_iterator mon_it; mon_it; ++mon_it)
1139 {
1140 if (mons_allows_beogh(**mon_it))
1141 env.level_state |= LSTATE_BEOGH;
1142 if (mon_it->has_ench(ENCH_STILL_WINDS))
1143 env.level_state |= LSTATE_STILL_WINDS;
1144 if (mon_it->has_ench(ENCH_AWAKEN_FOREST))
1145 {
1146 env.forest_awoken_until
1147 = you.elapsed_time
1148 + mon_it->get_ench(ENCH_AWAKEN_FOREST).duration;
1149 }
1150 }
1151
1152 #if TAG_MAJOR_VERSION == 34
1153 const bool have_ramparts = you.duration[DUR_FROZEN_RAMPARTS];
1154 const auto &ramparts_pos = you.props[FROZEN_RAMPARTS_KEY].get_coord();
1155 #endif
1156 for (rectangle_iterator ri(0); ri; ++ri)
1157 {
1158 if (env.grid(*ri) == DNGN_SLIMY_WALL)
1159 env.level_state |= LSTATE_SLIMY_WALL;
1160
1161 if (is_icecovered(*ri))
1162 #if TAG_MAJOR_VERSION == 34
1163 {
1164 // Buggy versions of Frozen Ramparts didn't properly clear
1165 // FPROP_ICY from walls in some cases, so we detect invalid walls
1166 // and remove the flag.
1167 if (have_ramparts
1168 && ramparts_pos.distance_from(*ri) <= 3
1169 && cell_see_cell(*ri, ramparts_pos, LOS_NO_TRANS))
1170 {
1171 #endif
1172 env.level_state |= LSTATE_ICY_WALL;
1173 #if TAG_MAJOR_VERSION == 34
1174 }
1175 else
1176 env.pgrid(*ri) &= ~FPROP_ICY;
1177 }
1178 #endif
1179 }
1180
1181 env.orb_pos = coord_def();
1182 if (item_def* orb = find_floor_item(OBJ_ORBS, ORB_ZOT))
1183 env.orb_pos = orb->pos;
1184 else if (player_has_orb())
1185 {
1186 env.orb_pos = you.pos();
1187 invalidate_agrid(true);
1188 }
1189 }
1190
new_level(bool restore)1191 void new_level(bool restore)
1192 {
1193 print_stats_level();
1194 #ifdef DGL_WHEREIS
1195 whereis_record();
1196 #endif
1197
1198 _update_level_state();
1199
1200 if (restore)
1201 return;
1202
1203 cancel_polar_vortex();
1204
1205 if (player_in_branch(BRANCH_ZIGGURAT))
1206 you.zig_max = max(you.zig_max, you.depth);
1207 }
1208