• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Lua Simple Push with Walkable POS check

mackerel

Well-Known Member
Joined
Apr 26, 2017
Messages
398
Solutions
18
Reaction score
74
LUA:
function onCastSpell(cid, var)
    if isPathable(getCreaturePosition(getCreatureTarget(cid))) then
        doMoveCreature(variantToNumber(var), Player(cid):getDirection())
    end
    return doCombat(cid, combat, var)
end

The second line:
isPathable(pos) needs to check for the position behind the target, but so far I can only get the position of the target.

It has to be based on the player direction, so if the player is north from target, it will push them south. And so it happens that I have this line here
Player(cid):getDirection()

But I have no clue how to implement that together in the if statement.

Just to be clear:

doMoveCreature - works fine
if isPathable - it does not work as intended; it needs to check for the position behind the target based on the player:getDirection

TFS 1.0

any help appreciated guys
 
Solution
Thanks very useful



All fixed except the protection zone, if you know how to do that, even in your code that would be great thanks

So, now I'm more alive and can think a little better, I rewrote the code for you including with config for it:
LUA:
local config = {
    push_player = true,            --Possible to push players?
    push_creature = true,        --Possible to push creatures?
    push_npc = true,            --Possible to push NPCs?
    pushInto_PZ = true,            --Possible to push players/creatures into PZ?
    pushInto_Creatures = true,    --Possible to push a player/creature into another player/creature?
}

function onCastSpell(cid, var)
    player = Player(cid)
    if player then
        target =...
I'm tired, a little headache, so don't be too hard on my code.
It's not tested but if I'm not wrong, it should be something you're looking for :)
Let me know how it works out.

ps, the code will favor vertical movements, if vertical difference match horizontal difference, it will go with south/north instead (if the two is exactly diagonal).
LUA:
function onCastSpell(cid, var)
   player = Player(cid)
   if player then
       target = Creature(variantToNumber(var))
       if target then
           local newPos = getPushPosition(player:getposition(), target:getPosition())
           if newPos then
               target:teleportTo(newPos, true)
           end
       end
   end
   return doCombat(cid, combat, var)
end

function getPushPosition(pos1, pos2)
   local xDif = math.abs(pos1.x - pos2.x)
   local yDif = math.abs(pos1.y - pos2.y)
   newPos = pos2
   if xDif <= yDif then
       if pos1.y < pos2.y then
           newPos.y = newPos.y+1
       else
           newPos.y = newPos.y-1
       end  
   else
       if pos1.x < pos2.x then
           newPos.x = newPos.x+1
       else
           newPos.x = newPos.x-1
       end
   end
  
   if newPos ~= pos2 then
       local newTile = Tile(newPos)
       if newTile then
           if not newTile:hasFlag(TILESTATE_BLOCKSOLID) then
               return newPos
           end
       end
   end
   return false
end
 
I'm tired, a little headache, so don't be too hard on my code.
It's not tested but if I'm not wrong, it should be something you're looking for :)
Let me know how it works out.

ps, the code will favor vertical movements, if vertical difference match horizontal difference, it will go with south/north instead (if the two is exactly diagonal).
LUA:
function onCastSpell(cid, var)
   player = Player(cid)
   if player then
       target = Creature(variantToNumber(var))
       if target then
           local newPos = getPushPosition(player:getposition(), target:getPosition())
           if newPos then
               target:teleportTo(newPos, true)
           end
       end
   end
   return doCombat(cid, combat, var)
end

function getPushPosition(pos1, pos2)
   local xDif = math.abs(pos1.x - pos2.x)
   local yDif = math.abs(pos1.y - pos2.y)
   newPos = pos2
   if xDif <= yDif then
       if pos1.y < pos2.y then
           newPos.y = newPos.y+1
       else
           newPos.y = newPos.y-1
       end
   else
       if pos1.x < pos2.x then
           newPos.x = newPos.x+1
       else
           newPos.x = newPos.x-1
       end
   end
 
   if newPos ~= pos2 then
       local newTile = Tile(newPos)
       if newTile then
           if not newTile:hasFlag(TILESTATE_BLOCKSOLID) then
               return newPos
           end
       end
   end
   return false
end

Thanks for such complex code, there is one little error

player:getposition()

should be:

player:getPosition()


but other than that, no errors and it does not work really, not sure why. Checked both, on players/creatures, with target/without target

I was trying to update my code posted in the first post but it still doesn't work:

LUA:
function isPathable(pos)
    local tile = Tile(pos)
    if tile then
        return not tile:hasFlag(TILESTATE_BLOCKSOLID)
    end
    return false
end

function onCastSpell(cid, var)
    if isPathable(Player(cid):getDirection(getCreaturePosition(getCreatureTarget(cid)))) then
        doMoveCreature(variantToNumber(var), Player(cid):getDirection())
    end
    return doCombat(cid, combat, var)
end
 
Thanks for such complex code, there is one little error

player:getposition()

should be:

player:getPosition()


but other than that, no errors and it does not work really, not sure why. Checked both, on players/creatures, with target/without target

I was trying to update my code posted in the first post but it still doesn't work:

LUA:
function isPathable(pos)
    local tile = Tile(pos)
    if tile then
        return not tile:hasFlag(TILESTATE_BLOCKSOLID)
    end
    return false
end

function onCastSpell(cid, var)
    if isPathable(Player(cid):getDirection(getCreaturePosition(getCreatureTarget(cid)))) then
        doMoveCreature(variantToNumber(var), Player(cid):getDirection())
    end
    return doCombat(cid, combat, var)
end
sorry, like I said, tired xD
So misspelling is pretty high atm :P

Anyhow, place a few "print()" here and there in the code..

etc, directly below every "if" statement, and have them print A, B, C and so on,
try the code and check console how many of the letters are printed, from the point there it doesn't print, you've found which statement isn't read and from there you can figure out which part isn't right :)
 
sorry, like I said, tired xD
So misspelling is pretty high atm :p

Anyhow, place a few "print()" here and there in the code..

etc, directly below every "if" statement, and have them print A, B, C and so on,
try the code and check console how many of the letters are printed, from the point there it doesn't print, you've found which statement isn't read and from there you can figure out which part isn't right :)

1. it stopped after

if newPos then, line 7

I created another script, more simplified which only works with four directions (SOUTH, NORTH, WEST, EAST) as I wanted but I have not stated that

2. I am really confused because the following code works:

target:teleportTo(targetPos)

but the other one does not:

doMoveCreature(target, targetPos)

3. I wanted to prevent from pushing targets into protection zone but that didn't work either, here is the full code:

LUA:
function isPathable(pos)
    local tile = Tile(pos)
    if tile then
        return not tile:hasFlag(TILESTATE_BLOCKSOLID) or tile:hasFlag(TILESTATE_PROTECTIONZONE) -- protectionzone does not work
    end
    return false
end

function onCastSpell(cid, var)
    local blocked = false
    local playerPos = Player(cid):getPosition()
    local target = Player(cid):getTarget()
    local targetPos = target:getPosition()

    if playerPos.x == targetPos.x and playerPos.y == targetPos.y + 1 then
        print("bottom")
        targetPos.y = playerPos.y - 2

    elseif playerPos.x == targetPos.x and playerPos.y == targetPos.y - 1 then
        print("top")
        targetPos.y = playerPos.y + 2

    elseif playerPos.y == targetPos.y and playerPos.x == targetPos.x + 1 then
        print("right")
        targetPos.x = playerPos.x - 2

    elseif playerPos.y == targetPos.y and playerPos.x == targetPos.x - 1 then
        print("left")
        targetPos.x = playerPos.x + 2

    else
        blocked = true
    end

    if isPathable(targetPos) and blocked == false then
        -- doMoveCreature(target, targetPos) -- this does not work
        -- target:teleportTo(targetPos) -- this method works
    end
    return doCombat(cid, combat, var)
end
 
2. I am really confused because the following code works:

target:teleportTo(targetPos)

but the other one does not:

doMoveCreature(target, targetPos)
teleportTo(POS, true), POS = where to, true = push/walk, if it's false, it will be like teleport.

if it's TFS 1.*, then doMoveCreature() isn't a a LUA function given out by C++ but by libs.
I'd suggest to use teleportTo() instead unless you want to write a more complex function yourself :)

Also, I can't help with the code now (tired etc), but I'll help you out tomorrow, I'll rewrite my piece of code and make sure it works and then hand it to you :)
 
teleportTo(POS, true), POS = where to, true = push/walk, if it's false, it will be like teleport.

Thanks very useful

if it's TFS 1.*, then doMoveCreature() isn't a a LUA function given out by C++ but by libs.
I'd suggest to use teleportTo() instead unless you want to write a more complex function yourself :)

Also, I can't help with the code now (tired etc), but I'll help you out tomorrow, I'll rewrite my piece of code and make sure it works and then hand it to you :)

All fixed except the protection zone, if you know how to do that, even in your code that would be great thanks
 
Thanks very useful



All fixed except the protection zone, if you know how to do that, even in your code that would be great thanks

So, now I'm more alive and can think a little better, I rewrote the code for you including with config for it:
LUA:
local config = {
    push_player = true,            --Possible to push players?
    push_creature = true,        --Possible to push creatures?
    push_npc = true,            --Possible to push NPCs?
    pushInto_PZ = true,            --Possible to push players/creatures into PZ?
    pushInto_Creatures = true,    --Possible to push a player/creature into another player/creature?
}

function onCastSpell(cid, var)
    player = Player(cid)
    if player then
        target = Creature(variantToNumber(var))
            npc = Npc(target.uid)
            if target and (not npc or config.push_npc) and (not target:isCreature() or config.push_creature) and (not Player(target.uid) or config.push_player) then
                local newPos = getPushPosition(player:getPosition(), target:getPosition())
                if newPos then
                    target:teleportTo(newPos, true)
                end
            end
    end
    return doCombat(cid, combat, var)
end
function getPushPosition(pos1, pos2)
    local xDif = math.abs(pos1.x - pos2.x)
    local yDif = math.abs(pos1.y - pos2.y)
    local newPos = pos2
    if xDif <= yDif then
        if pos1.y < pos2.y then
            newPos = {x = newPos.x, y = newPos.y+1, z = newPos.z}
        else
            newPos = {x = newPos.x, y = newPos.y-1, z = newPos.z}
        end 
    else
        if pos1.x < pos2.x then
            newPos = {x = newPos.x+1, y = newPos.y, z = newPos.z}
        else
            newPos = {x = newPos.x-1, y = newPos.y, z = newPos.z}
        end
    end

    if newPos then
        local newTile = Tile(newPos)
        if newTile then
            if not newTile:hasFlag(TILESTATE_BLOCKSOLID) and (not newTile:hasFlag(TILESTATE_PROTECTIONZONE) or config.pushInto_PZ) and (not newTile:getTopCreature() or config.pushInto_Creatures) then
                return newPos
            end
        end
    end
    return false
end

Simply just edit the config true/false to whatever you wish it to do :)
If you have a question, feel free to ask :)
 
Solution
Back
Top