KFEAT: feature names are now as in the dungeon_feature_type enum.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1930 c06c8d41-db1a-0410-9941-cceddc491573
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC QQJQXDH2ABPJREQBK3ITJYPX3V3VQNC47UIYQGBSPBMR5CHJ56UQC ITQ2EXDFLN3EHCURKYHZYVWFACD4KW7NA6CMHNKGWTDKHCHQAE6AC AYYQVALBAAKFK5U52WGHWE2N7LCVZM3BGRADPVJQWOFLS2TXK6QAC RDIHBEN2QCXK7AESR3GT7A7D3A2W3AXR5GTYEOJ2AA75ONXFQQTQC QIDA6PWWBPR6IJOXFCSPCGWV45PVRZ4TPWSL2TDATNVTYLDMVESQC AFE345BJ7IX2YYYX3I5I6RYLXNWJCFE4WMH6F5JMIR6X7WUP75CAC F4WAQJD7KLOXHZOTOT6WG26PVIDHYNVS3AV6ZNXGAS7PDR4HBWQAC NDTQUANX3GZ6HZP5FONYNJUYPD3R2P6SGRC3ICKJ7ZWF3KO23LTAC WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC TAHSTXR7ROOMDFUSBUU4ZAIEWQLAS5CIRCTARLD4Q2BGNLSL7E5QC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC RC6L3CIBLJEH4GWRFD7UQNGI6PZT74FRUVOYHSAN2XCC74NZUASQC ANJ4QWXY2LDCFJRUSYFOR56CYBNCFZOVYYXWCZIQIBOEHYLUDM3QC IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC AUYQDKLMOG4FGH2T3LACX4TH632DPKVXBNV5VU6PIVUEWSIO4LQQC W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC 34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC 3PY3L3A4QRW3Z5Y7SHO4TMVOOP2VNCO27X2MX4DTOP2SADLBQUOAC 7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC CEK6M777MI5JVDC3KHE3JD3FETVSJ4VN6DGATBI5P3O6P5XHY4DAC 5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC PJDC24L7LXX6NZ7J5P7MNJJHAKQDJQEBV4CMDR4VSXLMWRIBMNKQC GACH6PWPGGUBEE7PFEPQMOZKSR7HTQGL2WLGF2AQPJD3FCCSKZNQC PTB7I4WQ3NTF7BE3O6WKXDSJD6QRWSZIEWPBSZGCJJZVNKT4OL5AC 5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC T4IH76FA5TWHFOZUJFHLQXQJENJHWTUZZP4EGNA7D4GTZY7D4ZKAC QDWDUURSNLMT6AXNNJ3DEQCWAKCAIHV6MP5F7QGIBGXOG2BI2NPQC NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC KFJEFN377VIZ7OH2XCYOGCELNEGO4CIOOP7DNXEMX3LFKIKWXVTAC MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC B3SRWSFITQMJRVEBHGQQJARETYPSSDV6XKMQSSUTXEHTXRZKIQJQC OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC H3552BCIAVBLKAYKE4DHFLBLFW5RGRMYBMRRYHYEB5IPIJRUVU5QC JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC GRH4XPIYHDOXXF3R3QPMZTFHGLO2OJAZS4FLNBBXG3DHTQQM7RDQC AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC JTTHP2BEYEPBQMSDM7IKANTMKRPY6ACGL2JN4D3OBZ7HFXKAYEGQC RGHXFBNIULRVRYLBGG5JZDMYVM2E2JJ2Y5KQPMU6PUS3V26G6ZXQC JDPJS5SNW6ZTY5DYV5QUBG2WVJ45FJ4CAOK6KDJKPEI2HLIHVLRQC UU5EKED2RA2U3CFZ3UEJQEWSWHQPEU7ZD4KH3I22IIVZFHD4Y67QC IPXXB4VRVZWOU5DKQ5ZTD37LS3QNK2R6APNZUO672YEEJT6OFAYQC YHSVOROKPYS33Y4RYZRVZTE3G5LXOFX52HEDNLV6HIXOJYNOKH3QC YATODO2EN3AW7IXW5PL25HHK34YHF6Y32QBMOUZXEATZZ4YQQWZQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC 2G55UEHQ7554OPNSZVTUCZTWSHIFKGT56QEGSYFKCTX547I4AL3AC T6YW32VLZX2KKDMIS4G562ER73VHCAQZOQ6P4LSLVGVN25UD5UJQC IGHO5UHUXYBLIHLUMLZ672YHAYUSK4FSFX7SA42XARIKLIMCVLUAC CI5VTLSMB2L5W5ZVKDZEJFUARGSZP2FUSTRFV3MG6U44TDDUYH5AC HNXKX6ZDQJV33E7UKZOLBYWJMRZ4QLEMXVXJZNRCTOIG2KVRTIEAC YE7M665QKDGI7Y5WMERCWJNDZ4FUZ6GRUCK4E6GZH4SWCUM6RWLAC Q2FZIIGQECGP2FKKWLGDBBQVGCFZ4JTY53PFPJP6X7YKC23AQGFQC AVSMB4Y6F6ZMMNNPOAQQZ34OWC6N5JOURTEWFTUKDWMIIMLWWJUAC 5RRCORYDFW2N2YPUM4PDYZGI6RY7YWVMGWTY5ZIDVO6JRD5R5GAQC WE3JT43OR4L6675GINGU4B3YDBMURJZHDDYY3VLHUJEBAKH2HYEAC CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC 2ZZD6EYMSPVCXZTICL4VGYGGQRRWDLZ24KBCDBVIYC54OZ4C6GGAC R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC static void seen_staircase(unsigned char which_staircase,const coord_def& pos);static void seen_other_thing(unsigned char which_thing, const coord_def& pos);
static void seen_staircase(dungeon_feature_type which_staircase,const coord_def& pos);static void seen_other_thing(dungeon_feature_type which_thing,const coord_def& pos);
level_pos curpos(level_id::current());// XXX Is there really no better way to do this?curpos.pos.x = you.x_pos;curpos.pos.y = you.y_pos;if ( portals_present.find(curpos) != portals_present.end() )portals_present.erase(curpos);elsemprf(MSGCH_DIAGNOSTICS, "Oops - tried to unnotice bad portal.");
if (map.find(k) != map.end()){map.erase(k);return (true);}return (false);}static bool unnotice_portal(const level_pos &pos){return find_erase(portals_present, pos);}static bool unnotice_altar(const level_pos &pos){return find_erase(altars_present, pos);}static bool unnotice_shop(const level_pos &pos){return find_erase(shops_present, pos);}static bool unnotice_stair(const level_pos &pos){const dungeon_feature_type feat = grd(pos.pos);if (grid_is_branch_stairs(feat)){for (int i = 0; i < NUM_BRANCHES; ++i){if (branches[i].entry_stairs == feat){const branch_type br = static_cast<branch_type>(i);return (find_erase(stair_level, br));}}}return (false);}bool unnotice_feature(const level_pos &pos){return (unnotice_portal(pos)|| unnotice_altar(pos)|| unnotice_shop(pos)|| unnotice_stair(pos));
if (stair_find == DNGN_ENTER_LABYRINTH || stair_find == DNGN_ENTER_BAZAAR){// no longer a featureif (stair_find == DNGN_ENTER_LABYRINTH)unnotice_labyrinth_portal();grd[you.x_pos][you.y_pos] = DNGN_FLOOR;// remove any markers that were going to expire this labyrinth.if (map_marker *marker = env_find_marker(you.pos(), MAT_TIMED_FEATURE))dynamic_cast<map_timed_feature_marker*>(marker)->timeout(false);}
if (stair_find == DNGN_ENTER_LABYRINTH)dungeon_terrain_changed(you.pos(), DNGN_FLOOR);
const char *bell_urgency(int ticks) const;const char *noise_maker(int ticks) const;public:// Ticks are a tenth of a turn.int duration_ticks;int warn_threshold;
bool initialised;private:void check_register_table();bool get_table() const;void push_fn_args(const char *fn) const;bool callfn(const char *fn, bool warn_err = false) const;
map_timed_feature_marker::map_timed_feature_marker(const coord_def &_pos,int duration_turns,dungeon_feature_type _feat): map_feature_marker(_pos, _feat), duration_ticks(duration_turns * 10),warn_threshold(-1000)
map_lua_marker::map_lua_marker(): map_marker(MAT_LUA_MARKER, coord_def()), initialised(false)
dungeon_events.register_listener(DET_TURN_ELAPSED, this);
lua_stack_cleaner clean(dlua);if (dlua.loadstring(("return " + s).c_str(), "lua_marker"))mprf(MSGCH_WARN, "lua_marker load error: %s", dlua.error.c_str());if (!dlua.callfn("dgn_run_map", 1, 1))mprf(MSGCH_WARN, "lua_marker exec error: %s", dlua.error.c_str());check_register_table();}
const dungeon_feature_type ft = grd(pos);switch (ft){case DNGN_ENTER_BAZAAR:mprf(MSGCH_SOUND, "You %shear coins being counted.",duration_ticks < 1000? "can faintly " : "");break;case DNGN_ENTER_LABYRINTH:mprf(MSGCH_SOUND, "You hear a faint echoing snort.");break;default:break;}
lua_pushlightuserdata(dlua, this);lua_pushnil(dlua);lua_settable(dlua, LUA_REGISTRYINDEX);
std::string map_timed_feature_marker::describe() const{return make_stringf("timer: %d ticks (%s)",duration_ticks, dungeon_feature_name(feat));
// Key is this.lua_pushlightuserdata(dlua, this);// Move key before value.lua_insert(dlua, -2);lua_settable(dlua, LUA_REGISTRYINDEX);initialised = true;
if (ticks > 5000)return "stately ";else if (ticks > 4000)return "";else if (ticks > 2500)return "brisk ";else if (ticks > 1500)return "urgent ";else if (ticks > 0)return "frantic ";elsereturn "last, dying notes of the ";
// First save the unmarshall Lua function.lua_pushlightuserdata(dlua, const_cast<map_lua_marker*>(this));lua_gettable(dlua, LUA_REGISTRYINDEX);return (lua_istable(dlua, -1));
case DNGN_ENTER_LABYRINTH:return (ticks > 0? "tolling of a bell" : "bell");case DNGN_ENTER_BAZAAR:return (ticks > 0? "ticking of an ancient clock" : "clock");default:return (ticks > 0?"trickling of a stream filled with giant, killer bugs.": "stream");
mprf(MSGCH_WARN, "Couldn't find table.");init = false;
marshallByte(th, init);if (!init)return;// Call dlua_marker_function(table, 'read')lua_pushstring(dlua, "read");if (!dlua.callfn("dlua_marker_function", 2, 1))end(1, false, "lua_marker: write error: %s", dlua.error.c_str());// Right, what's on top should be a function. Save it.dlua_chunk reader(dlua);if (!reader.error.empty())end(1, false, "lua_marker: couldn't save read function: %s",reader.error.c_str());marshallString(th, reader.compiled_chunk());// Okay, saved the reader. Now ask the writer to do its thing.// Call: dlua_marker_method(table, fname, marker)get_table();lua_pushstring(dlua, "write");lua_pushlightuserdata(dlua, const_cast<map_lua_marker*>(this));lua_pushlightuserdata(dlua, &th);if (!dlua.callfn("dlua_marker_method", 4))end(1, false, "lua_marker::write error: %s", dlua.error.c_str());
if (warn_threshold == -1000)warn_threshold = std::max(50, duration_ticks - 500);duration_ticks -= e.elapsed_ticks;
lua_stack_cleaner cln(dlua);// Read the Lua chunk we saved.const std::string compiled = unmarshallString(th, LUA_CHUNK_MAX_SIZE);
if (duration_ticks < warn_threshold || duration_ticks <= 0){if (duration_ticks > 900)warn_threshold = duration_ticks - 500;elsewarn_threshold = duration_ticks - 250;if (duration_ticks > 0 && player_can_hear(pos))mprf(MSGCH_SOUND, "You hear the %s%s.",bell_urgency(duration_ticks),noise_maker(duration_ticks));
dlua_chunk chunk = dlua_chunk::precompiled(compiled);if (chunk.load(dlua))end(1, false, "lua_marker::read error: %s", chunk.error.c_str());dlua_push_userdata(dlua, this, MAPMARK_METATABLE);lua_pushlightuserdata(dlua, &th);if (!dlua.callfn("dlua_marker_read", 3, 1))end(1, false, "lua_marker::read error: %s", dlua.error.c_str());
if (verbose){if (see_grid(pos))mprf("%s disappears!",feature_description(grd(pos), NUM_TRAPS, false,DESC_CAP_THE, false).c_str());elsempr("The walls and floor vibrate strangely for a moment.");}
map_marker *marker = new map_lua_marker;marker->read(th);return (marker);}
dungeon_terrain_changed(pos);
bool map_lua_marker::callfn(const char *fn, bool warn_err) const{const int top = lua_gettop(dlua);push_fn_args(fn);const bool res =dlua.callfn("dlua_marker_method", lua_gettop(dlua) - top, 1);if (!res && warn_err)mprf(MSGCH_WARN, "mlua error: %s", dlua.error.c_str());return (res);}
// Kill this marker.env_remove_marker(this);
void map_lua_marker::notify_dgn_event(const dgn_event &e){lua_stack_cleaner clean(dlua);push_fn_args("event");clua_push_dgn_event(dlua, &e);if (!dlua.callfn("dlua_marker_method", 4, 0))mprf(MSGCH_WARN, "notify_dgn_event: Lua error: %s",dlua.error.c_str());
map_marker *mt = new map_timed_feature_marker();mt->read(th);return (mt);
lua_stack_cleaner cln(dlua);if (!callfn("describe"))return make_stringf("error: %s", dlua.error.c_str());std::string desc;if (lua_isstring(dlua, -1))desc = lua_tostring(dlua, -1);return desc;
strip_tag(raw, "timer:", true);int navg = strip_number_tag(raw, "avg:");if (navg == TAG_UNFOUND)navg = 1;if (navg < 1 || navg > 20)throw make_stringf("Bad marker spec '%s' (avg out of bounds)",s.c_str());dungeon_feature_type feat = DNGN_FLOOR;std::string fname = strip_tag_prefix(raw, "feat:");if (!fname.empty()&& (feat = dungeon_feature_by_name(fname)) == DNGN_UNSEEN)
strip_tag(raw, "lua:");map_lua_marker *mark = new map_lua_marker(raw, ctx);if (!mark->initialised)
std::vector<std::string> limits = split_string("-", raw);const int nlims = limits.size();if (nlims < 1 || nlims > 2)throw make_stringf("Malformed turn range (%s) in marker '%s'",raw.c_str(), s.c_str());const int low = atoi(limits[0].c_str());const int high = nlims == 1? low : atoi(limits[1].c_str());if (low == 0 || high < low)throw make_stringf("Malformed turn range (%s) in marker '%s'",raw.c_str(), s.c_str());const int duration = low == high? low : random_range(low, high, navg);return new map_timed_feature_marker(coord_def(0, 0),duration, feat);
return (mark);
: transforms(), markers(), lines(), map_width(0), solid_north(false),solid_east(false), solid_south(false), solid_west(false),solid_checked(false)
: transforms(), markers(), lines(), map_width(0),solid_north(false), solid_east(false), solid_south(false),solid_west(false), solid_checked(false)
map(), mons(), items(), keyspecs(), prelude("dlprelude"), main("dlmain"),validate("dlvalidate"), veto("dlveto"), index_only(false),cache_offset(0L)
map(), mons(), items(), keyspecs(), prelude("dlprelude"),main("dlmain"), validate("dlvalidate"), veto("dlveto"),index_only(false), cache_offset(0L)
}// Initialises a chunk from the function on the top of stack.// This function must not be a closure, i.e. must not have any upvalues.dlua_chunk::dlua_chunk(lua_State *ls): file(), chunk(), compiled(), context(), first(-1), last(-1), error(){clear();lua_stack_cleaner cln(ls);std::ostringstream out;const int err = lua_dump(ls, dlua_compiled_chunk_writer, &out);if (err){const char *e = lua_tostring(ls, -1);error = e? e : "Unknown error compiling chunk";}compiled = out.str();}dlua_chunk dlua_chunk::precompiled(const std::string &chunk){dlua_chunk dchunk;dchunk.compiled = chunk;return (dchunk);
}static const char *dgn_event_type_names[] ={"none", "turn", "mons_move", "player_move", "leave_level", "enter_level","player_los", "player_climb"};static dgn_event_type dgn_event_type_by_name(const std::string &name){for (unsigned i = 0; i < ARRAYSIZE(dgn_event_type_names); ++i)if (dgn_event_type_names[i] == name)return static_cast<dgn_event_type>(i? 1 << (i - 1) : 0);return (DET_NONE);}static const char *dgn_event_type_name(unsigned evmask){if (evmask == 0)return (dgn_event_type_names[0]);for (unsigned i = 1; i < ARRAYSIZE(dgn_event_type_names); ++i)if (evmask & (1 << (i - 1)))return (dgn_event_type_names[i]);return (dgn_event_type_names[0]);}static void dgn_push_event_type(lua_State *ls, int n){if (lua_isstring(ls, n))lua_pushnumber(ls, dgn_event_type_by_name(lua_tostring(ls, n)));else if (lua_isnumber(ls, n))lua_pushstring(ls, dgn_event_type_name(luaL_checkint(ls, n)));elselua_pushnil(ls);}static int dgn_dgn_event(lua_State *ls){const int start = lua_isuserdata(ls, 1)? 2 : 1;int retvals = 0;for (int i = start, nargs = lua_gettop(ls); i <= nargs; ++i){dgn_push_event_type(ls, i);retvals++;}return (retvals);}static int dgn_register_listener(lua_State *ls){unsigned mask = luaL_checkint(ls, 1);MAPMARKER(ls, 2, mark);map_lua_marker *listener = dynamic_cast<map_lua_marker*>(mark);coord_def pos;// Was a position supplied?if (lua_gettop(ls) == 4){pos.x = luaL_checkint(ls, 3);pos.y = luaL_checkint(ls, 4);}dungeon_events.register_listener(mask, listener, pos);return (0);}static int dgn_remove_listener(lua_State *ls){MAPMARKER(ls, 1, mark);map_lua_marker *listener = dynamic_cast<map_lua_marker*>(mark);coord_def pos;// Was a position supplied?if (lua_gettop(ls) == 3){pos.x = luaL_checkint(ls, 2);pos.y = luaL_checkint(ls, 3);}dungeon_events.remove_listener(listener, pos);return (0);}static int dgn_remove_marker(lua_State *ls){MAPMARKER(ls, 1, mark);env_remove_marker(mark);return (0);}static int dgn_feature_desc(lua_State *ls){const dungeon_feature_type feat =static_cast<dungeon_feature_type>(luaL_checkint(ls, 1));const description_level_type dtype =lua_isnumber(ls, 2)?static_cast<description_level_type>(luaL_checkint(ls, 2)) :description_type_by_name(lua_tostring(ls, 2));const bool need_stop = lua_isboolean(ls, 3)? lua_toboolean(ls, 3) : false;const std::string s =feature_description(feat, NUM_TRAPS, false, dtype, need_stop);lua_pushstring(ls, s.c_str());return (1);}static int dgn_terrain_changed(lua_State *ls){dungeon_feature_type type = DNGN_UNSEEN;if (lua_isnumber(ls, 3))type = static_cast<dungeon_feature_type>(luaL_checkint(ls, 3));else if (lua_isstring(ls, 3))type = dungeon_feature_by_name(lua_tostring(ls, 3));const bool affect_player =lua_isboolean(ls, 4)? lua_toboolean(ls, 4) : true;dungeon_terrain_changed( coord_def( luaL_checkint(ls, 1),luaL_checkint(ls, 2) ),type, affect_player );return (0);
static int file_marshall(lua_State *ls){if (lua_gettop(ls) != 2)luaL_error(ls, "Need two arguments: tag header and value");tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));if (lua_isnumber(ls, 2))marshallLong(th, luaL_checklong(ls, 2));else if (lua_isstring(ls, 2))marshallString(th, lua_tostring(ls, 2));else if (lua_isfunction(ls, 2)){dlua_chunk chunk(ls);marshallString(th, chunk.compiled_chunk());}return (0);}static int file_unmarshall_number(lua_State *ls){if (lua_gettop(ls) != 1)luaL_error(ls, "Need tag header as one argument");tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));lua_pushnumber(ls, unmarshallLong(th));return (1);}static int file_unmarshall_string(lua_State *ls){if (lua_gettop(ls) != 1)luaL_error(ls, "Need tag header as one argument");tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));lua_pushstring(ls, unmarshallString(th).c_str());return (1);}static int file_unmarshall_fn(lua_State *ls){if (lua_gettop(ls) != 1)luaL_error(ls, "Need tag header as one argument");tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));const std::string s(unmarshallString(th, LUA_CHUNK_MAX_SIZE));dlua_chunk chunk = dlua_chunk::precompiled(s);if (chunk.load(dlua))lua_pushnil(ls);return (1);}enum lua_persist_type{LPT_NONE,LPT_NUMBER,LPT_STRING,LPT_FUNCTION};static int file_marshall_meta(lua_State *ls){if (lua_gettop(ls) != 2)luaL_error(ls, "Need two arguments: tag header and value");tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));lua_persist_type ptype = LPT_NONE;if (lua_isnumber(ls, 2))ptype = LPT_NUMBER;else if (lua_isstring(ls, 2))ptype = LPT_STRING;else if (lua_isfunction(ls, 2))ptype = LPT_FUNCTION;elseluaL_error(ls, "Can marshall only numbers, strings and functions.");marshallByte(th, ptype);file_marshall(ls);return (0);}static int file_unmarshall_meta(lua_State *ls){tagHeader &th(*static_cast<tagHeader*>( lua_touserdata(ls, 1) ));const lua_persist_type ptype =static_cast<lua_persist_type>(unmarshallByte(th));switch (ptype){case LPT_NUMBER:return file_unmarshall_number(ls);case LPT_STRING:return file_unmarshall_string(ls);case LPT_FUNCTION:return file_unmarshall_fn(ls);default:luaL_error(ls, "Unexpected type signature.");}// Never get here.return (0);}static const struct luaL_reg file_lib[] ={{ "marshall", file_marshall },{ "marshall_meta", file_marshall_meta },{ "unmarshall_meta", file_unmarshall_meta },{ "unmarshall_number", file_unmarshall_number },{ "unmarshall_string", file_unmarshall_string },{ "unmarshall_fn", file_unmarshall_fn },{ NULL, NULL }};LUARET1(you_can_hear_pos, boolean,player_can_hear(luaL_checkint(ls,1), luaL_checkint(ls, 2)))static const struct luaL_reg you_lib[] ={{ "hear_pos", you_can_hear_pos },{ NULL, NULL }};static int dgnevent_type(lua_State *ls){DEVENT(ls, 1, dev);PLUARET(number, dev->type);}static int dgnevent_place(lua_State *ls){DEVENT(ls, 1, dev);lua_pushnumber(ls, dev->place.x);lua_pushnumber(ls, dev->place.y);return (2);}static int dgnevent_ticks(lua_State *ls){DEVENT(ls, 1, dev);PLUARET(number, dev->elapsed_ticks);}static const struct luaL_reg dgnevent_lib[] ={{ "type", dgnevent_type },{ "pos", dgnevent_place },{ "ticks", dgnevent_ticks },{ NULL, NULL }};static void luaopen_setmeta(lua_State *ls,const char *global,const luaL_reg *lua_lib,const char *meta){luaL_newmetatable(ls, meta);lua_setglobal(ls, global);luaL_openlib(ls, global, lua_lib, 0);// Do <global>.__index = <global>lua_pushstring(ls, "__index");lua_pushvalue(ls, -2);lua_settable(ls, -3);}static void luaopen_dgnevent(lua_State *ls){luaopen_setmeta(ls, "dgnevent", dgnevent_lib, DEVENT_METATABLE);}static int mapmarker_pos(lua_State *ls){MAPMARKER(ls, 1, mark);lua_pushnumber(ls, mark->pos.x);lua_pushnumber(ls, mark->pos.y);return (2);}static const struct luaL_reg mapmarker_lib[] ={{ "pos", mapmarker_pos },{ NULL, NULL }};static void luaopen_mapmarker(lua_State *ls){luaopen_setmeta(ls, "mapmarker", mapmarker_lib, MAPMARK_METATABLE);}
description_level_type description_type_by_name(const char *desc){if (!desc)return DESC_PLAIN;if (!strcmp("The", desc))return DESC_CAP_THE;else if (!strcmp("the", desc))return DESC_NOCAP_THE;else if (!strcmp("A", desc))return DESC_CAP_A;else if (!strcmp("a", desc))return DESC_NOCAP_A;else if (!strcmp("Your", desc))return DESC_CAP_YOUR;else if (!strcmp("your", desc))return DESC_NOCAP_YOUR;else if (!strcmp("its", desc))return DESC_NOCAP_ITS;else if (!strcmp("worn", desc))return DESC_INVENTORY_EQUIP;else if (!strcmp("inv", desc))return DESC_INVENTORY;return DESC_PLAIN;}
KFEAT: D = altar of TrogKFEAT: E = altar of MakhlebKFEAT: F = altar of OkawaruKFEAT: G = altar of The Shining OneKFEAT: H = altar of ZinKFEAT: I = altar of ElyvilonKFEAT: J = altar of Sif MunaKFEAT: K = altar of VehumetKFEAT: L = altar of KikubaaqudghaKFEAT: M = altar of YredelemnulKFEAT: N = altar of XomKFEAT: O = altar of Nemelex Xobeh
KFEAT: D = altar_trogKFEAT: E = altar_makhlebKFEAT: F = altar_okawaruKFEAT: G = altar_shining_oneKFEAT: H = altar_zinKFEAT: I = altar_elyvilonKFEAT: J = altar_sif_munaKFEAT: K = altar_vehumetKFEAT: L = altar_kikubaaqudghaKFEAT: M = altar_yredelemnulKFEAT: N = altar_xomKFEAT: O = altar_nemelex_xobeh
-------------------------------------------------------------------------------- luamark.lua:-- Lua map marker handling.------------------------------------------------------------------------------dofile('clua/lm_timed.lua')dofile('clua/lm_1way.lua')function dlua_marker_function(table, name)return table[name]endfunction dlua_marker_method(table, name, marker, ...)if table[name] thenreturn table[name](table, marker, ...)endendfunction dlua_marker_read(fn, marker, th)return fn(marker, th)endfunction timed_marker(pars)return TimedMarker.new(pars)endlmark = { }-- Marshalls a table comprising of keys that are strings or numbers only,-- and values that are strings, numbers, functions, or tables only. The table-- cannot have cycles, and the table's metatable is not preserved.function lmark.marshall_table(th, table)if not table thenfile.marshall(th, -1)returnend-- Count the number of elements first (ugh)local nsize = 0local tsize = 0for _, v in pairs(table) doif type(v) == 'table' thentsize = tsize + 1elsensize = nsize + 1endendfile.marshall(th, nsize)for key, value in pairs(table) doif type(value) ~= 'table' thenfile.marshall_meta(th, key)file.marshall_meta(th, value)endendfile.marshall(th, tsize)for key, value in pairs(table) doif type(value) == 'table' thenfile.marshall_meta(th, key)lmark.marshall_table(th, value)endendend-- Unmarshals a table marshaled by marshall_table.function lmark.unmarshall_table(th)local nsize = file.unmarshall_number(th)if nsize == -1 thenreturn nilendlocal ret = { }for i = 1, nsize dolocal key = file.unmarshall_meta(th)local val = file.unmarshall_meta(th)ret[key] = valendlocal tsize = file.unmarshall_number(th)for i = 1, tsize dolocal key = file.unmarshall_meta(th)local val = lmark.unmarshall_table(th)ret[key] = valendreturn retend
-------------------------------------------------------------------------------- lm_tmsg.lua:-- Messaging for timed Lua markers.------------------------------------------------------------------------------TimedMessaging = { }TimedMessaging.__index = TimedMessagingfunction TimedMessaging._new()local m = { }setmetatable(m, TimedMessaging)return mendfunction TimedMessaging.new(pars)pars = pars or { }local m = TimedMessaging._new()m.noisemaker = pars.noisemakerm.verb = pars.verbm.finalmsg = pars.finalmsgm.ranges = pars.rangesm.initmsg = pars.initmsg or ''return mendfunction TimedMessaging:init(tmarker, cm)local lab = dgn.grid(cm:pos()) == dgn.feature_number('enter_labyrinth')if not self.noisemaker thenself.noisemaker = lab and "an ancient clock" or "a massive bell"endself.verb = self.verb or (lab and 'ticking' or 'tolling')if not self.finalmsg thenself.finalmsg = lab and "last, dying ticks of the clock"or "last, dying notes of the bell"endif not self.ranges thenself.ranges = { { 5000, 'stately ' }, { 4000, '' },{ 2500, 'brisk ' }, { 1500, 'urgent ' },{ 0, 'frantic ' } }endself.check = self.check or tmarker.dur - 500if self.check < 50 thenself.check = 50endif #self.initmsg > 0 and you.hear_pos(cm:pos()) thencrawl.mpr(self.initmsg, "sound")endendfunction TimedMessaging:say_message(dur)self.sound_channel = self.sound_channel or crawl.msgch_num('sound')if dur <= 0 thencrawl.mpr("You hear the " .. self.finalmsg .. ".", self.sound_channel)returnendfor _, chk in ipairs(self.ranges) doif dur > chk[1] thencrawl.mpr("You hear the " .. chk[2] .. self.verb.. " of " .. self.noisemaker .. ".",self.sound_channel)breakendendendfunction TimedMessaging:event(luamark, cmarker, event)if luamark.dur < self.check or luamark.dur <= 0 thenself.check = luamark.dur - 250if luamark.dur > 900 thenself.check = self.check - 250endif you.hear_pos(cmarker:pos()) thenself:say_message(luamark.dur)endendendfunction TimedMessaging:write(th)file.marshall(th, self.check)file.marshall(th, self.noisemaker)file.marshall(th, self.verb)file.marshall(th, self.initmsg)file.marshall(th, self.finalmsg)lmark.marshall_table(th, self.ranges)endfunction TimedMessaging.read(th)local tm = TimedMessaging._new()tm.check = file.unmarshall_number(th)tm.noisemaker = file.unmarshall_string(th)tm.verb = file.unmarshall_string(th)tm.initmsg = file.unmarshall_string(th)tm.finalmsg = file.unmarshall_string(th)tm.ranges = lmark.unmarshall_table(th)return tmendfunction bell_clock_msg(pars)return TimedMessaging.new(pars)end
-------------------------------------------------------------------------------- lm_timed.lua:-- Lua timed map feature markers.------------------------------------------------------------------------------dofile('clua/lm_tmsg.lua')TimedMarker = { }TimedMarker.__index = TimedMarkerfunction TimedMarker._new()local marker = { }setmetatable(marker, TimedMarker)return markerendfunction TimedMarker.new(pars)pars = pars or { }if not pars.msg thenerror("No messaging object provided (msg = nil)")endpars.high = pars.high or pars.low or pars.turns or 1pars.low = pars.low or pars.high or pars.turns or 1local dur = crawl.random_range(pars.low, pars.high, pars.navg or 1)local feat = pars.feat or 'floor'local fnum = dgn.feature_number(feat)if fnum == dgn.feature_number('unseen') thenerror("Bad feature name: " .. feat)endlocal tmarker = TimedMarker._new()tmarker.dur = dur * 10tmarker.fnum = fnumtmarker.feat = feattmarker.msg = pars.msgreturn tmarkerendfunction TimedMarker:activate(marker)self.msg:init(self, marker)dgn.register_listener(dgn.dgn_event_type('turn'), marker)dgn.register_listener(dgn.dgn_event_type('player_climb'),marker, marker:pos())endfunction TimedMarker:timeout(marker, verbose, affect_player)local x, y = marker:pos()if verbose thenif you.see_grid(marker:pos()) thencrawl.mpr(dgn.feature_desc(dgn.grid(x, y), "The") .." disappears!")elsecrawl.mpr("The walls and floor vibrate strangely for a moment.")endenddgn.terrain_changed(x, y, self.fnum, affect_player)dgn.remove_listener(marker)dgn.remove_listener(marker, marker:pos())dgn.remove_marker(marker)endfunction TimedMarker:event(marker, ev)self.ticktype = self.ticktype or dgn.dgn_event_type('turn')self.stairtype = self.stairtype or dgn.dgn_event_type('player_climb')if ev:type() == self.stairtype thenlocal mx, my = marker:pos()local ex, ey = ev:pos()if mx == ex and my == ey thenself:timeout(marker, false, false)endreturnendif ev:type() ~= self.ticktype thenreturnendself.dur = self.dur - ev:ticks()self.msg:event(self, marker, ev)if self.dur <= 0 thenself:timeout(marker, true, true)endendfunction TimedMarker:describe(marker)return self.feat .. "/" .. tostring(self.dur)endfunction TimedMarker.read(marker, th)local marker = TimedMarker._new()marker.dur = file.unmarshall_number(th)marker.fnum = file.unmarshall_number(th)marker.feat = file.unmarshall_string(th)marker.msg = file.unmarshall_fn(th)(th)return markerendfunction TimedMarker:write(marker, th)file.marshall(th, self.dur)file.marshall(th, self.fnum)file.marshall(th, self.feat)file.marshall(th, self.msg.read)self.msg:write(th)end
-------------------------------------------------------------------------------- lm_1way.lua:-- One-way stair marker.------------------------------------------------------------------------------OneWayStair = { }OneWayStair.__index = OneWayStairfunction OneWayStair.new()local ows = { }setmetatable(ows, OneWayStair)return owsendfunction OneWayStair:activate(marker)local ev = dgn.dgn_event_type('player_climb')dgn.register_listener(ev, marker, marker:pos())endfunction OneWayStair:event(marker, ev)if ev:type() == dgn.dgn_event_type('player_climb') thenlocal x, y = ev:pos()dgn.terrain_changed(x, y, 'floor', false)dgn.remove_listener(marker, ev:pos())dgn.remove_marker(marker)endendfunction OneWayStair.read(marker, th)return OneWayStair.new()endfunction one_way_stair()return OneWayStair.new()end
lua_settop(_state, 1);
lua_pushboolean(_state, managed_vm);setregistry("lua_vm_is_managed");}bool CLua::is_managed_vm(lua_State *ls){lua_stack_cleaner clean(ls);lua_pushstring(ls, "lua_vm_is_managed");lua_gettable(ls, LUA_REGISTRYINDEX);return (lua_toboolean(ls, -1));
}static description_level_type desc_code(const char *desc){if (!desc)return DESC_PLAIN;if (!strcmp("The", desc))return DESC_CAP_THE;else if (!strcmp("the", desc))return DESC_NOCAP_THE;else if (!strcmp("A", desc))return DESC_CAP_A;else if (!strcmp("a", desc))return DESC_NOCAP_A;else if (!strcmp("Your", desc))return DESC_CAP_YOUR;else if (!strcmp("your", desc))return DESC_NOCAP_YOUR;else if (!strcmp("its", desc))return DESC_NOCAP_ITS;else if (!strcmp("worn", desc))return DESC_INVENTORY_EQUIP;else if (!strcmp("inv", desc))return DESC_INVENTORY;return DESC_PLAIN;
KFEAT features are specified as a unique substring of the in-gamedescription of the feature; simple * and ? wildcards can also beused. For instance, to place a portal to the Abyss, you can use:
KFEAT features are specified as a feature name (see section Ifor a full list of feature names). As another example, you canplace a portal to the Abyss as: