From: Pasi Kallinen Date: Sun, 13 Mar 2022 12:29:32 +0000 (+0200) Subject: Lua: object timers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20f214592ab70e5f9340dcf1cd7e7bdd9730c865;p=nethack Lua: object timers Expose object timers to lua scripts. For example: local o = obj.new("cockatrice egg"); o:placeobj(5, 5); o:start_timer("hatch-egg", 3); Available methods are: - obj.has_timer("rot-corpse") returns true if object has attached timer, false otherwise. - obj.peek_timer("hatch-egg") returns an integer value, which is the turn when the timer attached to the object would trigger. returns 0 if no such timer. - obj.stop_timer("shrink-glob") stops attached timer, or if no timer type is given, stops all timers attached to the object. - obj.start_timer("zombify-mon", 15) starts a timer with a trigger time in that many turns in the future. replaces any previous timer of the same type. Valid timers are "rot-organic", "rot-corpse", "revive-mon", "zombify-mon", "burn-obj", "hatch-egg", "fig-transform", and "shrink-glob". Also "melt-ice" is recognized, but does nothing to objects. --- diff --git a/include/extern.h b/include/extern.h index 8495288c9..41a1316b0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1755,6 +1755,7 @@ extern void nhl_error(lua_State *, const char *) NORETURN; extern void lcheck_param_table(lua_State *); extern schar get_table_mapchr(lua_State *, const char *); extern schar get_table_mapchr_opt(lua_State *, const char *, schar); +extern short nhl_get_timertype(lua_State *, int); extern void nhl_add_table_entry_int(lua_State *, const char *, int); extern void nhl_add_table_entry_char(lua_State *, const char *, char); extern void nhl_add_table_entry_str(lua_State *, const char *, const char *); diff --git a/include/timeout.h b/include/timeout.h index 28ae7428d..a36283cf3 100644 --- a/include/timeout.h +++ b/include/timeout.h @@ -39,6 +39,15 @@ enum timeout_types { NUM_TIME_FUNCS }; +#define timer_is_obj(ttype) ((ttype) == ROT_ORGANIC \ + || (ttype) == ROT_CORPSE \ + || (ttype) == REVIVE_MON \ + || (ttype) == ZOMBIFY_MON \ + || (ttype) == BURN_OBJECT \ + || (ttype) == HATCH_EGG \ + || (ttype) == FIG_TRANSFORM \ + || (ttype) == SHRINK_GLOB) + /* used in timeout.c */ typedef struct fe { struct fe *next; /* next item in chain */ diff --git a/src/nhlobj.c b/src/nhlobj.c index 88ef6d87b..85f0a266b 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -22,6 +22,10 @@ static int l_obj_placeobj(lua_State *); static int l_obj_to_table(lua_State *); static int l_obj_at(lua_State *); static int l_obj_container(lua_State *); +static int l_obj_timer_has(lua_State *); +static int l_obj_timer_peek(lua_State *); +static int l_obj_timer_stop(lua_State *); +static int l_obj_timer_start(lua_State *); #define lobj_is_ok(lo) ((lo) && (lo)->obj && (lo)->obj->where != OBJ_LUAFREE) @@ -431,6 +435,107 @@ l_obj_isnull(lua_State *L) return 1; } +/* does object have a timer of certain type? */ +/* local hastimer = o:has_timer("rot-organic"); */ +static 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"); */ +static 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"); + 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(); */ +static 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; +} + +/* start an object timer. */ +/* o:start_timer("hatch-egg", 10); */ +static 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; +} static const struct luaL_Reg l_obj_methods[] = { { "new", l_obj_new_readobjnam }, @@ -443,6 +548,10 @@ static const struct luaL_Reg l_obj_methods[] = { { "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 }, { NULL, NULL } }; diff --git a/src/nhlua.c b/src/nhlua.c index a26202919..9afce5629 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -191,6 +191,21 @@ get_table_mapchr_opt(lua_State *L, const char *name, schar defval) return typ; } +short +nhl_get_timertype(lua_State *L, int idx) +{ + static const char *const timerstr[NUM_TIME_FUNCS+1] = { + "rot-organic", "rot-corpse", "revive-mon", "zombify-mon", + "burn-obj", "hatch-egg", "fig-transform", "melt-ice", "shrink-glob", + NULL + }; + short ret = luaL_checkoption(L, idx, NULL, timerstr); + + if (ret < 0 || ret >= NUM_TIME_FUNCS) + nhl_error(L, "Unknown timer type"); + return ret; +} + void nhl_add_table_entry_int(lua_State *L, const char *name, int value) {