JCUAPVDH47W6LG4LU6S4QP6FZJJ2NVXJ6LKFSBMVY3AWMC2PALIAC N276A6EITTZ5F6LCJDHUJIHPS5KZ4S37DE2ZO72AZBXZ6PFNV4NQC WNC5SY6P2PBCU62Q2DB5J2M4HPDS5EJY76ZEPHRGGCLJ4BSLBSSQC WQBSKRTHZRKIYIDHROBSIEHEEQX26UAFDTMYY24UOPYNMYWXDFCAC LPTP6ZL7U4OVXLZ56TJKJ6HENDHE7ITFMFBXC5BKEBVXEGXPW44AC MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC CJKLBIIM2ZTWTLGISXEZOGK2JANEYUSLOKG3BBOAYAY7AFG33ELQC 3A5FX3Y4RPKWQEHKKXZKXZJ7RKV6RKWT7GTR4WFE5UBWKV2HT4RQC W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC SSCG2FLJMUTTIRXBFSPLAUUBUIN375ZGL5UOAF3SC62ZIILSMMKAC NKONHW4JNY6HP2M63MNPM3H64ZWSUNUT5FX2STW4KTS4AMXJXXVQC MT3256427VMCV4JUFWCN7ULY4KXSND5ZL5THDKYNWWYOXXR5DLIQC 5PE244O6RR2LB5YNIHPXYMOUYCDR4WIAQNV4DRPRZBXNGEC2K4XQC RA7UG6FR2WA4AWD3PW4Z25PKPP6ZX3LOA3V55CZHJHBH677MTUCQC 77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC EGOIFEAXIWSCOQ5RHOXNA45JN6HNUI2KOPLGWGPJSXA7EXIAJ6QQC ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC YFJLINBBEHE7RBETTARSYNWSO6QJ6MSPXFMSPSH2742QFC3L55SQC #include "AppHdr.h"#include "clua.h"#include "l_libs.h"#include "delay.h"#include "mon-util.h"#include "monstuff.h"/////////////////////////////////////////////////////////////////////// Monster handling#define MONS_METATABLE "monster.monsaccess"struct MonsterWrap{monsters *mons;long turn;};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;}#define MDEF(name) \static int l_mons_##name(lua_State *ls, monsters *mons, \const char *attr) \#define MDEFN(name, closure) \static int l_mons_##name(lua_State *ls, monsters *mons, const char *attrs) \{ \lua_pushlightuserdata(ls, mons); \lua_pushcclosure(ls, l_mons_do_dismiss, 1); \return (1); \}MDEF(name){PLUARET(string, mons_type_name(mons->type, DESC_PLAIN).c_str());}MDEF(x){PLUARET(number, int(mons->pos().x) - int(you.pos().x));}MDEF(y){PLUARET(number, int(mons->pos().y) - int(you.pos().y));}MDEF(hd){PLUARET(number, mons->hit_dice);}static const char *_monuse_names[] ={"nothing", "open_doors", "starting_equipment", "weapons_armour","magic_items"};static const char *_monuse_to_str(mon_itemuse_type utyp){COMPILE_CHECK(ARRAYSZ(_monuse_names) == NUM_MONUSE, c1);return _monuse_names[utyp];}MDEF(muse){if (const monsterentry *me = mons->find_monsterentry()){PLUARET(string, _monuse_to_str(me->gmon_use));}return (0);}static const char *_moneat_names[] ={"nothing", "items", "corpses", "food"};static const char *_moneat_to_str(mon_itemeat_type etyp){COMPILE_CHECK(ARRAYSZ(_moneat_names) == NUM_MONEAT, c1);return _moneat_names[etyp];}MDEF(meat){if (const monsterentry *me = mons->find_monsterentry()){PLUARET(string, _moneat_to_str(me->gmon_eat));}return (0);}static int l_mons_do_dismiss(lua_State *ls){// dismiss is only callable from dlua, not from managed VMs (i.e.// end-user scripts cannot dismiss monsters).ASSERT_DLUA;monsters *mons =util_get_userdata<monsters>(ls, lua_upvalueindex(1));if (mons->alive()){mons->flags |= MF_HARD_RESET;monster_die(mons, KILL_DISMISSED, NON_MONSTER);}return (0);}MDEFN(dismiss, do_dismiss)MDEF(experience){ASSERT_DLUA;PLUARET(number, exper_value(mons));}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 },{ "hd" , l_mons_hd },{ "muse", l_mons_muse },{ "meat", l_mons_meat },{ "dismiss", l_mons_dismiss },{ "experience", l_mons_experience },};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);}static const char *_monster_behaviour_names[] = {"sleep","wander","seek","flee","cornered","panic","lurk"};static beh_type behaviour_by_name(const std::string &name) {ASSERT(ARRAYSZ(_monster_behaviour_names) == NUM_BEHAVIOURS);for (unsigned i = 0; i < ARRAYSZ(_monster_behaviour_names); ++i)if (name == _monster_behaviour_names[i])return static_cast<beh_type>(i);return NUM_BEHAVIOURS;}static int monster_set(lua_State *ls){// Changing monster behaviour is for the dungeon builder only,// never for user scripts.ASSERT_DLUA;MonsterWrap *mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE);if (!mw || !mw->mons)return (0);const char *attr = luaL_checkstring(ls, 2);if (!attr)return (0);if (!strcmp(attr, "beh")) {const beh_type beh =lua_isnumber(ls, 3) ?static_cast<beh_type>(luaL_checkint(ls, 3)) :lua_isstring(ls, 3) ? behaviour_by_name(lua_tostring(ls, 3)) :NUM_BEHAVIOURS;if (beh != NUM_BEHAVIOURS)mw->mons->behaviour = beh;}return (0);}static int mons_behaviour(lua_State *ls) {if (lua_gettop(ls) < 1)return (0);if (lua_isnumber(ls, 1)) {lua_pushvalue(ls, 1);return (1);}else if (lua_isstring(ls, 1)) {const beh_type beh = behaviour_by_name(lua_tostring(ls, 1));if (beh != NUM_BEHAVIOURS) {lua_pushnumber(ls, beh);return (1);}}return (0);}static const struct luaL_reg mons_lib[] ={{ "behaviour", mons_behaviour },{ NULL, NULL }};void cluaopen_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);luaL_openlib(ls, "mons", mons_lib, 0);}
}/////////////////////////////////////////////////////////////////////// Monster handling#define MONS_METATABLE "monster.monsaccess"struct MonsterWrap{monsters *mons;long turn;};#define MDEF(name) \static int l_mons_##name(lua_State *ls, monsters *mons, \const char *attr) \#define MDEFN(name, closure) \static int l_mons_##name(lua_State *ls, monsters *mons, const char *attrs) \{ \lua_pushlightuserdata(ls, mons); \lua_pushcclosure(ls, l_mons_do_dismiss, 1); \return (1); \}MDEF(name){PLUARET(string, mons_type_name(mons->type, DESC_PLAIN).c_str());}MDEF(x){PLUARET(number, int(mons->pos().x) - int(you.pos().x));}MDEF(y){PLUARET(number, int(mons->pos().y) - int(you.pos().y));}MDEF(hd){PLUARET(number, mons->hit_dice);}static const char *_monuse_names[] ={"nothing", "open_doors", "starting_equipment", "weapons_armour","magic_items"};static const char *_monuse_to_str(mon_itemuse_type utyp){COMPILE_CHECK(ARRAYSZ(_monuse_names) == NUM_MONUSE, c1);return _monuse_names[utyp];}MDEF(muse){if (const monsterentry *me = mons->find_monsterentry()){PLUARET(string, _monuse_to_str(me->gmon_use));}return (0);}static const char *_moneat_names[] ={"nothing", "items", "corpses", "food"};static const char *_moneat_to_str(mon_itemeat_type etyp){COMPILE_CHECK(ARRAYSZ(_moneat_names) == NUM_MONEAT, c1);return _moneat_names[etyp];}MDEF(meat){if (const monsterentry *me = mons->find_monsterentry()){PLUARET(string, _moneat_to_str(me->gmon_eat));}return (0);}static int l_mons_do_dismiss(lua_State *ls){// dismiss is only callable from dlua, not from managed VMs (i.e.// end-user scripts cannot dismiss monsters).ASSERT_DLUA;monsters *mons =util_get_userdata<monsters>(ls, lua_upvalueindex(1));if (mons->alive()){mons->flags |= MF_HARD_RESET;monster_die(mons, KILL_DISMISSED, NON_MONSTER);}return (0);}MDEFN(dismiss, do_dismiss)MDEF(experience){ASSERT_DLUA;PLUARET(number, exper_value(mons));}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 },{ "hd" , l_mons_hd },{ "muse", l_mons_muse },{ "meat", l_mons_meat },{ "dismiss", l_mons_dismiss },{ "experience", l_mons_experience },};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);}static const char *_monster_behaviour_names[] = {"sleep","wander","seek","flee","cornered","panic","lurk"};static beh_type behaviour_by_name(const std::string &name) {ASSERT(ARRAYSZ(_monster_behaviour_names) == NUM_BEHAVIOURS);for (unsigned i = 0; i < ARRAYSZ(_monster_behaviour_names); ++i)if (name == _monster_behaviour_names[i])return static_cast<beh_type>(i);return NUM_BEHAVIOURS;
MonsterWrap *mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE);if (!mw || !mw->mons)return (0);const char *attr = luaL_checkstring(ls, 2);if (!attr)return (0);if (!strcmp(attr, "beh")) {const beh_type beh =lua_isnumber(ls, 3) ?static_cast<beh_type>(luaL_checkint(ls, 3)) :lua_isstring(ls, 3) ? behaviour_by_name(lua_tostring(ls, 3)) :NUM_BEHAVIOURS;if (beh != NUM_BEHAVIOURS)mw->mons->behaviour = beh;}return (0);}
}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;
if (lua_isnumber(ls, 1)) {lua_pushvalue(ls, 1);return (1);}else if (lua_isstring(ls, 1)) {const beh_type beh = behaviour_by_name(lua_tostring(ls, 1));if (beh != NUM_BEHAVIOURS) {lua_pushnumber(ls, beh);return (1);}}return (0);}static const struct luaL_reg mons_lib[] ={{ "behaviour", mons_behaviour },{ NULL, NULL }};void luaopen_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);luaL_openlib(ls, "mons", mons_lib, 0);}