• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[TFS 1.x] combat:setCallbackFunction(event, function)

Gesior.pl

Mega Noob&LOL 2012
Senator
Joined
Sep 18, 2007
Messages
2,964
Solutions
99
Reaction score
3,374
Location
Poland
GitHub
gesior
PROBLEM 1
combat:setCallback binds event function to combat by name (string) ex. "onGetFormulaValues", not by function ex. onGetFormulaValues:
Lua:
function onGetFormulaValues(x, y, z)
    return 0
end

combat = Combat()
combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

PROBLEM 2
You cannot use same callback function for 2 combats. It's removed from Lua, when you call setCallbackFunction ex.:
Lua:
function onGetFormulaValues(x, y, z)
    return 0
end

combat1 = Combat()
combat1:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")
-- NOW function onGetFormulaValues is not defined, it was removed from Lua by setCallback

combat2 = Combat()
-- THIS will throw error: "[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found."
combat2:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

It blocks possibility to add same callback to multiple combats in loop (ex. in spell with multiple delayed effects with addEvent):
Lua:
function onGetFormulaValues(x, y, z)
    return 0
end

local combats = {}

combats[1] = Combat()
combats[1]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_ENERGYAREA)

combats[2] = Combat()
combats[2]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_BLOCKHIT)

combats[3] = Combat()
combats[3]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_FIREAREA)

for i = 1, 3 do
    -- THIS will throw error after first loop
    combat[i]:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")
end

SOLUTION
Function that accepts function as parameter (not string with function name), copies it and binds to combat.
Add this in data/lib/lib.lua:
Lua:
function Combat.setCallbackFunction(self, event, callback)
    temporaryGlobalCallbackFunction = loadstring(string.dump(callback))
    self:setCallback(event, "temporaryGlobalCallbackFunction")
end
Now you can use it in loop:
(setCallbackFunction in place of setCallback and function onGetFormulaValues in place of function name (string) "onGetFormulaValues")
Lua:
(...) -- as in code above
for i = 1, 3 do
    combat[i]:setCallbackFunction(CALLBACK_PARAM_SKILLVALUE, onGetFormulaValues)
end
 
Last edited:
We could also debug why this LuaScriptInterface::getEvent messes it up, but debugging Lua was a pain for me, maybe we can get a tfs developer to explain it.
@Mark @Evil Hero

Basically the question is:
Why can't you pass the name of the same function to a callback multiple times?
Does the event take ownership of this function somewhere? Or is this just a bug?
 
Last edited:
Does the event take ownership of this function somewhere? Or is this just a bug?
I could not find code for that now, but I've debugged it some time ago. C++ code 'moves' that function from Lua to C++ and removes it from Lua.
I'm not sure why developers made it that way, not like addEvent - where you pass function, not function "name" -, but I'm 99% sure it's related to some crashes on /reload.

Edit: anyway, even if there was some not fixable C++ + Lua + reload bug, they should implement it in Lua as in this thread.
 
We could also debug why this LuaScriptInterface::getEvent messes it up, but debugging Lua was a pain for me, maybe we can get a tfs developer to explain it.
@Mark @

Basically the question is:
Why can't you pass the name of the same function to a callback multiple times?
Does the event take ownership of this function somewhere? Or is this just a bug?
I guess it's still kept that way for backwards compatibility, because you can actually change it to directly accept functions instead of a global search by name and fetch the function and then remove it from Lua.
There is no ownership, in fact with revscripts you can reuse global and local functions without any problem.
 
Back
Top