]> granicus.if.org Git - nethack/commitdiff
Lua: object timers
authorPasi Kallinen <paxed@alt.org>
Sun, 13 Mar 2022 12:29:32 +0000 (14:29 +0200)
committerPasi Kallinen <paxed@alt.org>
Sun, 13 Mar 2022 12:50:07 +0000 (14:50 +0200)
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.

include/extern.h
include/timeout.h
src/nhlobj.c
src/nhlua.c

index 8495288c94da2b493212394b80649054892adda7..41a1316b0aad5c93d9449d26b2b3c0dbb0d97695 100644 (file)
@@ -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 *);
index 28ae7428d395762dcf52707897fe294b99d3358f..a36283cf31421e96283bc7124ab7e3a9e8fa6113 100644 (file)
@@ -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 */
index 88ef6d87bb57222f3aef1366ca87a6c54eecfb5f..85f0a266bb220338907d200e79d9562a926f73ec 100644 (file)
@@ -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 }
 };
 
index a26202919b298e07b8970caac9cc71cd59933001..9afce562979ccbb7b2d56813780a5fc15f7c0e0a 100644 (file)
@@ -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)
 {