diff options
Diffstat (limited to 'stone_soup/crawl-ref/source/clua.cc')
-rw-r--r-- | stone_soup/crawl-ref/source/clua.cc | 2301 |
1 files changed, 0 insertions, 2301 deletions
diff --git a/stone_soup/crawl-ref/source/clua.cc b/stone_soup/crawl-ref/source/clua.cc deleted file mode 100644 index 41e703c2b0..0000000000 --- a/stone_soup/crawl-ref/source/clua.cc +++ /dev/null @@ -1,2301 +0,0 @@ -#include "AppHdr.h" - -#ifdef CLUA_BINDINGS - -#include "clua.h" - -#include "abl-show.h" -#include "command.h" -#include "chardump.h" -#include "food.h" -#include "invent.h" -#include "initfile.h" -#include "itemname.h" -#include "itemprop.h" -#include "items.h" -#include "item_use.h" -#include "libutil.h" -#include "macro.h" -#include "message.h" -#include "mon-util.h" -#include "output.h" -#include "player.h" -#include "randart.h" -#include "skills2.h" -#include "spl-util.h" -#include "stuff.h" -#include "wpn-misc.h" - -#include <cstring> - -#ifdef HASH_CONTAINERS -# include <hash_map> -# define CHMAP HASH_CONTAINER_NS::hash_map -#else -# include <map> -# define CHMAP std::map -#endif - -#include <cctype> - -#define CL_RESETSTACK_RETURN(ls, oldtop, retval) \ - if (true) {\ - if (oldtop != lua_gettop(ls)) { \ - lua_settop(ls, oldtop); \ - } \ - return (retval); \ - } \ - else - -CLua clua; - -CLua::CLua() : _state(NULL), sourced_files(), uniqindex(0L) -{ -} - -CLua::~CLua() -{ - if (_state) - lua_close(_state); -} - -// This has the disadvantage of repeatedly trying init_lua if it fails. -lua_State *CLua::state() -{ - if (!_state) - init_lua(); - return _state; -} - -void CLua::setglobal(const char *name) -{ - lua_setglobal(state(), name); -} - -void CLua::getglobal(const char *name) -{ - lua_getglobal(state(), name); -} - -std::string CLua::setuniqregistry() -{ - char name[100]; - snprintf(name, sizeof name, "__cru%lu", uniqindex++); - lua_pushstring(state(), name); - lua_insert(state(), -2); - lua_settable(state(), LUA_REGISTRYINDEX); - - return (name); -} - -void CLua::setregistry(const char *name) -{ - lua_pushstring(state(), name); - // Slide name round before the value - lua_insert(state(), -2); - lua_settable(state(), LUA_REGISTRYINDEX); -} - -void CLua::getregistry(const char *name) -{ - lua_pushstring(state(), name); - lua_gettable(state(), LUA_REGISTRYINDEX); -} - -void CLua::save(const char *file) -{ - if (!_state) - return; - - CLuaSave clsave = { file, NULL }; - callfn("c_save", "u", &clsave); - if (clsave.handle) - fclose(clsave.handle); -} - -int CLua::file_write(lua_State *ls) -{ - if (!lua_islightuserdata(ls, 1)) - { - luaL_argerror(ls, 1, "Expected filehandle at arg 1"); - return (0); - } - CLuaSave *sf = static_cast<CLuaSave *>( lua_touserdata(ls, 1) ); - if (!sf) - return (0); - - FILE *f = sf->get_file(); - if (!f) - return (0); - - const char *text = luaL_checkstring(ls, 2); - if (text) - fprintf(f, "%s", text); - return (0); -} - -FILE *CLua::CLuaSave::get_file() -{ - if (!handle) - handle = fopen(filename, "w"); - - return (handle); -} - -void CLua::set_error(int err, lua_State *ls) -{ - if (!err) - { - error.clear(); - return; - } - if (!ls && !(ls = _state)) - { - error = "<LUA not initialized>"; - return; - } - const char *serr = lua_tostring(ls, -1); - lua_pop(ls, 1); - error = serr? serr : "<Unknown error>"; -} - -int CLua::execstring(const char *s, const char *context) -{ - lua_State *ls = state(); - int err = luaL_loadbuffer(ls, s, strlen(s), context); - if (err) - { - set_error(err, ls); - return err; - } - err = lua_pcall(ls, 0, 0, 0); - set_error(err, ls); - return err; -} - -int CLua::execfile(const char *filename) -{ - if (sourced_files.find(filename) != sourced_files.end()) - return 0; - - sourced_files.insert(filename); - - FILE *f = fopen(filename, "r"); - if (f) - fclose(f); - else - { - error = std::string("Can't read ") + filename; - return -1; - } - - lua_State *ls = state(); - if (!ls) - return -1; - - int err = luaL_loadfile(ls, filename); - if (!err) - err = lua_pcall(ls, 0, 0, 0); - set_error(err); - return (err); -} - -bool CLua::runhook(const char *hook, const char *params, ...) -{ - error.clear(); - - lua_State *ls = state(); - if (!ls) - return (false); - - // Remember top of stack, for debugging porpoises - int stack_top = lua_gettop(ls); - lua_getglobal(ls, hook); - if (!lua_istable(ls, -1)) - { - lua_pop(ls, 1); - CL_RESETSTACK_RETURN( ls, stack_top, false ); - } - for (int i = 1; ; ++i) - { - int currtop = lua_gettop(ls); - lua_rawgeti(ls, -1, i); - if (!lua_isfunction(ls, -1)) - { - lua_pop(ls, 1); - break; - } - - // So what's on top *is* a function. Call it with the args we have. - va_list args; - va_start(args, params); - calltopfn(ls, params, args); - va_end(args); - - lua_settop(ls, currtop); - } - CL_RESETSTACK_RETURN( ls, stack_top, true ); -} - -void CLua::fnreturns(const char *format, ...) -{ - lua_State *ls = _state; - - if (!format || !ls) - return; - - va_list args; - va_start(args, format); - - vfnreturns(format, args); - - va_end(args); -} - -void CLua::vfnreturns(const char *format, va_list args) -{ - lua_State *ls = _state; - int nrets = return_count(ls, format); - int sp = -nrets - 1; - - const char *gs = strchr(format, '>'); - if (gs) - format = gs + 1; - else if ((gs = strchr(format, ':'))) - format = gs + 1; - - for (const char *run = format; *run; ++run) - { - char argtype = *run; - ++sp; - switch (argtype) - { - case 'u': - if (lua_islightuserdata(ls, sp)) - *(va_arg(args, void**)) = lua_touserdata(ls, sp); - break; - case 'd': - if (lua_isnumber(ls, sp)) - *(va_arg(args, int*)) = luaL_checkint(ls, sp); - break; - case 'b': - *(va_arg(args, bool *)) = lua_toboolean(ls, sp); - break; - case 's': - { - const char *s = lua_tostring(ls, sp); - if (s) - *(va_arg(args, std::string *)) = s; - break; - } - default: - break; - } - - } - // Pop args off the stack - lua_pop(ls, nrets); -} - -static void push_monster(lua_State *ls, monsters *mons); -static int push_activity_interrupt(lua_State *ls, activity_interrupt_data *t); -int CLua::push_args(lua_State *ls, const char *format, va_list args, - va_list *targ) -{ - if (!format) - { - if (targ) - va_copy(*targ, args); - return (0); - } - - const char *cs = strchr(format, ':'); - if (cs) - format = cs + 1; - - int argc = 0; - for (const char *run = format; *run; run++) { - if (*run == '>') - break; - - char argtype = *run; - ++argc; - switch (argtype) { - case 'u': // Light userdata - lua_pushlightuserdata(ls, va_arg(args, void*)); - break; - case 's': // String - { - const char *s = va_arg(args, const char *); - if (s) - lua_pushstring(ls, s); - else - lua_pushnil(ls); - break; - } - case 'd': // Integer - lua_pushnumber(ls, va_arg(args, int)); - break; - case 'L': - lua_pushnumber(ls, va_arg(args, long)); - break; - case 'b': - lua_pushboolean(ls, va_arg(args, int)); - break; - case 'M': - push_monster(ls, va_arg(args, monsters *)); - break; - case 'A': - argc += push_activity_interrupt( - ls, va_arg(args, activity_interrupt_data *)); - break; - default: - --argc; - break; - } - } - if (targ) - va_copy(*targ, args); - return (argc); -} - -int CLua::return_count(lua_State *ls, const char *format) -{ - if (!format) - return (0); - - const char *gs = strchr(format, '>'); - if (gs) - return (strlen(gs + 1)); - - const char *cs = strchr(format, ':'); - if (cs && isdigit(*format)) - { - char *es = NULL; - int ci = strtol(format, &es, 10); - // We're capping return at 10 here, which is arbitrary, but avoids - // blowing the stack. - if (ci < 0) - ci = 0; - else if (ci > 5) - ci = 10; - return (ci); - } - return (0); -} - -bool CLua::calltopfn(lua_State *ls, const char *params, va_list args, - int retc, va_list *copyto) -{ - // We guarantee to remove the function from the stack - int argc = push_args(ls, params, args, copyto); - if (retc == -1) - retc = return_count(ls, params); - int err = lua_pcall(ls, argc, retc, 0); - set_error(err, ls); - return (!err); -} - -bool CLua::callbooleanfn(bool def, const char *fn, const char *params, ...) -{ - error.clear(); - lua_State *ls = state(); - if (!ls) - return (def); - - int stacktop = lua_gettop(ls); - - lua_getglobal(ls, fn); - if (!lua_isfunction(ls, -1)) - { - lua_pop(ls, 1); - CL_RESETSTACK_RETURN(ls, stacktop, def); - } - - va_list args; - va_start(args, params); - bool ret = calltopfn(ls, params, args, 1); - if (!ret) - CL_RESETSTACK_RETURN(ls, stacktop, def); - - def = lua_toboolean(ls, -1); - CL_RESETSTACK_RETURN(ls, stacktop, def); -} - -bool CLua::proc_returns(const char *par) const -{ - return (strchr(par, '>') != NULL); -} - -bool CLua::callfn(const char *fn, const char *params, ...) -{ - error.clear(); - lua_State *ls = state(); - if (!ls) - return (false); - - lua_getglobal(ls, fn); - if (!lua_isfunction(ls, -1)) - { - lua_pop(ls, 1); - return (false); - } - - va_list args; - va_list fnret; - va_start(args, params); - bool ret = calltopfn(ls, params, args, -1, &fnret); - if (ret) - { - // If we have a > in format, gather return params now. - if (proc_returns(params)) - vfnreturns(params, fnret); - } - va_end(args); - va_end(fnret); - return (ret); -} - -bool CLua::callfn(const char *fn, int nargs, int nret) -{ - error.clear(); - lua_State *ls = state(); - if (!ls) - return (false); - - lua_getglobal(ls, fn); - if (!lua_isfunction(ls, -1)) - { - lua_settop(ls, -nargs - 2); - return (false); - } - - // Slide the function in front of its args and call it. - if (nargs) - lua_insert(ls, -nargs - 1); - int err = lua_pcall(ls, nargs, nret, 0); - set_error(err, ls); - return !err; -} - -// Defined in Kills.cc because the kill bindings refer to Kills.cc local -// structs -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); - - -void CLua::init_lua() -{ - if (_state) - return; - - _state = lua_open(); - if (!_state) - return; - luaopen_base(_state); - luaopen_string(_state); - luaopen_table(_state); - - // Open Crawl bindings - 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); - - lua_open_globals(_state); - - load_cmacro(); - load_chooks(); -} - -void CLua::load_chooks() -{ - // All hook names must be chk_???? - static const char *c_hooks = - "chk_startgame = { }" - ; - execstring(c_hooks, "base"); -} - -void CLua::load_cmacro() -{ - static const char *c_macro = - "function c_macro(fn)" - " if fn == nil then" - " if c_macro_coroutine ~= nil then" - " local coret, mret" - " coret, mret = coroutine.resume(c_macro_coroutine)" - " if not coret or not mret then" - " c_macro_coroutine = nil" - " c_macro_name = nil" - " end" - " if not coret and mret then" - " error(mret)" - " end" - " return (coret and mret)" - " end" - " return false" - " end" - " if _G[fn] == nil or type(_G[fn]) ~= 'function' then" - " return false" - " end" - " c_macro_name = fn" - " c_macro_coroutine = coroutine.create(_G[fn]) " - " return c_macro() " - "end"; - execstring(c_macro, "base"); -} - -///////////////////////////////////////////////////////////////////// - -#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 ) ); -} - -static void clua_register_metatable(lua_State *ls, const char *tn, - const luaL_reg *lr, - int (*gcfn)(lua_State *ls) = NULL) -{ - int top = lua_gettop(ls); - - luaL_newmetatable(ls, tn); - lua_pushstring(ls, "__index"); - lua_pushvalue(ls, -2); - lua_settable(ls, -3); - - if (gcfn) - { - lua_pushstring(ls, "__gc"); - lua_pushcfunction(ls, gcfn); - lua_settable(ls, -3); - } - - luaL_openlib(ls, NULL, lr, 0); - - lua_settop(ls, top); -} - -template <class T> T *clua_new_userdata( - lua_State *ls, const char *mt) -{ - void *udata = lua_newuserdata( ls, sizeof(T) ); - luaL_getmetatable(ls, mt); - lua_setmetatable(ls, -2); - return static_cast<T*>( udata ); -} - -///////////////////////////////////////////////////////////////////// -// Bindings to get information on the player -// - -static const char *transform_name() -{ - switch (you.attribute[ATTR_TRANSFORMATION]) - { - case TRAN_SPIDER: - return "spider"; - case TRAN_BLADE_HANDS: - return "blade"; - case TRAN_STATUE: - return "statue"; - case TRAN_ICE_BEAST: - return "ice"; - case TRAN_DRAGON: - return "dragon"; - case TRAN_LICH: - return "lich"; - case TRAN_SERPENT_OF_HELL: - return "serpent"; - case TRAN_AIR: - return "air"; - default: - return ""; - } -} - -LUARET1(you_turn_is_over, boolean, you.turn_is_over) -LUARET1(you_name, string, you.your_name) -LUARET1(you_race, string, species_name(you.species, you.experience_level)) -LUARET1(you_class, string, get_class_name(you.char_class)) -LUARET2(you_hp, number, you.hp, you.hp_max) -LUARET2(you_mp, number, you.magic_points, you.max_magic_points) -LUARET1(you_hunger, string, hunger_level()) -LUARET2(you_strength, number, you.strength, you.max_strength) -LUARET2(you_intelligence, number, you.intel, you.max_intel) -LUARET2(you_dexterity, number, you.dex, you.max_dex) -LUARET1(you_exp, number, you.experience_level) -LUARET1(you_exp_points, number, you.experience) -LUARET1(you_res_poison, number, player_res_poison(false)) -LUARET1(you_res_fire, number, player_res_fire(false)) -LUARET1(you_res_cold, number, player_res_cold(false)) -LUARET1(you_res_draining, number, player_prot_life(false)) -LUARET1(you_res_shock, number, player_res_electricity(false)) -LUARET1(you_res_statdrain, number, player_sust_abil(false)) -LUARET1(you_res_mutation, number, wearing_amulet(AMU_RESIST_MUTATION, false)) -LUARET1(you_res_slowing, number, wearing_amulet(AMU_RESIST_SLOW, false)) -LUARET1(you_gourmand, boolean, wearing_amulet(AMU_THE_GOURMAND, false)) -LUARET1(you_levitating, boolean, - player_is_levitating() && !wearing_amulet(AMU_CONTROLLED_FLIGHT)) -LUARET1(you_flying, boolean, - player_is_levitating() && wearing_amulet(AMU_CONTROLLED_FLIGHT)) -LUARET1(you_transform, string, transform_name()) -LUAWRAP(you_stop_activity, interrupt_activity(AI_FORCE_INTERRUPT)) - -void lua_push_floor_items(lua_State *ls); -static int you_floor_items(lua_State *ls) -{ - lua_push_floor_items(ls); - return (1); -} - -static int l_you_spells(lua_State *ls) -{ - lua_newtable(ls); - int index = 0; - for (int i = 0; i < 52; ++i) - { - const int spell = get_spell_by_letter( index_to_letter(i) ); - if (spell == SPELL_NO_SPELL) - continue; - - lua_pushstring(ls, spell_title(spell)); - lua_rawseti(ls, -2, ++index); - } - return (1); -} - -static int l_you_abils(lua_State *ls) -{ - lua_newtable(ls); - - std::vector<const char *>abils = get_ability_names(); - for (int i = 0, size = abils.size(); i < size; ++i) - { - lua_pushstring(ls, abils[i]); - lua_rawseti(ls, -2, i + 1); - } - return (1); -} - -static const struct luaL_reg you_lib[] = -{ - { "turn_is_over", you_turn_is_over }, - { "spells" , l_you_spells }, - { "abilities" , l_you_abils }, - { "name" , you_name }, - { "race" , you_race }, - { "class" , you_class }, - { "hp" , you_hp }, - { "mp" , you_mp }, - { "hunger" , you_hunger }, - { "strength" , you_strength }, - { "intelligence", you_intelligence }, - { "dexterity" , you_dexterity }, - { "exp" , you_exp }, - { "exp_points" , you_exp_points }, - - { "res_poison" , you_res_poison }, - { "res_fire" , you_res_fire }, - { "res_cold" , you_res_cold }, - { "res_draining", you_res_draining }, - { "res_shock" , you_res_shock }, - { "res_statdrain", you_res_statdrain }, - { "res_mutation", you_res_mutation }, - { "res_slowing", you_res_slowing }, - { "gourmand", you_gourmand }, - { "levitating", you_levitating }, - { "flying", you_flying }, - { "transform", you_transform }, - - { "stop_activity", you_stop_activity }, - - { "floor_items", you_floor_items }, - { NULL, NULL }, -}; - -void lua_open_you(lua_State *ls) -{ - luaL_openlib(ls, "you", you_lib, 0); -} - -///////////////////////////////////////////////////////////////////// -// Bindings to get information on items. We must be extremely careful -// to only hand out information the player already has. -// - -static const item_def *excl_item = NULL; - -#define LUA_ITEM(name, n) \ - if (!lua_islightuserdata(ls, n)) \ - { \ - luaL_argerror(ls, n, "Unexpected arg type"); \ - return (0); \ - } \ - \ - item_def *name = static_cast<item_def *>( lua_touserdata(ls, n ) ); \ - if (excl_item && name != excl_item) \ - { \ - luaL_argerror(ls, n, "Unexpected item"); \ - return (0); \ - } - -void lua_push_inv_items(lua_State *ls); - -void lua_set_exclusive_item(const item_def *item) -{ - excl_item = item; -} - -static int l_item_inventory(lua_State *ls) -{ - lua_push_inv_items(ls); - return (1); -} - -static int l_item_index_to_letter(lua_State *ls) -{ - int index = luaL_checkint(ls, 1); - char sletter[2] = "?"; - if (index >= 0 && index <= ENDOFPACK) - *sletter = index_to_letter(index); - lua_pushstring(ls, sletter); - return (1); -} - -static int l_item_letter_to_index(lua_State *ls) -{ - const char *s = luaL_checkstring(ls, 1); - if (!s || !*s || s[1]) - return (0); - lua_pushnumber(ls, letter_to_index(*s)); - return (1); -} - -static int l_item_swap_slots(lua_State *ls) -{ - int slot1 = luaL_checkint(ls, 1), - slot2 = luaL_checkint(ls, 2); - bool verbose = lua_toboolean(ls, 3); - if (slot1 < 0 || slot1 >= ENDOFPACK || - slot2 < 0 || slot2 >= ENDOFPACK || - slot1 == slot2 || !is_valid_item(you.inv[slot1])) - return (0); - - swap_inv_slots(slot1, slot2, verbose); - - return (0); -} - -static int l_item_wield(lua_State *ls) -{ - if (you.turn_is_over) - return (0); - - LUA_ITEM(item, 1); - int slot = -1; - if (item && is_valid_item(*item) && in_inventory(*item)) - slot = item->link; - bool res = wield_weapon(true, slot); - lua_pushboolean(ls, res); - return (1); -} - -static int l_item_wear(lua_State *ls) -{ - if (you.turn_is_over) - return (0); - - LUA_ITEM(item, 1); - if (!item || !in_inventory(*item)) - return (0); - - bool success = do_wear_armour(item->link, false); - lua_pushboolean(ls, success); - return (1); -} - -static int l_item_puton(lua_State *ls) -{ - if (you.turn_is_over) - return (0); - - LUA_ITEM(item, 1); - if (!item || !in_inventory(*item)) - return (0); - - lua_pushboolean(ls, puton_ring(item->link, false)); - return (1); -} - -static int l_item_remove(lua_State *ls) -{ - if (you.turn_is_over) - { - mpr("Turn is over"); - return (0); - } - - LUA_ITEM(item, 1); - if (!item || !in_inventory(*item)) - { - mpr("Bad item"); - return (0); - } - - int eq = get_equip_slot(item); - if (eq < 0 || eq >= NUM_EQUIP) - { - mpr("Item is not equipped"); - return (0); - } - - bool result = false; - if (eq == EQ_WEAPON) - result = wield_weapon(true, -1); - else if (eq == EQ_LEFT_RING || eq == EQ_RIGHT_RING || eq == EQ_AMULET) - result = remove_ring(item->link); - else - result = takeoff_armour(item->link); - lua_pushboolean(ls, result); - return (1); -} - -static int l_item_drop(lua_State *ls) -{ - if (you.turn_is_over) - return (0); - - LUA_ITEM(item, 1); - if (!item || !in_inventory(*item)) - return (0); - - int eq = get_equip_slot(item); - if (eq >= 0 && eq < NUM_EQUIP) - { - lua_pushboolean(ls, false); - lua_pushstring(ls, "Can't drop worn items"); - return (2); - } - - int qty = item->quantity; - if (lua_isnumber(ls, 2)) - { - int q = luaL_checkint(ls, 2); - if (q >= 1 && q <= item->quantity) - qty = q; - } - lua_pushboolean(ls, drop_item(item->link, qty)); - return (1); -} - -static int item_on_floor(const item_def &item, int x, int y); - -static item_def *dmx_get_item(lua_State *ls, int ndx, int subndx) -{ - if (lua_istable(ls, ndx)) - { - lua_rawgeti(ls, ndx, subndx); - item_def *item = util_get_userdata<item_def>(ls, -1); - lua_pop(ls, 1); - - return (item); - } - return util_get_userdata<item_def>(ls, ndx); -} - -static int dmx_get_qty(lua_State *ls, int ndx, int subndx) -{ - int qty = -1; - if (lua_istable(ls, ndx)) - { - lua_rawgeti(ls, ndx, subndx); - if (lua_isnumber(ls, -1)) - qty = luaL_checkint(ls, -1); - lua_pop(ls, 1); - } - else if (lua_isnumber(ls, ndx)) - { - qty = luaL_checkint(ls, ndx); - } - return (qty); -} - -static bool l_item_pickup2(item_def *item, int qty) -{ - if (!item || in_inventory(*item)) - return (false); - - int floor_link = item_on_floor(*item, you.x_pos, you.y_pos); - if (floor_link == NON_ITEM) - return (false); - - return pickup_single_item(floor_link, qty); -} - -static int l_item_pickup(lua_State *ls) -{ - if (you.turn_is_over) - return (0); - - if (lua_islightuserdata(ls, 1)) - { - LUA_ITEM(item, 1); - int qty = item->quantity; - if (lua_isnumber(ls, 2)) - qty = luaL_checkint(ls, 2); - - if (l_item_pickup2(item, qty)) - lua_pushnumber(ls, 1); - else - lua_pushnil(ls); - return (1); - } - else if (lua_istable(ls, 1)) - { - int dropped = 0; - for (int i = 1; ; ++i) - { - lua_rawgeti(ls, 1, i); - item_def *item = dmx_get_item(ls, -1, 1); - int qty = dmx_get_qty(ls, -1, 2); - lua_pop(ls, 1); - - if (l_item_pickup2(item, qty)) - dropped++; - else - { - // Yes, we bail out on first failure. - break; - } - } - if (dropped) - lua_pushnumber(ls, dropped); - else - lua_pushnil(ls); - return (1); - } - return (0); -} - -static int l_item_equipped(lua_State *ls) -{ - int eq = -1; - if (lua_isnumber(ls, 1)) - eq = luaL_checkint(ls, 1); - else if (lua_isstring(ls, 1)) - { - const char *eqname = lua_tostring(ls, 1); - if (!eqname) - return (0); - eq = equip_name_to_slot(eqname); - } - - if (eq < 0 || eq >= NUM_EQUIP) - return (0); - - if (you.equip[eq] != -1) - lua_pushlightuserdata(ls, &you.inv[you.equip[eq]]); - else - lua_pushnil(ls); - - return (1); -} - -static int l_item_class(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (item) - { - bool terse = false; - if (lua_isboolean(ls, 2)) - terse = lua_toboolean(ls, 2); - - std::string s = item_class_name(item->base_type, terse); - lua_pushstring(ls, s.c_str()); - } - else - lua_pushnil(ls); - return (1); -} - -// FIXME: Fold this back into itemname.cc. -static const char *ring_types[] = { - "regeneration", - "protection", - "protection from fire", - "poison resistance", - "protection from cold", - "strength", - "slaying", - "see invisible", - "invisibility", - "hunger", - "teleportation", - "evasion", - "sustain abilities", - "sustenance", - "dexterity", - "intelligence", - "wizardry", - "magical power", - "levitation", - "life protection", - "protection from magic", - "fire", - "ice", - "teleport control", -}; - -static const char *amulet_types[] = { - "rage", "resist slowing", "clarity", "warding", "resist corrosion", - "gourmand", "conservation", "controlled flight", "inaccuracy", - "resist mutation" -}; - -static int l_item_subtype(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (item) - { - if (item_type_known(*item)) - { - const char *s = NULL; - if (item->base_type == OBJ_JEWELLERY) - { - if (item->sub_type < AMU_RAGE) - s = ring_types[item->sub_type]; - else - s = amulet_types[ item->sub_type - AMU_RAGE ]; - } - - if (s) - lua_pushstring(ls, s); - else - lua_pushnil(ls); - - lua_pushnumber(ls, item->sub_type); - return (2); - } - } - - lua_pushnil(ls); - lua_pushnil(ls); - return (2); -} - -static int l_item_cursed(lua_State *ls) -{ - LUA_ITEM(item, 1); - bool cursed = item && item_ident(*item, ISFLAG_KNOW_CURSE) - && item_cursed(*item); - lua_pushboolean(ls, cursed); - return (1); -} - - -static int l_item_worn(lua_State *ls) -{ - LUA_ITEM(item, 1); - int worn = get_equip_slot(item); - if (worn != -1) - lua_pushnumber(ls, worn); - else - lua_pushnil(ls); - if (worn != -1) - lua_pushstring(ls, equip_slot_to_name(worn)); - else - lua_pushnil(ls); - return (2); -} - -static int 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; -} - -static int l_item_name(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (item) - { - int ndesc = DESC_PLAIN; - if (lua_isstring(ls, 2)) - ndesc = desc_code(lua_tostring(ls, 2)); - bool terse = lua_toboolean(ls, 3); - char bufitemname[ITEMNAME_SIZE]; - item_name(*item, ndesc, bufitemname, terse); - - lua_pushstring(ls, bufitemname); - } - else - lua_pushnil(ls); - return (1); -} - -static int l_item_quantity(lua_State *ls) -{ - LUA_ITEM(item, 1); - lua_pushnumber(ls, item? item->quantity : 0); - return (1); -} - -static int l_item_inslot(lua_State *ls) -{ - int index = luaL_checkint(ls, 1); - if (index >= 0 && index < 52 && is_valid_item(you.inv[index])) - lua_pushlightuserdata(ls, &you.inv[index]); - else - lua_pushnil(ls); - return (1); -} - -static int l_item_slot(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (item) - { - int slot = in_inventory(*item)? item->link : - letter_to_index(item->slot); - lua_pushnumber(ls, slot); - } - else - lua_pushnil(ls); - return (1); -} - -static int l_item_ininventory(lua_State *ls) -{ - LUA_ITEM(item, 1); - lua_pushboolean(ls, item && in_inventory(*item)); - return (1); -} - -static int l_item_equip_type(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (!item || !is_valid_item(*item)) - return (0); - - equipment_type eq = EQ_NONE; - - if (item->base_type == OBJ_WEAPONS || item->base_type == OBJ_STAVES) - eq = EQ_WEAPON; - else if (item->base_type == OBJ_ARMOUR) - eq = get_armour_slot(*item); - else if (item->base_type == OBJ_JEWELLERY) - eq = item->sub_type >= AMU_RAGE? EQ_AMULET : EQ_RINGS; - - if (eq != EQ_NONE) - { - lua_pushnumber(ls, eq); - lua_pushstring(ls, equip_slot_to_name(eq)); - } - else - { - lua_pushnil(ls); - lua_pushnil(ls); - } - return (2); -} - -static int l_item_weap_skill(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (!item || !is_valid_item(*item)) - return (0); - - int skill = range_skill(*item); - if (skill == SK_RANGED_COMBAT) - skill = weapon_skill(*item); - if (skill == SK_FIGHTING) - return (0); - - lua_pushstring(ls, skill_name(skill)); - lua_pushnumber(ls, skill); - return (2); -} - -static int l_item_artifact(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (!item || !is_valid_item(*item)) - return (0); - - lua_pushboolean(ls, item_ident(*item, ISFLAG_KNOW_PROPERTIES) - && (is_random_artefact(*item) || is_fixed_artefact(*item))); - return (1); -} - -static int l_item_branded(lua_State *ls) -{ - LUA_ITEM(item, 1); - if (!item || !is_valid_item(*item) || !item_ident(*item, ISFLAG_KNOW_TYPE)) - return (0); - - bool branded = false; - switch (item->base_type) - { - case OBJ_WEAPONS: - branded = get_weapon_brand(*item) != SPWPN_NORMAL; - break; - case OBJ_ARMOUR: - branded = get_armour_ego_type(*item) != SPARM_NORMAL; - break; - case OBJ_MISSILES: - branded = get_ammo_brand(*item) != SPMSL_NORMAL; - break; - } - lua_pushboolean(ls, branded); - return (1); -} - -static const struct luaL_reg item_lib[] = -{ - { "artifact", l_item_artifact }, - { "branded", l_item_branded }, - { "class", l_item_class }, - { "subtype", l_item_subtype }, - { "cursed", l_item_cursed }, - { "worn", l_item_worn }, - { "name", l_item_name }, - { "quantity", l_item_quantity }, - { "inslot", l_item_inslot }, - { "slot", l_item_slot }, - { "ininventory", l_item_ininventory }, - { "inventory", l_item_inventory }, - { "letter_to_index", l_item_letter_to_index }, - { "index_to_letter", l_item_index_to_letter }, - { "swap_slots", l_item_swap_slots }, - { "wield", l_item_wield }, - { "wear", l_item_wear }, - { "puton", l_item_puton }, - { "remove", l_item_remove }, - { "drop", l_item_drop }, - { "pickup", l_item_pickup }, - { "equipped_at", l_item_equipped }, - { "equip_type", l_item_equip_type }, - { "weap_skill", l_item_weap_skill }, - - { NULL, NULL }, -}; - -void lua_open_item(lua_State *ls) -{ - luaL_openlib(ls, "item", item_lib, 0); -} - -///////////////////////////////////////////////////////////////////// -// Food information. Some of this information is spoily (such as whether -// a given chunk is poisonous), but that can't be helped. -// - -static int food_do_eat(lua_State *ls) -{ - bool eaten = false; - if (!you.turn_is_over) - eaten = eat_food(false); - lua_pushboolean(ls, eaten); - return (1); -} - -static int food_prompt_floor(lua_State *ls) -{ - bool eaten = false; - if (!you.turn_is_over && (eaten = eat_from_floor())) - burden_change(); - lua_pushboolean(ls, eaten); - return (1); -} - -static int food_prompt_inventory(lua_State *ls) -{ - bool eaten = false; - if (!you.turn_is_over) - eaten = prompt_eat_from_inventory(); - lua_pushboolean(ls, eaten); - return (1); -} - -static int food_can_eat(lua_State *ls) -{ - LUA_ITEM(item, 1); - bool hungercheck = true; - - if (lua_isboolean(ls, 2)) - hungercheck = lua_toboolean(ls, 2); - - bool edible = item && can_ingest(item->base_type, - item->sub_type, - true, - true, - hungercheck); - lua_pushboolean(ls, edible); - return (1); -} - -static int item_on_floor(const item_def &item, int x, int y) -{ - // Check if the item is on the floor and reachable - for (int link = igrd[x][y]; link != NON_ITEM; link = mitm[link].link) - { - if (&mitm[link] == &item) - return (link); - } - return (NON_ITEM); -} - -static bool eat_item(const item_def &item) -{ - if (in_inventory(item)) - { - eat_from_inventory(item.link); - burden_change(); - you.turn_is_over = 1; - - return (true); - } - else - { - int ilink = item_on_floor(item, you.x_pos, you.y_pos); - - if (ilink != NON_ITEM) - { - eat_floor_item(ilink); - return (true); - } - return (false); - } -} - -static int food_eat(lua_State *ls) -{ - LUA_ITEM(item, 1); - - bool eaten = false; - if (!you.turn_is_over) - { - // When we get down to eating, we don't care if the eating is courtesy - // an un-ided amulet of the gourmand. - bool edible = item && can_ingest(item->base_type, - item->sub_type, - false, - false); - if (edible) - eaten = eat_item(*item); - } - lua_pushboolean(ls, eaten); - return (1); -} - -static int food_rotting(lua_State *ls) -{ - LUA_ITEM(item, 1); - bool rotting = false; - if (item && item->base_type == OBJ_FOOD && item->sub_type == FOOD_CHUNK) - { - rotting = item->special < 100; - } - lua_pushboolean(ls, rotting); - return (1); -} - -static int food_ischunk(lua_State *ls) -{ - LUA_ITEM(item, 1); - lua_pushboolean(ls, - item && item->base_type == OBJ_FOOD - && item->sub_type == FOOD_CHUNK); - return (1); -} - -static const struct luaL_reg food_lib[] = -{ - { "do_eat", food_do_eat }, - { "prompt_floor", food_prompt_floor }, - { "prompt_inventory", food_prompt_inventory }, - { "can_eat", food_can_eat }, - { "eat", food_eat }, - { "rotting", food_rotting }, - { "ischunk", food_ischunk }, - { NULL, NULL }, -}; - -void lua_open_food(lua_State *ls) -{ - luaL_openlib(ls, "food", food_lib, 0); -} - -///////////////////////////////////////////////////////////////////// -// General game bindings. -// - -static int crawl_mpr(lua_State *ls) -{ - const char *message = luaL_checkstring(ls, 1); - if (!message) - return (0); - - int ch = MSGCH_PLAIN; - const char *channel = lua_tostring(ls, 2); - if (channel) - ch = str_to_channel(channel); - if (ch == -1) - ch = MSGCH_PLAIN; - - mpr(message, ch); - - return (0); -} - -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); - else - lua_pushnil(ls); - return (1); -} - -LUARET1(crawl_getch, number, getch()) -LUARET1(crawl_kbhit, number, kbhit()) -LUAWRAP(crawl_flush_input, flush_input_buffer(FLUSH_LUA)) - -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); -} - -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_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); -} - -#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 int crawl_regex_gc(lua_State *ls) -{ - text_pattern **pattern = - clua_get_userdata< text_pattern* >(ls, REGEX_METATABLE); - if (pattern) - delete *pattern; - return (0); -} - -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 int crawl_messf_gc(lua_State *ls) -{ - message_filter **pattern = - clua_get_userdata< message_filter* >(ls, REGEX_METATABLE); - if (pattern) - delete *pattern; - 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 const struct luaL_reg crawl_lib[] = -{ - { "mpr", crawl_mpr }, - { "mesclr", crawl_mesclr }, - { "redraw_screen", crawl_redraw_screen }, - { "input_line", crawl_input_line }, - { "c_input_line", crawl_c_input_line}, - { "getch", crawl_getch }, - { "kbhit", crawl_kbhit }, - { "flush_input", crawl_flush_input }, - { "sendkeys", crawl_sendkeys }, - { "playsound", crawl_playsound }, - { "runmacro", crawl_runmacro }, - { "bindkey", crawl_bindkey }, - { "setopt", crawl_setopt }, - { "msgch_num", crawl_msgch_num }, - { "msgch_name", crawl_msgch_name }, - - { "regex", crawl_regex }, - { "message_filter", crawl_message_filter }, - { "trim", crawl_trim }, - { "split", crawl_split }, - { NULL, NULL }, -}; - -void lua_open_crawl(lua_State *ls) -{ - clua_register_metatable(ls, REGEX_METATABLE, crawl_regex_ops, - crawl_regex_gc); - clua_register_metatable(ls, MESSF_METATABLE, crawl_messf_ops, - crawl_messf_gc); - - luaL_openlib(ls, "crawl", crawl_lib, 0); -} - -/////////////////////////////////////////////////////////// -// File operations - - -static const struct luaL_reg file_lib[] = -{ - { "write", CLua::file_write }, - { NULL, NULL }, -}; - -void lua_open_file(lua_State *ls) -{ - luaL_openlib(ls, "file", file_lib, 0); -} - - -//////////////////////////////////////////////////////////////// -// Option handling - -typedef int (*ohandler)(lua_State *ls, const char *name, void *data, bool get); -struct option_handler -{ - const char *option; - void *data; - ohandler handler; -}; - -static int option_hboolean(lua_State *ls, const char *name, void *data, - bool get) -{ - if (get) - { - lua_pushboolean(ls, *static_cast<bool*>( data )); - return (1); - } - else - { - if (lua_isboolean(ls, 3)) - *static_cast<bool*>( data ) = lua_toboolean(ls, 3); - return (0); - } -} - -static option_handler handlers[] = -{ - // Boolean options come first - { "easy_open", &Options.easy_open, option_hboolean }, - { "verbose_dump", &Options.verbose_dump, option_hboolean }, - { "detailed_stat_dump", &Options.detailed_stat_dump, option_hboolean }, - { "colour_map", &Options.colour_map, option_hboolean }, - { "clean_map", &Options.clean_map, option_hboolean }, - { "show_uncursed", &Options.show_uncursed, option_hboolean }, - { "always_greet", &Options.always_greet, option_hboolean }, - { "easy_open", &Options.easy_open, option_hboolean }, - { "easy_armour", &Options.easy_armour, option_hboolean }, - { "easy_butcher", &Options.easy_butcher, option_hboolean }, - { "terse_hand", &Options.terse_hand, option_hboolean }, - { "delay_message_clear", &Options.delay_message_clear, option_hboolean }, - { "no_dark_brand", &Options.no_dark_brand, option_hboolean }, - { "auto_list", &Options.auto_list, option_hboolean }, - { "lowercase_invocations", &Options.lowercase_invocations, - option_hboolean }, - { "pickup_thrown", &Options.pickup_thrown, option_hboolean }, - { "pickup_dropped", &Options.pickup_dropped, option_hboolean }, - { "show_waypoints", &Options.show_waypoints, option_hboolean }, - { "item_colour", &Options.item_colour, option_hboolean }, - { "target_zero_exp", &Options.target_zero_exp, option_hboolean }, - { "target_wrap", &Options.target_wrap, option_hboolean }, - { "easy_exit_menu", &Options.easy_exit_menu, option_hboolean }, - { "dos_use_background_intensity", &Options.dos_use_background_intensity, - option_hboolean }, -}; - -static const option_handler *get_handler(const char *optname) -{ - if (optname) - { - for (int i = 0, count = sizeof(handlers) / sizeof(*handlers); - i < count; ++i) - { - if (!strcmp(handlers[i].option, optname)) - return &handlers[i]; - } - } - return (NULL); -} - -static int option_get(lua_State *ls) -{ - const char *opt = luaL_checkstring(ls, 2); - if (!opt) - return (0); - - // Is this a Lua named option? - game_options::opt_map::iterator i = Options.named_options.find(opt); - if (i != Options.named_options.end()) - { - const std::string &ov = i->second; - lua_pushstring(ls, ov.c_str()); - return (1); - } - - const option_handler *oh = get_handler(opt); - if (oh) - return (oh->handler(ls, opt, oh->data, true)); - - return (0); -} - -static int option_set(lua_State *ls) -{ - const char *opt = luaL_checkstring(ls, 2); - if (!opt) - return (0); - - const option_handler *oh = get_handler(opt); - if (oh) - oh->handler(ls, opt, oh->data, false); - - return (0); -} - -#define OPT_METATABLE "options.optaccess" -void lua_open_options(lua_State *ls) -{ - int top = lua_gettop(ls); - - luaL_newmetatable(ls, OPT_METATABLE); - lua_pushstring(ls, "__index"); - lua_pushcfunction(ls, option_get); - lua_settable(ls, -3); - - luaL_getmetatable(ls, OPT_METATABLE); - lua_pushstring(ls, "__newindex"); - lua_pushcfunction(ls, option_set); - lua_settable(ls, -3); - - lua_settop(ls, top); - - // Create dummy userdata to front for our metatable - int *dummy = static_cast<int *>( lua_newuserdata(ls, sizeof(int)) ); - // Mystic number - *dummy = 42; - - luaL_getmetatable(ls, OPT_METATABLE); - lua_setmetatable(ls, -2); - - clua.setglobal("options"); -} - -///////////////////////////////////////////////////////////////////// -// Monster handling - -#define MONS_METATABLE "monster.monsaccess" -struct MonsterWrap -{ - monsters *mons; - long turn; -}; - -static int l_mons_name(lua_State *ls, monsters *mons, const char *attr) -{ - char monnamebuf[ITEMNAME_SIZE]; // Le sigh. - moname(mons->type, true, DESC_PLAIN, monnamebuf); - lua_pushstring(ls, monnamebuf); - return (1); -} - -static int l_mons_x(lua_State *ls, monsters *mons, const char *attr) -{ - lua_pushnumber(ls, int(mons->x) - int(you.x_pos)); - return (1); -} - -static int l_mons_y(lua_State *ls, monsters *mons, const char *attr) -{ - lua_pushnumber(ls, int(mons->y) - int(you.y_pos)); - return (1); -} - -struct MonsAccessor { - const char *attribute; - int (*accessor)(lua_State *ls, monsters *mons, const char *attr); -}; - -static MonsAccessor mons_attrs[] = -{ - { "name", l_mons_name }, - { "x" , l_mons_x }, - { "y" , l_mons_y }, -}; - -static int monster_get(lua_State *ls) -{ - MonsterWrap *mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE); - if (!mw || mw->turn != you.num_turns || !mw->mons) - return (0); - - const char *attr = luaL_checkstring(ls, 2); - if (!attr) - return (0); - - for (unsigned i = 0; i < sizeof(mons_attrs) / sizeof(mons_attrs[0]); ++i) - { - if (!strcmp(attr, mons_attrs[i].attribute)) - return (mons_attrs[i].accessor(ls, mw->mons, attr)); - } - - return (0); -} - -// We currently permit no set operations on monsters -static int monster_set(lua_State *ls) -{ - return (0); -} - -static int push_activity_interrupt(lua_State *ls, activity_interrupt_data *t) -{ - if (!t->data) - { - lua_pushnil(ls); - return 0; - } - - switch (t->apt) - { - case AIP_HP_LOSS: - { - const ait_hp_loss *ahl = (const ait_hp_loss *) t->data; - lua_pushnumber(ls, ahl->hp); - lua_pushnumber(ls, ahl->hurt_type); - return 1; - } - case AIP_INT: - lua_pushnumber(ls, *(const int *) t->data); - break; - case AIP_STRING: - lua_pushstring(ls, (const char *) t->data); - break; - case AIP_MONSTER: - // FIXME: We're casting away the const... - push_monster(ls, (monsters *) t->data); - break; - default: - lua_pushnil(ls); - break; - } - return 0; -} - -static void push_monster(lua_State *ls, monsters *mons) -{ - MonsterWrap *mw = clua_new_userdata< MonsterWrap >(ls, MONS_METATABLE); - mw->turn = you.num_turns; - mw->mons = mons; -} - -void lua_open_monsters(lua_State *ls) -{ - luaL_newmetatable(ls, MONS_METATABLE); - lua_pushstring(ls, "__index"); - lua_pushcfunction(ls, monster_get); - lua_settable(ls, -3); - - lua_pushstring(ls, "__newindex"); - lua_pushcfunction(ls, monster_set); - lua_settable(ls, -3); - - // Pop the metatable off the stack. - lua_pop(ls, 1); -} - -////////////////////////////////////////////////////////////////////// -// Miscellaneous globals - -#define PATTERN_FLUSH_CEILING 100 - -typedef CHMAP<std::string, text_pattern> pattern_map; -static pattern_map pattern_cache; - -static text_pattern &get_text_pattern(const std::string &s, bool checkcase) -{ - pattern_map::iterator i = pattern_cache.find(s); - if (i != pattern_cache.end()) - return i->second; - - if (pattern_cache.size() > PATTERN_FLUSH_CEILING) - pattern_cache.clear(); - - pattern_cache[s] = text_pattern(s, !checkcase); - return pattern_cache[s]; -} - -static int lua_pmatch(lua_State *ls) -{ - const char *pattern = luaL_checkstring(ls, 1); - if (!pattern) - return (0); - - const char *text = luaL_checkstring(ls, 2); - if (!text) - return (0); - - bool checkcase = true; - if (lua_isboolean(ls, 3)) - checkcase = lua_toboolean(ls, 3); - - text_pattern &tp = get_text_pattern(pattern, checkcase); - lua_pushboolean( ls, tp.matches(text) ); - return (1); -} - -void lua_open_globals(lua_State *ls) -{ - lua_pushcfunction(ls, lua_pmatch); - lua_setglobal(ls, "pmatch"); -} - - -//////////////////////////////////////////////////////////////////////// -// lua_text_pattern - -// We could simplify this a great deal by just using lex and yacc, but I -// don't know if we want to introduce them. - -struct lua_pat_op { - const char *token; - const char *luatok; - - bool pretext; // Does this follow a pattern? - bool posttext; // Is this followed by a pattern? -}; - -static lua_pat_op pat_ops[] = { - { "<<", " ( ", false, true }, - { ">>", " ) ", true, false }, - { "!!", " not ", false, true }, - { "==", " == ", true, true }, - { "^^", " ~= ", true, true }, - { "&&", " and ", true, true }, - { "||", " or ", true, true }, -}; - -unsigned long lua_text_pattern::lfndx = 0L; - -bool lua_text_pattern::is_lua_pattern(const std::string &s) -{ - for (int i = 0, size = sizeof(pat_ops) / sizeof(*pat_ops); - i < size; ++i) - { - if (s.find(pat_ops[i].token) != std::string::npos) - return (true); - } - return (false); -} - -lua_text_pattern::lua_text_pattern(const std::string &_pattern) - : translated(false), isvalid(true), pattern(_pattern), lua_fn_name() -{ - lua_fn_name = new_fn_name(); -} - -lua_text_pattern::~lua_text_pattern() -{ - if (translated && !lua_fn_name.empty()) - { - lua_State *ls = clua; - if (ls) - { - lua_pushnil(ls); - clua.setglobal(lua_fn_name.c_str()); - } - } -} - -bool lua_text_pattern::valid() const -{ - return translated? isvalid : translate(); -} - -bool lua_text_pattern::matches( const std::string &s ) const -{ - if (isvalid && !translated) - translate(); - - if (!isvalid) - return (false); - - return clua.callbooleanfn(false, lua_fn_name.c_str(), "s", s.c_str()); -} - -void lua_text_pattern::pre_pattern(std::string &pat, std::string &fn) const -{ - // Trim trailing spaces - pat.erase( pat.find_last_not_of(" \t\n\r") + 1 ); - - fn += " pmatch([["; - fn += pat; - fn += "]], text, false) "; - - pat.clear(); -} - -void lua_text_pattern::post_pattern(std::string &pat, std::string &fn) const -{ - pat.erase( 0, pat.find_first_not_of(" \t\n\r") ); - - fn += " pmatch([["; - fn += pat; - fn += "]], text, false) "; - - pat.clear(); -} - -std::string lua_text_pattern::new_fn_name() -{ - char buf[100]; - snprintf(buf, sizeof buf, "__ch_stash_search_%lu", lfndx++); - return (buf); -} - -bool lua_text_pattern::translate() const -{ - if (translated || !isvalid) - return false; - - std::string textp; - std::string luafn; - const lua_pat_op *currop = NULL; - for (std::string::size_type i = 0; i < pattern.length(); ++i) - { - bool match = false; - for (unsigned p = 0; p < sizeof pat_ops / sizeof *pat_ops; ++p) - { - const lua_pat_op &lop = pat_ops[p]; - if (pattern.find(lop.token, i) == i) - { - match = true; - if (lop.pretext && (!currop || currop->posttext)) - { - if (currop) - textp.erase(0, textp.find_first_not_of(" \r\n\t")); - pre_pattern(textp, luafn); - } - - currop = &lop; - luafn += lop.luatok; - - i += strlen( lop.token ) - 1; - - break; - } - } - - if (match) - continue; - - textp += pattern[i]; - } - - if (currop && currop->posttext) - post_pattern(textp, luafn); - - luafn = "function " + lua_fn_name + "(text) return " + luafn + " end"; - - const_cast<lua_text_pattern *>(this)->translated = true; - - int err = clua.execstring( luafn.c_str(), "stash-search" ); - if (err) - { - lua_text_pattern *self = const_cast<lua_text_pattern *>(this); - self->isvalid = self->translated = false; - } - - return translated; -} - -#endif // CLUA_BINDINGS |