Anonymous | Login | 2024-04-23 16:35 CEST |
Main | My View | View Issues | Change Log | Wiki | Tavern | News |
Viewing Issue Simple Details [ Jump to Notes ] [ Wiki ] | [ View Advanced ] [ Issue History ] [ Print ] | ||||||||||||
ID | Category | Severity | Reproducibility | Date Submitted | Last Update | ||||||||
0007061 | [DCSS] Bug Report | minor | always | 2013-05-20 04:20 | 2015-03-26 05:32 | ||||||||
Reporter | elliptic | View Status | public | ||||||||||
Assigned To | Reaver | ||||||||||||
Priority | normal | Resolution | done | ||||||||||
Status | resolved | Product Branch | 0.13 ancient branch | ||||||||||
Summary | 0007061: Duplicate and inconsistent code for stair/shop traversal | ||||||||||||
Description | Was originally "Trying to use stairs in tree-form costs a turn.", but the bug goes deeper than that. See comments | ||||||||||||
Additional Information | |||||||||||||
Tags | No tags attached. | ||||||||||||
Attached Files |
0001-Clean-up-stairs-commands-and-checks.patch [^] (17,200 bytes) 2013-05-23 07:59 [Show Content] [Hide Content]From 7b3933b25a426d542ddea3982aa604f7c05e1caf Mon Sep 17 00:00:00 2001 From: Zannick <jokeserver@gmail.com> Date: Wed, 22 May 2013 22:37:08 -0700 Subject: [PATCH] Clean up stairs commands and checks. - Tree form is checked before the delay now. (#7074) - Tree form no longer blocks forced level-changing such as banishment, escaping the Abyss (the lugonu ability), falling down a shaft... (#7073). - Being turned into a tree interrupts stair travel. - Any tolls are checked before the player stops clinging or constricting. - Merge _up_stairs and _down_stairs in main.cc into one function, with some helper functions for checks and prompts. - Moved some duplicate checks from up_stairs and down_stairs into a helper function. - Removed redundant or invalid checks. --- crawl-ref/source/main.cc | 210 +++++++++++++++++------------------------ crawl-ref/source/stairs.cc | 118 +++++++++-------------- crawl-ref/source/transform.cc | 3 +- 3 files changed, 136 insertions(+), 195 deletions(-) diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index 0ac1ece..889b103 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -1373,17 +1373,75 @@ static void _input() crawl_state.clear_god_acting(); } -static bool _stairs_check_mesmerised() +static bool _can_take_stairs(dungeon_feature_type ftype, bool down, + bool known_shaft) { + // Immobile + if (you.form == TRAN_TREE) + { + canned_msg(MSG_CANNOT_MOVE); + return false; + } + + // Mesmerized if (you.beheld() && !you.confused()) { const monster* beholder = you.get_any_beholder(); mprf("You cannot move away from %s!", beholder->name(DESC_THE, true).c_str()); - return true; + return false; } - return false; + // Held + if (you.attribute[ATTR_HELD]) + { + mprf("You can't use stairs while %s.", held_status()); + return false; + } + + // Up and down both work for shops and portals. + if (ftype == DNGN_ENTER_SHOP) + { + if (you.berserk()) + canned_msg(MSG_TOO_BERSERK); + else + shop(); + // Even though we may have "succeeded", return false so we don't keep + // trying to go downstairs. + return false; + } + + // If it's not bidirectional, check that the player is headed + // in the right direction. + if (!feat_is_bidirectional_portal(ftype)) + { + if (feat_stair_direction(ftype) != (down ? CMD_GO_DOWNSTAIRS + : CMD_GO_UPSTAIRS) + // probably shouldn't be passed known_shaft=true + // if going up, but just in case... + && (!down || !known_shaft)) + { + if (ftype == DNGN_STONE_ARCH) + mpr("There is nothing on the other side of the stone arch."); + else if (ftype == DNGN_ABANDONED_SHOP) + mpr("This shop appears to be closed."); + else if (down) + mpr("You can't go down here!"); + else + mpr("You can't go up here!"); + return false; + } + } + + // Overloaded, can't go up stairs. + if (!down && you.burden_state == BS_OVERLOADED + && !feat_is_escape_hatch(ftype) && !feat_is_gate(ftype)) + { + mpr("You are carrying too much to climb upwards."); + return false; + } + + return true; } static bool _marker_vetoes_stair() @@ -1431,76 +1489,36 @@ static bool _prompt_unique_pan_rune(dungeon_feature_type ygrd) return true; } -static void _go_downstairs(); -static void _go_upstairs() +static bool _prompt_stairs(dungeon_feature_type ygrd, bool down) { - ASSERT(!crawl_state.game_is_arena() && !crawl_state.arena_suspended); - - const dungeon_feature_type ygrd = grd(you.pos()); - - if (_stairs_check_mesmerised()) - return; - - if (you.attribute[ATTR_HELD]) - { - mprf("You can't use stairs while %s.", held_status()); - return; - } - - if (ygrd == DNGN_ENTER_SHOP) - { - if (you.berserk()) - canned_msg(MSG_TOO_BERSERK); - else - shop(); - return; - } - // Up and down both work for portals. - else if (feat_is_bidirectional_portal(ygrd)) - ; - else if (feat_stair_direction(ygrd) != CMD_GO_UPSTAIRS) - { - if (ygrd == DNGN_STONE_ARCH) - mpr("There is nothing on the other side of the stone arch."); - else if (ygrd == DNGN_ABANDONED_SHOP) - mpr("This shop appears to be closed."); - else - mpr("You can't go up here!"); - return; - } - - if (!you.attempt_escape()) // false means constricted and don't escape - return; - + // Certain portal types always carry warnings. if (!_prompt_dangerous_portal(ygrd)) - return; + return false; // Does the next level have a warning annotation? + // Also checks for entering a labyrinth with teleportitis. if (!check_annotation_exclusion_warning()) - return; + return false; + // Toll portals, eg. troves, ziggurats. (Using vetoes like this is hacky.) if (_marker_vetoes_stair()) - return; - - if (you.burden_state == BS_OVERLOADED && !feat_is_escape_hatch(ygrd) - && !feat_is_gate(ygrd)) - { - mpr("You are carrying too much to climb upwards."); - return; - } + return false; + // Exiting Ziggurats early. if (ygrd == DNGN_EXIT_PORTAL_VAULT && player_in_branch(BRANCH_ZIGGURAT) && you.depth < brdepth[BRANCH_ZIGGURAT]) { if (!yesno("Are you sure you want to leave this Ziggurat?")) - return; + return false; } + // Leaving Pan runes behind. if (!_prompt_unique_pan_rune(ygrd)) - return; + return false; - if (ygrd == DNGN_EXIT_DUNGEON && !player_has_orb()) + // Escaping. + if (!down && ygrd == DNGN_EXIT_DUNGEON && !player_has_orb()) { string prompt = make_stringf("Are you sure you want to leave the " "Dungeon?%s", @@ -1509,81 +1527,29 @@ static void _go_upstairs() if (!yesno(prompt.c_str(), false, 'n')) { mpr("Alright, then stay!"); - return; + return false; } } - you.clear_clinging(); - you.stop_constricting_all(true); - you.stop_being_constricted(); - - tag_followers(); // Only those beside us right now can follow. - start_delay(DELAY_ASCENDING_STAIRS, - 1 + (you.burden_state > BS_UNENCUMBERED)); + return true; } -static void _go_downstairs() +static void _take_stairs(bool down) { ASSERT(!crawl_state.game_is_arena() && !crawl_state.arena_suspended); const dungeon_feature_type ygrd = grd(you.pos()); - const bool shaft = (get_trap_type(you.pos()) == TRAP_SHAFT - && ygrd != DNGN_UNDISCOVERED_TRAP); + const bool shaft = (down && get_trap_type(you.pos()) == TRAP_SHAFT + && ygrd != DNGN_UNDISCOVERED_TRAP); - if (_stairs_check_mesmerised()) + if (!_can_take_stairs(ygrd, down, shaft)) return; - // Up and down both work for shops. - if (ygrd == DNGN_ENTER_SHOP) - { - if (you.berserk()) - canned_msg(MSG_TOO_BERSERK); - else - shop(); - return; - } - // Up and down both work for portals. - else if (feat_is_bidirectional_portal(ygrd)) - ; - else if (feat_stair_direction(ygrd) != CMD_GO_DOWNSTAIRS - && !shaft) - { - if (ygrd == DNGN_STONE_ARCH) - mpr("There is nothing on the other side of the stone arch."); - else if (ygrd == DNGN_ABANDONED_SHOP) - mpr("This shop appears to be closed."); - else - mpr("You can't go down here!"); - return; - } - - if (you.attribute[ATTR_HELD]) - { - mprf("You can't use stairs while %s.", held_status()); - return; - } - if (!you.attempt_escape()) // false means constricted and don't escape return; - if (!_prompt_dangerous_portal(ygrd)) - return; - - // Does the next level have a warning annotation? - // Also checks for entering a labyrinth with teleportitis. - if (!check_annotation_exclusion_warning()) - return; - - if (ygrd == DNGN_EXIT_PORTAL_VAULT - && player_in_branch(BRANCH_ZIGGURAT) - && you.depth < brdepth[BRANCH_ZIGGURAT]) - { - if (!yesno("Are you sure you want to leave this Ziggurat?")) - return; - } - - if (!_prompt_unique_pan_rune(ygrd)) + if (!_prompt_stairs(ygrd, down)) return; you.clear_clinging(); @@ -1594,11 +1560,8 @@ static void _go_downstairs() start_delay(DELAY_DESCENDING_STAIRS, 0); else { - if (_marker_vetoes_stair()) - return; - tag_followers(); // Only those beside us right now can follow. - start_delay(DELAY_DESCENDING_STAIRS, + start_delay(down ? DELAY_DESCENDING_STAIRS : DELAY_ASCENDING_STAIRS, 1 + (you.burden_state > BS_UNENCUMBERED)); } } @@ -1910,9 +1873,12 @@ void process_command(command_type cmd) #endif case CMD_REST: _do_rest(); break; - case CMD_GO_UPSTAIRS: _go_upstairs(); break; - case CMD_GO_DOWNSTAIRS: _go_downstairs(); break; - case CMD_OPEN_DOOR: _open_door(0, 0); break; + case CMD_GO_UPSTAIRS: + case CMD_GO_DOWNSTAIRS: + _take_stairs(cmd == CMD_GO_DOWNSTAIRS); + break; + + case CMD_OPEN_DOOR: _open_door(0, 0); break; case CMD_CLOSE_DOOR: _close_door(coord_def(0, 0)); break; // Repeat commands. diff --git a/crawl-ref/source/stairs.cc b/crawl-ref/source/stairs.cc index b7f1262..377830e 100644 --- a/crawl-ref/source/stairs.cc +++ b/crawl-ref/source/stairs.cc @@ -311,42 +311,49 @@ static void _update_travel_cache(const level_id& old_level, } } +// These checks are probably unnecessary. +static bool _check_stairs(const dungeon_feature_type ftype, bool down = false) +{ + // If it's not bidirectional, check that the player is headed + // in the right direction. + if (!feat_is_bidirectional_portal(ftype)) + { + if (feat_stair_direction(ftype) != (down ? CMD_GO_DOWNSTAIRS + : CMD_GO_UPSTAIRS)) + { + if (ftype == DNGN_STONE_ARCH) + mpr("There is nothing on the other side of the stone arch."); + else if (ftype == DNGN_ABANDONED_SHOP) + mpr("This shop appears to be closed."); + else if (down) + mpr("You can't go down here!"); + else + mpr("You can't go up here!"); + return false; + } + } + + return true; +} + void up_stairs(dungeon_feature_type force_stair) { dungeon_feature_type stair_find = (force_stair ? force_stair : grd(you.pos())); const level_id old_level = level_id::current(); - if (you.form == TRAN_TREE) - { - canned_msg(MSG_CANNOT_MOVE); - return; - } - - // Up and down both work for shops. - if (stair_find == DNGN_ENTER_SHOP) - { - shop(); - return; - } - // Up and down both work for portals. + // Canonicalize the direction; hell exits into the vestibule are handled + // by up_stairs; everything else by down_stairs. if (feat_is_bidirectional_portal(stair_find)) { if (!(stair_find == DNGN_ENTER_HELL && player_in_hell())) return down_stairs(force_stair); } - // Probably still need this check here (teleportation) -- bwr - else if (feat_stair_direction(stair_find) != CMD_GO_UPSTAIRS) - { - if (stair_find == DNGN_STONE_ARCH) - mpr("There is nothing on the other side of the stone arch."); - else if (stair_find == DNGN_ABANDONED_SHOP) - mpr("This shop appears to be closed."); - else - mpr("You can't go up here."); + + // Only check the current position for a legal stair traverse. + if (!force_stair && !_check_stairs(stair_find)) return; - } if (_stair_moves_pre(stair_find)) return; @@ -635,6 +642,7 @@ static void _maybe_destroy_trap(const coord_def &p) trap->destroy(true); } +// TODO(Zannick): Fully merge with up_stairs into take_stairs. void down_stairs(dungeon_feature_type force_stair) { const level_id old_level = level_id::current(); @@ -642,79 +650,45 @@ void down_stairs(dungeon_feature_type force_stair) const dungeon_feature_type stair_find = force_stair ? force_stair : old_feat; - const bool shaft = (!force_stair - && get_trap_type(you.pos()) == TRAP_SHAFT - || force_stair == DNGN_TRAP_NATURAL); + // Taking a shaft manually + const bool known_shaft = (!force_stair + && get_trap_type(you.pos()) == TRAP_SHAFT + && stair_find != DNGN_UNDISCOVERED_TRAP); + // Latter case is falling down a shaft. + const bool shaft = known_shaft || (force_stair == DNGN_TRAP_NATURAL); level_id shaft_dest; - if (you.form == TRAN_TREE) - { - canned_msg(MSG_CANNOT_MOVE); - return; - } - - // Up and down both work for shops. - if (stair_find == DNGN_ENTER_SHOP) - { - shop(); - return; - } - // Up and down both work for portals. + // Canonicalize the direction; hell exits into the vestibule are handled + // by up_stairs; everything else by down_stairs. if (feat_is_bidirectional_portal(stair_find)) { if (stair_find == DNGN_ENTER_HELL && player_in_hell()) return up_stairs(force_stair); } - // Probably still need this check here (teleportation) -- bwr - else if (feat_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS && !shaft) - { - if (stair_find == DNGN_STONE_ARCH) - mpr("There is nothing on the other side of the stone arch."); - else if (stair_find == DNGN_ABANDONED_SHOP) - mpr("This shop appears to be closed."); - else - mpr("You can't go down here!"); - return; - } - - if (stair_find > DNGN_ENTER_LABYRINTH - && stair_find <= DNGN_ESCAPE_HATCH_DOWN - && player_in_branch(BRANCH_VESTIBULE_OF_HELL)) - { - // Down stairs in vestibule are one-way! - // This doesn't make any sense. Why would there be any down stairs - // in the Vestibule? {due, 9/2010} - mpr("A mysterious force prevents you from descending the staircase."); - return; - } - if (stair_find == DNGN_STONE_ARCH) - { - mpr("There is nothing on the other side of the stone arch."); + // Only check the current position for a legal stair traverse. + // If it's a known shaft that we're taking, then we're already good. + if (!known_shaft && !_check_stairs(stair_find, true)) return; - } if (_stair_moves_pre(stair_find)) return; if (shaft) { - const bool known_trap = (grd(you.pos()) != DNGN_UNDISCOVERED_TRAP - && !force_stair); - if (!is_valid_shaft_level()) { - if (known_trap) + if (known_shaft) mpr("The shaft disappears in a puff of logic!"); _maybe_destroy_trap(you.pos()); return; } - shaft_dest = you.shaft_dest(known_trap); + shaft_dest = you.shaft_dest(known_shaft); if (shaft_dest == level_id::current()) { - if (known_trap) + if (known_shaft) { mpr("Strange, the shaft seems to lead back to this level."); mpr("The strain on the space-time continuum destroys the " @@ -724,7 +698,7 @@ void down_stairs(dungeon_feature_type force_stair) return; } - if (!known_trap && shaft_dest.depth - you.depth > 1) + if (!known_shaft && shaft_dest.depth - you.depth > 1) { mark_milestone("shaft", "fell down a shaft to " + short_place_name(shaft_dest) + "."); diff --git a/crawl-ref/source/transform.cc b/crawl-ref/source/transform.cc index dbed059..f966a93 100644 --- a/crawl-ref/source/transform.cc +++ b/crawl-ref/source/transform.cc @@ -1107,7 +1107,8 @@ bool transform(int pow, transformation_type which_trans, bool force, // This only has an effect if the transformation happens passively, // for example if Xom decides to transform you while you're busy // running around or butchering corpses. - stop_delay(); + // If you're turned into a tree, you stop taking stairs. + stop_delay(which_trans == TRAN_TREE); if (crawl_state.which_god_acting() == GOD_XOM) you.transform_uncancellable = true; -- 1.7.4.4 0002-Merge-up_stairs-and-down_stairs-into-take_stairs.patch [^] (38,946 bytes) 2015-01-27 04:54 [Show Content] [Hide Content] From 58322f74cec90cc2ade1c788d972e267d202e8d2 Mon Sep 17 00:00:00 2001 From: Zannick <jokeserver@gmail.com> Date: Mon, 26 Jan 2015 19:34:04 -0800 Subject: [PATCH] Merge up_stairs and down_stairs into take_stairs. A handful of inconsistencies between the two old functions are left in (but obviously more noticeable) to avoid making this too much of a change in actual behavior. Actual behavior changed: - End searing ray when moving up as well as down. - The player can no longer trip down a shaft while confused. - Don't mark a milestone that the player took an exit from Pan into the Abyss when they got banished standing on the exit instead. Other code changes: - Condense _player_leaves_level_upstairs and _downstairs. - Change _check_stairs to take a bool "going_up" instead of "down", for consistency with _climb_message (and new helper functions). - Create a helper function _fall_down_stairs that takes care of both cases. - Create a helper function _require_runes which performs the fancy runelock animations. - Create a helper function _new_level_amuses_xom, except pull the abyss blood spatter generation out of it. It now skips the newlevel check, but Abyss should always be new levels anyway. - Remove the "You fly upwards" override (which mostly means taking hatches up while flying now produces the hatch message instead). - Move the -cTele warning later in the function as part of merging. - Move the helper function _maybe_destroy_trap above take_stairs. - Remove a redundant variable "stairs_taken". - Add a ton of comments. - up_stairs and down_stairs are left in as convenience functions that simply call take_stairs. --- crawl-ref/source/stairs.cc | 917 +++++++++++++++++++++----------------------- crawl-ref/source/stairs.h | 3 + crawl-ref/source/terrain.cc | 2 +- 3 files changed, 437 insertions(+), 485 deletions(-) diff --git a/crawl-ref/source/stairs.cc b/crawl-ref/source/stairs.cc index b775d1a..b69e8b9 100644 --- a/crawl-ref/source/stairs.cc +++ b/crawl-ref/source/stairs.cc @@ -105,10 +105,11 @@ static void _player_change_level_reset() you.prev_grd_targ.reset(); } -static void _player_change_level_upstairs(dungeon_feature_type feat) +static void _player_change_level(dungeon_feature_type feat, const string &dst) { - level_id lev = feat ? stair_destination(feat, "", true) - : stair_destination(you.pos(), true); + level_id lev = stair_destination(feat, dst, true); + if (!lev.is_valid()) + die("Unknown down stair: %s", dungeon_feature_name(feat)); you.depth = lev.depth; you.where_are_you = lev.branch; } @@ -118,6 +119,13 @@ static bool _marker_vetoes_level_change() return marker_vetoes_operation("veto_level_change"); } +static void _maybe_destroy_trap(const coord_def &p) +{ + trap_def* trap = find_trap(p); + if (trap) + trap->destroy(true); +} + static bool _stair_moves_pre(dungeon_feature_type stair) { if (crawl_state.prev_cmd == CMD_WIZARD) @@ -305,23 +313,23 @@ static void _update_travel_cache(const level_id& old_level, } // These checks are probably unnecessary. -static bool _check_stairs(const dungeon_feature_type ftype, bool down = false) +static bool _check_stairs(const dungeon_feature_type ftype, bool going_up) { // If it's not bidirectional, check that the player is headed // in the right direction. if (!feat_is_bidirectional_portal(ftype)) { - if (feat_stair_direction(ftype) != (down ? CMD_GO_DOWNSTAIRS - : CMD_GO_UPSTAIRS)) + if (feat_stair_direction(ftype) != (going_up ? CMD_GO_UPSTAIRS + : CMD_GO_DOWNSTAIRS)) { if (ftype == DNGN_STONE_ARCH) mpr("There is nothing on the other side of the stone arch."); else if (ftype == DNGN_ABANDONED_SHOP) mpr("This shop appears to be closed."); - else if (down) - mpr("You can't go down here!"); - else + else if (going_up) mpr("You can't go up here!"); + else + mpr("You can't go down here!"); return false; } } @@ -329,57 +337,277 @@ static bool _check_stairs(const dungeon_feature_type ftype, bool down = false) return true; } -void up_stairs(dungeon_feature_type force_stair, bool wizard) +static bool _fall_down_stairs(const dungeon_feature_type ftype, bool going_up) +{ + if (!you.airborne() + && you.confused() + && !feat_is_escape_hatch(ftype) + && coinflip()) + { + const char* fall_where = "down the stairs"; + if (!feat_is_staircase(ftype)) + fall_where = "through the gate"; + + mprf("In your confused state, you trip and fall %s%s.", + going_up ? "back " : "", fall_where); + if (!feat_is_staircase(ftype)) + ouch(1, KILLED_BY_FALLING_THROUGH_GATE); + else + ouch(1, KILLED_BY_FALLING_DOWN_STAIRS); + + // Note that this only does damage if going downstairs; + // it doesn't cancel the level transition. + if (going_up) + { + you.turn_is_over = true; + return true; + } + } + + return false; +} + +static bool _require_runes(dungeon_feature_type ftype) +{ + if (ftype != DNGN_ENTER_VAULTS + && ftype != DNGN_ENTER_ZOT + && ftype != DNGN_ENTER_ZIGGURAT) { + return false; + } + + if ((ftype == DNGN_ENTER_VAULTS + && is_existing_level(level_id(BRANCH_VAULTS, 1))) + || (ftype == DNGN_ENTER_ZOT + && is_existing_level(level_id(BRANCH_ZOT, 1)))) + { + return false; + } + + #define ZIG_RUNES 2 + const int min_runes = ((ftype == DNGN_ENTER_ZOT) ? NUMBER_OF_RUNES_NEEDED : + (ftype == DNGN_ENTER_VAULTS) ? 1 : ZIG_RUNES); + + if (runes_in_pack() < min_runes) + { + if (min_runes == 1) + mpr("You need a rune to enter this place."); + else + mprf("You need at least %d runes to enter this place.", min_runes); + return true; + } + + // Nothing even remotely flashy for Zig. + if (ftype != DNGN_ENTER_ZIGGURAT) { + vector<int> runes; + for (int i = 0; i < NUM_RUNE_TYPES; i++) + if (you.runes[i]) + runes.push_back(i); + + ASSERT(runes.size() >= 1); + shuffle_array(runes); + + // Zot is extra flashy. + if (ftype == DNGN_ENTER_ZOT) { + ASSERT(runes.size() >= 3); + + mprf("You insert the %s rune into the lock.", rune_type_name(runes[2])); +#ifdef USE_TILE_LOCAL + tiles.add_overlay(you.pos(), tileidx_zap(rune_colour(runes[2]))); + update_screen(); +#else + flash_view(UA_BRANCH_ENTRY, rune_colour(runes[2])); +#endif + mpr("The lock glows eerily!"); + more(); + + mprf("You insert the %s rune into the lock.", rune_type_name(runes[1])); + big_cloud(CLOUD_BLUE_SMOKE, &you, you.pos(), 20, 7 + random2(7)); + viewwindow(); + mpr("Heavy smoke blows from the lock!"); + more(); + } + + mprf("You insert the %s rune into the lock.", rune_type_name(runes[0])); + + if (silenced(you.pos())) + mpr("The gate opens wide!"); + else + mpr("With a loud hiss the gate opens wide!"); + more(); + } + + return false; +} + +static void _new_level_amuses_xom(dungeon_feature_type feat, + dungeon_feature_type old_feat, + bool shaft, int shaft_depth, bool voluntary) +{ + switch (you.where_are_you) + { + default: + // Xom thinks it's funny if you enter a new level via shaft + // or escape hatch, for shafts it's funnier the deeper you fell. + if (shaft || feat_is_escape_hatch(feat)) + xom_is_stimulated(shaft_depth * 50); + else if (!is_connected_branch(you.where_are_you)) + xom_is_stimulated(25); + else + xom_is_stimulated(10); + break; + + case BRANCH_ZIGGURAT: + // The best way to die currently. + xom_is_stimulated(50); + break; + + case BRANCH_LABYRINTH: + // Finding the way out of a labyrinth interests Xom. + xom_is_stimulated(75); + break; + + case BRANCH_PANDEMONIUM: + xom_is_stimulated(100); + break; + + case BRANCH_ABYSS: + if (voluntary && old_feat == DNGN_ENTER_ABYSS) + xom_is_stimulated(100, XM_INTRIGUED); + else + xom_is_stimulated(200); + break; + } +} + +void take_stairs(dungeon_feature_type force_stair, bool going_up, + bool force_known_shaft, bool wizard) { - dungeon_feature_type stair_find = (force_stair ? force_stair - : orig_terrain(you.pos())); const level_id old_level = level_id::current(); - // Up and down both work for portals. - // Canonicalize the direction; hell exits into the vestibule are handled - // by up_stairs; everything else by down_stairs. - if (feat_is_bidirectional_portal(stair_find)) + const dungeon_feature_type old_feat = orig_terrain(you.pos()); + dungeon_feature_type stair_find = force_stair ? force_stair : old_feat; + + // Taking a shaft manually + const bool known_shaft = (!force_stair + && get_trap_type(you.pos()) == TRAP_SHAFT + && stair_find != DNGN_UNDISCOVERED_TRAP) + || (force_stair == DNGN_TRAP_SHAFT + && force_known_shaft); + // Latter case is falling down a shaft. + const bool shaft = known_shaft || force_stair == DNGN_TRAP_SHAFT; + level_id shaft_dest; + if (shaft) { - if (!(stair_find == DNGN_ENTER_HELL && player_in_hell())) - return down_stairs(force_stair); + if (!is_valid_shaft_level()) + { + if (known_shaft) + mpr("The shaft disappears in a puff of logic!"); + _maybe_destroy_trap(you.pos()); + return; + } + + shaft_dest = you.shaft_dest(known_shaft); } + // How far down you fall via a shaft or hatch. + const int shaft_depth = (shaft ? shaft_dest.depth - you.depth : 1); + + // Up and down both work for some portals. + // Canonicalize the direction: hell exits into the vestibule are considered + // going up; everything else is going down. This mostly affects which way you + // fall if confused. + if (feat_is_bidirectional_portal(stair_find)) + going_up = (stair_find == DNGN_ENTER_HELL && player_in_hell()); // Only check the current position for a legal stair traverse. - if (!force_stair && !_check_stairs(stair_find)) + // Check that we're going the right way (if we're not falling through + // a shaft or being forced). + if (!shaft && !force_stair && !_check_stairs(stair_find, going_up)) return; if (_stair_moves_pre(stair_find)) return; - if (!you.airborne() - && you.confused() - && !feat_is_escape_hatch(stair_find) - && coinflip()) + // Falling down is checked before the transition if going upstairs, since + // it might prevent the transition itself. + if (going_up && _fall_down_stairs(stair_find, going_up)) + return; + + if (shaft) { - const char* fall_where = "down the stairs"; - if (!feat_is_staircase(stair_find)) - fall_where = "through the gate"; + if (shaft_dest == level_id::current()) + { + if (known_shaft) + { + mpr("Strange, the shaft seems to lead back to this level."); + mpr("The strain on the space-time continuum destroys the " + "shaft!"); + } + _maybe_destroy_trap(you.pos()); + return; + } - mprf("In your confused state, you trip and fall back %s.", fall_where); - if (!feat_is_staircase(stair_find)) - ouch(1, KILLED_BY_FALLING_THROUGH_GATE); - else - ouch(1, KILLED_BY_FALLING_DOWN_STAIRS); - you.turn_is_over = true; - return; + if (!known_shaft) + { + mark_milestone("shaft", "fell down a shaft to " + + shaft_dest.describe() + "."); + } + + handle_items_on_shaft(you.pos(), false); + + string howfar; + if (force_stair && shaft_depth > 1) + howfar = make_stringf(" for %d floors", shaft_depth); + + mprf("You %s a shaft%s!", you.flight_mode() ? "are sucked into" + : "fall through", + howfar.c_str()); + + // Shafts are one-time-use. + mpr("The shaft crumbles and collapses."); + _maybe_destroy_trap(you.pos()); } + // Check the player's runes and maybe perform the entry sequence. + if (_require_runes(stair_find)) + return; + // Bail if any markers veto the move. if (_marker_vetoes_level_change()) return; - // Magical level changes (don't exist yet in this direction) - // need this. + // All checks are done, the player is on the move now. + + // Magical level changes (which currently only exist "downwards") need this. clear_trapping_net(); + end_searing_ray(); + + // Markers might be deleted when removing portals. + const string dst = env.markers.property_at(you.pos(), MAT_ANY, "dst"); - // Checks are done, the character is committed to moving between levels. + // Fire level-leaving trigger. leaving_level_now(stair_find); + // Not entirely accurate - the player could die before + // reaching the Abyss. + if (!force_stair && old_feat == DNGN_ENTER_ABYSS) + { + mark_milestone("abyss.enter", "entered the Abyss!"); + take_note(Note(NOTE_MESSAGE, 0, 0, "Voluntarily entered the Abyss."), true); + } + else if (!force_stair && old_feat == DNGN_EXIT_THROUGH_ABYSS) + { + mark_milestone("abyss.enter", "escaped (hah) into the Abyss!"); + take_note(Note(NOTE_MESSAGE, 0, 0, "Took an exit into the Abyss."), true); + } + else if (stair_find == DNGN_EXIT_ABYSS + && you.char_direction != GDT_GAME_START) + { + mark_milestone("abyss.exit", "escaped from the Abyss!"); + you.attribute[ATTR_BANISHMENT_IMMUNITY] = you.elapsed_time + 100 + + random2(100); + you.banished_by = ""; + } + // Interlevel travel data. const bool collect_travel_data = can_travel_interlevel(); if (collect_travel_data) @@ -388,6 +616,8 @@ void up_stairs(dungeon_feature_type force_stair, bool wizard) old_level_info.update(); } + const coord_def stair_pos = you.pos(); + if (stair_find == DNGN_EXIT_DUNGEON) { you.depth = 0; @@ -399,48 +629,159 @@ void up_stairs(dungeon_feature_type force_stair, bool wizard) ouch(INSTANT_DEATH, KILLED_BY_LEAVING); } + if (stair_find == DNGN_ENTER_LABYRINTH || stair_find == DNGN_ENTER_ZIGGURAT) + dungeon_terrain_changed(you.pos(), DNGN_STONE_ARCH); + + if (stair_find == DNGN_ENTER_PANDEMONIUM + || stair_find == DNGN_ENTER_ABYSS + || feat_is_portal_entrance(stair_find)) + { + you.level_stack.push_back(level_pos::current()); + } + + // Actually change the player's branch and depth, along with some cleanup. _player_change_level_reset(); - _player_change_level_upstairs(force_stair); + if (shaft) + you.depth = shaft_dest.depth; + else + _player_change_level(stair_find, dst); + // Some branch specific messages. if (old_level.branch == BRANCH_VESTIBULE && !player_in_branch(BRANCH_VESTIBULE)) { mpr("Thank you for visiting Hell. Please come again soon."); } + if (stair_find == DNGN_EXIT_ABYSS + || stair_find == DNGN_EXIT_PANDEMONIUM + || stair_find == DNGN_EXIT_THROUGH_ABYSS) + { + mpr("You pass through the gate."); + take_note(Note(NOTE_MESSAGE, 0, 0, + stair_find == DNGN_EXIT_ABYSS ? "Escaped the Abyss" : + stair_find == DNGN_EXIT_PANDEMONIUM ? "Escaped Pandemonium" : + stair_find == DNGN_EXIT_THROUGH_ABYSS ? "Escaped into the Abyss" : + "Buggered into bugdom"), true); + + if (!you.wizard || !crawl_state.is_replaying_keys()) + more(); + } + // Fixup exits from the Hell branches. if (player_in_branch(BRANCH_VESTIBULE) && is_hell_subbranch(old_level.branch)) stair_find = branches[old_level.branch].entry_stairs; - const dungeon_feature_type stair_taken = stair_find; + // Special messages on returning from portal vaults, Abyss, Pan, etc. + if (!is_connected_branch(old_level.branch) + && player_in_connected_branch() + && old_level.branch != you.where_are_you) + { + mprf("Welcome %sto %s!", + you.char_direction == GDT_GAME_START ? "" : "back ", + branches[you.where_are_you].longname); + } - if (you.flight_mode() && !feat_is_gate(stair_find)) - mpr("You fly upwards."); - else - _climb_message(stair_find, true, old_level.branch); + // Falling down the stairs or portal. + if (!going_up && !shaft + && force_stair != DNGN_ENTER_ABYSS + && force_stair != DNGN_ABYSSAL_STAIR + && force_stair != DNGN_EXIT_ABYSS) + { + _fall_down_stairs(stair_find, !going_up); + } - _exit_stair_message(stair_find); + if (shaft) + stair_find = DNGN_TRAP_SHAFT; - if (old_level.branch != you.where_are_you) + switch (you.where_are_you) { - mprf("Welcome back to %s!", - branches[you.where_are_you].longname); - if ((brdepth[old_level.branch] > 1 - || old_level.branch == BRANCH_VESTIBULE) - && !you.branches_left[old_level.branch]) + case BRANCH_ABYSS: + // There are no abyssal stairs that go up, so this whole case is only + // when going down. + if (old_level.branch == BRANCH_ABYSS) { - string old_branch_string = branches[old_level.branch].longname; - if (old_branch_string.find("The ") == 0) - old_branch_string[0] = tolower(old_branch_string[0]); - mark_milestone("br.exit", "left " + old_branch_string + ".", - old_level.describe()); - you.branches_left.set(old_level.branch); + mprf(MSGCH_BANISHMENT, "You plunge deeper into the Abyss."); + break; } - } + if (!force_stair) + mpr("You enter the Abyss!"); - const coord_def stair_pos = you.pos(); + mpr("To return, you must find a gate leading back."); + if (you_worship(GOD_CHEIBRIADOS)) + { + mprf(MSGCH_GOD, GOD_CHEIBRIADOS, + "You feel Cheibriados slowing down the madness of this place."); + } - load_level(stair_taken, LOAD_ENTER_LEVEL, old_level); + // Re-entering the Abyss halves accumulated speed. + you.abyss_speed /= 2; + learned_something_new(HINT_ABYSS); + break; + + case BRANCH_PANDEMONIUM: + if (old_level.branch == BRANCH_PANDEMONIUM) + mpr("You pass into a different region of Pandemonium."); + break; + + default: + // This hits both cases. + if (!shaft) + _climb_message(stair_find, going_up, old_level.branch); + break; + } + + // An extra message from using this particular stair (e.g. hatches). + if (!shaft) + _exit_stair_message(stair_find); + + // Did we enter a new branch? + if (!player_in_branch(old_level.branch)) + { + const branch_type branch = you.where_are_you; + + if (going_up) + { + mprf("Welcome back to %s!", branches[branch].longname); + + // Left a notable branch for the first time. + if ((brdepth[old_level.branch] > 1 + || old_level.branch == BRANCH_VESTIBULE) + && !you.branches_left[old_level.branch]) + { + string old_branch_string = branches[old_level.branch].longname; + if (old_branch_string.find("The ") == 0) + old_branch_string[0] = tolower(old_branch_string[0]); + mark_milestone("br.exit", "left " + old_branch_string + ".", + old_level.describe()); + you.branches_left.set(old_level.branch); + } + } + else + { + // Entered a branch (including portals) through the front door. + if (stair_find == branches[branch].entry_stairs) + { + if (branches[branch].entry_message) + mpr(branches[branch].entry_message); + else + mprf("Welcome to %s!", branches[branch].longname); + } + + // Entered a regular (non-portal) branch from above. + if (parent_branch(branch) == old_level.branch) + enter_branch(branch, old_level); + } + } + + const bool newlevel = load_level(stair_find, LOAD_ENTER_LEVEL, old_level); + + if (newlevel) + _new_level_amuses_xom(stair_find, old_feat, shaft, shaft_depth, !force_stair); + + // This should maybe go in load_level? + if (you.where_are_you == BRANCH_ABYSS) + generate_random_blood_spatter_on_level(); you.turn_is_over = true; @@ -448,20 +789,49 @@ void up_stairs(dungeon_feature_type force_stair, bool wizard) new_level(); + // Dunno why this is on going down only. + if (!going_up) + { + moveto_location_effects(old_feat); + + // Clear list of beholding and constricting/constricted monsters. + you.clear_beholders(); + you.clear_fearmongers(); + you.stop_constricting_all(); + you.stop_being_constricted(); + + trackers_init_new_level(true); + } + if (!wizard) _update_travel_cache(old_level, stair_pos); + if (!allow_control_teleport(true)) + mprf(MSGCH_WARN, "You sense a powerful magical force warping space."); + // Preventing obvious finding of stairs at your position. env.map_seen.set(you.pos()); viewwindow(); - seen_monsters_react(); - - if (!allow_control_teleport(true)) - mprf(MSGCH_WARN, "You sense a powerful magical force warping space."); + // There's probably a reason for this. I don't know it. + if (going_up) + seen_monsters_react(); + else + maybe_update_stashes(); request_autopickup(); + + // Zotdef: returning from portals (e.g. bazaar) paralyses the player in + // place for 5 moves. Nasty, but punishes players for using portals as + // quick-healing stopovers. + if (!going_up && crawl_state.game_is_zotdef()) + start_delay(DELAY_UNINTERRUPTIBLE, 5); +} + +void up_stairs(dungeon_feature_type force_stair, bool wizard) +{ + take_stairs(force_stair, true, false, wizard); } // Find the other end of the stair or portal at location pos on the current @@ -611,432 +981,11 @@ level_id stair_destination(dungeon_feature_type feat, const string &dst, return level_id(); } -static void _player_change_level_downstairs(dungeon_feature_type stair_find, - const string &dst) -{ - level_id lev = stair_destination(stair_find, dst, true); - if (!lev.is_valid()) - die("Unknown down stair: %s", dungeon_feature_name(stair_find)); - you.depth = lev.depth; - you.where_are_you = lev.branch; -} - -static void _maybe_destroy_trap(const coord_def &p) -{ - trap_def* trap = find_trap(p); - if (trap) - trap->destroy(true); -} - // TODO(Zannick): Fully merge with up_stairs into take_stairs. void down_stairs(dungeon_feature_type force_stair, bool force_known_shaft, bool wizard) { - const level_id old_level = level_id::current(); - const dungeon_feature_type old_feat = orig_terrain(you.pos()); - const dungeon_feature_type stair_find = - force_stair ? force_stair : old_feat; - - // Taking a shaft manually - const bool known_shaft = (!force_stair - && get_trap_type(you.pos()) == TRAP_SHAFT - && stair_find != DNGN_UNDISCOVERED_TRAP) - || (force_stair == DNGN_TRAP_SHAFT - && force_known_shaft); - // Latter case is falling down a shaft. - const bool shaft = known_shaft || force_stair == DNGN_TRAP_SHAFT; - level_id shaft_dest; - - // Up and down both work for portals. - // Canonicalize the direction; hell exits into the vestibule are handled - // by up_stairs; everything else by down_stairs. - if (feat_is_bidirectional_portal(stair_find)) - { - if (stair_find == DNGN_ENTER_HELL && player_in_hell()) - return up_stairs(force_stair); - } - - // Only check the current position for a legal stair traverse. - // If it's a shaft that we're taking, then we're already good. - if (!shaft && !_check_stairs(stair_find, true)) - return; - - if (_stair_moves_pre(stair_find)) - return; - - if (shaft) - { - if (!is_valid_shaft_level()) - { - if (known_shaft) - mpr("The shaft disappears in a puff of logic!"); - _maybe_destroy_trap(you.pos()); - return; - } - - shaft_dest = you.shaft_dest(known_shaft); - } - const int shaft_depth = (shaft ? shaft_dest.depth - you.depth : 1); - if (shaft) - { - if (shaft_dest == level_id::current()) - { - if (known_shaft) - { - mpr("Strange, the shaft seems to lead back to this level."); - mpr("The strain on the space-time continuum destroys the " - "shaft!"); - } - _maybe_destroy_trap(you.pos()); - return; - } - - if (!known_shaft) - { - mark_milestone("shaft", "fell down a shaft to " - + shaft_dest.describe() + "."); - } - - handle_items_on_shaft(you.pos(), false); - - string howfar; - if (force_stair && shaft_depth > 1) - howfar = make_stringf(" for %d floors", shaft_depth); - - mprf("You %s a shaft%s!", you.flight_mode() ? "are sucked into" - : "fall through", - howfar.c_str()); - - // Shafts are one-time-use. - mpr("The shaft crumbles and collapses."); - _maybe_destroy_trap(you.pos()); - } - - if (stair_find == DNGN_ENTER_VAULTS - && !is_existing_level(level_id(BRANCH_VAULTS, 1))) - { - if (!runes_in_pack()) - { - mpr("You need a rune to enter this place."); - return; - } - - for (int i = 0; i < NUM_RUNE_TYPES; i++) - if (you.runes[i]) - { - mprf("You insert the %s rune into the lock.", - rune_type_name(i)); - break; - } - - if (silenced(you.pos())) - mpr("The gate opens wide!"); - else - mpr("With a loud hiss the gate opens wide!"); - more(); - } - - if (stair_find == DNGN_ENTER_ZOT - && !is_existing_level(level_id(BRANCH_ZOT, 1))) - { - vector<int> runes; - for (int i = 0; i < NUM_RUNE_TYPES; i++) - if (you.runes[i]) - runes.push_back(i); - - if (runes.size() < NUMBER_OF_RUNES_NEEDED) - { - mprf("You need at least %d runes to enter this place.", - NUMBER_OF_RUNES_NEEDED); - return; - } - - ASSERT(runes.size() >= 3); - - shuffle_array(runes); - mprf("You insert the %s rune into the lock.", rune_type_name(runes[0])); -#ifdef USE_TILE_LOCAL - tiles.add_overlay(you.pos(), tileidx_zap(rune_colour(runes[0]))); - update_screen(); -#else - flash_view(UA_BRANCH_ENTRY, rune_colour(runes[0])); -#endif - mpr("The lock glows eerily!"); - more(); - - mprf("You insert the %s rune into the lock.", rune_type_name(runes[1])); - big_cloud(CLOUD_BLUE_SMOKE, &you, you.pos(), 20, 7 + random2(7)); - viewwindow(); - mpr("Heavy smoke blows from the lock!"); - more(); - - mprf("You insert the %s rune into the lock.", rune_type_name(runes[2])); - - if (silenced(you.pos())) - mpr("The gate opens wide!"); - else - mpr("With a loud hiss the gate opens wide!"); - more(); - - } - - if (stair_find == DNGN_ENTER_ZIGGURAT) - { - #define ZIG_RUNES 2 - if (runes_in_pack() < ZIG_RUNES) - { - mprf("You need at least %d runes to enter this place.", ZIG_RUNES); - return; - } - } - - // Bail if any markers veto the move. - if (_marker_vetoes_level_change()) - return; - - // All checks are done, the player is on the move now. - - // Magical level changes (Portal, Banishment) need this. - clear_trapping_net(); - end_searing_ray(); - - // Markers might be deleted when removing portals. - const string dst = env.markers.property_at(you.pos(), MAT_ANY, "dst"); - - // Fire level-leaving trigger. - leaving_level_now(stair_find); - - // Not entirely accurate - the player could die before - // reaching the Abyss. - if (!force_stair && old_feat == DNGN_ENTER_ABYSS) - { - mark_milestone("abyss.enter", "entered the Abyss!"); - take_note(Note(NOTE_MESSAGE, 0, 0, "Voluntarily entered the Abyss."), true); - } - else if (old_feat == DNGN_EXIT_THROUGH_ABYSS) - { - mark_milestone("abyss.enter", "escaped (hah) into the Abyss!"); - take_note(Note(NOTE_MESSAGE, 0, 0, "Took an exit into the Abyss."), true); - } - else if (stair_find == DNGN_EXIT_ABYSS - && you.char_direction != GDT_GAME_START) - { - mark_milestone("abyss.exit", "escaped from the Abyss!"); - you.attribute[ATTR_BANISHMENT_IMMUNITY] = you.elapsed_time + 100 - + random2(100); - you.banished_by = ""; - } - - // Interlevel travel data. - const bool collect_travel_data = can_travel_interlevel(); - if (collect_travel_data) - { - LevelInfo &old_level_info = travel_cache.get_level_info(old_level); - old_level_info.update(); - } - const coord_def stair_pos = you.pos(); - - if (stair_find == DNGN_ENTER_LABYRINTH || stair_find == DNGN_ENTER_ZIGGURAT) - dungeon_terrain_changed(you.pos(), DNGN_STONE_ARCH); - - if (stair_find == DNGN_ENTER_PANDEMONIUM - || stair_find == DNGN_ENTER_ABYSS - || feat_is_portal_entrance(stair_find)) - { - you.level_stack.push_back(level_pos::current()); - } - - _player_change_level_reset(); - if (shaft) - you.depth = shaft_dest.depth; - else - _player_change_level_downstairs(stair_find, dst); - - if (stair_find == DNGN_EXIT_ABYSS - || stair_find == DNGN_EXIT_PANDEMONIUM - || stair_find == DNGN_EXIT_THROUGH_ABYSS) - { - mpr("You pass through the gate."); - take_note(Note(NOTE_MESSAGE, 0, 0, - stair_find == DNGN_EXIT_ABYSS ? "Escaped the Abyss" : - stair_find == DNGN_EXIT_PANDEMONIUM ? "Escaped Pandemonium" : - stair_find == DNGN_EXIT_THROUGH_ABYSS ? "Escaped into the Abyss" : - "Buggered into bugdom"), true); - - if (!you.wizard || !crawl_state.is_replaying_keys()) - more(); - } - - if (!is_connected_branch(old_level.branch) - && player_in_connected_branch() - && old_level.branch != you.where_are_you) - { - mprf("Welcome %sto %s!", - you.char_direction == GDT_GAME_START ? "" : "back ", - branches[you.where_are_you].longname); - } - - if (!you.airborne() - && you.confused() - && !feat_is_escape_hatch(stair_find) - && force_stair != DNGN_ENTER_ABYSS - && force_stair != DNGN_ABYSSAL_STAIR - && force_stair != DNGN_EXIT_ABYSS - && coinflip()) - { - const char* fall_where = "down the stairs"; - if (!feat_is_staircase(stair_find)) - fall_where = "through the gate"; - - mprf("In your confused state, you trip and fall %s.", fall_where); - // Note that this only does damage; it doesn't cancel the level - // transition. - if (!feat_is_staircase(stair_find)) - ouch(1, KILLED_BY_FALLING_THROUGH_GATE); - else - ouch(1, KILLED_BY_FALLING_DOWN_STAIRS); - } - - dungeon_feature_type stair_taken = stair_find; - - if (shaft) - stair_taken = DNGN_TRAP_SHAFT; - - switch (you.where_are_you) - { - case BRANCH_ABYSS: - if (old_level.branch == BRANCH_ABYSS) - { - mprf(MSGCH_BANISHMENT, "You plunge deeper into the Abyss."); - break; - } - if (!force_stair) - mpr("You enter the Abyss!"); - - mpr("To return, you must find a gate leading back."); - if (you_worship(GOD_CHEIBRIADOS)) - { - mprf(MSGCH_GOD, GOD_CHEIBRIADOS, - "You feel Cheibriados slowing down the madness of this place."); - } - - // Re-entering the Abyss halves accumulated speed. - you.abyss_speed /= 2; - learned_something_new(HINT_ABYSS); - break; - - case BRANCH_PANDEMONIUM: - if (old_level.branch == BRANCH_PANDEMONIUM) - mpr("You pass into a different region of Pandemonium."); - break; - - default: - if (!shaft) - _climb_message(stair_find, false, old_level.branch); - break; - } - - if (!shaft) - _exit_stair_message(stair_find); - - // Did we enter a new branch. - if (!player_in_branch(old_level.branch)) - { - const branch_type branch = you.where_are_you; - - // Entered a branch (including portals) through the front door. - if (stair_taken == branches[branch].entry_stairs) - { - if (branches[branch].entry_message) - mpr(branches[branch].entry_message); - else - mprf("Welcome to %s!", branches[branch].longname); - } - - // Entered a regular (non-portal) branch from above. - if (parent_branch(branch) == old_level.branch) - enter_branch(branch, old_level); - } - - const bool newlevel = load_level(stair_taken, LOAD_ENTER_LEVEL, old_level); - - if (newlevel) - { - switch (you.where_are_you) - { - default: - // Xom thinks it's funny if you enter a new level via shaft - // or escape hatch, for shafts it's funnier the deeper you fell. - if (shaft || feat_is_escape_hatch(stair_find)) - xom_is_stimulated(shaft_depth * 50); - else if (!is_connected_branch(you.where_are_you)) - xom_is_stimulated(25); - else - xom_is_stimulated(10); - break; - - case BRANCH_ZIGGURAT: - // The best way to die currently. - xom_is_stimulated(50); - break; - - case BRANCH_LABYRINTH: - // Finding the way out of a labyrinth interests Xom, - // but less so for Minotaurs. (though not now, as they cannot - // map the labyrinth any more {due}) - xom_is_stimulated(75); - break; - - case BRANCH_PANDEMONIUM: - xom_is_stimulated(100); - break; - - case BRANCH_ABYSS: - generate_random_blood_spatter_on_level(); - - if (!force_stair && old_feat == DNGN_ENTER_ABYSS) - xom_is_stimulated(100, XM_INTRIGUED); - else - xom_is_stimulated(200); - break; - } - } - - you.turn_is_over = true; - - save_game_state(); - - new_level(); - - moveto_location_effects(old_feat); - - // Clear list of beholding and constricting/constricted monsters. - you.clear_beholders(); - you.clear_fearmongers(); - you.stop_constricting_all(); - you.stop_being_constricted(); - - if (!allow_control_teleport(true)) - mprf(MSGCH_WARN, "You sense a powerful magical force warping space."); - - trackers_init_new_level(true); - if (!wizard) - _update_travel_cache(old_level, stair_pos); - - // Preventing obvious finding of stairs at your position. - env.map_seen.set(you.pos()); - - viewwindow(); - - maybe_update_stashes(); - - request_autopickup(); - - // Zotdef: returning from portals (e.g. bazaar) paralyses the player in - // place for 5 moves. Nasty, but punishes players for using portals as - // quick-healing stopovers. - if (crawl_state.game_is_zotdef()) - start_delay(DELAY_UNINTERRUPTIBLE, 5); + take_stairs(force_stair, false, force_known_shaft, wizard); } static bool _any_glowing_mold() diff --git a/crawl-ref/source/stairs.h b/crawl-ref/source/stairs.h index 151e41e..20c4535 100644 --- a/crawl-ref/source/stairs.h +++ b/crawl-ref/source/stairs.h @@ -10,6 +10,9 @@ bool check_annotation_exclusion_warning(); level_id stair_destination(dungeon_feature_type feat, const string &dst, bool for_real = false); level_id stair_destination(coord_def pos, bool for_real = false); +void take_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN, + bool going_up = false, bool force_known_shaft = false, + bool wizard = false); void down_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN, bool force_known_shaft = false, bool wizard = false); diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index c2328a8..0c9f505 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -527,7 +527,7 @@ bool feat_is_metal(dungeon_feature_type feat) return feat == DNGN_METAL_WALL || feat == DNGN_GRATE; } -/** XXX: not sure what this means +/** Is this feature ambivalent about whether we're going up or down? */ bool feat_is_bidirectional_portal(dungeon_feature_type feat) { -- 1.9.1 |
||||||||||||
|
Relationships | ||||||||||||||||
|
Notes | |
(0022711) neil (administrator) 2013-05-20 15:28 |
Tree form should be handled in _go_upstairs() and _go_downstairs(); otherwise it will call start_delay() and you won't find out it's impossible until later. There are various other inconsistencies: it is possible to enter a shop while netted with > but not with < (but in the latter case the message still refers to "using stairs"). It's not clear to me how tree form and netting should interact with shops: I would think it should be disallowed, but players seem to think that would be a pointless restriction. |
(0022717) neil (administrator) 2013-05-21 00:33 |
_go_downstairs and _go_upstairs should be merged I think. Also, there is a lot of duplication of checks between _go_downstairs() and down_stairs() (and likewise for up). The former handles the player command, while the latter handles the end of a delay; some checks are needed both places, for example if you are turned into a tree while in the process of climbing. Probably those checks should therefore be split into a separate function. |
(0022718) neil (administrator) 2013-05-21 00:40 |
Zannick is working on this, assigned to me since he doesn't have the right account bits. |
(0022788) Zannick (reporter) 2013-05-23 08:07 |
up_stairs() and down_stairs() have a lot of stuff in them that will take me a bit longer to work my way through in merging them, so I figured I'd wrap up my other changes (which resolve the treeform bugs reported here and in 0007073, 0007074) into a workable commit and post that before continuing. I also axed a handful of the checks in up_stairs and down_stairs since they're unlikely to ever go off: moving the player interrupts any delayed stair travel, so we shouldn't need to double-check whether there's a stair we can take, unless some magic effect is forcing us (a la banish) to take an invalid staircase. Entering a shop has no delay, and no effect forces the player into a shop (shop() relies on the player's position anyway). And the "down stairs in Vestibule" check couldn't be fulfilled, as it wanted (stair_find > 65 && stair_find <= 45) |
(0022802) neil (administrator) 2013-05-24 19:36 |
Applied in trunk (0.13-a0-897-gfcd48b8), thanks! I added one more commit (0.13-a0-898-g32ea864) that changes the held message to be less specific (because we don't yet know at that point in the code whether we're trying to take stairs or use a shop). |
(0022997) neil (administrator) 2013-06-01 06:06 |
Also applied in stable (0.12.1-54-gd6fb6a2). Not closing because there is still some duplication that should be refactored in 0.13, but the bugs seem to be fixed now. |
(0028365) Zannick (reporter) 2015-01-27 04:56 |
Sorry for the delay. =) Here is a commit merging up_stairs and down_stairs, which shouldn't be a large behavior change except for a couple of minor bugs I spotted, like tripping on the way down a shaft. |
(0028714) Reaver (developer) 2015-03-26 05:32 |
Patch pushed as of 0.17-a0-185-gba09013, thanks! |
Mantis 1.1.8[^] Copyright © 2000 - 2009 Mantis Group |