Lua NetHack obj bindings

This commit is contained in:
Pasi Kallinen
2019-12-06 21:29:12 +02:00
parent 1c30c437c3
commit 7043e2134a
10 changed files with 476 additions and 6 deletions

356
src/nhlobj.c Normal file
View File

@@ -0,0 +1,356 @@
/* NetHack 3.7 nhlobj.c $NHDT-Date: 1574646948 2019/11/25 01:55:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */
/* Copyright (c) 2019 by Pasi Kallinen */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "sp_lev.h"
struct _lua_obj {
int state; /* UNUSED */
struct obj *obj;
};
struct _lua_obj *
l_obj_check(L, index)
lua_State *L;
int index;
{
struct _lua_obj *lo;
luaL_checktype(L, index, LUA_TUSERDATA);
lo = (struct _lua_obj *)luaL_checkudata(L, index, "obj");
if (!lo)
nhl_error(L, "Obj error");
return lo;
}
static int
l_obj_gc(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj) {
/* free-floating objects are deallocated */
if (lo->obj->where == OBJ_FREE) {
if (Has_contents(lo->obj)) {
struct obj *otmp;
while ((otmp = lo->obj->cobj) != 0) {
obj_extract_self(otmp);
dealloc_obj(otmp);
}
}
dealloc_obj(lo->obj);
}
lo->obj = NULL;
}
return 0;
}
static struct _lua_obj *
l_obj_push(L, otmp)
lua_State *L;
struct obj *otmp;
{
struct _lua_obj *lo = (struct _lua_obj *)lua_newuserdata(L, sizeof(struct _lua_obj));
luaL_getmetatable(L, "obj");
lua_setmetatable(L, -2);
lo->state = 0;
lo->obj = otmp;
return lo;
}
/* local o = obj.new("large chest");
local cobj = o:contents(); */
static int
l_obj_getcontents(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
struct obj *obj = lo->obj;
if (!obj)
nhl_error(L, "l_obj_getcontents: no obj");
if (!obj->cobj)
nhl_error(L, "l_obj_getcontents: no cobj");
(void) l_obj_push(L, obj->cobj);
return 1;
}
/* local box = obj.new("large chest");
box.addcontent(obj.new("rock"));
*/
static int
l_obj_add_to_container(L)
lua_State *L;
{
struct _lua_obj *lobox = l_obj_check(L, 1);
struct _lua_obj *lo = l_obj_check(L, 2);
struct obj *otmp;
if (!lo->obj || !lobox->obj)
nhl_error(L, "l_obj_add_to_container: no obj");
if (!Is_container(lobox->obj))
nhl_error(L, "l_obj_add_to_container: not a container");
otmp = add_to_container(lobox->obj, lo->obj);
/* was lo->obj merged? FIXME: causes problems if both lo->obj and
the one it merged with are handled by lua. Use lo->state? */
if (otmp != lo->obj)
lo->obj = otmp;
return 0;
}
/* Create a lua table representation of the object, unpacking all the object fields.
local o = obj.new("rock");
local otbl = o:totable(); */
static int
l_obj_to_table(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
struct obj *obj = lo->obj;
char buf[BUFSZ];
lua_newtable(L);
if (!obj) {
nhl_add_table_entry_int(L, "NO_OBJ", 1);
return 1;
}
nhl_add_table_entry_int(L, "has_contents", Has_contents(obj));
nhl_add_table_entry_int(L, "is_container", Is_container(obj));
nhl_add_table_entry_int(L, "o_id", obj->o_id);
nhl_add_table_entry_int(L, "ox", obj->ox);
nhl_add_table_entry_int(L, "oy", obj->oy);
nhl_add_table_entry_int(L, "otyp", obj->otyp);
if (OBJ_NAME(objects[obj->otyp]))
nhl_add_table_entry_str(L, "otyp_name", OBJ_NAME(objects[obj->otyp]));
if (OBJ_DESCR(objects[obj->otyp]))
nhl_add_table_entry_str(L, "otyp_descr", OBJ_DESCR(objects[obj->otyp]));
nhl_add_table_entry_int(L, "owt", obj->owt);
nhl_add_table_entry_int(L, "quan", obj->quan);
nhl_add_table_entry_int(L, "spe", obj->spe);
nhl_add_table_entry_char(L, "oclass", def_oc_syms[obj->oclass].sym);
nhl_add_table_entry_char(L, "invlet", obj->invlet);
/* TODO: nhl_add_table_entry_char(L, "oartifact", obj->oartifact);*/
nhl_add_table_entry_int(L, "where", obj->where);
/* TODO: nhl_add_table_entry_int(L, "timed", obj->timed); */
nhl_add_table_entry_int(L, "cursed", obj->cursed);
nhl_add_table_entry_int(L, "blessed", obj->blessed);
nhl_add_table_entry_int(L, "unpaid", obj->unpaid);
nhl_add_table_entry_int(L, "no_charge", obj->no_charge);
nhl_add_table_entry_int(L, "known", obj->known);
nhl_add_table_entry_int(L, "dknown", obj->dknown);
nhl_add_table_entry_int(L, "bknown", obj->bknown);
nhl_add_table_entry_int(L, "rknown", obj->rknown);
if (obj->oclass == POTION_CLASS)
nhl_add_table_entry_int(L, "odiluted", obj->odiluted);
else
nhl_add_table_entry_int(L, "oeroded", obj->oeroded);
nhl_add_table_entry_int(L, "oeroded2", obj->oeroded2);
/* TODO: orotten, norevive */
nhl_add_table_entry_int(L, "oerodeproof", obj->oerodeproof);
nhl_add_table_entry_int(L, "olocked", obj->olocked);
nhl_add_table_entry_int(L, "obroken", obj->obroken);
if (is_poisonable(obj))
nhl_add_table_entry_int(L, "opoisoned", obj->opoisoned);
else
nhl_add_table_entry_int(L, "otrapped", obj->otrapped);
/* TODO: degraded_horn */
nhl_add_table_entry_int(L, "recharged", obj->recharged);
/* TODO: on_ice */
nhl_add_table_entry_int(L, "lamplit", obj->lamplit);
nhl_add_table_entry_int(L, "globby", obj->globby);
nhl_add_table_entry_int(L, "greased", obj->greased);
nhl_add_table_entry_int(L, "nomerge", obj->nomerge);
nhl_add_table_entry_int(L, "was_thrown", obj->was_thrown);
nhl_add_table_entry_int(L, "in_use", obj->in_use);
nhl_add_table_entry_int(L, "bypass", obj->bypass);
nhl_add_table_entry_int(L, "cknown", obj->cknown);
nhl_add_table_entry_int(L, "lknown", obj->lknown);
nhl_add_table_entry_int(L, "corpsenm", obj->corpsenm);
if (obj->corpsenm != NON_PM && (obj->otyp == TIN || obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == FIGURINE || obj->otyp == STATUE))
nhl_add_table_entry_str(L, "corpsenm_name", mons[obj->corpsenm].mname);
/* TODO: leashmon, fromsink, novelidx, record_achieve_special */
nhl_add_table_entry_int(L, "usecount", obj->usecount);
/* TODO: spestudied */
nhl_add_table_entry_int(L, "oeaten", obj->oeaten);
nhl_add_table_entry_int(L, "age", obj->age);
nhl_add_table_entry_int(L, "owornmask", obj->owornmask);
/* TODO: more of oextra */
nhl_add_table_entry_int(L, "has_oname", has_oname(obj));
if (has_oname(obj))
nhl_add_table_entry_str(L, "oname", ONAME(obj));
return 1;
}
/* create a new object via wishing routine */
/* local o = obj.new("rock"); */
static int
l_obj_new_readobjnam(L)
lua_State *L;
{
int argc = lua_gettop(L);
if (argc == 1) {
char buf[BUFSZ];
struct obj *otmp;
Sprintf(buf, "%s", luaL_checkstring(L, 1));
lua_pop(L, 1);
otmp = readobjnam(buf, NULL);
(void) l_obj_push(L, otmp);
return 1;
} else
nhl_error(L, "l_obj_new_readobjname: Wrong args");
return 0;
}
/* Get the topmost object on the map at x,y */
/* local o = obj.at(x, y); */
static int
l_obj_at(L)
lua_State *L;
{
int argc = lua_gettop(L);
if (argc == 2) {
int x, y;
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
lua_pop(L, 2);
(void) l_obj_push(L, g.level.objects[x][y]);
return 1;
} else
nhl_error(L, "l_obj_at: Wrong args");
return 0;
}
/* Place an object on the map at (x,y).
local o = obj.new("rock");
o:placeobj(u.ux, u.uy); */
static int
l_obj_placeobj(L)
lua_State *L;
{
int argc = lua_gettop(L);
struct _lua_obj *lo = l_obj_check(L, 1);
if (argc != 3)
nhl_error(L, "l_obj_placeobj: Wrong args");
if (lo && lo->obj) {
int x, y;
x = luaL_checkinteger(L, 2);
y = luaL_checkinteger(L, 3);
lua_pop(L, 3);
place_object(lo->obj, x, y);
} else
nhl_error(L, "l_obj_placeobj: Wrong args");
return 0;
}
/* Get the next object in the object chain */
/* local o = obj.at(x, y);
local o2 = o:next();
*/
static int
l_obj_nextobj(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj)
(void) l_obj_push(L, lo->obj->where == OBJ_FLOOR ? lo->obj->nexthere : lo->obj->nobj);
return 1;
}
/* Get the container object is in */
/* local box = o:container(); */
static int
l_obj_container(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj && lo->obj->where == OBJ_CONTAINED) {
(void) l_obj_push(L, lo->obj->ocontainer);
return 1;
}
(void) l_obj_push(L, NULL);
return 1;
}
/* Is the object a null? */
/* local badobj = o:isnull(); */
static int
l_obj_isnull(L)
lua_State *L;
{
struct _lua_obj *lo = l_obj_check(L, 1);
lua_pushboolean(L, lo && lo->obj);
return 1;
}
static const struct luaL_Reg l_obj_methods[] = {
{ "new", l_obj_new_readobjnam },
{ "isnull", l_obj_isnull },
{ "at", l_obj_at },
{ "next", l_obj_nextobj },
{ "totable", l_obj_to_table },
{ "placeobj", l_obj_placeobj },
{ "container", l_obj_container },
{ "contents", l_obj_getcontents },
{ "addcontent", l_obj_add_to_container },
{ NULL, NULL }
};
static const luaL_Reg l_obj_meta[] = {
{ "__gc", l_obj_gc },
{ NULL, NULL }
};
int
l_obj_register(L)
lua_State *L;
{
int lib_id, meta_id;
/* newclass = {} */
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
/* metatable = {} */
luaL_newmetatable(L, "obj");
meta_id = lua_gettop(L);
luaL_setfuncs(L, l_obj_meta, 0);
/* metatable.__index = _methods */
luaL_newlib(L, l_obj_methods);
lua_setfield(L, meta_id, "__index");
/* metatable.__metatable = _meta */
luaL_newlib(L, l_obj_meta);
lua_setfield(L, meta_id, "__metatable");
/* class.__metatable = metatable */
lua_setmetatable(L, lib_id);
/* _G["obj"] = newclass */
lua_setglobal(L, "obj");
return 0;
}