• 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!

Spell [TFS 1.X] Shove

Leo32

Getting back into it...
Joined
Sep 21, 2007
Messages
987
Solutions
14
Reaction score
532
This is a replacement for groundshaker on my OT.
It pushes monsters and players away from the caster.

If the target is stuck up against a wall, they are stunned and receive a high amount of damage.

UgsHCKK.gif


You will need to add CONDITION_STUN your sources to use this spell.
Spell - [TFS 1.X] Shield Bash (https://otland.net/threads/tfs-1-x-shield-bash.268433/#post-2591129)

spells.xml
XML:
<instant group="attack" name="Shove" words="shove" lvl="30" mana="200" exhaustion="6000" groupcooldown="2000" script="custom/shove.lua">
    <vocation name="..." />
</instant>

scripts/custom/shove.lua
Lua:
-- Damaging Area
local hitArea = {
    {1, 1, 1},
    {1, 2, 1},
    {1, 1, 1}
}

-- Animation Frames
local animationArea = {
    {
        {0, 0, 0, 0, 0},
        {0, 0, 1, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 1, 0, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 1, 1, 1, 0},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {0, 1, 1, 1, 0}
    }
}

-- Get position behind target
function Position:getBehindPos(direction, steps)
    local offset = Position.directionOffset[direction]
    if offset then
        steps = steps or 1
        self.x = self.x + offset.x * steps
        self.y = self.y + offset.y * steps
    end
    return self
end

-- For shuffling the secondaryPosition table
function shuffle(t)
    local rand = math.random
    assert(t, "table.shuffle() expected a table, got nil")
    local iterations = #t
    local j
 
    for i = iterations, 2, -1 do
        j = rand(i)
        t[i], t[j] = t[j], t[i]
    end
end

-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
    local dir = DIRECTION_NORTH
    if(self.x > toPosition.x) then
        dir = DIRECTION_WEST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHWEST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHWEST
        end
    elseif(self.x < toPosition.x) then
        dir = DIRECTION_EAST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHEAST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHEAST
        end
    else
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTH
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTH
        end
    end
    return dir
end

-- Animation frame magic effect
function animation(pos, playerpos, animationType)
    if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
        if Position(pos):isSightClear(playerpos) then
            if animationType == 0 then
                Position(pos):sendMagicEffect(CONST_ME_POFF)
            end
            Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
        end
    end
end

-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
    if counter ~= 0 and Creature(stunnedcreature) then
        stunnedpos:sendMagicEffect(CONST_ME_STUN)
        counter = counter - 1
        addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
    end
    return true
end

-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
    local skillTotal = skill * attack
    local levelTotal = player:getLevel() / 5
    return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
 
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
    combat:setArea(createCombatArea(hitArea))
    combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(creature, var)
 
    -- Defaults
    local centre = {}
    local damageArea = {}
    local pushTargets = {}
    local blockedPos = {}
    local playerPos = creature:getPosition()
    local delay = 100
    local stunDuration = 2000
 
    -- Get creatures in squares around caster
    local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
 
    -- Shuffle targets so its random who prioritizes which squares/positions
    shuffle(getTargets)
 
    for _,target in pairs(getTargets) do
        if target.uid ~= creature.uid then -- If target is not the caster
            if not target:isNpc() then -- only target Players and Monsters
                local targetPos = target:getPosition()
                local playerDir = playerPos:getDirectionTo(targetPos)
                if playerDir then
                    local nextPos = Position(targetPos):getBehindPos(playerDir, 1) -- Tile to push to
                    if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
                      
                        -- Alternative push positions
                        local secondaryPositions = {}
                      
                        -- Get alternative push positions
                        if playerDir == DIRECTION_NORTH then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_EAST, 1))
                        elseif playerDir == DIRECTION_EAST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHEAST, 1))
                        elseif playerDir == DIRECTION_SOUTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_EAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTH, 1))
                        elseif playerDir == DIRECTION_SOUTH then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHWEST, 1))
                        elseif playerDir == DIRECTION_SOUTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_WEST, 1))
                        elseif playerDir == DIRECTION_WEST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_SOUTHWEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_WEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getBehindPos(DIRECTION_NORTH, 1))
                        end
                      
                        -- Shuffle alternative push positions
                        shuffle(secondaryPositions)
                      
                        -- Check for valid positions
                        local validSecondary = false
                        for i = 1, #secondaryPositions do
                            if not validSecondary then
                                local position = secondaryPositions[i]
                                local creatureCheck = Tile(nextPos):getCreatureCount()
                                if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
                                    if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
                                        nextPos = secondaryPositions[i]
                                        validSecondary = true
                                    end
                                end
                            end
                        end
                      
                        -- If valid alternative push position
                        if validSecondary and not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        else -- Monster is stuck, stun them against wall
                            if target:isPlayer() then
                                stunDuration = stunDuration / 2
                            end
                            -- Headbutt the wall fam
                            target:setDirection(playerDir)
                            nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
                          
                            -- Stun
                            local stun = Condition(CONDITION_STUN)
                            stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(stun)
                          
                            -- Mute
                            local mute = Condition(CONDITION_MUTED)
                            mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(mute)

                            addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
                        end
                      
                    else -- Regular push position is valid
                        if not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        end
                    end
                end
            end
        end
    end

    -- Push targets
    for i = 1, #pushTargets do
        local target = Creature(pushTargets[i][1])
        target:teleportTo(pushTargets[i][2], true)
    end
 
    -- animation
    local animationType = 0
    for j = 1, #animationArea do
        if j > 2 then
            animationType = 1
        end
        for k,v in ipairs(animationArea[j]) do
            for i = 1, #v do
                if v[i] == 3 or v[i] == 2 then
                    centre.Row = k
                    centre.Column = i
                elseif v[i] == 1 then
                    local darea = {}
                    darea.Row = k
                    darea.Column = i
                    darea.Delay = math.random(j * delay, (j * delay) + delay)
                    darea.Animation = animationType
                    table.insert(damageArea, darea)
                end
            end
        end
    end
    for i = 1,#damageArea do
        local modifierx = damageArea[i].Column - centre.Column
        local modifiery = damageArea[i].Row - centre.Row
        local animationPos = Position(playerPos)
        animationPos.x = animationPos.x + modifierx
        animationPos.y = animationPos.y + modifiery
        local animationDelay = damageArea[i].Delay or 0
        addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
    end
 
    -- Execute Damage
    return combat:execute(creature, var)
end

Edit: Fixed this line target:setDirection(playerDir)
TBH this line should get the direction of the wall they're hitting, instead of assuming playerDir is right, improvement suggestion if you are using this spell ;)
 
Last edited:
This is a replacement for groundshaker on my OT.
It pushes monsters and players away from the caster.

If the target is stuck up against a wall, they are stunned and receive a high amount of damage.

UgsHCKK.gif


You will need to add CONDITION_STUN your sources to use this spell.
Spell - [TFS 1.X] Shield Bash (https://otland.net/threads/tfs-1-x-shield-bash.268433/#post-2591129)

spells.xml
XML:
<instant group="attack" name="Shove" words="shove" lvl="30" mana="200" exhaustion="6000" groupcooldown="2000" script="custom/shove.lua">
    <vocation name="..." />
</instant>

scripts/custom/shove.lua
Lua:
-- Damaging Area
local hitArea = {
    {1, 1, 1},
    {1, 2, 1},
    {1, 1, 1}
}

-- Animation Frames
local animationArea = {
    {
        {0, 0, 0, 0, 0},
        {0, 0, 1, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 1, 0, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 1, 1, 1, 0},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {0, 1, 1, 1, 0}
    }
}

-- For shuffling the secondaryPosition table
function shuffle(t)
    local rand = math.random
    assert(t, "table.shuffle() expected a table, got nil")
    local iterations = #t
    local j
   
    for i = iterations, 2, -1 do
        j = rand(i)
        t[i], t[j] = t[j], t[i]
    end
end

-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
    local dir = DIRECTION_NORTH
    if(self.x > toPosition.x) then
        dir = DIRECTION_WEST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHWEST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHWEST
        end
    elseif(self.x < toPosition.x) then
        dir = DIRECTION_EAST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHEAST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHEAST
        end
    else
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTH
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTH
        end
    end
    return dir
end

-- Animation frame magic effect
function animation(pos, playerpos, animationType)
    if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
        if Position(pos):isSightClear(playerpos) then
            if animationType == 0 then
                Position(pos):sendMagicEffect(CONST_ME_POFF)
            end
            Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
        end
    end
end

-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
    if counter ~= 0 and Creature(stunnedcreature) then
        stunnedpos:sendMagicEffect(CONST_ME_STUN)
        counter = counter - 1
        addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
    end
    return true
end

-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
    local skillTotal = skill * attack
    local levelTotal = player:getLevel() / 5
    return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
   
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
    combat:setArea(createCombatArea(hitArea))
    combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(creature, var)
   
    -- Defaults
    local centre = {}
    local damageArea = {}
    local pushTargets = {}
    local blockedPos = {}
    local playerPos = creature:getPosition()
    local delay = 100
    local stunDuration = 2000
   
    -- Get creatures in squares around caster
    local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
   
    -- Shuffle targets so its random who prioritizes which squares/positions
    shuffle(getTargets)
   
    for _,target in pairs(getTargets) do
        if target.uid ~= creature.uid then -- If target is not the caster
            if not target:isNpc() then -- only target Players and Monsters
                local targetPos = target:getPosition()
                local playerDir = playerPos:getDirectionTo(targetPos)
                if playerDir then
                    local nextPos = Position(targetPos):getNextPosition(playerDir, 1) -- Tile to push to
                    if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
                       
                        -- Alternative push positions
                        local secondaryPositions = {}
                       
                        -- Get alternative push positions
                        if playerDir == DIRECTION_NORTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                        elseif playerDir == DIRECTION_EAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                        elseif playerDir == DIRECTION_SOUTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                        elseif playerDir == DIRECTION_SOUTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                        elseif playerDir == DIRECTION_SOUTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                        elseif playerDir == DIRECTION_WEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                        end
                       
                        -- Shuffle alternative push positions
                        shuffle(secondaryPositions)
                       
                        -- Check for valid positions
                        local validSecondary = false
                        for i = 1, #secondaryPositions do
                            if not validSecondary then
                                local position = secondaryPositions[i]
                                local creatureCheck = Tile(nextPos):getCreatureCount()
                                if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
                                    if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
                                        nextPos = secondaryPositions[i]
                                        validSecondary = true
                                    end
                                end
                            end
                        end
                       
                        -- If valid alternative push position
                        if validSecondary and not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        else -- Monster is stuck, stun them against wall
                            if target:isPlayer() then
                                stunDuration = stunDuration / 2
                            end
                            -- Headbutt the wall fam
                            target:setDirection(playerDir)
                            nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
                           
                            -- Stun
                            local stun = Condition(CONDITION_STUN)
                            stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(stun)
                           
                            -- Mute
                            local mute = Condition(CONDITION_MUTED)
                            mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(mute)

                            addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
                        end
                       
                    else -- Regular push position is valid
                        if not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        end
                    end
                end
            end
        end
    end

    -- Push targets
    for i = 1, #pushTargets do
        local target = Creature(pushTargets[i][1])
        target:teleportTo(pushTargets[i][2], true)
    end
   
    -- animation
    local animationType = 0
    for j = 1, #animationArea do
        if j > 2 then
            animationType = 1
        end
        for k,v in ipairs(animationArea[j]) do
            for i = 1, #v do
                if v[i] == 3 or v[i] == 2 then
                    centre.Row = k
                    centre.Column = i
                elseif v[i] == 1 then
                    local darea = {}
                    darea.Row = k
                    darea.Column = i
                    darea.Delay = math.random(j * delay, (j * delay) + delay)
                    darea.Animation = animationType
                    table.insert(damageArea, darea)
                end
            end
        end
    end
    for i = 1,#damageArea do
        local modifierx = damageArea[i].Column - centre.Column
        local modifiery = damageArea[i].Row - centre.Row
        local animationPos = Position(playerPos)
        animationPos.x = animationPos.x + modifierx
        animationPos.y = animationPos.y + modifiery
        local animationDelay = damageArea[i].Delay or 0
        addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
    end
   
    -- Execute Damage
    return combat:execute(creature, var)
end

Edit: Fixed this line target:setDirection(playerDir)
Nice spell! And I learned new function Game.getSpectators :)
 
hi its look awesome, nice work :)
I try add it on my server but dosnt work well when im close target 1sqm(melle dyst) i cant use it, when I get away a little bit i can cast it but it do nothing 0 dmg etc.
error in consol

Code:
Lua Script Error: [Spell Interface]
data/spells/scripts/custom/boom.lua:onCastSpell
data/spells/scripts/custom/boom.lua:132: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/custom/boom.lua:132: in function <data/spells/scripts/custom/boom.lua:108>
Maybe you know what is going on? ;/
 
Last edited:
hi its look awesome, nice work :)
I try add it on my server but dosnt work well when im close target 1sqm(melle dyst) i cant use it, when I get away a little bit i can cast it but it do nothing 0 dmg etc.
error in consol

Code:
Lua Script Error: [Spell Interface]
data/spells/scripts/custom/boom.lua:onCastSpell
data/spells/scripts/custom/boom.lua:132: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/custom/boom.lua:132: in function <data/spells/scripts/custom/boom.lua:108>
Maybe you know what is going on? ;/

This is the line that is erroring out:
Lua:
if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked

To figure out what is happening on your server, add the following lines above it:
Lua:
print(nextPos)
print(Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID))
print(Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE))
print(Tile(nextPos):getCreatureCount())

What prints to the console when you trigger the error this time?
 
i add it after
Code:
local nextPos = Position(targetPos):getNextPosition(playerDir, 1) -- Tile to push to
i dont have this parametrs, in consol still only the same error ;/
i look the same but i have now error in line with
Code:
print(Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID))
 
Last edited:
Try this:
Lua:
if Tile(nextPos):hasFlag(TILESTATE_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
 
Maybe someone have idea why is it like that, i tried it on clear TSF 1.3 but errer stil the same ;/
 
Last edited:
hello its me again i dont focus on this spell before but now i whant check something and i found (just print it) problem
in consol
Code:
table: 0x20bf2cf0     getTargets
table: 0x2beccc88      playerPos
5       playerDir
table: 0x30cd0a68       targetPos
nil    nextPos

Lua Script Error: [Spell Interface]
data/spells/scripts/custom/shove.lua:onCastSpell
data/spells/scripts/custom/shove.lua:135: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/custom/shove.lua:135: in function <data/spells/scripts/custom/shove.lua:108>
I dont know how fix it ;/
can you help me with it?
 
Last edited:
hello its me again i dont focus on this spell before but now i whant check something and i found (just print it) problem
in consol
Code:
table: 0x20bf2cf0     getTargets
table: 0x2beccc88      playerPos
5       playerDir
table: 0x30cd0a68       targetPos
nil    nextPos

Lua Script Error: [Spell Interface]
data/spells/scripts/custom/shove.lua:onCastSpell
data/spells/scripts/custom/shove.lua:135: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/custom/shove.lua:135: in function <data/spells/scripts/custom/shove.lua:108>
I dont know how fix it ;/
can you help me with it?

You've made changes because line 135 can't throw that error in the original script.
Post your shove.lua here and I'll fix it for you.
 
thats the point that I dont change anything so its weird
Lua:
-- Damaging Area
local hitArea = {
    {1, 1, 1},
    {1, 2, 1},
    {1, 1, 1}
}

-- Animation Frames
local animationArea = {
    {
        {0, 0, 0, 0, 0},
        {0, 0, 1, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 1, 0, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 1, 1, 1, 0},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {0, 1, 1, 1, 0}
    }
}

-- For shuffling the secondaryPosition table
function shuffle(t)
    local rand = math.random
    assert(t, "table.shuffle() expected a table, got nil")
    local iterations = #t
    local j
    
    for i = iterations, 2, -1 do
        j = rand(i)
        t[i], t[j] = t[j], t[i]
    end
end

-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
    local dir = DIRECTION_NORTH
    if(self.x > toPosition.x) then
        dir = DIRECTION_WEST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHWEST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHWEST
        end
    elseif(self.x < toPosition.x) then
        dir = DIRECTION_EAST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHEAST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHEAST
        end
    else
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTH
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTH
        end
    end
    return dir
end

-- Animation frame magic effect
function animation(pos, playerpos, animationType)
    if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
        if Position(pos):isSightClear(playerpos) then
            if animationType == 0 then
                Position(pos):sendMagicEffect(CONST_ME_POFF)
            end
            Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
        end
    end
end

-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
    if counter ~= 0 and Creature(stunnedcreature) then
        stunnedpos:sendMagicEffect(CONST_ME_STUN)
        counter = counter - 1
        addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
    end
    return true
end

-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
    local skillTotal = skill * attack
    local levelTotal = player:getLevel() / 5
    return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
    
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
    combat:setArea(createCombatArea(hitArea))
    combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(creature, var)
    
    -- Defaults
    local centre = {}
    local damageArea = {}
    local pushTargets = {}
    local blockedPos = {}
    local playerPos = creature:getPosition()
    print(playerPos,'playerPos')
    local delay = 100
    local stunDuration = 2000
    
    -- Get creatures in squares around caster
    local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
    
    -- Shuffle targets so its random who prioritizes which squares/positions
    shuffle(getTargets)
    
    for _,target in pairs(getTargets) do
    print(getTargets)
        if target.uid ~= creature.uid then -- If target is not the caster
            if not target:isNpc() then -- only target Players and Monsters
                local targetPos = target:getPosition()
                local playerDir = playerPos:getDirectionTo(targetPos)
                if playerDir then
                print(playerDir,'playerDir')
                print(targetPos,'targetPos')
                    local nextPos = Position(targetPos):getNextPosition(playerDir, 1) -- Tile to push to
                    print(nextPos)
        print(Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID))
        print(Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE))
        print(Tile(nextPos):getCreatureCount())
                    if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
                        
                        -- Alternative push positions
                        local secondaryPositions = {}
                        
                        -- Get alternative push positions
                        if playerDir == DIRECTION_NORTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                        elseif playerDir == DIRECTION_EAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                        elseif playerDir == DIRECTION_SOUTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                        elseif playerDir == DIRECTION_SOUTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                        elseif playerDir == DIRECTION_SOUTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                        elseif playerDir == DIRECTION_WEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                        end
                        
                        -- Shuffle alternative push positions
                        shuffle(secondaryPositions)
                        
                        -- Check for valid positions
                        local validSecondary = false
                        for i = 1, #secondaryPositions do
                            if not validSecondary then
                                local position = secondaryPositions[i]
                                local creatureCheck = Tile(nextPos):getCreatureCount()
                                if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
                                    if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
                                        nextPos = secondaryPositions[i]
                                        validSecondary = true
                                    end
                                end
                            end
                        end
                        
                        -- If valid alternative push position
                        if validSecondary and not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        else -- Monster is stuck, stun them against wall
                            if target:isPlayer() then
                                stunDuration = stunDuration / 2
                            end
                            -- Headbutt the wall fam
                            target:setDirection(playerDir)
                            nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
                            
                            -- Stun
                            local stun = Condition(CONDITION_STUN)
                            stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(stun)
                            
                            -- Mute
                            local mute = Condition(CONDITION_MUTED)
                            mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(mute)

                            addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
                        end
                        
                    else -- Regular push position is valid
                        if not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        end
                    end
                end
            end
        end
    end

    -- Push targets
    for i = 1, #pushTargets do
        local target = Creature(pushTargets[i][1])
        target:teleportTo(pushTargets[i][2], true)
    end
    
    -- animation
    local animationType = 0
    for j = 1, #animationArea do
        if j > 2 then
            animationType = 1
        end
        for k,v in ipairs(animationArea[j]) do
            for i = 1, #v do
                if v[i] == 3 or v[i] == 2 then
                    centre.Row = k
                    centre.Column = i
                elseif v[i] == 1 then
                    local darea = {}
                    darea.Row = k
                    darea.Column = i
                    darea.Delay = math.random(j * delay, (j * delay) + delay)
                    darea.Animation = animationType
                    table.insert(damageArea, darea)
                end
            end
        end
    end
    for i = 1,#damageArea do
        local modifierx = damageArea[i].Column - centre.Column
        local modifiery = damageArea[i].Row - centre.Row
        local animationPos = Position(playerPos)
        animationPos.x = animationPos.x + modifierx
        animationPos.y = animationPos.y + modifiery
        local animationDelay = damageArea[i].Delay or 0
        addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
    end
    
    -- Execute Damage
    return combat:execute(creature, var)
end
 
yes i have it ;/ i coped lib folder again today but nothing changes ;/
 
yes i have it ;/ i coped lib folder again today but nothing changes ;/
Lua:
-- Damaging Area
local hitArea = {
    {1, 1, 1},
    {1, 2, 1},
    {1, 1, 1}
}

-- Animation Frames
local animationArea = {
    {
        {0, 0, 0, 0, 0},
        {0, 0, 1, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 1, 0, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 1, 1, 1, 0},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {0, 1, 1, 1, 0}
    }
}

-- For shuffling the secondaryPosition table
function shuffle(t)
    local rand = math.random
    assert(t, "table.shuffle() expected a table, got nil")
    local iterations = #t
    local j
    
    for i = iterations, 2, -1 do
        j = rand(i)
        t[i], t[j] = t[j], t[i]
    end
end

-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
    local dir = DIRECTION_NORTH
    if(self.x > toPosition.x) then
        dir = DIRECTION_WEST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHWEST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHWEST
        end
    elseif(self.x < toPosition.x) then
        dir = DIRECTION_EAST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHEAST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHEAST
        end
    else
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTH
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTH
        end
    end
    return dir
end

-- Animation frame magic effect
function animation(pos, playerpos, animationType)
    if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
        if Position(pos):isSightClear(playerpos) then
            if animationType == 0 then
                Position(pos):sendMagicEffect(CONST_ME_POFF)
            end
            Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
        end
    end
end

-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
    if counter ~= 0 and Creature(stunnedcreature) then
        stunnedpos:sendMagicEffect(CONST_ME_STUN)
        counter = counter - 1
        addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
    end
    return true
end

-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
    local skillTotal = skill * attack
    local levelTotal = player:getLevel() / 5
    return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
    
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
    combat:setArea(createCombatArea(hitArea))
    combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(creature, var)
    
    -- Defaults
    local centre = {}
    local damageArea = {}
    local pushTargets = {}
    local blockedPos = {}
    local playerPos = creature:getPosition()
    local delay = 100
    local stunDuration = 2000
    
    -- Get creatures in squares around caster
    local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
    
    -- Shuffle targets so its random who prioritizes which squares/positions
    shuffle(getTargets)
    
    for _,target in pairs(getTargets) do
        if target.uid ~= creature.uid then -- If target is not the caster
            if not target:isNpc() then -- only target Players and Monsters
                local targetPos = target:getPosition()
                local playerDir = playerPos:getDirectionTo(targetPos)
                if playerDir then
                    local nextPos = Position(targetPos):getNextPosition(playerDir, 1) -- Tile to push to
                    local nextTile = Tile(nextPos)
                    if nextTile then
                        if nextTile:hasProperty(CONST_PROP_BLOCKSOLID) or nextTile:hasFlag(TILESTATE_FLOORCHANGE) or nextTile:getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
                            
                            -- Alternative push positions
                            local secondaryPositions = {}
                            
                            -- Get alternative push positions
                            if playerDir == DIRECTION_NORTH then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                            elseif playerDir == DIRECTION_NORTHEAST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                            elseif playerDir == DIRECTION_EAST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                            elseif playerDir == DIRECTION_SOUTHEAST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                            elseif playerDir == DIRECTION_SOUTH then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                            elseif playerDir == DIRECTION_SOUTHWEST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                            elseif playerDir == DIRECTION_WEST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                            elseif playerDir == DIRECTION_NORTHWEST then
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                                table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                            end
                            
                            -- Shuffle alternative push positions
                            shuffle(secondaryPositions)
                            
                            -- Check for valid positions
                            local validSecondary = false
                            for i = 1, #secondaryPositions do
                                if not validSecondary then
                                    local position = secondaryPositions[i]
                                    local creatureCheck = Tile(nextPos):getCreatureCount()
                                    if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
                                        if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
                                            nextPos = secondaryPositions[i]
                                            validSecondary = true
                                        end
                                    end
                                end
                            end
                            
                            -- If valid alternative push position
                            if validSecondary and not isInArray(blockedPos, nextPos) then
                                table.insert(blockedPos, nextPos)
                                table.insert(pushTargets, {target.uid, nextPos})
                            else -- Monster is stuck, stun them against wall
                                if target:isPlayer() then
                                    stunDuration = stunDuration / 2
                                end
                                -- Headbutt the wall fam
                                target:setDirection(playerDir)
                                nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
                                
                                -- Stun
                                local stun = Condition(CONDITION_STUN)
                                stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                                target:addCondition(stun)
                                
                                -- Mute
                                local mute = Condition(CONDITION_MUTED)
                                mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                                target:addCondition(mute)

                                addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
                            end
                            
                        else -- Regular push position is valid
                            if not isInArray(blockedPos, nextPos) then
                                table.insert(blockedPos, nextPos)
                                table.insert(pushTargets, {target.uid, nextPos})
                            end
                        end
                    end
                end
            end
        end
    end

    -- Push targets
    for i = 1, #pushTargets do
        local target = Creature(pushTargets[i][1])
        target:teleportTo(pushTargets[i][2], true)
    end
    
    -- animation
    local animationType = 0
    for j = 1, #animationArea do
        if j > 2 then
            animationType = 1
        end
        for k,v in ipairs(animationArea[j]) do
            for i = 1, #v do
                if v[i] == 3 or v[i] == 2 then
                    centre.Row = k
                    centre.Column = i
                elseif v[i] == 1 then
                    local darea = {}
                    darea.Row = k
                    darea.Column = i
                    darea.Delay = math.random(j * delay, (j * delay) + delay)
                    darea.Animation = animationType
                    table.insert(damageArea, darea)
                end
            end
        end
    end
    for i = 1,#damageArea do
        local modifierx = damageArea[i].Column - centre.Column
        local modifiery = damageArea[i].Row - centre.Row
        local animationPos = Position(playerPos)
        animationPos.x = animationPos.x + modifierx
        animationPos.y = animationPos.y + modifiery
        local animationDelay = damageArea[i].Delay or 0
        addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
    end
    
    -- Execute Damage
    return combat:execute(creature, var)
end
 
thats the point that I dont change anything so its weird
Lua:
-- Damaging Area
local hitArea = {
    {1, 1, 1},
    {1, 2, 1},
    {1, 1, 1}
}

-- Animation Frames
local animationArea = {
    {
        {0, 0, 0, 0, 0},
        {0, 0, 1, 0, 0},
        {0, 1, 2, 1, 0},
        {0, 0, 1, 0, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0},
        {0, 1, 0, 1, 0},
        {0, 0, 0, 0, 0}
    },
    {
        {0, 1, 1, 1, 0},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {1, 0, 0, 0, 1},
        {0, 1, 1, 1, 0}
    }
}

-- For shuffling the secondaryPosition table
function shuffle(t)
    local rand = math.random
    assert(t, "table.shuffle() expected a table, got nil")
    local iterations = #t
    local j
   
    for i = iterations, 2, -1 do
        j = rand(i)
        t[i], t[j] = t[j], t[i]
    end
end

-- Get 8-Axis direction of fromPos -> toPos
function Position:getDirectionTo(toPosition)
    local dir = DIRECTION_NORTH
    if(self.x > toPosition.x) then
        dir = DIRECTION_WEST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHWEST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHWEST
        end
    elseif(self.x < toPosition.x) then
        dir = DIRECTION_EAST
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTHEAST
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTHEAST
        end
    else
        if(self.y > toPosition.y) then
            dir = DIRECTION_NORTH
        elseif(self.y < toPosition.y) then
            dir = DIRECTION_SOUTH
        end
    end
    return dir
end

-- Animation frame magic effect
function animation(pos, playerpos, animationType)
    if not Tile(Position(pos)):hasProperty(CONST_PROP_BLOCKPROJECTILE) then
        if Position(pos):isSightClear(playerpos) then
            if animationType == 0 then
                Position(pos):sendMagicEffect(CONST_ME_POFF)
            end
            Position(pos):sendMagicEffect(CONST_ME_GROUNDSHAKER)
        end
    end
end

-- Stun animation magic effect
function stunAnimation(stunnedcreature, stunnedpos, counter)
    if counter ~= 0 and Creature(stunnedcreature) then
        stunnedpos:sendMagicEffect(CONST_ME_STUN)
        counter = counter - 1
        addEvent(stunAnimation, 500, stunnedcreature, stunnedpos, counter)
    end
    return true
end

-- Damage Formula
function onGetFormulaValues(player, skill, attack, factor)
    local skillTotal = skill * attack
    local levelTotal = player:getLevel() / 5
    return -(((skillTotal * 0.06) + 13) + (levelTotal)), -(((skillTotal * 0.11) + 27) + (levelTotal))
end
   
local combat = Combat()
    combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
    combat:setParameter(COMBAT_PARAM_BLOCKARMOR, 1)
    combat:setArea(createCombatArea(hitArea))
    combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(creature, var)
   
    -- Defaults
    local centre = {}
    local damageArea = {}
    local pushTargets = {}
    local blockedPos = {}
    local playerPos = creature:getPosition()
    print(playerPos,'playerPos')
    local delay = 100
    local stunDuration = 2000
   
    -- Get creatures in squares around caster
    local getTargets = Game.getSpectators(playerPos, false, false, 1, 1, 1, 1)
   
    -- Shuffle targets so its random who prioritizes which squares/positions
    shuffle(getTargets)
   
    for _,target in pairs(getTargets) do
    print(getTargets)
        if target.uid ~= creature.uid then -- If target is not the caster
            if not target:isNpc() then -- only target Players and Monsters
                local targetPos = target:getPosition()
                local playerDir = playerPos:getDirectionTo(targetPos)
                if playerDir then
                print(playerDir,'playerDir')
                print(targetPos,'targetPos')
                    local nextPos = Position(targetPos):getNextPosition(playerDir, 1) -- Tile to push to
                    print(nextPos)
        print(Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID))
        print(Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE))
        print(Tile(nextPos):getCreatureCount())
                    if Tile(nextPos):hasProperty(CONST_PROP_BLOCKSOLID) or Tile(nextPos):hasFlag(TILESTATE_FLOORCHANGE) or Tile(nextPos):getCreatureCount() > 0 then -- If tile to push to is invalid/blocked
                       
                        -- Alternative push positions
                        local secondaryPositions = {}
                       
                        -- Get alternative push positions
                        if playerDir == DIRECTION_NORTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                        elseif playerDir == DIRECTION_EAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                        elseif playerDir == DIRECTION_SOUTHEAST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_EAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                        elseif playerDir == DIRECTION_SOUTH then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHEAST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                        elseif playerDir == DIRECTION_SOUTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTH, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                        elseif playerDir == DIRECTION_WEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_SOUTHWEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTHWEST, 1))
                        elseif playerDir == DIRECTION_NORTHWEST then
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_WEST, 1))
                            table.insert(secondaryPositions, Position(targetPos):getNextPosition(DIRECTION_NORTH, 1))
                        end
                       
                        -- Shuffle alternative push positions
                        shuffle(secondaryPositions)
                       
                        -- Check for valid positions
                        local validSecondary = false
                        for i = 1, #secondaryPositions do
                            if not validSecondary then
                                local position = secondaryPositions[i]
                                local creatureCheck = Tile(nextPos):getCreatureCount()
                                if not Tile(position):hasFlag(TILESTATE_FLOORCHANGE) then
                                    if not Tile(position):hasProperty(CONST_PROP_BLOCKSOLID) and Tile(position):getCreatureCount() < 1 then -- Ensure alternative push position is valid
                                        nextPos = secondaryPositions[i]
                                        validSecondary = true
                                    end
                                end
                            end
                        end
                       
                        -- If valid alternative push position
                        if validSecondary and not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        else -- Monster is stuck, stun them against wall
                            if target:isPlayer() then
                                stunDuration = stunDuration / 2
                            end
                            -- Headbutt the wall fam
                            target:setDirection(playerDir)
                            nextPos:sendMagicEffect(CONST_ME_DRAWBLOOD)
                           
                            -- Stun
                            local stun = Condition(CONDITION_STUN)
                            stun:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(stun)
                           
                            -- Mute
                            local mute = Condition(CONDITION_MUTED)
                            mute:setParameter(CONDITION_PARAM_TICKS, stunDuration)
                            target:addCondition(mute)

                            addEvent(stunAnimation, 0, target.uid, target:getPosition(), (stunDuration / 1000) * 2)
                        end
                       
                    else -- Regular push position is valid
                        if not isInArray(blockedPos, nextPos) then
                            table.insert(blockedPos, nextPos)
                            table.insert(pushTargets, {target.uid, nextPos})
                        end
                    end
                end
            end
        end
    end

    -- Push targets
    for i = 1, #pushTargets do
        local target = Creature(pushTargets[i][1])
        target:teleportTo(pushTargets[i][2], true)
    end
   
    -- animation
    local animationType = 0
    for j = 1, #animationArea do
        if j > 2 then
            animationType = 1
        end
        for k,v in ipairs(animationArea[j]) do
            for i = 1, #v do
                if v[i] == 3 or v[i] == 2 then
                    centre.Row = k
                    centre.Column = i
                elseif v[i] == 1 then
                    local darea = {}
                    darea.Row = k
                    darea.Column = i
                    darea.Delay = math.random(j * delay, (j * delay) + delay)
                    darea.Animation = animationType
                    table.insert(damageArea, darea)
                end
            end
        end
    end
    for i = 1,#damageArea do
        local modifierx = damageArea[i].Column - centre.Column
        local modifiery = damageArea[i].Row - centre.Row
        local animationPos = Position(playerPos)
        animationPos.x = animationPos.x + modifierx
        animationPos.y = animationPos.y + modifiery
        local animationDelay = damageArea[i].Delay or 0
        addEvent(animation, animationDelay, animationPos, playerPos, damageArea[i].Animation)
    end
   
    -- Execute Damage
    return combat:execute(creature, var)
end

You need to add return self inside Position.getNextPosition, @Leo32 must've forgotten he changed it himself.
 
You need to add return self inside Position.getNextPosition, @Leo32 must've forgotten he changed it himself.

giphy.gif


lib/core/position.lua
Lua:
function Position:getNextPosition(direction, steps)
    local offset = Position.directionOffset[direction]
    if offset then
        steps = steps or 1
        self.x = self.x + offset.x * steps
        self.y = self.y + offset.y * steps
    end
    return self
end
 
@oen432 i dont know what have you change but now i can cast spell near monster but push doesnt work
View attachment 42871
Because there is no nextTile, update getNextPosition function from @Leo32 post.
Lua:
function Position:getNextPosition(direction, steps)
    local offset = Position.directionOffset[direction]
    if offset then
        steps = steps or 1
        self.x = self.x + offset.x * steps
        self.y = self.y + offset.y * steps
    end
    return self
end
 
Back
Top