Lua (Lua code can be embedded with {{ <lua code here> }} constructs) that is run to produce the final map.
Some maps may be broken, this is untested, lots more work needs to be done.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1629 c06c8d41-db1a-0410-9941-cceddc491573
W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC HNXKX6ZDQJV33E7UKZOLBYWJMRZ4QLEMXVXJZNRCTOIG2KVRTIEAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC JQFQX7IWSJ4TYWVUVXAFMCPSAN67PRMNECDQI5WMON2JFMQVVUEQC 34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC WKTZHLOJ65WSK6FR5MF7RWGSMZ22T2D6LHB66FV3IPGXIBLYHHNAC JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC AUYQDKLMOG4FGH2T3LACX4TH632DPKVXBNV5VU6PIVUEWSIO4LQQC RIRJ746W5ESARX4HUEA4JRVAKXXF3WYVXUCFFONPJMMKWHQAGI2AC A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC JR2RAQ523LOWNDYJNK6AZVKI6WVMI622PIV72XWOVZYPXPUKSQWAC 7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC KFM2ARORBIJ6BGX456VFW7EAVRIYBVFUV53JH63GSKNOKVPJWQ2QC SIKFXNXSAMU6IYRGDG6SWP3LOX6SEE7PDFA7RVQAGG2SLWQ72D2QC ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC KFJEFN377VIZ7OH2XCYOGCELNEGO4CIOOP7DNXEMX3LFKIKWXVTAC 5E7K2S4F4QDZC5UH3JVMYQ5SFJIKIATZII4EJL7IOT66ZBJ5GUPQC MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC YE7M665QKDGI7Y5WMERCWJNDZ4FUZ6GRUCK4E6GZH4SWCUM6RWLAC %token <i> NAME DEPTH ORIENT PLACE CHANCE FLAGS MONS ITEM%token <i> ROOT_DEPTH ENTRY_MSG EXIT_MSG%token <i> ROCK_COLOUR FLOOR_COLOUR%token <i> ENCOMPASS FLOAT%token <i> NORTH EAST SOUTH WEST%token <i> NORTHEAST SOUTHEAST SOUTHWEST NORTHWEST%token <i> LEVEL END PVAULT PMINIVAULT MONSTERS ENDMONSTERS
%token <i> NAME DEPTH ORIENT PLACE CHANCE MONS ITEM%token <i> PRELUDE MAIN
defdepth : DEFAULT_DEPTH{ lc_default_depths.clear(); }default_depth_ranges
defdepth : DEFAULT_DEPTH STRING{dgn_reset_default_depth();std::string err = dgn_set_default_depth($2);if (!err.empty())yyerror(make_stringf("Bad default-depth: %s (%s)",$2, err.c_str()).c_str());}
if (lc_map.orient == MAP_FLOAT|| lc_map.is_minivault()){if (lc_map.map.width() > GXM - MAPGEN_BORDER * 2|| lc_map.map.height() > GYM - MAPGEN_BORDER * 2){char buf[300];snprintf(buf, sizeof buf,"%s is too big: %dx%d - max %dx%d",lc_map.is_minivault()? "Minivault" : "Float",lc_map.map.width(), lc_map.map.height(),GXM - MAPGEN_BORDER * 2,GYM - MAPGEN_BORDER * 2);yyerror(buf);}}else{if (lc_map.map.width() > GXM|| lc_map.map.height() > GYM){char buf[300];snprintf(buf, sizeof buf,"Map is too big: %dx%d - max %dx%d",lc_map.map.width(), lc_map.map.height(),GXM, GYM);yyerror(buf);}}if (lc_map.map.height() == 0)yyerror("Must define map.");
std::string err = lc_map.validate();if (!err.empty())yyerror(err.c_str());
main_lua : MAIN main_lua_lines { }main_lua_lines : /* empty */ { }| main_lua_lines main_lua_line { };main_lua_line : LUA_LINE{lc_map.main.add(yylineno, $1);}prelude_lua : PRELUDE prelude_lua_lines { }prelude_lua_lines : /* empty */ { }| prelude_lua_lines prelude_lua_line { };prelude_lua_line : LUA_LINE{lc_map.prelude.add(yylineno, $1);}
std::string err = lc_map.map.add_shuffle($1);if (!err.empty())yyerror(make_stringf("Bad shuffle argument: '%s' (%s)",$1, err.c_str() ).c_str() );
lc_map.main.add(yylineno,make_stringf("shuffle(\"%s\")",quote_lua_string($1).c_str()));
std::string err = lc_map.map.add_subst($1);if (!err.empty())yyerror(make_stringf("Bad SUBST argument: '%s' (%s)",$1, err.c_str() ).c_str() );
lc_map.main.add(yylineno,make_stringf("subst(\"%s\")",quote_lua_string($1).c_str()));
std::string error = lc_map.items.add_item($1);if (error.size()){char errbuf[300];snprintf(errbuf, sizeof errbuf,"Invalid item descriptor: '%s' (%s)",$1, error.c_str());yyerror(errbuf);}if (lc_map.items.size() > 8)yyerror("Too many items specified (max 8)");
lc_map.main.add(yylineno,make_stringf("item(\"%s\")",quote_lua_string($1).c_str()));
std::string err = lc_map.mons.add_mons($1);if (!err.empty()){char buf[300];snprintf(buf, sizeof buf,"bad monster spec '%s' (%s)",$1, err.c_str());yyerror(buf);}if (lc_map.mons.size() > 7)yyerror("Too many monsters specified (max 7)");
lc_map.main.add(yylineno,make_stringf("mons(\"%s\")",quote_lua_string($1).c_str()));
| DEPTH extended_depth_ranges {};default_depth_ranges :ext_range{lc_default_depths.push_back($1);}| default_depth_ranges COMMA ext_range{lc_default_depths.push_back($3);};extended_depth_ranges :ext_range{lc_map.add_depth($1);}| extended_depth_ranges COMMA ext_range{lc_map.add_depth($3);};ext_range : lev_range { $$ = $1; }| NOT lev_range { $$ = $2; $$.deny = true; };lev_range : IDENTIFIER{$$ = set_range($1, 1, 100);}| IDENTIFIER COLON STAR{$$ = set_range($1, 1, 100);}| IDENTIFIER COLON INTEGER DASH INTEGER{$$ = set_range($1, $3, $5);}| IDENTIFIER COLON INTEGER
| DEPTH STRING
$$ = set_range($1, $3, $3);}| INTEGER DASH INTEGER{$$ = set_range("Any", $1, $3);}| INTEGER{$$ = set_range("Any", $1, $1);
lc_map.main.add(yylineno,make_stringf("depth(\"%s\")",quote_lua_string($2).c_str()));
| ORIENT orient_name{lc_map.orient = (map_section_type) $2;};orient_name : ENCOMPASS { $$ = MAP_ENCOMPASS; }| NORTH { $$ = MAP_NORTH; }| EAST { $$ = MAP_EAST; }| SOUTH { $$ = MAP_SOUTH; }| WEST { $$ = MAP_WEST; }| NORTHEAST { $$ = MAP_NORTHEAST; }| SOUTHEAST { $$ = MAP_SOUTHEAST; }| SOUTHWEST { $$ = MAP_SOUTHWEST; }| NORTHWEST { $$ = MAP_NORTHWEST; }| FLOAT { $$ = MAP_FLOAT; };flags : FLAGS flagnames {};flagnames : /* empty */| flagname flagnames
| ORIENT STRING
switch ($1) {case NO_HMIRROR:lc_map.flags &= ~MAPF_MIRROR_HORIZONTAL;break;case NO_VMIRROR:lc_map.flags &= ~MAPF_MIRROR_VERTICAL;break;case NO_ROTATE:lc_map.flags &= ~MAPF_ROTATE;break;}
lc_map.main.add(yylineno,make_stringf("orient(\"%s\")",quote_lua_string($2).c_str()));
BRANCHDEF: return BRANCH;DEFAULT return DEFAULT;DESC: return DESC;BRANCH: return BRANCH;ROOT_DEPTH: return ROOT_DEPTH;FLOOR_COLOUR: return FLOOR_COLOUR;ROCK_COLOUR: return ROCK_COLOUR;LEVEL return LEVEL;END return END;PVAULT: return PVAULT;PMINIVAULT: return PMINIVAULT;ENTRY_MSG: { BEGIN(ARGUMENT); return ENTRY_MSG; }EXIT_MSG: { BEGIN(ARGUMENT); return EXIT_MSG; }MONSTERS return MONSTERS;ENDMONSTERS return ENDMONSTERS;pandemonic return PANDEMONIC;no_hmirror return NO_HMIRROR;no_vmirror return NO_VMIRROR;no_rotate return NO_ROTATE;encompass return ENCOMPASS;north return NORTH;south return SOUTH;east return EAST;west return WEST;northeast return NORTHEAST;northwest return NORTHWEST;southeast return SOUTHEAST;southwest return SOUTHWEST;float return FLOAT;
parse_maps( lc_desfile = datafile_path( "splev.des" ) );parse_maps( lc_desfile = datafile_path( "vaults.des" ) );parse_maps( lc_desfile = datafile_path( "entry.des" ) );parse_maps( lc_desfile = datafile_path( "ebranch.des" ) );
static const char *map_files[] ={"entry.des", "splev.des", "vaults.des", "ebranch.des"};for (unsigned i = 0; i < ARRAYSIZE(map_files); ++i)parse_maps( lc_desfile = datafile_path( map_files[i] ) );
enum map_flags{MAPF_PANDEMONIUM_VAULT = 0x01, // A pandemonium minivault.MAPF_MIRROR_VERTICAL = 0x10, // The map may be mirrored verticallyMAPF_MIRROR_HORIZONTAL = 0x20, // may be mirrored horizontally.MAPF_ROTATE = 0x40 // may be rotated};
level_range level_range::parse(std::string s) throw (std::string){level_range lr;trim_string(s);if (s[0] == '!'){lr.deny = true;s = trimmed_string(s.substr(1));}std::string::size_type cpos = s.find(':');if (cpos == std::string::npos)parse_partial(lr, s);else{std::string branch = trimmed_string(s.substr(0, cpos));std::string depth = trimmed_string(s.substr(cpos + 1));parse_depth_range(depth, &lr.shallowest, &lr.deepest);lr.set(branch, lr.shallowest, lr.deepest);}return (lr);}void level_range::parse_partial(level_range &lr, const std::string &s)throw (std::string){if (isdigit(s[0])){lr.branch = NUM_BRANCHES;parse_depth_range(s, &lr.shallowest, &lr.deepest);}elselr.set(s, 1, 100);}void level_range::parse_depth_range(const std::string &s, int *l, int *h)throw (std::string){if (s == "*"){*l = 1;*h = 100;return;}std::string::size_type hy = s.find('-');if (hy == std::string::npos){*l = *h = atoi(s.c_str());if (!*l)throw std::string("Bad depth: ") + s;}else{*l = atoi(s.substr(0, hy).c_str());std::string tail = s.substr(hy + 1);if (tail.empty())*h = 100;else*h = atoi(tail.c_str());if (!*l || !*h || *l > *h)throw std::string("Bad depth: ") + s;}}
void map_lines::remove_shuffle(const std::string &raw){std::string s = raw;const std::string err = check_shuffle(s);if (err.empty()){const shuffle_spec ss(s);for (int i = 0, size = transforms.size(); i < size; ++i){if (transforms[i]->type() == map_transformer::TT_SHUFFLE){const shuffle_spec *other =dynamic_cast<shuffle_spec*>(transforms[i]);if (ss == *other){delete transforms[i];transforms.erase( transforms.begin() + i );return;}}}}}void map_lines::remove_subst(const std::string &raw){// Parsing subst specs is a pain, so we just let add_subst do the// work, then pop the subst off the end of the vector.if (add_subst(raw).empty()){map_transformer *sub = *transforms.rbegin();subst_spec spec = *dynamic_cast<subst_spec*>(sub);delete sub;transforms.pop_back();for (int i = 0, size = transforms.size(); i < size; ++i){if (transforms[i]->type() == map_transformer::TT_SUBST){subst_spec *cand = dynamic_cast<subst_spec*>(transforms[i]);if (spec == *cand){delete cand;transforms.erase( transforms.begin() + i );return;}}}}}void map_lines::clear_transforms(map_transformer::transform_type tt){if (transforms.empty())return;for (int i = transforms.size() - 1; i >= 0; --i)if (transforms[i]->type() == tt){delete transforms[i];transforms.erase( transforms.begin() + i );}}void map_lines::clear_shuffles(){clear_transforms(map_transformer::TT_SHUFFLE);}void map_lines::clear_substs(){clear_transforms(map_transformer::TT_SUBST);}
}std::vector<std::string> map_lines::get_shuffle_strings() const{std::vector<std::string> shuffles;for (int i = 0, size = transforms.size(); i < size; ++i)if (transforms[i]->type() == map_transformer::TT_SHUFFLE)shuffles.push_back( transforms[i]->describe() );return (shuffles);}std::vector<std::string> map_lines::get_subst_strings() const{std::vector<std::string> substs;for (int i = 0, size = transforms.size(); i < size; ++i)if (transforms[i]->type() == map_transformer::TT_SUBST)substs.push_back( transforms[i]->describe() );return (substs);
void map_def::set_file(const std::string &s){prelude.set_file(s);main.set_file(s);}void map_def::run_strip_prelude(){run_lua(false);prelude.clear();}void map_def::strip_lua(){prelude.clear();main.clear();}std::string map_def::run_lua(bool run_main){dlua.callfn("dgn_set_map", "m", this);int err = prelude.load(&dlua);if (err == -1000)lua_pushnil(dlua);else if (err)return (prelude.orig_error());if (!run_main)lua_pushnil(dlua);else{err = main.load(&dlua);if (err == -1000)lua_pushnil(dlua);else if (err)return (main.orig_error());}if (!dlua.callfn("dgn_run_map", 2, 0))return (dlua.error);// Clear the map setting.dlua.callfn("dgn_set_map", 0, 0);return (dlua.error);}std::string map_def::validate(){std::string err = run_lua(true);if (!err.empty())return (err);if (orient == MAP_FLOAT || is_minivault()){if (map.width() > GXM - MAPGEN_BORDER * 2|| map.height() > GYM - MAPGEN_BORDER * 2){return make_stringf("%s is too big: %dx%d - max %dx%d",is_minivault()? "Minivault" : "Float",map.width(), map.height(),GXM - MAPGEN_BORDER * 2,GYM - MAPGEN_BORDER * 2);}}else{if (map.width() > GXM|| map.height() > GYM){return make_stringf("Map is too big: %dx%d - max %dx%d",map.width(), map.height(),GXM, GYM);}}if (map.height() == 0)return ("Must define map.");return ("");}
}std::string item_list::set_item(int index, const std::string &spec){error.clear();if (index < 0)return (error = make_stringf("Index %d out of range", index));item_spec_slot sp = parse_item_spec(spec);if (error.empty()){if (index >= (int) items.size()){items.reserve(index + 1);items.resize(index + 1, item_spec_slot());}items.push_back(sp);}return (error);
}map_transformer::transform_type subst_spec::type() const{return (TT_SUBST);}std::string subst_spec::describe() const{std::string subst(1, foo);subst += std::string(" ") + (fix? ':' : '=');for (int i = 0, size = repl.size(); i < size; ++i){const glyph_weighted_replacement_t &gly = repl[i];subst += " ";subst += static_cast<char>(gly.first);if (gly.second != 10)subst += make_stringf(":%d", gly.second);}return (subst);}bool subst_spec::operator == (const subst_spec &other) const{if (foo != other.foo || fix != other.fix)return (false);if (repl.size() != other.repl.size())return (false);for (int i = 0, size = repl.size(); i < size; ++i){if (repl[i] != other.repl[i])return (false);}return (true);
-------------------------------------------------------------------------------- dungeon.lua:-- Dungeoneering functions.-------------------------------------------------------------------------------- Given an object and a table (dgn), returns a table with functions-- that translate into method calls on the object. This table is-- suitable for setfenv() on a function that expects to directly-- address a map object.function dgn_map_meta_wrap(obj, tab)local meta = { }for fn, val in pairs(tab) dometa[fn] = function (...)return val(obj, ...)endendmeta.wrapped_instance = objlocal meta_meta = { __index = _G }setmetatable(meta, meta_meta)return metaendfunction dgn_set_map(map)g_dgn_curr_map = mapendfunction dgn_run_map(prelude, main)if prelude or main thenenv = dgn_map_meta_wrap(g_dgn_curr_map, dgn)if prelude thensetfenv(prelude, env)()endif main thensetfenv(main, env)()end-- Return the environment in case we want to chain further-- calls.return envendend
#define LUAWRAP(name, wrapexpr) \static int name(lua_State *ls) \{ \wrapexpr; \return (0); \}#define PLUARET(type, val) \lua_push##type(ls, val); \return (1);#define LUARET1(name, type, val) \static int name(lua_State *ls) \{ \lua_push##type(ls, val); \return (1); \}
#define LUARET2(name, type, val1, val2) \static int name(lua_State *ls) \{ \lua_push##type(ls, val1); \lua_push##type(ls, val2); \return (2); \}template <class T>inline static T *util_get_userdata(lua_State *ls, int ndx){return (lua_islightuserdata(ls, ndx))?static_cast<T *>( lua_touserdata(ls, ndx) ): NULL;}template <class T>inline static T *clua_get_userdata(lua_State *ls, const char *mt){return static_cast<T*>( luaL_checkudata( ls, 1, mt ) );}std::string quote_lua_string(const std::string &s);#define MAP_METATABLE "dgn.mtmap"
extern void lua_open_kills(lua_State *ls);void lua_open_you(lua_State *ls);void lua_open_item(lua_State *ls);void lua_open_food(lua_State *ls);void lua_open_crawl(lua_State *ls);void lua_open_file(lua_State *ls);void lua_open_options(lua_State *ls);void lua_open_monsters(lua_State *ls);void lua_open_globals(lua_State *ls);
extern void luaopen_kills(lua_State *ls);
lua_open_kills(_state);lua_open_you(_state);lua_open_item(_state);lua_open_food(_state);lua_open_crawl(_state);lua_open_file(_state);lua_open_options(_state);lua_open_monsters(_state);
luaopen_kills(_state);luaopen_you(_state);luaopen_item(_state);luaopen_food(_state);luaopen_crawl(_state);luaopen_file(_state);luaopen_options(_state);luaopen_monsters(_state);
#define LUAWRAP(name, wrapexpr) \static int name(lua_State *ls) \{ \wrapexpr; \return (0); \}#define LUARET1(name, type, val) \static int name(lua_State *ls) \{ \lua_push##type(ls, val); \return (1); \}#define LUARET2(name, type, val1, val2) \static int name(lua_State *ls) \{ \lua_push##type(ls, val1); \lua_push##type(ls, val2); \return (2); \}template <class T> T *util_get_userdata(lua_State *ls, int ndx){return (lua_islightuserdata(ls, ndx))?static_cast<T *>( lua_touserdata(ls, ndx) ): NULL;}template <class T> T *clua_get_userdata(lua_State *ls, const char *mt){return static_cast<T*>( luaL_checkudata( ls, 1, mt ) );}
std::string quote_lua_string(const std::string &s){return replace_all_of(replace_all_of(s, "\\", "\\\\"), "\"", "\\\"");}