Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/fxdata/lua/classes/Thing.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
---@field health integer
---@field max_health integer If the health gets beyond this point, it will be decreased.
---@field picked_up boolean
---@field lua_data table A table that can be used to store any Lua data on the thing. arbitrary data accessible from all Lua code.
if not Thing then Thing = {} end

---@class Object: Thing
Expand Down
10 changes: 9 additions & 1 deletion config/fxdata/lua/triggers/Builtins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
-- Entry points for engine-triggered events (e.g. OnPowerCast, OnGameTick).
-- These functions are called by the C engine and dispatch event data to the Lua trigger system.

---@alias event_type "PowerCast"|"Death"|"SpecialActivated"|"GameTick"|"ChatMsg"|"DungeonDestroyed"|"TrapPlaced"|"ApplyDamage"|"LevelUp"|"Rebirth"|"SlabKindChange"|"SlabOwnerChange"|"RoomOwnerChange"|"ShotHitThing"|"Destroyed"
---@alias event_type "PowerCast"|"Death"|"SpecialActivated"|"GameTick"|"ChatMsg"|"DungeonDestroyed"|"TrapPlaced"|"ApplyDamage"|"LevelUp"|"Rebirth"|"SlabKindChange"|"SlabOwnerChange"|"RoomOwnerChange"|"ShotHitThing"|"Destroyed"|"ThingDeleted"

--- Called when a spell is cast on a unit
--- @param pwkind power_kind
Expand Down Expand Up @@ -153,4 +153,12 @@ function OnShotHit(shot, shooter, target, next_stl_x, next_stl_y, rebound_hit)
eventData.next_stl_y = next_stl_y
eventData.rebound_hit = rebound_hit
ProcessEvent("ShotHitThing",eventData)
end

--- Called when a thing is deleted
---@param thing Thing the thing being deleted.
function OnThingDeleted(thing)
local eventData = {}
eventData.thing = thing
ProcessEvent("ThingDeleted",eventData)
end
14 changes: 14 additions & 0 deletions config/fxdata/lua/triggers/Events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,18 @@ function RegisterOnShotHitEvent(action, shooter_type, target_type, shot_type)
TriggerAddCondition(trigger, function(eventData, triggerData) return eventData.shot.model == triggerData.shot_type end)
end
return trigger
end

---Triggers when a shot hits something
---eventData.thing contains the deleted thing
---@param action function|string the function to call when the event happens
---@param thing? Thing the thing that was deleted (nil for any)
---@return table
function RegisterThingDeletedEvent(action, thing)
local trigData = {thing = thing}
local trigger = CreateTrigger("ThingDeleted", action, trigData)
if thing then
TriggerAddCondition(trigger, function(eventData, triggerData) return eventData.thing == triggerData.thing end)
end
return trigger
end
53 changes: 53 additions & 0 deletions src/lua_api_things.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,63 @@
#include "lua_utils.h"


#include "lua_api.h"

#include "post_inc.h"

/**********************************************/
static int thing_set_field(lua_State *L);
static int thing_get_field(lua_State *L);

static void get_or_create_lua_data_table(lua_State *L, struct Thing* thing) {
// Get the global Game table
lua_getglobal(L, "Game");
if (!lua_istable(L, -1)) {
lua_pop(L, 1); // Pop whatever is on top
lua_newtable(L);
lua_setglobal(L, "Game");
lua_getglobal(L, "Game");
}

// Get or create Game.LuaData
lua_getfield(L, -1, "LuaData");
if (!lua_istable(L, -1)) {
lua_pop(L, 1); // Pop nil
lua_newtable(L);
lua_setfield(L, -2, "LuaData"); // Set Game.LuaData
lua_getfield(L, -1, "LuaData");
}

// Get or create Game.LuaData.Thing
lua_getfield(L, -1, "Thing");
if (!lua_istable(L, -1)) {
lua_pop(L, 1); // Pop nil
lua_newtable(L);
lua_setfield(L, -2, "Thing"); // Set Game.LuaData.Thing
lua_getfield(L, -1, "Thing");
}

// Now Game.LuaData.Thing is at the top of the stack.
// Create a unique key for the thing's data table
char key[40];
snprintf(key, sizeof(key), "thing_%d_%d", thing->index, thing->creation_turn);

// Get or create the specific table for this thing
lua_getfield(L, -1, key);
if (lua_isnil(L, -1)) {
lua_pop(L, 1); // Pop nil
lua_newtable(L);
lua_setfield(L, -2, key); // Set Game.LuaData.Thing[key]
lua_getfield(L, -1, key);
}

// The desired table is now at the top of the stack.
// We need to clean up the stack, leaving only the thing's data table.
lua_remove(L, -2); // Remove Game.LuaData.Thing
lua_remove(L, -2); // Remove Game.LuaData
lua_remove(L, -2); // Remove Game
}

static const struct luaL_Reg thing_methods[];


Expand Down Expand Up @@ -481,6 +532,8 @@ static int thing_get_field(lua_State *L) {
lua_pushboolean(L, thing_is_picked_up(thing));
} else if (strcmp(key, "thing_class") == 0) {
lua_pushstring(L, thing_class_code_name(thing->class_id));
} else if (strcmp(key, "lua_data") == 0) {
get_or_create_lua_data_table(L, thing);
} else if (try_get_from_methods(L, 1, key)) {
return 1;
}
Expand Down
34 changes: 34 additions & 0 deletions src/lua_triggers.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@

#include "post_inc.h"

static void delete_thing_lua_data(lua_State *L, struct Thing* thing) {

// Get Game.LuaData.Thing table
lua_getglobal(L, "Game");
if (!lua_istable(L, -1)) { lua_pop(L, 1); return; }
lua_getfield(L, -1, "LuaData");
if (!lua_istable(L, -1)) { lua_pop(L, 2); return; }
lua_getfield(L, -1, "Thing");
if (!lua_istable(L, -1)) { lua_pop(L, 3); return; }

char key[40];
snprintf(key, sizeof(key), "thing_%d_%d", thing->index, thing->creation_turn);
lua_pushnil(L);
lua_setfield(L, -2, key);

lua_pop(L, 3);
}

void lua_on_thing_deleted(struct Thing *thing)
{
SYNCDBG(6, "Starting");
delete_thing_lua_data(Lvl_script, thing);
lua_getglobal(Lvl_script, "OnThingDeleted");
if (lua_isfunction(Lvl_script, -1))
{
lua_pushThing(Lvl_script, thing);
CheckLua(Lvl_script, lua_pcall(Lvl_script, 1, 0, 0), "OnThingDeleted");
}
else
{
lua_pop(Lvl_script, 1);
}
}

void lua_on_dungeon_destroyed(PlayerNumber plyr_idx)
{
SYNCDBG(6,"Starting");
Expand Down
1 change: 1 addition & 0 deletions src/lua_triggers.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void lua_on_slab_kind_change(MapSlabCoord slb_x, MapSlabCoord slb_y, SlabKind ol
void lua_on_slab_owner_change(MapSlabCoord slb_x, MapSlabCoord slb_y, PlayerNumber old_owner);
void lua_on_room_owner_change(struct Room *room, PlayerNumber old_owner);
void lua_on_shot_hit(struct Thing *shot, struct Thing *shooter, struct Thing *target, MapSubtlCoord next_stl_x, MapSubtlCoord next_stl_y, bool rebound_hit);
void lua_on_thing_deleted(struct Thing *thing);

#ifdef __cplusplus
}
Expand Down
2 changes: 2 additions & 0 deletions src/thing_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "engine_arrays.h"
#include "kjm_input.h"
#include "gui_topmsg.h"
#include "lua_triggers.h"
#include "post_inc.h"

#ifdef __cplusplus
Expand Down Expand Up @@ -159,6 +160,7 @@ void delete_thing_structure_f(struct Thing *thing, TbBool deleting_everything, c
remove_first_creature(thing);
}
if (!deleting_everything) {
lua_on_thing_deleted(thing);
struct CreatureControl *cctrl = creature_control_get_from_thing(thing);
if (!creature_control_invalid(cctrl)) {
if (creature_under_spell_effect(thing, CSAfF_Armour)) {
Expand Down