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
KSM4H3SBM6FIQTUEGHXXYATJXEOJ4EKUBAFCRMFKSHY7N2HWECRQC
S4RG6BEPNGMZELQ3HDRLX6XI5Y4FYLZME5FVO76WNRN4J52IAZRQC
7G2RWMLC5YBT3W7DNXDGEA4SMTI524RJIH3VO7MOQYGBMQHML2MAC
CI2RMLJLIAZMEGNN6LJN6PSHXHLPG7PXFIDYRGFPVMDPJ2R4S4NQC
CM2YC5KBTUB4JFT3CL3NRS7V5X76M7RI7SNT4XK6IOVBZA2URRKAC
CPBVQFT7NWEYLYD34D5VYZIEOZ32YADXYTSFMS635YNXX4OFIZVAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
4N5PW5S3OV25HFN634NNWMMYX26NA2TB6TVFG4UMYSZ2VBJWKE4QC
DKRSOHZXL6EPSLKOKHF7GJXSZEJVY7CXGACSHWLM5B5FTRETWWCAC
T4IH76FA5TWHFOZUJFHLQXQJENJHWTUZZP4EGNA7D4GTZY7D4ZKAC
6HG6JFO47Y3BZLU7Y6G3R2CX6JFGN4X5PKK6S5IGUXUYQ5GVZYFQC
RISMOCQM6BKK4XSIRKYLOBB2UPDYJNDAL6OGIIR5GGNZQAK5YSZAC
ZVK4J5HTKFNOOIVCI62ZWEYGXEE5TYJ65DLYYZAZWTADFSXE62ZAC
ANBVGN4RZOMY5LI4QSHOV2477FN55H353ZYLSVCPTXC7AWWSQZBAC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
WX2VFNANQZ3IRHBXSLKJT3G3OAQREAZISXLOTG6JO7KXFBHQFOYAC
NKONHW4JNY6HP2M63MNPM3H64ZWSUNUT5FX2STW4KTS4AMXJXXVQC
G3UKWY6JNG2ZQO6R2UTAAIQ3ECJIGEKEHTKOJNL5EN4YBC7U44KQC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
Q2AYZGR7UBWG4CKVR6PJQD3UHDEBMAFBQ5PZLHT64CTREG3JYFZAC
T6TL6NTIOBYNUIONGK3JFZJ5ONWV6S4CTIRDC5JMKMCBGG5IY3EAC
WF2DSJGR6PKLGQSXEFF4ZW4EZZFGMHXPXWUYAKYBPFJH6KJKAANQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
WQLOHSNCA3VOMDJF6IINJYKSYVYZEBPJJWBB33QSNE4RP5HEXPMAC
6L4EP4ZRWWYLT55PD5KTTJON5J2JB5VV5MWNHF5VPZQZ5BKEYZ4QC
T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
FMKQARDH6JZ7DUTPPQ6I3LLNQAFGXS36XJCSROUJMEIYQYJDVITQC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
74LQ7JXVLAFSHLI7LCBKFX47CNTYSKGUQSXNX5FCIUIGCC2JTR3QC
6LT6USGJOTDMRJGXLAN2NSZXK2GKWEXDKKUV6SVV7ZC6WI6EKMDQC
VXSORUQOM2VZA4CAZDC6KPAY373NQIN3UT7CXQXTRCYXO2WM62DAC
O6SX3NYKNE2YSFLFOXGJQGL7SMVDFQYDQG6OR6MUEPVQKBRI45XQC
M27JU3PI7UXV4S4LTHOCGVASHX2RBXL5ZU4MLFWCQCSMGQC53IAAC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
3CY6KJWHQUZFZGO2C7VVCO32RRHUIMQQQJAE2MUXFF45F7ECRLJQC
F4WAQJD7KLOXHZOTOT6WG26PVIDHYNVS3AV6ZNXGAS7PDR4HBWQAC
6GSGCC5JQJ5NOKX36UHRNOCXNHDBS2A2TDMAR34UBOGWE2DORXIQC
TO43FWKHNIA5MVDOFXYHQODTLBQYEZKX5UIUGID57436UF7G2EXQC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
SBTVKHKZRMVDBYLGQNMZMJXPAYJG43UWBBD7HQJWIPN3BMMHUBJAC
NXIVXEHVXS22UDSQL4KZQ4VHK3XTW7DAGA5LLL3EXY5MHPIUXL7AC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
ZBPS5ZTPF3DVTR5WET4XEFHYXU26CRHU2OHX3YO6PD4MTM2DUXAQC
CK7CT5TUFUL2AQY7FUHB5JI3FC2KSPWUWHXC6VEUJJ7G4OWUQFTAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
BPSH3LUDUTXMK2QZKSMFDTBNDD6HPILMCBLZNMCRLZZQKPS5QOQQC
XKQ2XYVSHYRTEKIYXFLXCPULEEO6IQUSKQHX32UZGNMAMQN2CTMQC
4C6O4H7IO3LDZPBDGRST3QUFKMNQRB4Y6JXUV3NKIJVVPLAA2AWQC
AXB2FZCJPA5YETYDCAEQ7ZS5HBT2KAS4NBVUVWKH5TQJI2O2DMVQC
RWSXCNYUGDSMP2GKN22HROC5Q2GHSAVJJUDRT3Z53WU2DAI4IZOQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
X7MFMKQTNZ2IWBFVGS6WQV7NRNKJ3DWQAW2X7IQMFQQXW24AHPZQC
IVVRQ52VA3MAD25ZMPID3GCRBBFYR54CH33DKXYTRAGUBLTRAZNAC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
OYYZVCE3QHBVJM6IEKK5HTJRG5YOVQNCBRMSJENTHOI2WPJLNCFAC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
C55G5JGGSVWMU7XVEJL6YZZLDXQZGRN7JQOAALS6WIKFPX3L2U6QC
PDOFPXD2X6VI23AHKCGQ5RVDBG74CNP2E3YOHKXLOARHHBXEK3HQC
5B5DP5S6A6LQMKZYVLQAEMHQZWFWYDHPCKQGRNSCNNYIBQYZ6BIQC
SW3RLYFNRT3IJBK6LYKHKP2J2YDU7SXQWAJZX7U6S7ICYW43OMNQC
PJ7HBIWAV3H23LXGZAAD2QYJ7HMOFOIR5ZJ4U2UTHI766LOTRRWQC
YF2GZWXNV6NVFFEBEOYS67JQJQK2IUS5BZMGJW3XQPYIJYHQJCEQC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
// 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();
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&);
};
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);
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);
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() );
}
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;
}
}
// 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;
_player_change_level_reset();
_player_change_level_upstairs(stair_find, destination_override);
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 ))
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:
// 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++;
}
}
// 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--;
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
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)
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);
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--;
}
if (you.level_type == LEVEL_DUNGEON
&& old_branch == BRANCH_VESTIBULE_OF_HELL
&& stair_taken == DNGN_STONE_STAIRS_UP_I)
if (stair_taken == DNGN_EXIT_PANDEMONIUM)
// 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.
// 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();
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&);
};