• 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+ addEvent with Spell Behaviour

mackerel

Well-Known Member
Joined
Apr 26, 2017
Messages
398
Solutions
18
Reaction score
72
for the past few hours I was trying to figure out why my spells behave that way, here is an example video. Followed by the actual script. If anyone has solution, please let me know. Thank you :p


XML:
    <instant group="attack" name="testb" words="testb" lvl="0" mana="0" prem="0" direction="1" blockwalls="1" exhaustion="2000" groupcooldown="1000" needlearn="0" script="test.lua">
        <vocation name="Elder Druid"/>
    </instant>

Lua:
local combat = {}
local area = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}

for i = 1, #area do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, 38)
    combat[i]:setArea(createCombatArea(area[i]))
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
 
    function onGetFormulaValues(cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
end

local function myLoop(myArray, combatType)
    local player = Player(myArray.cid)
    if not player then
        return false
    end
    
    return combatType:execute(myArray.cid, myArray.var)
end

function onCastSpell(cid, var)
    local player = Player(cid)
 
    local myArray = {
        cid = cid,
        var = var
    }
 
    addEvent(myLoop, 100, myArray, combat[2])
    addEvent(myLoop, 200, myArray, combat[3])
    addEvent(myLoop, 300, myArray, combat[4])
    addEvent(myLoop, 400, myArray, combat[5])
 
    return combat[1]:execute(cid, var)
end
 
The way you have it written seems rather unnecessary.
Combat 1 will execute before combat 2 - 5 even tho visually its written for 2 -5 to execute 1st, but function calls although they execute in a procedural manner, they execute faster than 100 milliseconds.

Since this is the case you don't need to specify the order of execution and also you don't need to return "combatType:execute(myArray.cid, myArray.var)" the reason is because the return value is lost when the addEvent executes myLoop.

Simply put the code could be written like this.
Lua:
local combat = {}
local area = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}
for i = 1, #area do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, 38)
 
    _G['onGetFormulaValues'..i] = function (cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
 
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues"..i)
    combat[i]:setArea(createCombatArea(area[i]))
end

local time = {1, 100, 200, 300, 400}
function onCastSpell(cid, var)
    if #time == #area then
        for index, interval in ipairs(time) do
            addEvent(function(cid, var, x)
                if Player(cid) then
                    combat[x]:execute(cid, var)
                end
            end,
            interval, cid, var, index)
        end
    end
    return true
end
 
The way you have it written seems rather unnecessary.
Combat 1 will execute before combat 2 - 5 even tho visually its written for 2 -5 to execute 1st, but function calls although they execute in a procedural manner, they execute faster than 100 milliseconds.

Since this is the case you don't need to specify the order of execution and also you don't need to return "combatType:execute(myArray.cid, myArray.var)" the reason is because the return value is lost when the addEvent executes myLoop.

Simply put the code could be written like this.
Lua:
local combat = {}
local area = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}
for i = 1, #area do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, 38)
 
    _G['onGetFormulaValues'..i] = function (cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
 
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues"..i)
    combat[i]:setArea(createCombatArea(area[i]))
end

local time = {1, 100, 200, 300, 400}
function onCastSpell(cid, var)
    if #time == #area then
        for index, interval in ipairs(time) do
            addEvent(function(cid, var, x)
                if Player(cid) then
                    combat[x]:execute(cid, var)
                end
            end,
            interval, cid, var, index)
        end
    end
    return true
end

Hi,

Thanks for trying bayview. It didn't change anything. I copied entire code but it's just the same effect as in video
 
Hi,

Thanks for trying bayview. It didn't change anything. I copied entire code but it's just the same effect as in video
I was just correcting the code not resolving the issue.

However the numbers in the table are what is causing the issue.
3 is used for directional, 2 is for non-directional and 1 & 0 are to determine the area to the effect & application of the outcome where 1 there is an effect & application and 0 there is none.
 
I was just correcting the code not resolving the issue.

However the numbers in the table are what is causing the issue.
3 is used for directional, 2 is for non-directional and 1 & 0 are to determine the area to the effect & application of the outcome where 1 there is an effect & application and 0 there is none.

I doubt its the table, I was trying to enter 3 instead of 2 in before. Even trying different grids.

As long as the player stays still, it seems to be okay. Just when they move in different direction, it starts to calculate the position of the player again or something similar :confused:
 
I doubt its the table, I was trying to enter 3 instead of 2 in before. Even trying different grids.

As long as the player stays still, it seems to be okay. Just when they move in different direction, it starts to calculate the position of the player again or something similar :confused:

Maybe this will work better.

Lua:
local combat = Combat()
combat:setArea(createCombatArea({ 
    {1,1,1},
    {1,1,1},
    {1,1,1},
    {1,1,1},
    {1,3,1},
    {1,0,1}
}))

function onTargetTile(creature, position)
    addEvent(function()
        local tile = Tile(position)
        if tile and
        not tile:hasFlag(TILESTATE_PROTECTIONZONE) and
        not tile:hasFlag(TILESTATE_TELEPORT) and
        not tile:hasFlag(TILESTATE_FLOORCHANGE) and
        not tile:hasFlag(TILESTATE_BLOCKSOLID) and
        not tile:hasFlag(TILESTATE_NOPVPZONE) then
            position:sendMagicEffect(CONST_ME_ENERGYAREA)
            local targets = tile:getCreatures()
            for key, target in pairs(targets) do
                local level, maglevel = creature:getLevel(), creature:getMagicLevel()
                local min = -((level / 5) + (maglevel * 10) + 25)
                local max = -((level / 5) + (maglevel * 20) + 50)
                doTargetCombatHealth(creature, target, COMBAT_ENERGYDAMAGE, min, max, CONST_ME_ENERGYAREA)
            end
        end
    end, 100 * getDistanceBetween(creature:getPosition(), position))
end

combat:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")

function onCastSpell(creature, variant)
    return combat:execute(creature, variant)
end

I'm sure there is a better way to set the min and max globally within script so you don't have to recall the level and ml every time.

Also I would take into consideration of people possibly complaining of it being slow and able to dodge out of the way of the spell. If so you could re-include the COMBAT_PARAM_TYPE and the CALLBACK_PARAM_LEVELMAGICVALUE without an effect remove the doTargetCombatHealth and let the damage all occur at once. Then the visual effects will execute alone within the onTargetTile.
 
Back
Top