diff --git a/docs/game_data/spel2.lua b/docs/game_data/spel2.lua index 8c57890d4..a4227a2e4 100644 --- a/docs/game_data/spel2.lua +++ b/docs/game_data/spel2.lua @@ -2566,6 +2566,10 @@ function PRNG:random(min, max) end ---@field set_post_activate fun(self, fun: fun(self: Entity, activator: Entity): boolean): CallbackId @Hooks after the virtual function.
The callback signature is `nil activate(Entity self, Entity activator)`
Virtual function docs:
Activates a button prompt (with the Use door/Buy button), e.g. buy shop item, activate drill, read sign, interact in camp, ... `get_entity():activate(players[1])` (make sure player 1 has the udjat eye though) ---@field set_pre_on_collision2 fun(self, fun: fun(self: Entity, other_entity: Entity): boolean): CallbackId @Hooks before the virtual function.
The callback signature is `bool on_collision2(Entity self, Entity other_entity)` ---@field set_post_on_collision2 fun(self, fun: fun(self: Entity, other_entity: Entity): boolean): CallbackId @Hooks after the virtual function.
The callback signature is `nil on_collision2(Entity self, Entity other_entity)` + ---@field set_pre_get_metadata fun(self, fun: fun(self: Entity): integer?): CallbackId @Hooks before the virtual function.
The callback signature is `optional get_metadata(Entity self)`
Virtual function docs:
e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred) + ---@field set_post_get_metadata fun(self, fun: fun(self: Entity): integer?): CallbackId @Hooks after the virtual function.
The callback signature is `nil get_metadata(Entity self)`
Virtual function docs:
e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred) + ---@field set_pre_apply_metadata fun(self, fun: fun(self: Entity, metadata: integer): boolean): CallbackId @Hooks before the virtual function.
The callback signature is `bool apply_metadata(Entity self, integer metadata)` + ---@field set_post_apply_metadata fun(self, fun: fun(self: Entity, metadata: integer): boolean): CallbackId @Hooks after the virtual function.
The callback signature is `nil apply_metadata(Entity self, integer metadata)` ---@field set_pre_walked_on fun(self, fun: fun(self: Entity, Entity: ): boolean): CallbackId @Hooks before the virtual function.
The callback signature is `bool walked_on(Entity self, Entity)` ---@field set_post_walked_on fun(self, fun: fun(self: Entity, Entity: ): boolean): CallbackId @Hooks after the virtual function.
The callback signature is `nil walked_on(Entity self, Entity)` ---@field set_pre_walked_off fun(self, fun: fun(self: Entity, Entity: ): boolean): CallbackId @Hooks before the virtual function.
The callback signature is `bool walked_off(Entity self, Entity)` diff --git a/docs/src/includes/_enums.md b/docs/src/includes/_enums.md index c814abaf5..cf9ee146a 100644 --- a/docs/src/includes/_enums.md +++ b/docs/src/includes/_enums.md @@ -240,6 +240,8 @@ Name | Data | Description [TRIGGER_ACTION](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.TRIGGER_ACTION) | 24 | [ACTIVATE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.ACTIVATE) | 25 | [ON_COLLISION2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.ON_COLLISION2) | 26 | +[GET_METADATA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.GET_METADATA) | 27 | +[APPLY_METADATA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.APPLY_METADATA) | 28 | [WALKED_ON](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.WALKED_ON) | 29 | [WALKED_OFF](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.WALKED_OFF) | 30 | [LEDGE_GRAB](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.LEDGE_GRAB) | 31 | diff --git a/docs/src/includes/_types.md b/docs/src/includes/_types.md index ebdf84372..b02bb935e 100644 --- a/docs/src/includes/_types.md +++ b/docs/src/includes/_types.md @@ -4286,6 +4286,10 @@ nil | [clear_virtual(CallbackId callback_id)](https://github.com/spelunky-fyi/ov [CallbackId](#Aliases) | [set_post_activate(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_activate) | Hooks after the virtual function.
The callback signature is `nil activate(Entity self, Entity activator)`
Virtual function docs:
Activates a button prompt (with the Use door/Buy button), e.g. buy shop item, activate drill, read sign, interact in camp, ... `get_entity():activate(players[1])` (make sure player 1 has the udjat eye though) [CallbackId](#Aliases) | [set_pre_on_collision2(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_on_collision2) | Hooks before the virtual function.
The callback signature is `bool on_collision2(Entity self, Entity other_entity)` [CallbackId](#Aliases) | [set_post_on_collision2(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_on_collision2) | Hooks after the virtual function.
The callback signature is `nil on_collision2(Entity self, Entity other_entity)` +[CallbackId](#Aliases) | [set_pre_get_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_get_metadata) | Hooks before the virtual function.
The callback signature is `optional get_metadata(Entity self)`
Virtual function docs:
e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred) +[CallbackId](#Aliases) | [set_post_get_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_get_metadata) | Hooks after the virtual function.
The callback signature is `nil get_metadata(Entity self)`
Virtual function docs:
e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred) +[CallbackId](#Aliases) | [set_pre_apply_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_apply_metadata) | Hooks before the virtual function.
The callback signature is `bool apply_metadata(Entity self, int metadata)` +[CallbackId](#Aliases) | [set_post_apply_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_apply_metadata) | Hooks after the virtual function.
The callback signature is `nil apply_metadata(Entity self, int metadata)` [CallbackId](#Aliases) | [set_pre_walked_on(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_walked_on) | Hooks before the virtual function.
The callback signature is `bool walked_on(Entity self, Entity)` [CallbackId](#Aliases) | [set_post_walked_on(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_walked_on) | Hooks after the virtual function.
The callback signature is `nil walked_on(Entity self, Entity)` [CallbackId](#Aliases) | [set_pre_walked_off(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_walked_off) | Hooks before the virtual function.
The callback signature is `bool walked_off(Entity self, Entity)` diff --git a/examples/entity_metadata.lua b/examples/entity_metadata.lua new file mode 100644 index 000000000..69dc96857 --- /dev/null +++ b/examples/entity_metadata.lua @@ -0,0 +1,69 @@ +meta.name = 'Entity Metatable Override' +meta.description = 'Demonstrate information transfer from one entity to another thru level transition using metadata. Using overlunky UI change the width and height of rock entity and bring it to the next level' +meta.author = 'Mr-Auto' + +local metadata_table = {} +local metadata_next_uid = 1 + +set_callback(function() + metadata_table = {} + metadata_next_uid = 1 +end, ON.START) + +function get_new_medata_uid() + local uid = metadata_next_uid + metadata_next_uid = metadata_next_uid + 1 + -- matedata is stored as 16bit integer, we can't store bigger number + -- this could be improved by lookup for an cleared id instead of just override whatever is there at index 1 and up + -- but 65535 is a lot and should be enough for most use cases + if metadata_next_uid > 65535 then + metadata_next_uid = 1 + end + return uid +end + +local inner_call = false -- used to prevent infinite recursion + +function get_metadata_override(ent) + if not inner_call then + inner_call = true + local org_data = ent:get_metadata() -- call original to get the actual metadata + inner_call = false + + -- for stuff like rock that doesn't use metadata we probably could just simplify all of this + -- but this example is meant to work for any entity, also this supports multiple scripts with this code running at the same time + local uid = get_new_medata_uid() + metadata_table[uid] = { + metadata = org_data, + data = Vec2:new(ent.width, ent.height) + -- can get most types of data from entity, also stuff from user_data + -- exception for color, since game changes it to black when going thru layer door + } + return uid + end +end + +function apply_metadata_override(ent, uid) + if uid ~= 0 then + if metadata_table[uid] then + if not inner_call then + inner_call = true + ent:apply_metadata(metadata_table[uid].metadata) -- call original to apply the actual metadata + inner_call = false + + -- need to apply back all the data + ent.width = metadata_table[uid].data.x + ent.height = metadata_table[uid].data.y + metadata_table[uid] = nil + return true -- just to skip the execution of the game funcitonf + end + end + end +end + +set_post_entity_spawn(function(ent) + -- called when level unloads, probably one of the last chances to get entity information + ent:set_pre_get_metadata(get_metadata_override) + -- called after spawning of the entity that was transferred thru level/wadler storage + ent:set_pre_apply_metadata(apply_metadata_override) +end, SPAWN_TYPE.ANY, MASK.ANY, ENT_TYPE.ITEM_ROCK) diff --git a/src/game_api/script/usertypes/vtables_lua.cpp b/src/game_api/script/usertypes/vtables_lua.cpp index 5cb5f67f7..eafeb2028 100644 --- a/src/game_api/script/usertypes/vtables_lua.cpp +++ b/src/game_api/script/usertypes/vtables_lua.cpp @@ -32,6 +32,8 @@ void register_usertypes(sol::state& lua) VTableEntry<"trigger_action", 0x18, void(Entity*)>, VTableEntry<"activate", 0x19, void(Entity*)>, VTableEntry<"on_collision2", 0x1a, void(Entity*)>, + VTableEntry<"get_metadata", 0x1b, uint16_t()>, + VTableEntry<"apply_metadata", 0x1c, void(uint16_t)>, VTableEntry<"walked_on", 0x1d, void(Entity*)>, VTableEntry<"walked_off", 0x1e, void(Entity*)>, VTableEntry<"ledge_grab", 0x1f, void(Entity*)>,