Skip to content

Instantly share code, notes, and snippets.

@LaughingLeader
Last active October 27, 2022 01:08
Show Gist options
  • Save LaughingLeader/f32d91b188c81ca392a5054d1f5676b1 to your computer and use it in GitHub Desktop.
Save LaughingLeader/f32d91b188c81ca392a5054d1f5676b1 to your computer and use it in GitHub Desktop.
Example of making a system for registering functions to call when flags are set, for Divinity: Original Sin 2 with the Script Extender.
EventManager = {
Register = {},
}
---@alias EventManagerObjectFlagSetCallback fun(flag:string, targetGUID:GUID, dialogInstance:integer)
local _Callbacks = {
ObjectFlagSet = {
---@type table<string, EventManagerObjectFlagSetCallback[]>
Active = {},
Regions = {
__ANY__ = {}, -- Any region,
}
},
}
local function _GetCurrentLevel()
local current = Ext.Entity.GetCurrentLevel()
if current then
return current.LevelDesc.LevelName
end
return ""
end
--[[
This is configured to be 1 function per flag (using a key-value type table where the flag is the key),
but could be changed to support multiple callbacks for the same flags.
]]
---Register a function to call when the given flag(s) are set.
---@param flag string|string[] Any single flag, or a table of flags.
---@param callback EventManagerObjectFlagSetCallback
---@param region string|nil
function EventManager.Register.ObjectFlagSet(flag, callback, region)
if not region then
region = "__ANY__"
end
if _Callbacks.ObjectFlagSet.Regions[region] == nil then
_Callbacks.ObjectFlagSet.Regions[region] = {}
end
local t = type(flag)
if t == "table" then
for _,v in pairs(flag) do
_Callbacks.ObjectFlagSet.Regions[region][v] = callback
end
elseif t == "string" then
_Callbacks.ObjectFlagSet.Regions[region][flag] = callback
else
error("Wrong flag type: " .. t, 2)
end
end
local function _BuildCallbacks(region)
local tbl = {}
local regionCallbacks = _Callbacks.ObjectFlagSet.Regions[region]
if regionCallbacks then
for flag,v in pairs(regionCallbacks) do
if tbl[flag] == nil then tbl[flag] = {} end
table.insert(tbl[flag], v)
end
end
for flag,v in pairs(_Callbacks.ObjectFlagSet.Regions.__ANY__) do
if tbl[flag] == nil then tbl[flag] = {} end
table.insert(tbl[flag], v)
end
_Callbacks.ObjectFlagSet.Active = tbl
end
Ext.Osiris.RegisterListener("RegionStarted", 1, "after", _BuildCallbacks)
Ext.Events.ResetCompleted:Subscribe(function (e) _BuildCallbacks(_GetCurrentLevel()) end)
Ext.Osiris.RegisterListener("ObjectFlagSet", 3, "after", function (flag, targetGUID, inst)
---@cast flag string
local callbacks = _Callbacks.ObjectFlagSet.Active[flag]
if callbacks then
targetGUID = GetUUID(targetGUID)
for _,v in pairs(callbacks) do
local b,err = xpcall(v, debug.traceback, flag, targetGUID, inst)
if not b then
Ext.Utils.PrintError(err)
end
end
end
end)
--[[
--Usage Example:
EventManager.Register.ObjectFlagSet({"QuestUpdate_TUT_ShipMurder_Fled", "QuestUpdate_TUT_ShipMurder_Rescued", "QuestUpdate_TUT_ShipMurder_Failed"},
function (flag, targetGUID, dialogInstance)
for key, value in pairs(TUT_Char) do
if CharacterIsDead(value) == 0 then
Crew[value] = true
else
Crew[value] = nil
end
end
end, "TUT_Tutorial_A")
]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment