From 814eea8e1855e58cf1364ea06ff7e88d84e1f533 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 31 Oct 2026 13:29:07 -0500 Subject: [PATCH] add `dfhack.timeout_until` callback triggered on a specific tick --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 9 +++++++++ library/LuaTools.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index c2470dbe87..011579b80b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -69,6 +69,7 @@ Template for new versions: ## API ## Lua +- ``dfhack.timeout_until``: new function to schedule a callback to run on a specified in-game tick ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 2f55e17184..9ef2f50ec5 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3824,6 +3824,15 @@ Core context specific functions: Returns the timer id, or *nil* if unsuccessful due to world being unloaded. +* ``dfhack.timeout_until(tick,callback)`` + + Arranges for the callback to be called once the in-game + tick count (``df.global.world.frame_counter``) reaches + the specified value. The timer is canceled when the + world is unloaded, and cannot be queued until it is + loaded again. Returns the timer id, or *nil* if + unsuccessful due to world being unloaded. + * ``dfhack.timeout_active(id[,new_callback])`` Returns the active callback with the given id, or *nil* diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 3b4bf16fe9..44fe872cb8 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -2036,6 +2036,38 @@ int dfhack_timeout(lua_State *L) return 1; } +int dfhack_timeout_until(lua_State *L) +{ + using df::global::world; + + // Parse arguments + lua_Number tick = luaL_checknumber(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_settop(L, 2); + + if (!Core::getInstance().isWorldLoaded()) + { + lua_pushnil(L); + return 1; + } + + int delta = tick - world->frame_counter; + + if (delta <= 0) + luaL_error(L, "Invalid timeout: %d", delta); + + // Queue the timeout + int id = next_timeout_id++; + tick_timers.insert(std::pair(tick, id)); + + lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN); + lua_swap(L); + lua_rawseti(L, -2, id); + + lua_pushinteger(L, id); + return 1; +} + int dfhack_timeout_active(lua_State *L) { int id = luaL_optint(L, 1, -1); @@ -2147,6 +2179,8 @@ static void Lua::Core::InitCoreContext(color_ostream &out) lua_pushcfunction(State, dfhack_timeout); lua_setfield(State, -2, "timeout"); + lua_pushcfunction(State, dfhack_timeout_until); + lua_setfield(State, -2, "timeout_until"); lua_pushcfunction(State, dfhack_timeout_active); lua_setfield(State, -2, "timeout_active");