The g? structs had a mix of variables that were written to
the savefile, and those that were not.
For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.
This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.
Details:
gb.bases -> svb.bases
gb.bbubbles -> svb.bbubbles
gb.branches -> svb.branches
gc.context -> svc.context
gd.disco -> svd.disco
gd.dndest -> svd.dndest
gd.doors -> svd.doors
gd.doors_alloc -> svd.doors_alloc
gd.dungeon_topology -> svd.dungeon_topology
gd.dungeons -> svd.dungeons
ge.exclusion_zones -> sve.exclusion_zones
gh.hackpid -> svh.hackpid
gi.inv_pos -> svi.inv_pos
gk.killer -> svk.killer
gl.lastseentyp -> svl.lastseentyp
gl.level -> svl.level
gl.level_info -> svl.level_info
gm.mapseenchn -> svm.mapseenchn
gm.moves -> svm.moves
gm.mvitals -> svm.mvitals
gn.n_dgns -> svn.n_dgns
gn.n_regions -> svn.n_regions
gn.nroom -> svn.nroom
go.oracle_cnt -> svo.oracle_cnt
gp.pl_character -> svp.pl_character
gp.pl_fruit -> svp.pl_fruit
gp.plname -> svp.plname
gp.program_state -> svp.program_state
gq.quest_status -> svq.quest_status
gr.rooms -> svr.rooms
gs.sp_levchn -> svs.sp_levchn
gs.spl_book -> svs.spl_book
gt.timer_id -> svt.timer_id
gt.tune -> svt.tune
gu.updest -> svu.updest
gx.xmax -> svx.xmax
gx.xmin -> svx.xmin
gy.ymax -> svy.ymax
gy.ymin -> svy.ymin
Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
gf.ftrap, gl.light_base, gt.timer_base
667 lines
19 KiB
C
667 lines
19 KiB
C
/* NetHack 3.7 nhlobj.c $NHDT-Date: 1576097301 2019/12/11 20:48:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */
|
|
/* 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;
|
|
};
|
|
|
|
staticfn struct _lua_obj *l_obj_check(lua_State *, int);
|
|
staticfn int l_obj_add_to_container(lua_State *);
|
|
staticfn int l_obj_gc(lua_State *);
|
|
staticfn int l_obj_getcontents(lua_State *);
|
|
staticfn int l_obj_isnull(lua_State *);
|
|
staticfn int l_obj_new_readobjnam(lua_State *);
|
|
staticfn int l_obj_nextobj(lua_State *);
|
|
staticfn int l_obj_objects_to_table(lua_State *);
|
|
staticfn int l_obj_placeobj(lua_State *);
|
|
staticfn int l_obj_to_table(lua_State *);
|
|
staticfn int l_obj_at(lua_State *);
|
|
staticfn int l_obj_container(lua_State *);
|
|
staticfn int l_obj_timer_has(lua_State *);
|
|
staticfn int l_obj_timer_peek(lua_State *);
|
|
staticfn int l_obj_timer_stop(lua_State *);
|
|
staticfn int l_obj_timer_start(lua_State *);
|
|
staticfn int l_obj_bury(lua_State *);
|
|
staticfn struct _lua_obj *l_obj_push(lua_State *, struct obj *);
|
|
|
|
#define lobj_is_ok(lo) ((lo) && (lo)->obj && (lo)->obj->where != OBJ_LUAFREE)
|
|
|
|
staticfn struct _lua_obj *
|
|
l_obj_check(lua_State *L, int indx)
|
|
{
|
|
struct _lua_obj *lo;
|
|
|
|
luaL_checktype(L, indx, LUA_TUSERDATA);
|
|
lo = (struct _lua_obj *) luaL_checkudata(L, indx, "obj");
|
|
if (!lo)
|
|
nhl_error(L, "Obj error");
|
|
return lo;
|
|
}
|
|
|
|
staticfn int
|
|
l_obj_gc(lua_State *L)
|
|
{
|
|
struct obj *obj, *otmp;
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
|
|
if (lo && (obj = lo->obj) != 0) {
|
|
if (obj->lua_ref_cnt > 0)
|
|
obj->lua_ref_cnt--;
|
|
/* free-floating objects with no other refs are deallocated. */
|
|
if (!obj->lua_ref_cnt
|
|
&& (obj->where == OBJ_FREE || obj->where == OBJ_LUAFREE)) {
|
|
if (Has_contents(obj)) {
|
|
while ((otmp = obj->cobj) != 0) {
|
|
obj_extract_self(otmp);
|
|
dealloc_obj(otmp);
|
|
}
|
|
}
|
|
obj->where = OBJ_FREE;
|
|
dealloc_obj(obj), obj = 0;
|
|
}
|
|
lo->obj = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
staticfn struct _lua_obj *
|
|
l_obj_push(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;
|
|
if (otmp)
|
|
otmp->lua_ref_cnt++;
|
|
|
|
return lo;
|
|
}
|
|
|
|
void
|
|
nhl_push_obj(lua_State *L, struct obj *otmp)
|
|
{
|
|
(void) l_obj_push(L, otmp);
|
|
}
|
|
|
|
/* local o = obj.new("large chest");
|
|
local cobj = o:contents(); */
|
|
staticfn int
|
|
l_obj_getcontents(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");
|
|
|
|
(void) l_obj_push(L, obj->cobj);
|
|
return 1;
|
|
}
|
|
|
|
/* Puts object inside another object. */
|
|
/* local box = obj.new("large chest");
|
|
box:addcontent(obj.new("rock"));
|
|
*/
|
|
staticfn int
|
|
l_obj_add_to_container(lua_State *L)
|
|
{
|
|
struct _lua_obj *lobox = l_obj_check(L, 1);
|
|
struct _lua_obj *lo = l_obj_check(L, 2);
|
|
struct obj *otmp;
|
|
int refs;
|
|
|
|
if (!lobj_is_ok(lo) || !lobj_is_ok(lobox))
|
|
return 0;
|
|
|
|
refs = lo->obj->lua_ref_cnt;
|
|
|
|
obj_extract_self(lo->obj);
|
|
otmp = add_to_container(lobox->obj, lo->obj);
|
|
|
|
/* was lo->obj merged? */
|
|
if (otmp != lo->obj) {
|
|
lo->obj = otmp;
|
|
lo->obj->lua_ref_cnt += refs;
|
|
}
|
|
lobox->obj->owt = weight(lobox->obj);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Put object into player's inventory */
|
|
/* u.giveobj(obj.new("rock")); */
|
|
int
|
|
nhl_obj_u_giveobj(lua_State *L)
|
|
{
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
struct obj *otmp;
|
|
int refs;
|
|
|
|
if (!lobj_is_ok(lo) || lo->obj->where == OBJ_INVENT)
|
|
return 0;
|
|
|
|
refs = lo->obj->lua_ref_cnt;
|
|
|
|
obj_extract_self(lo->obj);
|
|
otmp = addinv(lo->obj);
|
|
|
|
if (otmp != lo->obj) {
|
|
lo->obj->lua_ref_cnt += refs;
|
|
lo->obj = otmp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DISABLE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* Get a table of object class data. */
|
|
/* local odata = obj.class(otbl.otyp); */
|
|
/* local odata = obj.class(obj.new("rock")); */
|
|
/* local odata = o:class(); */
|
|
staticfn int
|
|
l_obj_objects_to_table(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
int otyp = -1;
|
|
struct objclass *o;
|
|
|
|
if (argc != 1) {
|
|
nhl_error(L, "l_obj_objects_to_table: Wrong args");
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
otyp = (int) luaL_checkinteger(L, 1);
|
|
} else if (lua_type(L, 1) == LUA_TUSERDATA) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
if (lo && lo->obj)
|
|
otyp = lo->obj->otyp;
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
if (otyp == -1) {
|
|
nhl_error(L, "l_obj_objects_to_table: Wrong args");
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
o = &objects[otyp];
|
|
|
|
lua_newtable(L);
|
|
|
|
if (OBJ_NAME(objects[otyp]))
|
|
nhl_add_table_entry_str(L, "name", OBJ_NAME(objects[otyp]));
|
|
if (OBJ_DESCR(objects[otyp]))
|
|
nhl_add_table_entry_str(L, "descr",
|
|
OBJ_DESCR(objects[otyp]));
|
|
if (o->oc_uname)
|
|
nhl_add_table_entry_str(L, "uname", o->oc_uname);
|
|
|
|
nhl_add_table_entry_int(L, "name_known", o->oc_name_known);
|
|
nhl_add_table_entry_int(L, "merge", o->oc_merge);
|
|
nhl_add_table_entry_int(L, "uses_known", o->oc_uses_known);
|
|
nhl_add_table_entry_int(L, "pre_discovered", o->oc_pre_discovered);
|
|
nhl_add_table_entry_int(L, "magic", o->oc_magic);
|
|
nhl_add_table_entry_int(L, "charged", o->oc_charged);
|
|
nhl_add_table_entry_int(L, "unique", o->oc_unique);
|
|
nhl_add_table_entry_int(L, "nowish", o->oc_nowish);
|
|
nhl_add_table_entry_int(L, "big", o->oc_big);
|
|
/* TODO: oc_bimanual, oc_bulky */
|
|
nhl_add_table_entry_int(L, "tough", o->oc_tough);
|
|
nhl_add_table_entry_int(L, "dir", o->oc_dir); /* TODO: convert to text */
|
|
nhl_add_table_entry_int(L, "material", o->oc_material); /* TODO: convert to text */
|
|
/* TODO: oc_subtyp, oc_skill, oc_armcat */
|
|
nhl_add_table_entry_int(L, "oprop", o->oc_oprop);
|
|
nhl_add_table_entry_char(L, "class",
|
|
def_oc_syms[(uchar) o->oc_class].sym);
|
|
nhl_add_table_entry_int(L, "delay", o->oc_delay);
|
|
nhl_add_table_entry_int(L, "color", o->oc_color); /* TODO: text? */
|
|
nhl_add_table_entry_int(L, "prob", o->oc_prob);
|
|
nhl_add_table_entry_int(L, "weight", o->oc_weight);
|
|
nhl_add_table_entry_int(L, "cost", o->oc_cost);
|
|
nhl_add_table_entry_int(L, "damage_small", o->oc_wsdam);
|
|
nhl_add_table_entry_int(L, "damage_large", o->oc_wldam);
|
|
/* TODO: oc_oc1, oc_oc2, oc_hitbon, a_ac, a_can, oc_level */
|
|
nhl_add_table_entry_int(L, "nutrition", o->oc_nutrition);
|
|
|
|
return 1;
|
|
}
|
|
|
|
RESTORE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* Create a lua table representation of the object, unpacking all the
|
|
object fields.
|
|
local o = obj.new("rock");
|
|
local otbl = o:totable(); */
|
|
staticfn int
|
|
l_obj_to_table(lua_State *L)
|
|
{
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
struct obj *obj = lo->obj;
|
|
|
|
lua_newtable(L);
|
|
|
|
if (!obj || obj->where == OBJ_LUAFREE) {
|
|
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);
|
|
|
|
if (obj->otyp == STATUE)
|
|
nhl_add_table_entry_int(L, "historic",
|
|
(obj->spe & CORPSTAT_HISTORIC) != 0);
|
|
if (obj->otyp == CORPSE || obj->otyp == STATUE) {
|
|
nhl_add_table_entry_int(L, "male",
|
|
(obj->spe & CORPSTAT_MALE) != 0);
|
|
nhl_add_table_entry_int(L, "female",
|
|
(obj->spe & CORPSTAT_FEMALE) != 0);
|
|
}
|
|
|
|
nhl_add_table_entry_char(L, "oclass",
|
|
def_oc_syms[(uchar) 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, "how_lost", obj->how_lost);
|
|
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].pmnames[NEUTRAL]);
|
|
/* 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;
|
|
}
|
|
|
|
DISABLE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* create a new object via wishing routine */
|
|
/* local o = obj.new("rock"); */
|
|
staticfn int
|
|
l_obj_new_readobjnam(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);
|
|
if ((otmp = readobjnam(buf, NULL)) == &hands_obj)
|
|
otmp = NULL;
|
|
(void) l_obj_push(L, otmp);
|
|
return 1;
|
|
} else
|
|
nhl_error(L, "l_obj_new_readobjname: Wrong args");
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
/* Get the topmost object on the map at x,y */
|
|
/* local o = obj.at(x, y); */
|
|
staticfn int
|
|
l_obj_at(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 2) {
|
|
coordxy x, y;
|
|
|
|
x = (coordxy) luaL_checkinteger(L, 1);
|
|
y = (coordxy) luaL_checkinteger(L, 2);
|
|
cvt_to_abscoord(&x, &y);
|
|
|
|
lua_pop(L, 2);
|
|
(void) l_obj_push(L, svl.level.objects[x][y]);
|
|
return 1;
|
|
} else
|
|
nhl_error(L, "l_obj_at: Wrong args");
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
/* Place an object on the map at (x,y).
|
|
local o = obj.new("rock");
|
|
o:placeobj(u.ux, u.uy); */
|
|
staticfn int
|
|
l_obj_placeobj(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
coordxy x, y;
|
|
|
|
if (argc != 3)
|
|
nhl_error(L, "l_obj_placeobj: Wrong args");
|
|
|
|
x = (coordxy) luaL_checkinteger(L, 2);
|
|
y = (coordxy) luaL_checkinteger(L, 3);
|
|
cvt_to_abscoord(&x, &y);
|
|
|
|
lua_pop(L, 3);
|
|
|
|
if (lobj_is_ok(lo)) {
|
|
obj_extract_self(lo->obj);
|
|
place_object(lo->obj, x, y);
|
|
newsym(x, y);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
RESTORE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* Get the next object in the object chain */
|
|
/* local o = obj.at(x, y);
|
|
local o2 = o:next(true);
|
|
local firstobj = obj.next();
|
|
*/
|
|
staticfn int
|
|
l_obj_nextobj(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 0) {
|
|
(void) l_obj_push(L, fobj);
|
|
} else {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
boolean use_nexthere = FALSE;
|
|
|
|
if (argc == 2)
|
|
use_nexthere = lua_toboolean(L, 2);
|
|
|
|
if (lo && lo->obj)
|
|
(void) l_obj_push(L, (use_nexthere && lo->obj->where == OBJ_FLOOR)
|
|
? lo->obj->nexthere
|
|
: lo->obj->nobj);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Get the container object is in */
|
|
/* local box = o:container(); */
|
|
staticfn int
|
|
l_obj_container(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);
|
|
else
|
|
(void) l_obj_push(L, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/* Is the object a null? */
|
|
/* local badobj = o:isnull(); */
|
|
staticfn int
|
|
l_obj_isnull(lua_State *L)
|
|
{
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
|
|
lua_pushboolean(L, !lobj_is_ok(lo));
|
|
return 1;
|
|
}
|
|
|
|
DISABLE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* does object have a timer of certain type? */
|
|
/* local hastimer = o:has_timer("rot-organic"); */
|
|
staticfn int
|
|
l_obj_timer_has(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 2) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
short timertype = nhl_get_timertype(L, 2);
|
|
|
|
if (timer_is_obj(timertype) && lo && lo->obj) {
|
|
lua_pushboolean(L, obj_has_timer(lo->obj, timertype));
|
|
return 1;
|
|
} else {
|
|
lua_pushboolean(L, FALSE);
|
|
return 1;
|
|
}
|
|
} else
|
|
nhl_error(L, "l_obj_timer_has: Wrong args");
|
|
return 0;
|
|
}
|
|
|
|
/* peek at an object timer. return the turn when timer triggers.
|
|
returns 0 if no such timer attached to the object. */
|
|
/* local timeout = o:peek_timer("hatch-egg"); */
|
|
staticfn int
|
|
l_obj_timer_peek(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 2) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
short timertype = nhl_get_timertype(L, 2);
|
|
|
|
if (timer_is_obj(timertype) && lo && lo->obj) {
|
|
lua_pushinteger(L, peek_timer(timertype, obj_to_any(lo->obj)));
|
|
return 1;
|
|
} else {
|
|
lua_pushinteger(L, 0);
|
|
return 1;
|
|
}
|
|
} else
|
|
nhl_error(L, "l_obj_timer_peek: Wrong args");
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
/* stop object timer(s). return the turn when timer triggers.
|
|
returns 0 if no such timer attached to the object.
|
|
without a timer type parameter, stops all timers for the object. */
|
|
/* local timeout = o:stop_timer("rot-organic"); */
|
|
/* o:stop_timer(); */
|
|
staticfn int
|
|
l_obj_timer_stop(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 1) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
|
|
if (lo && lo->obj)
|
|
obj_stop_timers(lo->obj);
|
|
return 0;
|
|
|
|
} else if (argc == 2) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
short timertype = nhl_get_timertype(L, 2);
|
|
|
|
if (timer_is_obj(timertype) && lo && lo->obj) {
|
|
lua_pushinteger(L, stop_timer(timertype, obj_to_any(lo->obj)));
|
|
return 1;
|
|
} else {
|
|
lua_pushinteger(L, 0);
|
|
return 1;
|
|
}
|
|
} else
|
|
nhl_error(L, "l_obj_timer_stop: Wrong args");
|
|
return 0;
|
|
}
|
|
|
|
RESTORE_WARNING_UNREACHABLE_CODE
|
|
|
|
/* start an object timer. */
|
|
/* o:start_timer("hatch-egg", 10); */
|
|
staticfn int
|
|
l_obj_timer_start(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
|
|
if (argc == 3) {
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
short timertype = nhl_get_timertype(L, 2);
|
|
long when = luaL_checkinteger(L, 3);
|
|
|
|
if (timer_is_obj(timertype) && lo && lo->obj && when > 0) {
|
|
if (obj_has_timer(lo->obj, timertype))
|
|
stop_timer(timertype, obj_to_any(lo->obj));
|
|
start_timer(when, TIMER_OBJECT, timertype, obj_to_any(lo->obj));
|
|
}
|
|
} else
|
|
nhl_error(L, "l_obj_timer_start: Wrong args");
|
|
return 0;
|
|
}
|
|
|
|
/* bury an obj. returns true if object is gone (merged with ground),
|
|
false otherwise. */
|
|
/* local ogone = o:bury(); */
|
|
/* local ogone = o:bury(5,5); */
|
|
staticfn int
|
|
l_obj_bury(lua_State *L)
|
|
{
|
|
int argc = lua_gettop(L);
|
|
boolean dealloced = FALSE;
|
|
struct _lua_obj *lo = l_obj_check(L, 1);
|
|
coordxy x = 0, y = 0;
|
|
|
|
if (argc == 1) {
|
|
x = lo->obj->ox;
|
|
y = lo->obj->oy;
|
|
} else if (argc == 3) {
|
|
x = (coordxy) lua_tointeger(L, 2);
|
|
y = (coordxy) lua_tointeger(L, 3);
|
|
cvt_to_abscoord(&x, &y);
|
|
} else
|
|
nhl_error(L, "l_obj_bury: Wrong args");
|
|
|
|
if (lobj_is_ok(lo) && isok(x, y)) {
|
|
lo->obj->ox = x;
|
|
lo->obj->oy = y;
|
|
(void) bury_an_obj(lo->obj, &dealloced);
|
|
}
|
|
lua_pushboolean(L, dealloced);
|
|
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 },
|
|
{ "class", l_obj_objects_to_table },
|
|
{ "placeobj", l_obj_placeobj },
|
|
{ "container", l_obj_container },
|
|
{ "contents", l_obj_getcontents },
|
|
{ "addcontent", l_obj_add_to_container },
|
|
{ "has_timer", l_obj_timer_has },
|
|
{ "peek_timer", l_obj_timer_peek },
|
|
{ "stop_timer", l_obj_timer_stop },
|
|
{ "start_timer", l_obj_timer_start },
|
|
{ "bury", l_obj_bury },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
static const luaL_Reg l_obj_meta[] = {
|
|
{ "__gc", l_obj_gc },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
int
|
|
l_obj_register(lua_State *L)
|
|
{
|
|
/* Table of instance methods (e.g. an_object:isnull())
|
|
and static methods (e.g. obj.new("dagger")). */
|
|
luaL_newlib(L, l_obj_methods);
|
|
|
|
/* metatable = { __name = "obj", __gc = l_obj_gc } */
|
|
luaL_newmetatable(L, "obj");
|
|
luaL_setfuncs(L, l_obj_meta, 0);
|
|
/* metatable.__index points at the object method table. */
|
|
lua_pushvalue(L, -2);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
/* Don't let lua code mess with the real metatable.
|
|
Instead offer a fake one that only contains __gc. */
|
|
luaL_newlib(L, l_obj_meta);
|
|
lua_setfield(L, -2, "__metatable");
|
|
|
|
/* We don't need the metatable anymore. It's safe in the
|
|
Lua registry for use by luaL_setmetatable. */
|
|
lua_pop(L, 1);
|
|
|
|
/* global obj = the method table we created at the start */
|
|
lua_setglobal(L, "obj");
|
|
return 0;
|
|
}
|
|
|
|
/* for 'onefile' processing where end of this file isn't necessarily the
|
|
end of the source code seen by the compiler */
|
|
#undef lobj_is_ok
|
|
|
|
/*nhlobj.c*/
|