summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-25 00:01:38 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-25 00:01:38 +0000
commit97f93f7d2dd30fee884ee4eeb8a16dcb51cf4a7c (patch)
treeef959b41c9373a02d6424717be5cbcbd1c72782f
parentbe49ad27a08b4d5a5e347e6d8a2e6852f81c4a8b (diff)
downloadcrawl-ref-97f93f7d2dd30fee884ee4eeb8a16dcb51cf4a7c.tar.gz
crawl-ref-97f93f7d2dd30fee884ee4eeb8a16dcb51cf4a7c.zip
Allow ziggurats placed in Pandemonium to return to the same Pan level when the player leaves the ziggurat. Breaks saves.
Cleaned up up_stairs() and down_stairs() to remove spurious depth changes when changing you.level_type - depth (you.your_level) now changes only for stairs with both ends in LEVEL_DUNGEON. All levels are now saved on exit, including non LEVEL_DUNGEON levels. Re-entering non-dungeon levels from down_stairs will still delete the old level. Re-entering non-dungeon levels from up_stairs (i.e. returning to a non-dungeon level from some other place, like a ziggurat) will reload the old level. Fixed bogus marker trashing when player attempts to use a Zot entrance with insufficient runes. Delete .msg files when game ends. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7598 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/dat/clua/ziggurat.lua7
-rw-r--r--crawl-ref/source/externs.h101
-rw-r--r--crawl-ref/source/files.cc42
-rw-r--r--crawl-ref/source/files.h4
-rw-r--r--crawl-ref/source/luadgn.cc8
-rw-r--r--crawl-ref/source/misc.cc359
-rw-r--r--crawl-ref/source/newgame.cc2
-rw-r--r--crawl-ref/source/ouch.cc22
-rw-r--r--crawl-ref/source/player.cc5
-rw-r--r--crawl-ref/source/tags.cc55
-rw-r--r--crawl-ref/source/travel.h101
11 files changed, 405 insertions, 301 deletions
diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua
index f3981c731d..65927e7b1f 100644
--- a/crawl-ref/source/dat/clua/ziggurat.lua
+++ b/crawl-ref/source/dat/clua/ziggurat.lua
@@ -23,7 +23,8 @@ function cleanup_ziggurat()
return one_way_stair {
onclimb = function(...)
dgn.persist.ziggurat = { }
- end
+ end,
+ dstplace = zig().origin_level
}
end
@@ -43,6 +44,8 @@ function initialise_ziggurat(z)
z.colour = ziggurat_wall_colour()
z.level = { }
+
+ z.origin_level = dgn.level_name(dgn.level_id())
end
function ziggurat_initialiser()
@@ -409,8 +412,6 @@ local function ziggurat_rectangle_builder(e)
end
dgn.colour_map(needs_colour, zig().colour)
-
- crawl.mpr("Ziggurat depth is now " .. zig_depth(), "diagnostic")
end
----------------------------------------------------------------------
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 6c75be735d..ef22c4eb6d 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -434,6 +434,107 @@ struct delay_queue_item
};
+// Identifies a level. Should never include virtual methods or
+// dynamically allocated memory (see code to push level_id onto Lua
+// stack in luadgn.cc)
+class level_id
+{
+public:
+ branch_type branch; // The branch in which the level is.
+ int depth; // What depth (in this branch - starting from 1)
+ level_area_type level_type;
+
+public:
+ // Returns the level_id of the current level.
+ static level_id current();
+
+ // Returns the level_id of the level that the stair/portal/whatever at
+ // 'pos' on the current level leads to.
+ static level_id get_next_level_id(const coord_def &pos);
+
+ level_id()
+ : branch(BRANCH_MAIN_DUNGEON), depth(-1),
+ level_type(LEVEL_DUNGEON)
+ {
+ }
+ level_id(branch_type br, int dep, level_area_type ltype = LEVEL_DUNGEON)
+ : branch(br), depth(dep), level_type(ltype)
+ {
+ }
+ level_id(const level_id &ot)
+ : branch(ot.branch), depth(ot.depth), level_type(ot.level_type)
+ {
+ }
+ level_id(level_area_type ltype)
+ : branch(BRANCH_MAIN_DUNGEON), depth(-1), level_type(ltype)
+ {
+ }
+
+ static level_id parse_level_id(const std::string &s) throw (std::string);
+
+ unsigned short packed_place() const;
+ std::string describe(bool long_name = false, bool with_number = true) const;
+
+ void clear()
+ {
+ branch = BRANCH_MAIN_DUNGEON;
+ depth = -1;
+ level_type = LEVEL_DUNGEON;
+ }
+
+ int absdepth() const;
+
+ bool is_valid() const
+ {
+ return (branch != NUM_BRANCHES && depth != -1)
+ || level_type != LEVEL_DUNGEON;
+ }
+
+ const level_id &operator = (const level_id &id)
+ {
+ branch = id.branch;
+ depth = id.depth;
+ level_type = id.level_type;
+ return (*this);
+ }
+
+ bool operator == ( const level_id &id ) const
+ {
+ return (level_type == id.level_type
+ && (level_type != LEVEL_DUNGEON
+ || (branch == id.branch && depth == id.depth)));
+ }
+
+ bool operator != ( const level_id &id ) const
+ {
+ return !operator == (id);
+ }
+
+ bool operator <( const level_id &id ) const
+ {
+ if (level_type != id.level_type)
+ return (level_type < id.level_type);
+
+ if (level_type != LEVEL_DUNGEON)
+ return (false);
+
+ return (branch < id.branch) || (branch==id.branch && depth < id.depth);
+ }
+
+ bool operator == ( const branch_type _branch ) const
+ {
+ return (branch == _branch && level_type == LEVEL_DUNGEON);
+ }
+
+ bool operator != ( const branch_type _branch ) const
+ {
+ return !operator == (_branch);
+ }
+
+ void save(writer&) const;
+ void load(reader&);
+};
+
struct item_def
{
object_class_type base_type; // basic class (ie OBJ_WEAPON)
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index d2085cc678..057a3a32bc 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -827,15 +827,7 @@ static void _place_player_on_stair(level_area_type old_level_type,
bool find_first = true;
// Order is important here.
- if (you.level_type == LEVEL_DUNGEON
- && old_branch == BRANCH_VESTIBULE_OF_HELL
- && stair_taken == DNGN_STONE_STAIRS_UP_I)
- {
- // Leaving hell - look for entry portal first.
- stair_taken = DNGN_ENTER_HELL;
- find_first = false;
- }
- else if (stair_taken == DNGN_EXIT_PANDEMONIUM)
+ if (stair_taken == DNGN_EXIT_PANDEMONIUM)
{
stair_taken = DNGN_ENTER_PANDEMONIUM;
find_first = false;
@@ -845,6 +837,10 @@ static void _place_player_on_stair(level_area_type old_level_type,
stair_taken = DNGN_ENTER_ABYSS;
find_first = false;
}
+ else if (stair_taken == DNGN_EXIT_HELL)
+ {
+ stair_taken = DNGN_ENTER_HELL;
+ }
else if (stair_taken == DNGN_ENTER_HELL)
{
// The vestibule and labyrinth always start from this stair.
@@ -885,9 +881,15 @@ static void _place_player_on_stair(level_area_type old_level_type,
- DNGN_ENTER_FIRST_BRANCH);
}
else if (stair_taken >= DNGN_ENTER_DIS
- && stair_taken <= DNGN_TRANSIT_PANDEMONIUM)
+ && stair_taken <= DNGN_ENTER_TARTARUS)
+ {
+ // Only when entering a hell - when exiting, go back to the
+ // entry stair.
+ if (player_in_hell())
+ stair_taken = DNGN_STONE_STAIRS_UP_I;
+ }
+ else if (stair_taken == DNGN_EXIT_ABYSS)
{
- // When entering a hell or pandemonium.
stair_taken = DNGN_STONE_STAIRS_UP_I;
}
else if (stair_taken == DNGN_ENTER_PORTAL_VAULT)
@@ -1078,13 +1080,14 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode,
if (you.level_type == LEVEL_DUNGEON && old_level_type == LEVEL_DUNGEON
|| load_mode == LOAD_START_GAME && you.char_direction != GDT_GAME_START)
{
- if (tmp_file_pairs[you.your_level][you.where_are_you] == false)
+ const level_id current(level_id::current());
+ if (Generated_Levels.find(current) == Generated_Levels.end())
{
// Make sure the old file is gone.
unlink(cha_fil.c_str());
// Save the information for later deletion -- DML 6/11/99
- tmp_file_pairs[you.your_level][you.where_are_you] = true;
+ Generated_Levels.insert(current);
}
}
@@ -1104,8 +1107,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode,
{
_grab_followers();
- if (old_level_type == LEVEL_DUNGEON)
- _save_level( old_level, LEVEL_DUNGEON, old_branch );
+ _save_level( old_level, old_level_type, old_branch );
}
if (make_changes)
@@ -1135,7 +1137,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode,
// generation.
you.your_level = 0;
you.char_direction = GDT_DESCENDING;
- tmp_file_pairs[you.your_level][you.where_are_you] = true;
+ Generated_Levels.insert(level_id::current());
}
_clear_env_map();
@@ -1657,13 +1659,11 @@ static void _restore_level(const level_id &original)
you.level_type, you.your_level, you.where_are_you );
}
-// Given a level in the dungeon (i.e. level_type == LEVEL_DUNGEON),
-// returns true if the level has been created already in this game.
-// Asserts if the level_type is not LEVEL_DUNGEON.
+// Given a level returns true if the level has been created already
+// in this game.
bool is_existing_level(const level_id &level)
{
- ASSERT(level.level_type == LEVEL_DUNGEON);
- return (tmp_file_pairs[level.absdepth()][level.branch]);
+ return (Generated_Levels.find(level) != Generated_Levels.end());
}
// Applies an operation (applicator) after switching to the specified level.
diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h
index f2e8c006a1..2a60fbeb77 100644
--- a/crawl-ref/source/files.h
+++ b/crawl-ref/source/files.h
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <string>
#include <vector>
+#include <set>
enum load_mode_type
{
@@ -28,7 +29,8 @@ enum load_mode_type
#define MAX_LEVELS 50
// referenced in files - newgame - ouch:
-extern FixedArray<bool, MAX_LEVELS, NUM_BRANCHES> tmp_file_pairs;
+typedef std::set<level_id> level_id_set;
+extern level_id_set Generated_Levels;
bool file_exists(const std::string &name);
bool dir_exists(const std::string &dir);
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 0e81370fbe..53194de4ea 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -2225,6 +2225,13 @@ LUAFN(dgn_level_id)
return (1);
}
+LUAFN(dgn_level_name)
+{
+ const level_id lid(_lua_level_id(ls, 1));
+ lua_pushstring(ls, lid.describe().c_str());
+ return (1);
+}
+
LUAFN(dgn_set_level_type_origin)
{
if (you.level_type != LEVEL_PORTAL_VAULT)
@@ -2484,6 +2491,7 @@ static const struct luaL_reg dgn_lib[] =
{ "br_parent_branch", dgn_br_parent_branch },
{ "level_id", dgn_level_id },
+ { "level_name", dgn_level_name },
{ "set_level_type_origin", dgn_set_level_type_origin },
{ "map_by_tag", dgn_map_by_tag },
{ "map_in_depth", dgn_map_in_depth },
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 810b708294..91545ab67e 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1512,6 +1512,102 @@ bool check_annotation_exclusion_warning()
return (true);
}
+static void _player_change_level_reset()
+{
+ you.prev_targ = MHITNOT;
+ if (you.pet_target != MHITYOU)
+ you.pet_target = MHITNOT;
+
+ you.prev_grd_targ = coord_def(0, 0);
+}
+
+static level_id _stair_destination_override()
+{
+ const std::string force_place =
+ env.markers.property_at(you.pos(), MAT_ANY, "dstplace");
+ if (!force_place.empty())
+ {
+ try
+ {
+ const level_id place = level_id::parse_level_id(force_place);
+ return (place);
+ }
+ catch (const std::string &err)
+ {
+ end(1, false, "Marker set with invalid level name: %s",
+ force_place.c_str());
+ }
+ }
+
+ const level_id invalid;
+ return (invalid);
+}
+
+static bool _stair_force_destination(const level_id &override)
+{
+ if (override.is_valid())
+ {
+ if (override.level_type == LEVEL_DUNGEON)
+ {
+ you.where_are_you = override.branch;
+ you.your_level = override.absdepth();
+ you.level_type = override.level_type;
+ }
+ else
+ {
+ you.level_type = override.level_type;
+ }
+ return (true);
+ }
+ return (false);
+}
+
+static void _player_change_level_upstairs(dungeon_feature_type stair_find,
+ const level_id &place_override)
+{
+ if (_stair_force_destination(place_override))
+ return;
+
+ if (you.level_type == LEVEL_DUNGEON)
+ you.your_level--;
+
+ // Make sure we return to our main dungeon level... labyrinth entrances
+ // in the abyss or pandemonium are a bit trouble (well the labyrinth does
+ // provide a way out of those places, its really not that bad I suppose).
+ if (level_type_exits_up(you.level_type))
+ you.level_type = LEVEL_DUNGEON;
+
+ if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ {
+ you.where_are_you = BRANCH_MAIN_DUNGEON;
+ you.your_level = you.hell_exit;
+ }
+
+ if (player_in_hell())
+ {
+ you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
+ you.your_level = 27;
+ }
+
+ // Did we take a branch stair?
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (branches[i].exit_stairs == stair_find
+ && you.where_are_you == i)
+ {
+ you.where_are_you = branches[i].parent_branch;
+
+ // If leaving a branch which wasn't generated in this
+ // particular game (like the Swamp or Shoals), then
+ // its startdepth is set to -1; compensate for that,
+ // so we don't end up on "level -1".
+ if (branches[i].startdepth == -1)
+ you.your_level += 2;
+ break;
+ }
+ }
+}
+
void up_stairs(dungeon_feature_type force_stair,
entry_cause_type entry_cause)
{
@@ -1536,9 +1632,6 @@ void up_stairs(dungeon_feature_type force_stair,
return;
}
- level_id old_level_id = level_id::current();
- LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id);
-
// Since the overloaded message set turn_is_over, I'm assuming that
// the overloaded character makes an attempt... so we're doing this
// check before that one. -- bwr
@@ -1566,7 +1659,12 @@ void up_stairs(dungeon_feature_type force_stair,
return;
}
- if (you.your_level == 0
+ const level_id destination_override(_stair_destination_override());
+ const bool leaving_dungeon =
+ level_id::current() == level_id(BRANCH_MAIN_DUNGEON, 1)
+ && !destination_override.is_valid();
+
+ if (leaving_dungeon
&& !yesno("Are you sure you want to leave the Dungeon?", false, 'n'))
{
mpr("Alright, then stay!");
@@ -1576,29 +1674,25 @@ void up_stairs(dungeon_feature_type force_stair,
// Checks are done, the character is committed to moving between levels.
leaving_level_now();
- int old_level = you.your_level;
+ const int old_level = you.your_level;
// Interlevel travel data.
const bool collect_travel_data = can_travel_interlevel();
+ level_id old_level_id = level_id::current();
+ LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id);
+
if (collect_travel_data)
old_level_info.update();
- // Make sure we return to our main dungeon level... labyrinth entrances
- // in the abyss or pandemonium are a bit trouble (well the labyrinth does
- // provide a way out of those places, its really not that bad I suppose).
- if (level_type_exits_up(you.level_type))
- you.level_type = LEVEL_DUNGEON;
-
- you.your_level--;
-
- int i = 0;
+ _player_change_level_reset();
+ _player_change_level_upstairs(stair_find, destination_override);
if (you.your_level < 0)
{
mpr("You have escaped!");
- for (i = 0; i < ENDOFPACK; i++)
+ for (int i = 0; i < ENDOFPACK; i++)
{
if (is_valid_item( you.inv[i] )
&& you.inv[i].base_type == OBJ_ORBS)
@@ -1610,39 +1704,30 @@ void up_stairs(dungeon_feature_type force_stair,
ouch(INSTANT_DEATH, NON_MONSTER, KILLED_BY_LEAVING);
}
- you.prev_targ = MHITNOT;
- if (you.pet_target != MHITYOU)
- you.pet_target = MHITNOT;
-
- you.prev_grd_targ = coord_def(0, 0);
-
- if (player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
+ if (old_level_id.branch == BRANCH_VESTIBULE_OF_HELL
+ && !player_in_branch( BRANCH_VESTIBULE_OF_HELL ))
{
mpr("Thank you for visiting Hell. Please come again soon.");
- you.where_are_you = BRANCH_MAIN_DUNGEON;
- you.your_level = you.hell_exit;
- stair_find = DNGN_STONE_STAIRS_UP_I;
}
- if (player_in_hell())
- {
- you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
- you.your_level = 27;
- }
-
- // Did we take a branch stair?
- for (i = 0; i < NUM_BRANCHES; ++i)
+ // Fixup exits from the Hell branches.
+ if (player_in_branch(BRANCH_VESTIBULE_OF_HELL))
{
- if (branches[i].exit_stairs == stair_find)
+ switch (old_level_id.branch)
{
- you.where_are_you = branches[i].parent_branch;
-
- // If leaving a branch which wasn't generated in this
- // particular game (like the Swamp or Shoals), then
- // its startdepth is set to -1; compensate for that,
- // so we don't end up on "level -1".
- if (branches[i].startdepth == -1)
- you.your_level += 2;
+ case BRANCH_COCYTUS:
+ stair_find = DNGN_ENTER_COCYTUS;
+ break;
+ case BRANCH_DIS:
+ stair_find = DNGN_ENTER_DIS;
+ break;
+ case BRANCH_GEHENNA:
+ stair_find = DNGN_ENTER_GEHENNA;
+ break;
+ case BRANCH_TARTARUS:
+ stair_find = DNGN_ENTER_TARTARUS;
+ break;
+ default:
break;
}
}
@@ -1789,17 +1874,79 @@ static void _mark_portal_return_point(const coord_def &pos)
}
}
+// All changes to you.level_type, you.where_are_you and you.your_level
+// for descending stairs should happen here.
+static void _player_change_level_downstairs(
+ dungeon_feature_type stair_find,
+ const level_id &place_override,
+ bool shaft,
+ int shaft_level,
+ const level_id &shaft_dest)
+{
+ if (_stair_force_destination(place_override))
+ return;
+
+ const level_area_type original_level_type(you.level_type);
+
+ if (you.level_type != LEVEL_DUNGEON
+ && (you.level_type != LEVEL_PANDEMONIUM
+ || stair_find != DNGN_TRANSIT_PANDEMONIUM)
+ && (you.level_type != LEVEL_PORTAL_VAULT
+ || !grid_is_stone_stair(stair_find)))
+ {
+ you.level_type = LEVEL_DUNGEON;
+ }
+
+ if (stair_find == DNGN_ENTER_HELL)
+ {
+ you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
+ you.hell_exit = you.your_level;
+
+ you.your_level = 26;
+ }
+
+ // Welcome message.
+ // Try to find a branch stair.
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (branches[i].entry_stairs == stair_find)
+ {
+ you.where_are_you = branches[i].id;
+ break;
+ }
+ }
+
+ if (stair_find == DNGN_ENTER_LABYRINTH)
+ you.level_type = LEVEL_LABYRINTH;
+ else if (stair_find == DNGN_ENTER_ABYSS)
+ you.level_type = LEVEL_ABYSS;
+ else if (stair_find == DNGN_ENTER_PANDEMONIUM)
+ you.level_type = LEVEL_PANDEMONIUM;
+ else if (stair_find == DNGN_ENTER_PORTAL_VAULT)
+ you.level_type = LEVEL_PORTAL_VAULT;
+
+ if (shaft)
+ {
+ you.your_level = shaft_level;
+ you.where_are_you = shaft_dest.branch;
+ }
+ else if (original_level_type == LEVEL_DUNGEON
+ && you.level_type == LEVEL_DUNGEON)
+ {
+ you.your_level++;
+ }
+}
+
void down_stairs( int old_level, dungeon_feature_type force_stair,
entry_cause_type entry_cause )
{
- int i;
const level_area_type old_level_type = you.level_type;
const dungeon_feature_type stair_find =
force_stair? force_stair : grd(you.pos());
branch_type old_where = you.where_are_you;
- bool shaft = (!force_stair
+ const bool shaft = (!force_stair
&& get_trap_type(you.pos()) == TRAP_SHAFT
|| force_stair == DNGN_TRAP_NATURAL);
level_id shaft_dest;
@@ -1836,6 +1983,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
return;
}
+
if (shaft)
{
const bool known_trap = (grd(you.pos()) != DNGN_UNDISCOVERED_TRAP
@@ -1883,33 +2031,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
mpr("You fall through a shaft!");
}
- // All checks are done, the player is on the move now.
-
- // Fire level-leaving trigger.
- leaving_level_now();
-
-#ifdef DGL_MILESTONES
- if (!force_stair)
- {
- // Not entirely accurate - the player could die before
- // reaching the Abyss.
- if (grd(you.pos()) == DNGN_ENTER_ABYSS)
- mark_milestone("abyss.enter", "entered the Abyss!");
- else if (grd(you.pos()) == DNGN_EXIT_ABYSS
- && you.char_direction != GDT_GAME_START)
- {
- mark_milestone("abyss.exit", "escaped from the Abyss!");
- }
- }
-#endif
-
- // [ds] Descending into the Labyrinth increments your_level. Going
- // downstairs from a labyrinth implies that you've been banished (or been
- // sent to Pandemonium somehow). Decrementing your_level here is needed
- // to fix this buggy sequence: D:n -> Labyrinth -> Abyss -> D:(n+1).
- if (level_type_exits_up(you.level_type))
- you.your_level--;
-
if (stair_find == DNGN_ENTER_ZOT)
{
const int num_runes = runes_in_pack();
@@ -1930,6 +2051,27 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
}
}
+ const level_id destination_override(_stair_destination_override());
+
+ // All checks are done, the player is on the move now.
+ // Fire level-leaving trigger.
+ leaving_level_now();
+
+#ifdef DGL_MILESTONES
+ if (!force_stair)
+ {
+ // Not entirely accurate - the player could die before
+ // reaching the Abyss.
+ if (grd(you.pos()) == DNGN_ENTER_ABYSS)
+ mark_milestone("abyss.enter", "entered the Abyss!");
+ else if (grd(you.pos()) == DNGN_EXIT_ABYSS
+ && you.char_direction != GDT_GAME_START)
+ {
+ mark_milestone("abyss.exit", "escaped from the Abyss!");
+ }
+ }
+#endif
+
// Interlevel travel data.
const bool collect_travel_data = can_travel_interlevel();
@@ -1943,42 +2085,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
if (you.level_type == LEVEL_ABYSS)
save_abyss_uniques();
- if (you.level_type != LEVEL_DUNGEON
- && (you.level_type != LEVEL_PANDEMONIUM
- || stair_find != DNGN_TRANSIT_PANDEMONIUM)
- && (you.level_type != LEVEL_PORTAL_VAULT
- || !grid_is_stone_stair(stair_find)))
- {
- you.level_type = LEVEL_DUNGEON;
- }
-
- you.prev_targ = MHITNOT;
- if (you.pet_target != MHITYOU)
- you.pet_target = MHITNOT;
-
- you.prev_grd_targ = coord_def(0, 0);
-
- if (stair_find == DNGN_ENTER_HELL)
- {
- you.where_are_you = BRANCH_VESTIBULE_OF_HELL;
- you.hell_exit = you.your_level;
-
- you.your_level = 26;
- }
-
- // Welcome message.
- // Try to find a branch stair.
- bool entered_branch = false;
- for (i = 0; i < NUM_BRANCHES; ++i)
- {
- if (branches[i].entry_stairs == stair_find)
- {
- entered_branch = true;
- you.where_are_you = branches[i].id;
- break;
- }
- }
-
if (stair_find == DNGN_ENTER_LABYRINTH)
dungeon_terrain_changed(you.pos(), DNGN_STONE_ARCH);
@@ -1988,14 +2094,9 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
_mark_portal_return_point(you.pos());
}
- if (stair_find == DNGN_ENTER_LABYRINTH)
- you.level_type = LEVEL_LABYRINTH;
- else if (stair_find == DNGN_ENTER_ABYSS)
- you.level_type = LEVEL_ABYSS;
- else if (stair_find == DNGN_ENTER_PANDEMONIUM)
- you.level_type = LEVEL_PANDEMONIUM;
- else if (stair_find == DNGN_ENTER_PORTAL_VAULT)
- you.level_type = LEVEL_PORTAL_VAULT;
+ _player_change_level_reset();
+ _player_change_level_downstairs(stair_find, destination_override, shaft,
+ shaft_level, shaft_dest);
// When going downstairs into a special level, delete any previous
// instances of it.
@@ -2005,11 +2106,16 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
you.where_are_you,
you.level_type, false);
#if DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "Deleting: %s", lname.c_str() );
+ mprf( MSGCH_WARN, "Deleting: %s", lname.c_str() );
#endif
unlink(lname.c_str());
}
+ // Did we enter a new branch.
+ const bool entered_branch(
+ you.where_are_you != old_level_id.branch
+ && branches[you.where_are_you].parent_branch == old_level_id.branch);
+
if (stair_find == DNGN_EXIT_ABYSS || stair_find == DNGN_EXIT_PANDEMONIUM)
{
mpr("You pass through the gate.");
@@ -2045,14 +2151,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
KILLED_BY_FALLING_DOWN_STAIRS);
}
- if (shaft)
- {
- you.your_level = shaft_level;
- you.where_are_you = shaft_dest.branch;
- }
- else if (you.level_type == LEVEL_DUNGEON)
- you.your_level++;
-
dungeon_feature_type stair_taken = stair_find;
if (you.level_type == LEVEL_ABYSS)
@@ -2196,19 +2294,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
unsigned char pc = 0;
unsigned char pt = random2avg(28, 3);
- if (shaft)
- {
- you.your_level = shaft_level;
- you.where_are_you = shaft_dest.branch;
- }
- else if (level_type_exits_up(you.level_type))
- you.your_level++;
- else if (level_type_exits_down(you.level_type)
- && !level_type_exits_down(old_level_type))
- {
- you.your_level--;
- }
-
switch (you.level_type)
{
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 6f2dbccc15..8f62376770 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -1267,7 +1267,7 @@ game_start:
set_mp( you.max_magic_points, false );
// tmpfile purging removed in favour of marking
- tmp_file_pairs.init(false);
+ Generated_Levels.clear();
_initialise_branch_depths();
init_level_connectivity();
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 8d797a1e31..a00a296e8d 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -1007,18 +1007,16 @@ void end_game( scorefile_entry &se )
}
// clean all levels that we think we have ever visited
- for (int level = 0; level < MAX_LEVELS; level++)
+ for (level_id_set::const_iterator i = Generated_Levels.begin();
+ i != Generated_Levels.end(); ++i)
{
- for (int dungeon = 0; dungeon < NUM_BRANCHES; dungeon++)
- {
- if (tmp_file_pairs[level][dungeon])
- {
- unlink(
- make_filename( you.your_name, level,
- static_cast<branch_type>(dungeon),
- LEVEL_DUNGEON, false ).c_str() );
- }
- }
+ const level_id &place(*i);
+ unlink(
+ make_filename( you.your_name,
+ place.absdepth(),
+ place.branch,
+ place.level_type,
+ false ).c_str() );
}
// temp levels, if any
@@ -1041,7 +1039,7 @@ void end_game( scorefile_entry &se )
#ifdef PACKAGE_SUFFIX
PACKAGE_SUFFIX ,
#endif
- ".st", ".kil", ".tc", ".nts", ".tut", ".sav"
+ ".st", ".kil", ".tc", ".nts", ".tut", ".sav", ".msg"
};
const int num_suffixes = sizeof(suffixes) / sizeof(const char*);
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 7fcace5605..b386f0f4cb 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -6957,7 +6957,10 @@ void PlaceInfo::assert_validity() const
if (level_type == LEVEL_LABYRINTH || level_type == LEVEL_ABYSS)
ASSERT(num_visits == levels_seen);
else if (level_type == LEVEL_PANDEMONIUM)
- ASSERT(num_visits <= levels_seen);
+ // Ziggurats can allow a player to return to the same
+ // Pandemonium level.
+ // ASSERT(num_visits <= levels_seen);
+ ;
else if (level_type == LEVEL_DUNGEON && branches[branch].depth > 0)
ASSERT(levels_seen <= (unsigned long) branches[branch].depth);
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 3e6c484140..409b35f06a 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -96,7 +96,8 @@ extern std::map<level_pos, char> portal_vault_colours;
extern std::map<level_id, std::string> level_annotations;
// temp file pairs used for file level cleanup
-FixedArray < bool, MAX_LEVELS, NUM_BRANCHES > tmp_file_pairs;
+
+level_id_set Generated_Levels;
// The minor version for the tag currently being read.
static int _tag_minor_version = -1;
@@ -292,6 +293,16 @@ void marshall_as_long(writer& th, const T& t)
marshallLong( th, static_cast<long>(t) );
}
+template <typename data>
+void marshallSet(writer &th, const std::set<data> &s,
+ void (*marshall)(writer &, const data &))
+{
+ marshallLong( th, s.size() );
+ typename std::set<data>::const_iterator i = s.begin();
+ for ( ; i != s.end(); ++i)
+ marshall(th, *i);
+}
+
template<typename key, typename value>
void marshallMap(writer &th, const std::map<key,value>& data,
void (*key_marshall)(writer&, const key&),
@@ -354,6 +365,16 @@ void marshall_level_pos( writer& th, const level_pos& lpos )
marshall_level_id(th, lpos.id);
}
+template <typename data, typename set>
+void unmarshallSet(reader &th, set &dset,
+ data (*data_unmarshall)(reader &))
+{
+ dset.clear();
+ long len = unmarshallLong(th);
+ for (long i = 0L; i < len; ++i)
+ dset.insert(data_unmarshall(th));
+}
+
template<typename key, typename value, typename map>
void unmarshallMap(reader& th, map& data,
key (*key_unmarshall) (reader&),
@@ -1096,25 +1117,20 @@ static void marshallPlaceInfo(writer &th, PlaceInfo place_info)
static void tag_construct_you_dungeon(writer &th)
{
- int i,j;
-
// how many unique creatures?
marshallShort(th, NUM_MONSTERS);
- for (j = 0; j < NUM_MONSTERS; ++j)
+ for (int j = 0; j < NUM_MONSTERS; ++j)
marshallByte(th,you.unique_creatures[j]); // unique beasties
// how many branches?
marshallByte(th, NUM_BRANCHES);
- for (j = 0; j < NUM_BRANCHES; ++j)
+ for (int j = 0; j < NUM_BRANCHES; ++j)
{
marshallLong(th, branches[j].startdepth);
marshallLong(th, branches[j].branch_flags);
}
- marshallShort(th, MAX_LEVELS);
- for (i = 0; i < MAX_LEVELS; ++i)
- for (j = 0; j < NUM_BRANCHES; ++j)
- marshallBoolean(th, tmp_file_pairs[i][j]);
+ marshallSet(th, Generated_Levels, marshall_level_id);
marshallMap(th, stair_level,
marshall_as_long<branch_type>, marshall_level_id);
@@ -1542,16 +1558,10 @@ static PlaceInfo unmarshallPlaceInfo(reader &th)
static void tag_read_you_dungeon(reader &th)
{
- int i,j;
- int count_c;
- short count_s;
-
- unsigned short count_p;
-
// how many unique creatures?
- count_c = unmarshallShort(th);
+ int count_c = unmarshallShort(th);
you.unique_creatures.init(false);
- for (j = 0; j < count_c; ++j)
+ for (int j = 0; j < count_c; ++j)
{
const bool created = static_cast<bool>(unmarshallByte(th));
@@ -1561,16 +1571,13 @@ static void tag_read_you_dungeon(reader &th)
// how many branches?
count_c = unmarshallByte(th);
- for (j = 0; j < count_c; ++j)
+ for (int j = 0; j < count_c; ++j)
{
branches[j].startdepth = unmarshallLong(th);
branches[j].branch_flags = (unsigned long) unmarshallLong(th);
}
- count_s = unmarshallShort(th);
- for (i = 0; i < count_s; ++i)
- for (j = 0; j < count_c; ++j)
- tmp_file_pairs[i][j] = unmarshallBoolean(th);
+ unmarshallSet(th, Generated_Levels, unmarshall_level_id);
unmarshallMap(th, stair_level,
unmarshall_long_as<branch_type>,
@@ -1593,12 +1600,12 @@ static void tag_read_you_dungeon(reader &th)
you.set_place_info(place_info);
std::vector<PlaceInfo> list = you.get_all_place_info();
- count_p = (unsigned short) unmarshallShort(th);
+ unsigned short count_p = (unsigned short) unmarshallShort(th);
// Use "<=" so that adding more branches or non-dungeon places
// won't break save-file compatibility.
ASSERT(count_p <= list.size());
- for (i = 0; i < count_p; i++)
+ for (int i = 0; i < count_p; i++)
{
place_info = unmarshallPlaceInfo(th);
ASSERT(!place_info.is_global());
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index 65e2bcd08a..419d0e3a32 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -179,107 +179,6 @@ enum explore_stop_type
////////////////////////////////////////////////////////////////////////////
// Structs for interlevel travel.
-// Identifies a level. Should never include virtual methods or
-// dynamically allocated memory (see code to push level_id onto Lua
-// stack in luadgn.cc)
-class level_id
-{
-public:
- branch_type branch; // The branch in which the level is.
- int depth; // What depth (in this branch - starting from 1)
- level_area_type level_type;
-
-public:
- // Returns the level_id of the current level.
- static level_id current();
-
- // Returns the level_id of the level that the stair/portal/whatever at
- // 'pos' on the current level leads to.
- static level_id get_next_level_id(const coord_def &pos);
-
- level_id()
- : branch(BRANCH_MAIN_DUNGEON), depth(-1),
- level_type(LEVEL_DUNGEON)
- {
- }
- level_id(branch_type br, int dep, level_area_type ltype = LEVEL_DUNGEON)
- : branch(br), depth(dep), level_type(ltype)
- {
- }
- level_id(const level_id &ot)
- : branch(ot.branch), depth(ot.depth), level_type(ot.level_type)
- {
- }
- level_id(level_area_type ltype)
- : branch(BRANCH_MAIN_DUNGEON), depth(-1), level_type(ltype)
- {
- }
-
- static level_id parse_level_id(const std::string &s) throw (std::string);
-
- unsigned short packed_place() const;
- std::string describe(bool long_name = false, bool with_number = true) const;
-
- void clear()
- {
- branch = BRANCH_MAIN_DUNGEON;
- depth = -1;
- level_type = LEVEL_DUNGEON;
- }
-
- int absdepth() const;
-
- bool is_valid() const
- {
- return (branch != NUM_BRANCHES && depth != -1)
- || level_type != LEVEL_DUNGEON;
- }
-
- const level_id &operator = (const level_id &id)
- {
- branch = id.branch;
- depth = id.depth;
- level_type = id.level_type;
- return (*this);
- }
-
- bool operator == ( const level_id &id ) const
- {
- return (level_type == id.level_type
- && (level_type != LEVEL_DUNGEON
- || (branch == id.branch && depth == id.depth)));
- }
-
- bool operator != ( const level_id &id ) const
- {
- return !operator == (id);
- }
-
- bool operator <( const level_id &id ) const
- {
- if (level_type != id.level_type)
- return (level_type < id.level_type);
-
- if (level_type != LEVEL_DUNGEON)
- return (false);
-
- return (branch < id.branch) || (branch==id.branch && depth < id.depth);
- }
-
- bool operator == ( const branch_type _branch ) const
- {
- return (branch == _branch && level_type == LEVEL_DUNGEON);
- }
-
- bool operator != ( const branch_type _branch ) const
- {
- return !operator == (_branch);
- }
-
-
- void save(writer&) const;
- void load(reader&);
-};
// A position on a particular level.
struct level_pos