To avoid name clashes, rename dlua libs from *_lib to *_dlib.
CJKLBIIM2ZTWTLGISXEZOGK2JANEYUSLOKG3BBOAYAY7AFG33ELQC 3X5BATS2ME2B46CLUQMAIWX47C3B4X3V6I5E2NCANA3VAZAHMMHAC I7MMXEIUB2RUYPWROY6PHKUO6VXXHG7CRLYTBEGIW4ERKQZIARLQC FSEZWFGR4YUDIRSQ4UKZW2ZPXY5RMJWELKP6PVLXEXQHFRIMYRRAC XPIE6FG6SYZXNQFBRWUBJ3NR5Q6MOMRXAFW3WTKMSLMKKA55ZWCQC 2VAIMVOC3GPYJKN5ICAS4LHNS6IAQAZGWJRTR2WVBEJAOHEGRJEQC JTVUAALTZP6FW3D3QJUSOUGMEDNZB4F4HGUMYFHWGEJV2ETRBIBQC LPTP6ZL7U4OVXLZ56TJKJ6HENDHE7ITFMFBXC5BKEBVXEGXPW44AC WQBSKRTHZRKIYIDHROBSIEHEEQX26UAFDTMYY24UOPYNMYWXDFCAC T7CCGLOZ25B7BQKKGR6IA6LWBRKUWTXLTIRXUQ4YKQRVAA7AHZKQC K73AS36BODJSSKMT2LRFDKS7BAMETNFLWHZEPQEZFM6KQB6KRA4AC 3A5FX3Y4RPKWQEHKKXZKXZJ7RKV6RKWT7GTR4WFE5UBWKV2HT4RQC 754PQVFHYQER7P7NEHYNLQVOEALF6I23IQDNGNCOK5IV7OLAEXRQC A2JHMM2QW2Q5OZ4DY4N3VIT53SOPTI434NJB72XBMJD67YJRI4CQC RXYHE3C7R3EGCRZEJT2ZO4ALLRDR3HF66VHZZNF7TT3DFWZ6BJCQC NOQ4LTFDCNNSHUE2AHXYBVXUTTXBDZOHNCK5V4TWVDBIYRC3VUCQC O6QYS2KYXUXMODO3X4SYX7SPZE7AOIFT2XJZHRABMMQFEUN4UXLAC RJIGO3YE7LKSLASPVA7K6CNWJAPKXD7ENJDURI5GXBGIEXFBBINAC 7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC LE5U6CTXEIETQN5GOVYF2K2VCISRXR3ULORXDKIKWYDVBG5GS3WAC AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC D6A2MLKI7UQPZ4A4D6QSM6STFVDY77IY5APXCBT3LNH6CDVKT67QC 63CAVB2MMXOQHGV2N7B5AE2HJKBPPSBKJDLX3EGKEZN52KUIWPQQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC NCDWWDJQLAU5ORSAQGZKJJ5E22VTDGGPJMVVBWQFHQ2B3U3UFHDQC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC WE3JT43OR4L6675GINGU4B3YDBMURJZHDDYY3VLHUJEBAKH2HYEAC WCK6TM2ZD56WSOK6SMMKBYAYGG4OUCTILLMVVLMB4QO5I5S2IVNAC 53QXO6XQ6QAKCN6T5ADIKZM6UZCSAOAVKIJBHRN56BUVA653OZFAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC NOUFW6ACJ7KPVHSPF4WLRAVOWI7PZ6OAVYDRMI3WYNPXVMGAB3QAC 4V4YGPXG45JV5ZPAFDEHTLLGAQIFISMHKCZMMJRAD62FVDCL255AC TP5EDQXPVPTKQYTAMN3VQYHM4WRT2RNIR4EDLWLDAV2OQGKSB6KAC C55G5JGGSVWMU7XVEJL6YZZLDXQZGRN7JQOAALS6WIKFPX3L2U6QC LSI55NUVW3PC33MGHLN3BGJ5KL7SJTBWT4JEOTZ7ZGRS2SK4ON7AC B3SRWSFITQMJRVEBHGQQJARETYPSSDV6XKMQSSUTXEHTXRZKIQJQC HXIETRYLTZYNJR4QHS5ZN4ZZR76SLRIXTEJQQJGI33XMXHO6MNBAC OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC QIDA6PWWBPR6IJOXFCSPCGWV45PVRZ4TPWSL2TDATNVTYLDMVESQC PRG7UT7G56GT4W3FQ3KG5JRPGMKKJBFDLVHDLYFQK6IZW25JQLBQC FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC SM6YRPYZS6LMDQA6X3VAOK2PGMUFKPD7JMWJISOQSMX2CBR4ISPAC UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC extern const struct luaL_reg crawl_lib[];extern const struct luaL_reg debug_lib[];extern const struct luaL_reg dgn_lib[];extern const struct luaL_reg dgn_build_lib[];extern const struct luaL_reg dgn_event_lib[];extern const struct luaL_reg dgn_grid_lib[];extern const struct luaL_reg dgn_item_lib[];extern const struct luaL_reg dgn_level_lib[];extern const struct luaL_reg dgn_mons_lib[];extern const struct luaL_reg dgn_tile_lib[];extern const struct luaL_reg file_lib[];extern const struct luaL_reg los_lib[];extern const struct luaL_reg mapmarker_lib[];extern const struct luaL_reg you_lib[];
extern const struct luaL_reg debug_dlib[];extern const struct luaL_reg dgn_dlib[];extern const struct luaL_reg dgn_build_dlib[];extern const struct luaL_reg dgn_event_dlib[];extern const struct luaL_reg dgn_grid_dlib[];extern const struct luaL_reg dgn_item_dlib[];extern const struct luaL_reg dgn_level_dlib[];extern const struct luaL_reg dgn_mons_dlib[];extern const struct luaL_reg dgn_tile_dlib[];extern const struct luaL_reg file_dlib[];extern const struct luaL_reg los_dlib[];extern const struct luaL_reg mapmarker_dlib[];extern const struct luaL_reg you_dlib[];
const char *message = luaL_checkstring(ls, 1);if (!message)return (0);int ch = MSGCH_PLAIN;if (lua_isnumber(ls, 2))ch = luaL_checkint(ls, 2);else{const char *channel = lua_tostring(ls, 2);if (channel)ch = str_to_channel(channel);}if (ch < 0 || ch >= NUM_MESSAGE_CHANNELS)ch = MSGCH_PLAIN;mpr(message, static_cast<msg_channel_type>(ch));return (0);}static int crawl_formatted_mpr(lua_State *ls){if (!crawl_state.io_inited)return (0);const char *message = luaL_checkstring(ls, 1);if (!message)return (0);int ch = MSGCH_PLAIN;if (lua_isnumber(ls, 2))ch = luaL_checkint(ls, 2);else{const char *channel = lua_tostring(ls, 2);if (channel)ch = str_to_channel(channel);}if (ch < 0 || ch >= NUM_MESSAGE_CHANNELS)ch = MSGCH_PLAIN;formatted_mpr(formatted_string::parse_string(message),static_cast<msg_channel_type>(ch));return (0);}LUAWRAP(crawl_more, more())LUAWRAP(crawl_mesclr, mesclr())LUAWRAP(crawl_redraw_screen, redraw_screen())static int crawl_input_line(lua_State *ls){// This is arbitrary, but anybody entering so many characters is psychotic.char linebuf[500];get_input_line(linebuf, sizeof linebuf);lua_pushstring(ls, linebuf);return (1);}static int crawl_c_input_line(lua_State *ls){char linebuf[500];bool valid = !cancelable_get_line(linebuf, sizeof linebuf);if (valid)lua_pushstring(ls, linebuf);elselua_pushnil(ls);return (1);}LUARET1(crawl_getch, number, getch())LUARET1(crawl_kbhit, number, kbhit())LUAWRAP(crawl_flush_input, flush_input_buffer(FLUSH_LUA))static char _lua_char(lua_State *ls, int ndx, char defval = 0){return (lua_isnone(ls, ndx) || !lua_isstring(ls, ndx)? defval: lua_tostring(ls, ndx)[0]);}static int crawl_yesno(lua_State *ls){const char *prompt = luaL_checkstring(ls, 1);const bool safe = lua_toboolean(ls, 2);const int safeanswer = _lua_char(ls, 3);const bool clear_after =lua_isnone(ls, 4) ? true : lua_toboolean(ls, 4);const bool interrupt_delays =lua_isnone(ls, 5) ? true : lua_toboolean(ls, 5);const bool noprompt =lua_isnone(ls, 6) ? false : lua_toboolean(ls, 6);cursor_control con(true);lua_pushboolean(ls, yesno(prompt, safe, safeanswer, clear_after,interrupt_delays, noprompt));return (1);}static int crawl_yesnoquit(lua_State *ls){const char *prompt = luaL_checkstring(ls, 1);const bool safe = lua_toboolean(ls, 2);const int safeanswer = _lua_char(ls, 3);const bool allow_all =lua_isnone(ls, 4) ? false : lua_toboolean(ls, 4);const bool clear_after =lua_isnone(ls, 5) ? true : lua_toboolean(ls, 5);// Skipping the other params until somebody needs them.cursor_control con(true);lua_pushnumber(ls, yesnoquit(prompt, safe, safeanswer, allow_all,clear_after));return (1);}static void crawl_sendkeys_proc(lua_State *ls, int argi){if (lua_isstring(ls, argi)){const char *keys = luaL_checkstring(ls, argi);if (!keys)return;for ( ; *keys; ++keys)macro_buf_add(*keys);}else if (lua_istable(ls, argi)){for (int i = 1; ; ++i){lua_rawgeti(ls, argi, i);if (lua_isnil(ls, -1)){lua_pop(ls, 1);return;}crawl_sendkeys_proc(ls, lua_gettop(ls));lua_pop(ls, 1);}}else if (lua_isnumber(ls, argi)){int key = luaL_checkint(ls, argi);macro_buf_add(key);}}static int crawl_sendkeys(lua_State *ls){int top = lua_gettop(ls);for (int i = 1; i <= top; ++i)crawl_sendkeys_proc(ls, i);return (0);}// Tell Crawl to process one command.static int crawl_process_command(lua_State *ls){const bool will_process =current_delay_action() == DELAY_MACRO || !you_are_delayed();if (will_process){// This should only be called from a macro delay, but run_macro// may not have started the macro delay; do so now.if (!you_are_delayed())start_delay(DELAY_MACRO, 1);start_delay(DELAY_MACRO_PROCESS_KEY, 1);}lua_pushboolean(ls, will_process);return (1);}static int crawl_playsound(lua_State *ls){const char *sf = luaL_checkstring(ls, 1);if (!sf)return (0);play_sound(sf);return (0);}static int crawl_runmacro(lua_State *ls){const char *macroname = luaL_checkstring(ls, 1);if (!macroname)return (0);run_macro(macroname);return (0);}static int crawl_setopt(lua_State *ls){if (!lua_isstring(ls, 1))return (0);const char *s = lua_tostring(ls, 1);if (s){// Note that the conditional script can contain nested Lua[ ]Lua code.read_options(s, true);}return (0);}static int crawl_read_options(lua_State *ls){if (!lua_isstring(ls, 1))return (0);const char* filename = lua_tostring(ls, 1);Options.include(filename, true, true);return (0);}static int crawl_bindkey(lua_State *ls){const char *s = NULL;if (lua_isstring(ls, 1)){s = lua_tostring(ls, 1);}if (!s || !lua_isfunction(ls, 2) || lua_gettop(ls) != 2)return (0);lua_pushvalue(ls, 2);std::string name = clua.setuniqregistry();if (lua_gettop(ls) != 2){fprintf(stderr, "Stack top has changed!\n");lua_settop(ls, 2);}macro_userfn(s, name.c_str());return (0);}static int crawl_msgch_num(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);int ch = str_to_channel(s);if (ch == -1)return (0);lua_pushnumber(ls, ch);return (1);}static int crawl_msgch_name(lua_State *ls){int num = luaL_checkint(ls, 1);std::string name = channel_to_str(num);lua_pushstring(ls, name.c_str());return (1);}static int crawl_take_note(lua_State *ls){const char* msg = luaL_checkstring(ls, 1);take_note(Note(NOTE_MESSAGE, 0, 0, msg));return (0);}#define REGEX_METATABLE "crawl.regex"#define MESSF_METATABLE "crawl.messf"static int crawl_regex(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);text_pattern **tpudata =clua_new_userdata< text_pattern* >(ls, REGEX_METATABLE);if (tpudata){*tpudata = new text_pattern(s);return (1);}return (0);}static int crawl_regex_find(lua_State *ls){text_pattern **pattern =clua_get_userdata< text_pattern* >(ls, REGEX_METATABLE);if (!pattern)return (0);const char *text = luaL_checkstring(ls, -1);if (!text)return (0);lua_pushboolean(ls, (*pattern)->matches(text));return (1);}static const luaL_reg crawl_regex_ops[] ={{ "matches", crawl_regex_find },{ NULL, NULL }};static int crawl_message_filter(lua_State *ls){const char *pattern = luaL_checkstring(ls, 1);if (!pattern)return (0);int num = lua_isnumber(ls, 2)? luaL_checkint(ls, 2) : -1;message_filter **mf =clua_new_userdata< message_filter* >( ls, MESSF_METATABLE );if (mf){*mf = new message_filter( num, pattern );return (1);}return (0);}static int crawl_messf_matches(lua_State *ls){message_filter **mf =clua_get_userdata< message_filter* >(ls, MESSF_METATABLE);if (!mf)return (0);const char *pattern = luaL_checkstring(ls, 2);int ch = luaL_checkint(ls, 3);if (pattern){bool filt = (*mf)->is_filtered(ch, pattern);lua_pushboolean(ls, filt);return (1);}return (0);}static const luaL_reg crawl_messf_ops[] ={{ "matches", crawl_messf_matches },{ NULL, NULL }};static int crawl_trim(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);std::string text = s;trim_string(text);lua_pushstring(ls, text.c_str());return (1);}static int crawl_split(lua_State *ls){const char *s = luaL_checkstring(ls, 1),*token = luaL_checkstring(ls, 2);if (!s || !token)return (0);std::vector<std::string> segs = split_string(token, s);lua_newtable(ls);for (int i = 0, count = segs.size(); i < count; ++i){lua_pushstring(ls, segs[i].c_str());lua_rawseti(ls, -2, i + 1);}return (1);}static int _crawl_grammar(lua_State *ls){description_level_type ndesc = DESC_PLAIN;if (lua_isstring(ls, 2))ndesc = description_type_by_name(lua_tostring(ls, 2));PLUARET(string,thing_do_grammar(ndesc, false,false, luaL_checkstring(ls, 1)).c_str());}static int crawl_article_a(lua_State *ls){const char *s = luaL_checkstring(ls, 1);bool lowercase = true;if (lua_isboolean(ls, 2))lowercase = lua_toboolean(ls, 2);lua_pushstring(ls, article_a(s, lowercase).c_str());return (1);}LUARET1(crawl_game_started, boolean, crawl_state.need_save)LUARET1(crawl_random2, number, random2( luaL_checkint(ls, 1) ))LUARET1(crawl_one_chance_in, boolean, one_chance_in( luaL_checkint(ls, 1) ))LUARET1(crawl_random2avg, number,random2avg( luaL_checkint(ls, 1), luaL_checkint(ls, 2) ))LUARET1(crawl_random_range, number,random_range( luaL_checkint(ls, 1), luaL_checkint(ls, 2),lua_isnumber(ls, 3)? luaL_checkint(ls, 3) : 1 ))LUARET1(crawl_coinflip, boolean, coinflip())LUARET1(crawl_roll_dice, number,lua_gettop(ls) == 1? roll_dice( 1, luaL_checkint(ls, 1) ): roll_dice( luaL_checkint(ls, 1), luaL_checkint(ls, 2) ))static int crawl_random_element(lua_State *ls){const int table_idx = 1;const int value_idx = 2;if (lua_gettop(ls) == 0){lua_pushnil(ls);return 1;}// Only the first arg does anything now. Maybe this should// select from a variable number of table args?lua_pop(ls, lua_gettop(ls) - 1);// Keep max value on the stack, as it could be any type of value.lua_pushnil(ls);int rollsize = 0;lua_pushnil(ls);while (lua_next(ls, table_idx) != 0){const int weight_idx = -1;const int key_idx = -2;int this_weight = lua_isnil(ls, weight_idx) ?1 : (int)lua_tonumber(ls, weight_idx);if (rollsize > 0){rollsize += this_weight;if (x_chance_in_y(this_weight, rollsize)){lua_pushvalue(ls, key_idx);lua_replace(ls, value_idx);}}else{lua_pushvalue(ls, key_idx);lua_replace(ls, value_idx);rollsize = this_weight;}lua_pop(ls, 1);}lua_pushvalue(ls, value_idx);return 1;}static int crawl_err_trace(lua_State *ls){const int nargs = lua_gettop(ls);const int err = lua_pcall(ls, nargs - 1, LUA_MULTRET, 0);if (err){// This code from lua.c:traceback() (mostly)const char *errs = lua_tostring(ls, 1);std::string errstr = errs? errs : "";lua_getfield(ls, LUA_GLOBALSINDEX, "debug");if (!lua_istable(ls, -1)){lua_pop(ls, 1);return lua_error(ls);}lua_getfield(ls, -1, "traceback");if (!lua_isfunction(ls, -1)){lua_pop(ls, 2);return lua_error(ls);}lua_pushvalue(ls, 1);lua_pushinteger(ls, 2); // Skip crawl_err_trace and traceback.lua_call(ls, 2, 1);// What's on top should be the error.lua_error(ls);}return (lua_gettop(ls));}static const struct luaL_reg crawl_clib[] ={{ "mpr", crawl_mpr },{ "formatted_mpr", crawl_formatted_mpr },{ "more", crawl_more },{ "mesclr", crawl_mesclr },{ "random2", crawl_random2 },{ "one_chance_in", crawl_one_chance_in },{ "random2avg" , crawl_random2avg },{ "coinflip", crawl_coinflip },{ "roll_dice", crawl_roll_dice },{ "random_range", crawl_random_range },{ "random_element", crawl_random_element },{ "redraw_screen", crawl_redraw_screen },{ "input_line", crawl_input_line },{ "c_input_line", crawl_c_input_line},{ "getch", crawl_getch },{ "yesno", crawl_yesno },{ "yesnoquit", crawl_yesnoquit },{ "kbhit", crawl_kbhit },{ "flush_input", crawl_flush_input },{ "sendkeys", crawl_sendkeys },{ "process_command", crawl_process_command },{ "playsound", crawl_playsound },{ "runmacro", crawl_runmacro },{ "bindkey", crawl_bindkey },{ "setopt", crawl_setopt },{ "read_options", crawl_read_options },{ "msgch_num", crawl_msgch_num },{ "msgch_name", crawl_msgch_name },{ "take_note", crawl_take_note },{ "regex", crawl_regex },{ "message_filter", crawl_message_filter },{ "trim", crawl_trim },{ "split", crawl_split },{ "grammar", _crawl_grammar },{ "article_a", crawl_article_a },{ "game_started", crawl_game_started },{ "err_trace", crawl_err_trace },{ NULL, NULL },};void cluaopen_crawl(lua_State *ls){clua_register_metatable(ls, REGEX_METATABLE, crawl_regex_ops,lua_object_gc<text_pattern>);clua_register_metatable(ls, MESSF_METATABLE, crawl_messf_ops,lua_object_gc<message_filter>);luaL_openlib(ls, "crawl", crawl_clib, 0);}/////////////////////////////////////////////////////////////////////// Non-user-accessible bindings (dlua).//
void dluaopen_crawl(lua_State *ls){luaL_openlib(ls, "crawl", crawl_dlib, 0);}
luaL_openlib(dlua, "dgn", dgn_lib, 0);luaL_openlib(dlua, "dgn", dgn_build_lib, 0);luaL_openlib(dlua, "dgn", dgn_event_lib, 0);luaL_openlib(dlua, "dgn", dgn_grid_lib, 0);luaL_openlib(dlua, "dgn", dgn_item_lib, 0);luaL_openlib(dlua, "dgn", dgn_level_lib, 0);luaL_openlib(dlua, "dgn", dgn_mons_lib, 0);luaL_openlib(dlua, "dgn", dgn_tile_lib, 0);
dluaopen_crawl(dlua);luaL_openlib(dlua, "dgn", dgn_dlib, 0);luaL_openlib(dlua, "dgn", dgn_build_dlib, 0);luaL_openlib(dlua, "dgn", dgn_event_dlib, 0);luaL_openlib(dlua, "dgn", dgn_grid_dlib, 0);luaL_openlib(dlua, "dgn", dgn_item_dlib, 0);luaL_openlib(dlua, "dgn", dgn_level_dlib, 0);luaL_openlib(dlua, "dgn", dgn_mons_dlib, 0);luaL_openlib(dlua, "dgn", dgn_tile_dlib, 0);
luaL_openlib(dlua, "crawl", crawl_lib, 0);luaL_openlib(dlua, "debug", debug_lib, 0);luaL_openlib(dlua, "file", file_lib, 0);luaL_openlib(dlua, "you", you_lib, 0);luaL_openlib(dlua, "los", los_lib, 0);
luaL_openlib(dlua, "debug", debug_dlib, 0);luaL_openlib(dlua, "file", file_dlib, 0);luaL_openlib(dlua, "you", you_dlib, 0);luaL_openlib(dlua, "los", los_dlib, 0);
}/////////////////////////////////////////////////////////////////////// General game bindings.//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);int ch = MSGCH_PLAIN;if (lua_isnumber(ls, 2))ch = luaL_checkint(ls, 2);else{const char *channel = lua_tostring(ls, 2);if (channel)ch = str_to_channel(channel);}if (ch < 0 || ch >= NUM_MESSAGE_CHANNELS)ch = MSGCH_PLAIN;mpr(message, static_cast<msg_channel_type>(ch));return (0);}static int crawl_formatted_mpr(lua_State *ls){if (!crawl_state.io_inited)return (0);const char *message = luaL_checkstring(ls, 1);if (!message)return (0);int ch = MSGCH_PLAIN;if (lua_isnumber(ls, 2))ch = luaL_checkint(ls, 2);else{const char *channel = lua_tostring(ls, 2);if (channel)ch = str_to_channel(channel);}if (ch < 0 || ch >= NUM_MESSAGE_CHANNELS)ch = MSGCH_PLAIN;formatted_mpr(formatted_string::parse_string(message),static_cast<msg_channel_type>(ch));return (0);}LUAWRAP(crawl_more, more())LUAWRAP(crawl_mesclr, mesclr())LUAWRAP(crawl_redraw_screen, redraw_screen())static int crawl_input_line(lua_State *ls){// This is arbitrary, but anybody entering so many characters is psychotic.char linebuf[500];get_input_line(linebuf, sizeof linebuf);lua_pushstring(ls, linebuf);return (1);}static int crawl_c_input_line(lua_State *ls){char linebuf[500];bool valid = !cancelable_get_line(linebuf, sizeof linebuf);if (valid)lua_pushstring(ls, linebuf);elselua_pushnil(ls);return (1);}LUARET1(crawl_getch, number, getch())LUARET1(crawl_kbhit, number, kbhit())LUAWRAP(crawl_flush_input, flush_input_buffer(FLUSH_LUA))static char _lua_char(lua_State *ls, int ndx, char defval = 0){return (lua_isnone(ls, ndx) || !lua_isstring(ls, ndx)? defval: lua_tostring(ls, ndx)[0]);}static int crawl_yesno(lua_State *ls){const char *prompt = luaL_checkstring(ls, 1);const bool safe = lua_toboolean(ls, 2);const int safeanswer = _lua_char(ls, 3);const bool clear_after =lua_isnone(ls, 4) ? true : lua_toboolean(ls, 4);const bool interrupt_delays =lua_isnone(ls, 5) ? true : lua_toboolean(ls, 5);const bool noprompt =lua_isnone(ls, 6) ? false : lua_toboolean(ls, 6);cursor_control con(true);lua_pushboolean(ls, yesno(prompt, safe, safeanswer, clear_after,interrupt_delays, noprompt));return (1);}static int crawl_yesnoquit(lua_State *ls){const char *prompt = luaL_checkstring(ls, 1);const bool safe = lua_toboolean(ls, 2);const int safeanswer = _lua_char(ls, 3);const bool allow_all =lua_isnone(ls, 4) ? false : lua_toboolean(ls, 4);const bool clear_after =lua_isnone(ls, 5) ? true : lua_toboolean(ls, 5);// Skipping the other params until somebody needs them.cursor_control con(true);lua_pushnumber(ls, yesnoquit(prompt, safe, safeanswer, allow_all,clear_after));return (1);}static void crawl_sendkeys_proc(lua_State *ls, int argi){if (lua_isstring(ls, argi)){const char *keys = luaL_checkstring(ls, argi);if (!keys)return;for ( ; *keys; ++keys)macro_buf_add(*keys);}else if (lua_istable(ls, argi)){for (int i = 1; ; ++i){lua_rawgeti(ls, argi, i);if (lua_isnil(ls, -1)){lua_pop(ls, 1);return;}crawl_sendkeys_proc(ls, lua_gettop(ls));lua_pop(ls, 1);}}else if (lua_isnumber(ls, argi)){int key = luaL_checkint(ls, argi);macro_buf_add(key);}}static int crawl_sendkeys(lua_State *ls){int top = lua_gettop(ls);for (int i = 1; i <= top; ++i)crawl_sendkeys_proc(ls, i);return (0);}// Tell Crawl to process one command.static int crawl_process_command(lua_State *ls){const bool will_process =current_delay_action() == DELAY_MACRO || !you_are_delayed();if (will_process){// This should only be called from a macro delay, but run_macro// may not have started the macro delay; do so now.if (!you_are_delayed())start_delay(DELAY_MACRO, 1);start_delay(DELAY_MACRO_PROCESS_KEY, 1);}lua_pushboolean(ls, will_process);return (1);}static int crawl_playsound(lua_State *ls){const char *sf = luaL_checkstring(ls, 1);if (!sf)return (0);play_sound(sf);return (0);}static int crawl_runmacro(lua_State *ls){const char *macroname = luaL_checkstring(ls, 1);if (!macroname)return (0);run_macro(macroname);return (0);
const char *s = lua_tostring(ls, 1);if (s){// Note that the conditional script can contain nested Lua[ ]Lua code.read_options(s, true);}return (0);}static int crawl_read_options(lua_State *ls){if (!lua_isstring(ls, 1))return (0);const char* filename = lua_tostring(ls, 1);Options.include(filename, true, true);return (0);}static int crawl_bindkey(lua_State *ls){const char *s = NULL;if (lua_isstring(ls, 1)){s = lua_tostring(ls, 1);}if (!s || !lua_isfunction(ls, 2) || lua_gettop(ls) != 2)return (0);lua_pushvalue(ls, 2);std::string name = clua.setuniqregistry();if (lua_gettop(ls) != 2){fprintf(stderr, "Stack top has changed!\n");lua_settop(ls, 2);}macro_userfn(s, name.c_str());return (0);}static int crawl_msgch_num(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);int ch = str_to_channel(s);if (ch == -1)return (0);lua_pushnumber(ls, ch);return (1);}static int crawl_msgch_name(lua_State *ls){int num = luaL_checkint(ls, 1);std::string name = channel_to_str(num);lua_pushstring(ls, name.c_str());return (1);}static int crawl_take_note(lua_State *ls){const char* msg = luaL_checkstring(ls, 1);take_note(Note(NOTE_MESSAGE, 0, 0, msg));return (0);}#define REGEX_METATABLE "crawl.regex"#define MESSF_METATABLE "crawl.messf"static int crawl_regex(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);text_pattern **tpudata =clua_new_userdata< text_pattern* >(ls, REGEX_METATABLE);if (tpudata){*tpudata = new text_pattern(s);return (1);}return (0);}static int crawl_regex_find(lua_State *ls){text_pattern **pattern =clua_get_userdata< text_pattern* >(ls, REGEX_METATABLE);if (!pattern)return (0);const char *text = luaL_checkstring(ls, -1);if (!text)return (0);lua_pushboolean(ls, (*pattern)->matches(text));return (1);}static const luaL_reg crawl_regex_ops[] ={{ "matches", crawl_regex_find },{ NULL, NULL }};static int crawl_message_filter(lua_State *ls){const char *pattern = luaL_checkstring(ls, 1);if (!pattern)return (0);int num = lua_isnumber(ls, 2)? luaL_checkint(ls, 2) : -1;message_filter **mf =clua_new_userdata< message_filter* >( ls, MESSF_METATABLE );if (mf){*mf = new message_filter( num, pattern );return (1);}return (0);}static int crawl_messf_matches(lua_State *ls){message_filter **mf =clua_get_userdata< message_filter* >(ls, MESSF_METATABLE);if (!mf)return (0);const char *pattern = luaL_checkstring(ls, 2);int ch = luaL_checkint(ls, 3);if (pattern){bool filt = (*mf)->is_filtered(ch, pattern);lua_pushboolean(ls, filt);return (1);}return (0);}static const luaL_reg crawl_messf_ops[] ={{ "matches", crawl_messf_matches },{ NULL, NULL }};static int crawl_trim(lua_State *ls){const char *s = luaL_checkstring(ls, 1);if (!s)return (0);std::string text = s;trim_string(text);lua_pushstring(ls, text.c_str());return (1);}static int crawl_split(lua_State *ls){const char *s = luaL_checkstring(ls, 1),*token = luaL_checkstring(ls, 2);if (!s || !token)return (0);std::vector<std::string> segs = split_string(token, s);lua_newtable(ls);for (int i = 0, count = segs.size(); i < count; ++i){lua_pushstring(ls, segs[i].c_str());lua_rawseti(ls, -2, i + 1);}return (1);}static int _crawl_grammar(lua_State *ls){description_level_type ndesc = DESC_PLAIN;if (lua_isstring(ls, 2))ndesc = description_type_by_name(lua_tostring(ls, 2));PLUARET(string,thing_do_grammar(ndesc, false,false, luaL_checkstring(ls, 1)).c_str());}static int crawl_article_a(lua_State *ls){const char *s = luaL_checkstring(ls, 1);bool lowercase = true;if (lua_isboolean(ls, 2))lowercase = lua_toboolean(ls, 2);lua_pushstring(ls, article_a(s, lowercase).c_str());return (1);}LUARET1(crawl_game_started, boolean, crawl_state.need_save)LUARET1(crawl_random2, number, random2( luaL_checkint(ls, 1) ))LUARET1(crawl_one_chance_in, boolean, one_chance_in( luaL_checkint(ls, 1) ))LUARET1(crawl_random2avg, number,random2avg( luaL_checkint(ls, 1), luaL_checkint(ls, 2) ))LUARET1(crawl_random_range, number,random_range( luaL_checkint(ls, 1), luaL_checkint(ls, 2),lua_isnumber(ls, 3)? luaL_checkint(ls, 3) : 1 ))LUARET1(crawl_coinflip, boolean, coinflip())LUARET1(crawl_roll_dice, number,lua_gettop(ls) == 1? roll_dice( 1, luaL_checkint(ls, 1) ): roll_dice( luaL_checkint(ls, 1), luaL_checkint(ls, 2) ))static int crawl_random_element(lua_State *ls){const int table_idx = 1;const int value_idx = 2;if (lua_gettop(ls) == 0){lua_pushnil(ls);return 1;}// Only the first arg does anything now. Maybe this should// select from a variable number of table args?lua_pop(ls, lua_gettop(ls) - 1);// Keep max value on the stack, as it could be any type of value.lua_pushnil(ls);int rollsize = 0;lua_pushnil(ls);while (lua_next(ls, table_idx) != 0){const int weight_idx = -1;const int key_idx = -2;int this_weight = lua_isnil(ls, weight_idx) ?1 : (int)lua_tonumber(ls, weight_idx);if (rollsize > 0){rollsize += this_weight;if (x_chance_in_y(this_weight, rollsize)){lua_pushvalue(ls, key_idx);lua_replace(ls, value_idx);}}else{lua_pushvalue(ls, key_idx);lua_replace(ls, value_idx);rollsize = this_weight;}lua_pop(ls, 1);}lua_pushvalue(ls, value_idx);return 1;}static int crawl_err_trace(lua_State *ls){const int nargs = lua_gettop(ls);const int err = lua_pcall(ls, nargs - 1, LUA_MULTRET, 0);if (err){// This code from lua.c:traceback() (mostly)const char *errs = lua_tostring(ls, 1);std::string errstr = errs? errs : "";lua_getfield(ls, LUA_GLOBALSINDEX, "debug");if (!lua_istable(ls, -1)){lua_pop(ls, 1);return lua_error(ls);}lua_getfield(ls, -1, "traceback");if (!lua_isfunction(ls, -1)){lua_pop(ls, 2);return lua_error(ls);}lua_pushvalue(ls, 1);lua_pushinteger(ls, 2); // Skip crawl_err_trace and traceback.lua_call(ls, 2, 1);// What's on top should be the error.lua_error(ls);}return (lua_gettop(ls));}static const struct luaL_reg crawl_lib[] ={{ "mpr", crawl_mpr },{ "formatted_mpr", crawl_formatted_mpr },{ "more", crawl_more },{ "mesclr", crawl_mesclr },{ "random2", crawl_random2 },{ "one_chance_in", crawl_one_chance_in },{ "random2avg" , crawl_random2avg },{ "coinflip", crawl_coinflip },{ "roll_dice", crawl_roll_dice },{ "random_range", crawl_random_range },{ "random_element", crawl_random_element },{ "redraw_screen", crawl_redraw_screen },{ "input_line", crawl_input_line },{ "c_input_line", crawl_c_input_line},{ "getch", crawl_getch },{ "yesno", crawl_yesno },{ "yesnoquit", crawl_yesnoquit },{ "kbhit", crawl_kbhit },{ "flush_input", crawl_flush_input },{ "sendkeys", crawl_sendkeys },{ "process_command", crawl_process_command },{ "playsound", crawl_playsound },{ "runmacro", crawl_runmacro },{ "bindkey", crawl_bindkey },{ "setopt", crawl_setopt },{ "read_options", crawl_read_options },{ "msgch_num", crawl_msgch_num },{ "msgch_name", crawl_msgch_name },{ "take_note", crawl_take_note },{ "regex", crawl_regex },{ "message_filter", crawl_message_filter },{ "trim", crawl_trim },{ "split", crawl_split },{ "grammar", _crawl_grammar },{ "article_a", crawl_article_a },{ "game_started", crawl_game_started },{ "err_trace", crawl_err_trace },{ NULL, NULL },};void luaopen_crawl(lua_State *ls){clua_register_metatable(ls, REGEX_METATABLE, crawl_regex_ops,lua_object_gc<text_pattern>);clua_register_metatable(ls, MESSF_METATABLE, crawl_messf_ops,lua_object_gc<message_filter>);luaL_openlib(ls, "crawl", crawl_lib, 0);}