summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-06-24 16:27:58 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-06-24 16:27:58 +0000
commit93f5fdd067279f953af9440fa7c712985e6ecf34 (patch)
tree177f36448c1dbeedf772d627e654714c704d6b22 /crawl-ref
parentc633d5d2b956aab18819d51236982db57ee17134 (diff)
downloadcrawl-ref-93f5fdd067279f953af9440fa7c712985e6ecf34.tar.gz
crawl-ref-93f5fdd067279f953af9440fa7c712985e6ecf34.zip
Implemented .des file caching (speeds startup a fair bit): .des files are
parsed only once (unless they're modified again). Crawl also keeps only map stubs in memory (name, place, orient, tags) and loads the map body only when it is actually selected by the dungeon builder. This probably breaks the Windows build, will be fixed soonish. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1637 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/acr.cc2
-rw-r--r--crawl-ref/source/clua.cc3
-rw-r--r--crawl-ref/source/database.cc23
-rw-r--r--crawl-ref/source/files.cc86
-rw-r--r--crawl-ref/source/files.h28
-rw-r--r--crawl-ref/source/luadgn.cc12
-rw-r--r--crawl-ref/source/luadgn.h1
-rw-r--r--crawl-ref/source/makefile.mgw2
-rw-r--r--crawl-ref/source/makefile.unix3
-rw-r--r--crawl-ref/source/mapdef.cc109
-rw-r--r--crawl-ref/source/mapdef.h21
-rw-r--r--crawl-ref/source/maps.cc193
-rw-r--r--crawl-ref/source/maps.h10
-rw-r--r--crawl-ref/source/player.cc2
-rw-r--r--crawl-ref/source/util/levcomp.cc19
-rw-r--r--crawl-ref/source/util/levcomp.h12
-rw-r--r--crawl-ref/source/util/levcomp.ypp5
17 files changed, 434 insertions, 97 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 35f57a4f3c..e0cc7e3538 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -3070,6 +3070,8 @@ static bool initialise(void)
strncpy(you.your_name, yname.c_str(), kNameLen);
you.your_name[kNameLen - 1] = 0;
+ run_map_preludes();
+
// In case Lua changed the character set.
init_char_table(Options.char_set);
init_feature_table();
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 15c0bbbfc4..6f891072df 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -1522,6 +1522,9 @@ void luaopen_food(lua_State *ls)
static int crawl_mpr(lua_State *ls)
{
+ if (!crawl_state.io_inited)
+ return (0);
+
const char *message = luaL_checkstring(ls, 1);
if (!message)
return (0);
diff --git a/crawl-ref/source/database.cc b/crawl-ref/source/database.cc
index ed4994cbfb..66e7ad3a69 100644
--- a/crawl-ref/source/database.cc
+++ b/crawl-ref/source/database.cc
@@ -31,29 +31,6 @@ DBM *descriptionDB;
static void generate_description_db();
-time_t file_modtime(const std::string &file)
-{
- struct stat filestat;
- if (stat(file.c_str(), &filestat))
- return (0);
-
- return (filestat.st_mtime);
-}
-
-// Returns true if file a is newer than file b.
-bool is_newer(const std::string &a, const std::string &b)
-{
- return (file_modtime(a) > file_modtime(b));
-}
-
-void check_newer(const std::string &target,
- const std::string &dependency,
- void (*action)())
-{
- if (is_newer(dependency, target))
- action();
-}
-
void databaseSystemInit()
{
if (!descriptionDB)
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 114a3f23a2..f16cea7262 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -226,6 +226,50 @@ std::string get_parent_directory(const std::string &filename)
return ("");
}
+std::string get_base_filename(const std::string &filename)
+{
+ std::string::size_type pos = filename.rfind(FILE_SEPARATOR);
+ if (pos != std::string::npos)
+ return filename.substr(pos + 1);
+#ifdef ALT_FILE_SEPARATOR
+ pos = filename.rfind(ALT_FILE_SEPARATOR);
+ if (pos != std::string::npos)
+ return filename.substr(pos + 1);
+#endif
+ return (filename);
+}
+
+std::string change_file_extension(const std::string &filename,
+ const std::string &ext)
+{
+ const std::string::size_type pos = filename.rfind('.');
+ return ((pos == std::string::npos? filename : filename.substr(0, pos))
+ + ext);
+}
+
+time_t file_modtime(const std::string &file)
+{
+ struct stat filestat;
+ if (stat(file.c_str(), &filestat))
+ return (0);
+
+ return (filestat.st_mtime);
+}
+
+// Returns true if file a is newer than file b.
+bool is_newer(const std::string &a, const std::string &b)
+{
+ return (file_modtime(a) > file_modtime(b));
+}
+
+void check_newer(const std::string &target,
+ const std::string &dependency,
+ void (*action)())
+{
+ if (is_newer(dependency, target))
+ action();
+}
+
static bool file_exists(const std::string &name)
{
FILE *f = fopen(name.c_str(), "r");
@@ -351,13 +395,12 @@ std::string datafile_path(std::string basename,
return ("");
}
-bool check_dir(const std::string &whatdir, std::string &dir)
+bool check_dir(const std::string &whatdir, std::string &dir, bool silent)
{
if (dir.empty())
return (true);
- std::string sep = " ";
- sep[0] = FILE_SEPARATOR;
+ const std::string sep(1, FILE_SEPARATOR);
dir = replace_all_of(dir, "/", sep);
dir = replace_all_of(dir, "\\", sep);
@@ -368,9 +411,10 @@ bool check_dir(const std::string &whatdir, std::string &dir)
if (!dir_exists(dir) && !create_dirs(dir))
{
- fprintf(stderr, "%s \"%s\" does not exist "
- "and I can't create it.\n",
- whatdir.c_str(), dir.c_str());
+ if (!silent)
+ fprintf(stderr, "%s \"%s\" does not exist "
+ "and I can't create it.\n",
+ whatdir.c_str(), dir.c_str());
return (false);
}
@@ -378,10 +422,17 @@ bool check_dir(const std::string &whatdir, std::string &dir)
}
// Given a simple (relative) name of a save file, returns the full path of
-// the file in the Crawl saves directory.
+// the file in the Crawl saves directory. You can use path segments in
+// shortpath (separated by /) and get_savedir_path will canonicalise them
+// to the platform's native file separator.
std::string get_savedir_path(const std::string &shortpath)
{
- return (Options.save_dir + shortpath);
+ const std::string file = Options.save_dir + shortpath;
+#if FILE_SEPARATOR != '/'
+ return (replace_all(file, "/", std::string(1, FILE_SEPARATOR)));
+#else
+ return (file);
+#endif
}
/*
@@ -1090,7 +1141,7 @@ void save_level(int level_saved, level_area_type old_ltype,
} // end save_level()
-void save_game(bool leave_game)
+void save_game(bool leave_game, const char *farewellmsg)
{
unwind_bool saving_game(crawl_state.saving_game, true);
@@ -1181,11 +1232,11 @@ void save_game(bool leave_game)
DO_CHMOD_PRIVATE ( (basename + PACKAGE_SUFFIX).c_str() );
#endif
- cprintf( "See you soon, %s!" EOL , you.your_name );
#ifdef DGL_WHEREIS
whereis_record("saved");
#endif
- end(0);
+ end(0, false, farewellmsg? "%s" : "See you soon, %s!",
+ farewellmsg? farewellmsg : you.your_name);
} // end save_game()
// Saves the game without exiting.
@@ -1543,9 +1594,6 @@ void generate_random_demon()
menv[rdem].pandemon_init();
} // end generate_random_demon()
-// Largest string we'll save
-#define STR_CAP 1000
-
void writeShort(FILE *file, short s)
{
char data[2];
@@ -1586,17 +1634,19 @@ void writeString(FILE* file, const std::string &s, int cap)
write2(file, s.c_str(), length);
}
-std::string readString(FILE *file)
+std::string readString(FILE *file, int cap)
{
short length = readShort(file);
if (length > 0)
{
- if (length <= STR_CAP)
+ if (length <= cap)
{
- char buf[STR_CAP + 1];
+ char *buf = new char[length + 1];
read2(file, buf, length);
buf[length] = 0;
- return (buf);
+ const std::string s = buf;
+ delete [] buf;
+ return (s);
}
end(1, false, "String too long: %d bytes\n", length);
diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h
index c32cc52561..c210a1d534 100644
--- a/crawl-ref/source/files.h
+++ b/crawl-ref/source/files.h
@@ -30,7 +30,8 @@ std::string datafile_path(std::string basename,
bool croak_on_fail = true,
bool test_base_path = false);
std::string get_parent_directory(const std::string &filename);
-bool check_dir(const std::string &what, std::string &dir);
+std::string get_base_filename(const std::string &filename);
+bool check_dir(const std::string &what, std::string &dir, bool silent = false);
bool travel_load_map( branch_type branch, int absdepth );
@@ -42,8 +43,15 @@ std::string get_savedir_filename(const std::string &pre,
const std::string &ext,
bool suppress_uid = false);
std::string get_savedir_path(const std::string &shortpath);
-
std::string get_prefs_filename();
+std::string change_file_extension(const std::string &file,
+ const std::string &ext);
+
+time_t file_modtime(const std::string &file);
+bool is_newer(const std::string &a, const std::string &b);
+void check_newer(const std::string &target,
+ const std::string &dependency,
+ void (*action)());
bool load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth,
int old_level, branch_type where_were_you2 );
@@ -52,7 +60,7 @@ bool load( int stair_taken, load_mode_type load_mode, bool was_a_labyrinth,
/* ***********************************************************************
* called from: acr - misc
* *********************************************************************** */
-void save_game(bool leave_game);
+void save_game(bool leave_game, const char *bye = NULL);
// Save game without exiting (used when changing levels).
void save_game_state();
@@ -77,20 +85,16 @@ void save_ghost( bool force = false );
std::string make_filename( const char *prefix, int level, branch_type branch,
level_area_type lt, bool isGhost );
-void writeShort(FILE *file, short s);
+// Default cap on strings marshalled.
+#define STR_CAP 1000
+void writeShort(FILE *file, short s);
short readShort(FILE *file);
-
void writeByte(FILE *file, unsigned char byte);
-
unsigned char readByte(FILE *file);
-
-void writeString(FILE* file, const std::string &s, int cap = 200);
-
-std::string readString(FILE *file);
-
+void writeString(FILE* file, const std::string &s, int cap = STR_CAP);
+std::string readString(FILE *file, int cap = STR_CAP);
void writeLong(FILE* file, long num);
-
long readLong(FILE *file);
FILE *lk_open(const char *mode, const std::string &file);
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 1857cdf4d0..2381dcfa97 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -70,6 +70,11 @@ void dlua_chunk::add(int line, const std::string &s)
last = line;
}
+void dlua_chunk::set_chunk(const std::string &s)
+{
+ chunk = s;
+}
+
int dlua_chunk::check_op(CLua *interp, int err)
{
error = interp->error;
@@ -472,9 +477,16 @@ static int dgn_kitem(lua_State *ls)
return (0);
}
+static int dgn_name(lua_State *ls)
+{
+ MAP(ls, 1, map);
+ PLUARET(string, map->name.c_str());
+}
+
static const struct luaL_reg dgn_lib[] =
{
{ "default_depth", dgn_default_depth },
+ { "name", dgn_name },
{ "depth", dgn_depth },
{ "place", dgn_place },
{ "tags", dgn_tags },
diff --git a/crawl-ref/source/luadgn.h b/crawl-ref/source/luadgn.h
index ca778c4b19..199939dad2 100644
--- a/crawl-ref/source/luadgn.h
+++ b/crawl-ref/source/luadgn.h
@@ -30,6 +30,7 @@ public:
dlua_chunk();
void clear();
void add(int line, const std::string &line);
+ void set_chunk(const std::string &s);
int load(CLua *interp);
int load_call(CLua *interp, const char *function);
diff --git a/crawl-ref/source/makefile.mgw b/crawl-ref/source/makefile.mgw
index a9c3fbe381..58a48d662d 100644
--- a/crawl-ref/source/makefile.mgw
+++ b/crawl-ref/source/makefile.mgw
@@ -74,7 +74,7 @@ DOYACC :=
endif
# Do the levcomp stuff first because that's the most likely to fail.
-OBJECTS := levcomp.tab.o levcomp.lex.o levcomp.o \
+OBJECTS := levcomp.tab.o levcomp.lex.o \
$(OBJECTS)
OBJECTS := $(foreach file,$(OBJECTS),$(OPATH)/$(file))
diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix
index 9a6ed5998f..7563a43c4c 100644
--- a/crawl-ref/source/makefile.unix
+++ b/crawl-ref/source/makefile.unix
@@ -130,8 +130,7 @@ UTIL = util/
YTABC := levcomp.tab.c
YTABH := levcomp.tab.h
-OBJECTS := $(UTIL)levcomp.tab.o $(UTIL)levcomp.lex.o $(UTIL)levcomp.o \
- $(OBJECTS)
+OBJECTS := $(UTIL)levcomp.tab.o $(UTIL)levcomp.lex.o $(OBJECTS)
ifeq ($(LEX),)
DOYACC :=
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 5e4cf0c5e2..8a4c40ff39 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -7,10 +7,12 @@
#include "branch.h"
#include "describe.h"
#include "direct.h"
+#include "files.h"
#include "invent.h"
#include "items.h"
#include "libutil.h"
#include "mapdef.h"
+#include "maps.h"
#include "misc.h"
#include "monplace.h"
#include "mon-util.h"
@@ -136,6 +138,22 @@ level_range::level_range(const raw_range &r)
{
}
+void level_range::write(FILE *outf) const
+{
+ writeShort(outf, branch);
+ writeShort(outf, shallowest);
+ writeShort(outf, deepest);
+ writeByte(outf, deny);
+}
+
+void level_range::read(FILE *inf)
+{
+ branch = static_cast<branch_type>( readShort(inf) );
+ shallowest = readShort(inf);
+ deepest = readShort(inf);
+ deny = readByte(inf);
+}
+
std::string level_range::str_depth_range() const
{
if (shallowest == -1)
@@ -826,10 +844,97 @@ void map_def::reinit()
mons.clear();
}
+void map_def::write_full(FILE *outf)
+{
+ cache_offset = ftell(outf);
+ writeShort(outf, 0x1eaf); // Level indicator.
+ writeString(outf, name);
+ writeString(outf, prelude.lua_string(), LUA_CHUNK_MAX_SIZE);
+ writeString(outf, main.lua_string(), LUA_CHUNK_MAX_SIZE);
+}
+
+void map_def::read_full(FILE *inf)
+{
+ // There's a potential race-condition here:
+ // - If someone modifies a .des file while there are games in progress,
+ // - a new Crawl process will overwrite the .dsc.
+ // - older Crawl processes trying to reading the new .dsc will be hosed.
+ // We could try to recover from the condition (by locking and
+ // reloading the index), but it's easier to save the game at this
+ // point and let the player reload.
+
+ if (readShort(inf) != 0x1eaf || readString(inf) != name)
+ save_game(true,
+ make_stringf("Level file cache for %s is out-of-sync! "
+ "Please reload your game.",
+ file.c_str()).c_str());
+
+ prelude.set_chunk(readString(inf, LUA_CHUNK_MAX_SIZE));
+ main.set_chunk(readString(inf, LUA_CHUNK_MAX_SIZE));
+}
+
+void map_def::load()
+{
+ if (!index_only)
+ return;
+
+ const std::string loadfile = get_descache_path(file, ".dsc");
+ FILE *inf = fopen(loadfile.c_str(), "r");
+ fseek(inf, cache_offset, SEEK_SET);
+ read_full(inf);
+ fclose(inf);
+
+ index_only = false;
+}
+
+void map_def::write_index(FILE *outf) const
+{
+ if (!cache_offset)
+ end(1, false, "Map %s: can't write index - cache offset not set!",
+ name.c_str());
+ writeString(outf, name);
+ writeShort(outf, orient);
+ writeLong(outf, chance);
+ writeLong(outf, cache_offset);
+ writeString(outf, tags);
+ writeString(outf, place);
+ write_depth_ranges(outf);
+ writeString(outf, prelude.lua_string(), LUA_CHUNK_MAX_SIZE);
+}
+
+void map_def::read_index(FILE *inf)
+{
+ name = readString(inf);
+ orient = static_cast<map_section_type>( readShort(inf) );
+ chance = readLong(inf);
+ cache_offset = readLong(inf);
+ tags = readString(inf);
+ place = readString(inf);
+ read_depth_ranges(inf);
+ prelude.set_chunk(readString(inf, LUA_CHUNK_MAX_SIZE));
+ index_only = true;
+}
+
+void map_def::write_depth_ranges(FILE *outf) const
+{
+ writeShort(outf, depths.size());
+ for (int i = 0, size = depths.size(); i < size; ++i)
+ depths[i].write(outf);
+}
+
+void map_def::read_depth_ranges(FILE *inf)
+{
+ depths.clear();
+ const int nranges = readShort(inf);
+ for (int i = 0; i < nranges; ++i)
+ depths[i].read(inf);
+}
+
void map_def::set_file(const std::string &s)
{
prelude.set_file(s);
main.set_file(s);
+ file = get_base_filename(s);
}
void map_def::run_strip_prelude()
@@ -838,10 +943,10 @@ void map_def::run_strip_prelude()
prelude.clear();
}
-void map_def::strip_lua()
+void map_def::strip_main()
{
- prelude.clear();
main.clear();
+ index_only = true;
}
std::string map_def::run_lua(bool run_main)
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index bf6251597e..94bad0bc8f 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include <cstdio>
#include "luadgn.h"
#include "enum.h"
@@ -41,6 +42,9 @@ public:
bool matches(const level_id &) const;
bool matches(int depth) const;
+ void write(FILE *) const;
+ void read(FILE *);
+
bool valid() const;
int span() const;
@@ -390,6 +394,9 @@ typedef std::map<int, keyed_mapspec> keyed_specs;
typedef std::vector<level_range> depth_ranges;
+// Lua chunks cannot exceed 512K. Which is plenty!
+const int LUA_CHUNK_MAX_SIZE = 512 * 1024;
+
class map_def
{
public:
@@ -413,16 +420,25 @@ private:
// This map has been loaded from an index, and not fully realised.
bool index_only;
long cache_offset;
+ std::string file;
public:
map_def();
void init();
void reinit();
+ void load();
+
+ void write_index(FILE *) const;
+ void write_full(FILE *);
+
+ void read_index(FILE *);
+ void read_full(FILE *);
+
void set_file(const std::string &s);
std::string run_lua(bool skip_main);
void run_strip_prelude();
- void strip_lua();
+ void strip_main();
std::string validate();
@@ -463,6 +479,9 @@ public:
std::vector<std::string> get_subst_strings() const;
private:
+ void write_depth_ranges(FILE *) const;
+ void read_depth_ranges(FILE *);
+
std::string add_key_field(
const std::string &s,
std::string (keyed_mapspec::*set_field)(
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index 97a2eec5d8..3e27840dd3 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -27,9 +27,7 @@
#include "misc.h"
#include "stuff.h"
-#include "levcomp.h"
-
-static int write_vault(const map_def &mdef, map_type mt,
+static int write_vault(map_def &mdef, map_type mt,
vault_placement &,
std::vector<vault_placement> *);
static int apply_vault_definition(
@@ -80,10 +78,12 @@ int vault_main(
return write_vault( vdefs[which_vault], vgrid, place, avoid );
} // end vault_main()
-static int write_vault(const map_def &mdef, map_type map,
+static int write_vault(map_def &mdef, map_type map,
vault_placement &place,
std::vector<vault_placement> *avoid)
{
+ mdef.load();
+
// Copy the map so we can monkey with it.
place.map = mdef;
@@ -354,8 +354,176 @@ const map_def *map_by_index(int index)
/////////////////////////////////////////////////////////////////////////////
// Reading maps from .des files.
+dlua_chunk lc_file_prelude;
+std::string lc_desfile;
+map_def lc_map;
+level_range lc_range;
+depth_ranges lc_default_depths;
+
+std::set<std::string> map_files_read;
+
+extern int yylineno;
+
+void reset_map_parser()
+{
+ lc_map.init();
+ lc_range.reset();
+ lc_default_depths.clear();
+ lc_file_prelude.clear();
+
+ yylineno = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+static bool checked_des_index_dir = false;
+
+#define DESCACHE_VER 1000
+
+static void check_des_index_dir()
+{
+ if (checked_des_index_dir)
+ return;
+
+ std::string desdir = get_savedir_path("des");
+ if (!check_dir("Data file cache", desdir, true))
+ end(1, true, "Can't create data file cache: %s", desdir.c_str());
+
+ checked_des_index_dir = true;
+}
+
+std::string get_descache_path(const std::string &file,
+ const std::string &ext)
+{
+ const std::string basename =
+ change_file_extension(get_base_filename(file), ext);
+ return get_savedir_path("des/" + basename);
+}
+
+static bool verify_file_version(const std::string &file)
+{
+ FILE *inf = fopen(file.c_str(), "rb");
+ if (!inf)
+ return (false);
+
+ const long ver = readLong(inf);
+ fclose(inf);
+
+ return (ver == DESCACHE_VER);
+}
+
+static bool verify_map_index(const std::string &base)
+{
+ return verify_file_version(base + ".idx");
+}
+
+static bool verify_map_full(const std::string &base)
+{
+ return verify_file_version(base + ".dsc");
+}
+
+static bool load_map_index(const std::string &base)
+{
+ FILE *inf = fopen((base + ".idx").c_str(), "rb");
+ // Discard version (it's been checked by verify_map_index).
+ readLong(inf);
+ const int nmaps = readShort(inf);
+ const int nexist = vdefs.size();
+ vdefs.resize( nexist + nmaps, map_def() );
+ for (int i = 0; i < nmaps; ++i)
+ {
+ vdefs[nexist + i].read_index(inf);
+ vdefs[nexist + i].set_file(base);
+ }
+ fclose(inf);
+
+ return (true);
+}
+
+static bool load_map_cache(const std::string &filename)
+{
+ check_des_index_dir();
+ const std::string descache_base = get_descache_path(filename, "");
+
+ file_lock deslock(descache_base + ".lk", "rb", false);
+
+ if (is_newer(filename, descache_base + ".idx")
+ || is_newer(filename, descache_base + ".dsc"))
+ return (false);
+
+ if (!verify_map_index(descache_base) || !verify_map_full(descache_base))
+ return (false);
+
+ return load_map_index(descache_base);
+}
+
+static void write_map_prelude(const std::string &filebase)
+{
+ const std::string luafile = filebase + ".lua";
+ if (lc_file_prelude.empty())
+ {
+ unlink(luafile.c_str());
+ return;
+ }
+
+ FILE *outf = fopen(luafile.c_str(), "w");
+ if (!outf)
+ end(1, true, "Unable to open %s for writing", luafile.c_str());
+ fprintf(outf, "%s", lc_file_prelude.lua_string().c_str());
+ fclose(outf);
+}
+
+static void write_map_full(const std::string &filebase, size_t vs, size_t ve)
+{
+ const std::string cfile = filebase + ".dsc";
+ FILE *outf = fopen(cfile.c_str(), "wb");
+ if (!outf)
+ end(1, true, "Unable to open %s for writing", cfile.c_str());
+
+ writeLong(outf, DESCACHE_VER);
+ for (size_t i = vs; i < ve; ++i)
+ vdefs[i].write_full(outf);
+ fclose(outf);
+}
+
+static void write_map_index(const std::string &filebase, size_t vs, size_t ve)
+{
+ const std::string cfile = filebase + ".idx";
+ FILE *outf = fopen(cfile.c_str(), "wb");
+ if (!outf)
+ end(1, true, "Unable to open %s for writing", cfile.c_str());
+
+ writeLong(outf, DESCACHE_VER);
+ writeShort(outf, ve > vs? ve - vs : 0);
+ for (size_t i = vs; i < ve; ++i)
+ vdefs[i].write_index(outf);
+ fclose(outf);
+}
+
+static void write_map_cache(const std::string &filename, size_t vs, size_t ve)
+{
+ check_des_index_dir();
+
+ const std::string descache_base = get_descache_path(filename, "");
+
+ file_lock deslock(descache_base + ".lk", "wb");
+
+ write_map_prelude(descache_base);
+ write_map_full(descache_base, vs, ve);
+ write_map_index(descache_base, vs, ve);
+}
+
static void parse_maps(const std::string &s)
{
+ const std::string base = get_base_filename(s);
+ if (map_files_read.find(base) != map_files_read.end())
+ end(1, false, "Map file %s has already been read.", base.c_str());
+
+ map_files_read.insert(base);
+
+ if (load_map_cache(s))
+ return;
+
FILE *dat = fopen(s.c_str(), "r");
if (!dat)
end(1, true, "Failed to open %s for reading", s.c_str());
@@ -366,8 +534,11 @@ static void parse_maps(const std::string &s)
extern FILE *yyin;
yyin = dat;
+ size_t file_start = vdefs.size();
yyparse();
fclose(dat);
+
+ write_map_cache(s, file_start, vdefs.size());
}
void read_maps()
@@ -397,3 +568,17 @@ void add_parsed_map( const map_def &md )
map.fixup();
vdefs.push_back( map );
}
+
+void run_map_preludes()
+{
+ for (int i = 0, size = vdefs.size(); i < size; ++i)
+ {
+ if (!vdefs[i].prelude.empty())
+ {
+ std::string err = vdefs[i].run_lua(true);
+ if (!err.empty())
+ mprf(MSGCH_WARN, "Lua error (map %s): %s",
+ vdefs[i].name.c_str(), err.c_str());
+ }
+ }
+}
diff --git a/crawl-ref/source/maps.h b/crawl-ref/source/maps.h
index 6b3ab76089..8274a957e9 100644
--- a/crawl-ref/source/maps.h
+++ b/crawl-ref/source/maps.h
@@ -47,5 +47,15 @@ int random_map_for_tag(const std::string &tag, bool want_minivault,
void add_parsed_map(const map_def &md);
void read_maps();
+void run_map_preludes();
+void reset_map_parser();
+std::string get_descache_path(const std::string &file,
+ const std::string &ext);
+
+extern dlua_chunk map_file_prelude;
+extern std::string lc_desfile;
+extern map_def lc_map;
+extern level_range lc_range;
+extern depth_ranges lc_default_depths;
#endif
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 5e15851978..e2dfda3b8f 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -5025,7 +5025,7 @@ int player::shield_bonus() const
// Condensation shield is guided by the mind.
stat = intel / 2;
- return random2(player_shield_class())
+ return random2(shield_class)
+ (random2(stat) / 4)
+ (random2(skill_bump(SK_SHIELDS)) / 4)
- 1;
diff --git a/crawl-ref/source/util/levcomp.cc b/crawl-ref/source/util/levcomp.cc
deleted file mode 100644
index af92a23bb6..0000000000
--- a/crawl-ref/source/util/levcomp.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "AppHdr.h"
-#include "levcomp.h"
-#include <vector>
-
-std::string lc_desfile;
-map_def lc_map;
-level_range lc_range;
-depth_ranges lc_default_depths;
-
-extern int yylineno;
-
-void reset_map_parser()
-{
- lc_map.init();
- lc_range.reset();
- lc_default_depths.clear();
-
- yylineno = 1;
-}
diff --git a/crawl-ref/source/util/levcomp.h b/crawl-ref/source/util/levcomp.h
deleted file mode 100644
index c3bf3a73ea..0000000000
--- a/crawl-ref/source/util/levcomp.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <cstdio>
-#include <string>
-#include <vector>
-#include "mapdef.h"
-#include "maps.h"
-
-extern map_def lc_map;
-extern level_range lc_range;
-extern depth_ranges lc_default_depths;
-extern std::string lc_desfile;
-
-void reset_map_parser();
diff --git a/crawl-ref/source/util/levcomp.ypp b/crawl-ref/source/util/levcomp.ypp
index 757fc02504..bedd60c7ba 100644
--- a/crawl-ref/source/util/levcomp.ypp
+++ b/crawl-ref/source/util/levcomp.ypp
@@ -3,9 +3,9 @@
#include "AppHdr.h"
#include "clua.h"
#include "libutil.h"
-#include "levcomp.h"
#include "luadgn.h"
#include "mapdef.h"
+#include "maps.h"
#include "stuff.h"
#include <map>
@@ -106,7 +106,8 @@ level : name metalines map_def metalines
if (!lc_map.has_depth() && !lc_default_depths.empty())
lc_map.add_depths(lc_default_depths.begin(),
lc_default_depths.end());
- add_parsed_map( lc_map );
+ lc_map.set_file(lc_desfile);
+ add_parsed_map(lc_map);
}
;