• 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+ How to Attach an Effect to a Moving Target in Code

Tbol

Well-Known Member
Joined
Apr 7, 2019
Messages
592
Reaction score
64
I have a question: this code applies an effect (+/-) only when sendDistanceEffect reaches the target, and it applies the effect to the target. However, there's an issue—if the target changes position, such as moving one tile away, the effect is displayed at the original position instead of on the target. Is it possible to attach the effect to the creature so that it moves with the target even if their position changes?
LUA:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)

function onGetFormulaValues(player, level, maglevel)
    local min = (level * 5) + (maglevel * 12.5) + 25
    local max = (level * 5) + (maglevel * 14) + 50
    return -min, -max
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

local function callback(creature, variant)
    local target = Creature(variant:getNumber())
    if not target then return false end

    local creaturePos = creature:getPosition()
    local targetPos = target:getPosition()
    local distance = creaturePos:getDistance(targetPos)
    local milliseconds = distance * 80

    creaturePos:sendDistanceEffect(targetPos, 23)

    addEvent(function()
        combat:execute(creature, variant)
        local effectPosition = targetPos + Position(1, 1, 0)
        effectPosition:sendMagicEffect(986)
    end, milliseconds)

    return true
end

function onCastSpell(creature, variant)
    return callback(creature, variant)
end
 
the sendMagicEffect function is applied to a specific and constant position, it is not attached to a player-.

Code:
       // position:sendMagicEffect(magicEffect[, players = {}])

"Attach?? "

the only thing I know that attaches THINGS (effect, outfit, distances,widget,texture(png), particles, etc..) can be attached to a player is what mehah does with his otc

example sendMagicEffect vs attachEffectById


Code:
Player("MePlayer"):getPosition():sendMagicEffect(10)

1735843189618.gif


Code:
Player("MePlayer"):attachEffectById(10)
Code:
AttachedEffectManager.register(10, 'Example', 10, ThingCategoryEffect, {
    duration = 3000
})

1735843199618.gif

read : Tutorial Attached Effects (https://github.com/mehah/otclient/wiki/Tutorial-Attached-Effects)
 
Last edited:
This spell script creates an energy damage effect that follows the target's movement. The effect is checked every 100ms and the total duration depends on the distance between caster and target (80ms per tile). When the target moves, a magic effect is displayed on their position.

If you want to see print outputs to the console to get information about which creature moved and display the effect, just uncomment and test.

LUA:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)

function onGetFormulaValues(player, level, maglevel)
    local min = (level * 5) + (maglevel * 12.5) + 25
    local max = (level * 5) + (maglevel * 14) + 50
    return -min, -max
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

local function monitorTarget(creature, target, duration, effectId, combat, variant)
    local startTime = os.time()
    local lastPos = target:getPosition()
    local interval = 100 -- 100 milliseconds (0.1 seconds)

    local function updateEffect()
        if os.time() - startTime > duration / 1000 then
            if target and target:getPosition() then
                combat:execute(creature, variant)
                target:getPosition():sendMagicEffect(effectId)
            end
            return
        end

        if target and target:getPosition() then
            local currentPos = target:getPosition()
            local deltaX = math.abs(currentPos.x - lastPos.x)
            local deltaY = math.abs(currentPos.y - lastPos.y)

            if (deltaX == 1 and deltaY == 0) or (deltaY == 1 and deltaX == 0) then
                --print(string.format("[DEBUG] Creature moved from (%d, %d, %d) to (%d, %d, %d)", lastPos.x, lastPos.y, lastPos.z, currentPos.x, currentPos.y, currentPos.z))
                currentPos:sendMagicEffect(effectId)
                lastPos = currentPos
            end
        end

        addEvent(updateEffect, interval)
    end

    updateEffect()
end

local function executeSpell(creature, variant)
    local target = Creature(variant:getNumber())
    if not target then
        return false
    end

    local creaturePos = creature:getPosition()
    local targetPos = target:getPosition()
    local distance = creaturePos:getDistance(targetPos)
    local duration = distance * 80 -- 80 milliseconds multiplied by the distance in tiles

    --print(string.format("[DEBUG] Casting spell from %s to %s at distance of %d tiles.",  creature:getName(), target:getName(), distance))

    creaturePos:sendDistanceEffect(targetPos, 23)
    monitorTarget(creature, target, duration, 986, combat, variant)

    return true
end

function onCastSpell(creature, variant)
    return executeSpell(creature, variant)
end

To know how to change the effect, just modify this line you see on line 986,
monitorTarget(creature, target, duration, 986, combat, variant)
 
This spell script creates an energy damage effect that follows the target's movement. The effect is checked every 100ms and the total duration depends on the distance between caster and target (80ms per tile). When the target moves, a magic effect is displayed on their position.

If you want to see print outputs to the console to get information about which creature moved and display the effect, just uncomment and test.

LUA:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)

function onGetFormulaValues(player, level, maglevel)
    local min = (level * 5) + (maglevel * 12.5) + 25
    local max = (level * 5) + (maglevel * 14) + 50
    return -min, -max
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

local function monitorTarget(creature, target, duration, effectId, combat, variant)
    local startTime = os.time()
    local lastPos = target:getPosition()
    local interval = 100 -- 100 milliseconds (0.1 seconds)

    local function updateEffect()
        if os.time() - startTime > duration / 1000 then
            if target and target:getPosition() then
                combat:execute(creature, variant)
                target:getPosition():sendMagicEffect(effectId)
            end
            return
        end

        if target and target:getPosition() then
            local currentPos = target:getPosition()
            local deltaX = math.abs(currentPos.x - lastPos.x)
            local deltaY = math.abs(currentPos.y - lastPos.y)

            if (deltaX == 1 and deltaY == 0) or (deltaY == 1 and deltaX == 0) then
                --print(string.format("[DEBUG] Creature moved from (%d, %d, %d) to (%d, %d, %d)", lastPos.x, lastPos.y, lastPos.z, currentPos.x, currentPos.y, currentPos.z))
                currentPos:sendMagicEffect(effectId)
                lastPos = currentPos
            end
        end

        addEvent(updateEffect, interval)
    end

    updateEffect()
end

local function executeSpell(creature, variant)
    local target = Creature(variant:getNumber())
    if not target then
        return false
    end

    local creaturePos = creature:getPosition()
    local targetPos = target:getPosition()
    local distance = creaturePos:getDistance(targetPos)
    local duration = distance * 80 -- 80 milliseconds multiplied by the distance in tiles

    --print(string.format("[DEBUG] Casting spell from %s to %s at distance of %d tiles.",  creature:getName(), target:getName(), distance))

    creaturePos:sendDistanceEffect(targetPos, 23)
    monitorTarget(creature, target, duration, 986, combat, variant)

    return true
end

function onCastSpell(creature, variant)
    return executeSpell(creature, variant)
end

To know how to change the effect, just modify this line you see on line 986,
It has strange beheviour which if target moves it calls the effect multiple time on his moved tiles
 
Back
Top