• 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+ Cannot rope invisible

Solution
Line 262: return thing:teleportTo(toPosition:moveUpstairs())

View attachment 70417
We need to account for unmoveable items like the ground it returns.
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
 
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
 
    local ground = tile:getGround()
 
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
 
    if not isInArray(holeId, target.itemid) then
        return false
    end
 
    toPosition.z = toPosition.z + 1
    tile =...
can you post your rope script? data/actions/lib/actions.lua
and let us know your specific server version?
 
can you post your rope script? data/actions/lib/actions.lua
and let us know your specific server version?
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
    local targetId = target.itemid
    local tile = Tile(toPosition)
    local ground = tile:getGround()
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    elseif isInArray(holeId, targetId) then
        toPosition.z = toPosition.z + 1
        tile = Tile(toPosition)
        if tile then
            local thing = tile:getTopVisibleThing()
            if thing:isItem() and thing:getType():isMovable() then
                return thing:moveTo(toPosition:moveUpstairs())
            elseif thing:isCreature() then
                if thing:isPlayer() then
                    local playerId = thing:getId()
                    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
                        if thing:teleportTo(toPosition:moveUpstairs()) then
                            ropeExhaust[playerId] = os.time() + 1
                            return true
                        end
                    else
                        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
                    end
                else
                    return thing:teleportTo(toPosition:moveUpstairs())
                end
            end
        end
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
    return false
end

TFS 1.3
 
It's very strange to see this many nested if's in a tfs 1.3 script.
and to see isInArray instead of table.contains

Anyway, here's my suggested edit

Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
    
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
        
    local ground = tile:getGround()
    
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
    
    if not isInArray(holeId, target.itemid) then
        return false
    end
    
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
    
    local thing = tile:getTopVisibleThing()
    
    if thing:isItem() and thing:getType():isMovable() then
        return thing:moveTo(toPosition:moveUpstairs())
    end
    
    if not thing:isCreature() then -- this section is the main edit.
        thing = tile:getTopCreature() -- we try to grab Any creature on the tile
        if not thing:isCreature() then
            local tileCreatures = tile:getCreatures() -- the above somehow fails, we try grabbing a list of All creatures on the tile
            if tileCreatures then
                thing = Creature(tileCreatures[1])
            end
            if not thing:isCreature() then
                return false
            end
        end
    end
        
    if not thing:isPlayer() then
        return thing:teleportTo(toPosition:moveUpstairs())
    end
    
    local playerId = thing:getId()
    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
            return true
        end
    else
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
    
    return false
end
 
After all local thing = tile:getTopVisibleThing() checks if the creature is visible

@up
good, but it will produce different behavior, getTopVisibleThing() returns creatures first, then items
hence you should check for top creature first, then top visible thing - this will allow you to avoid this nasty if not thing:isCreature() then and just early return instead ;)
 
Last edited:
It's very strange to see this many nested if's in a tfs 1.3 script.
and to see isInArray instead of table.contains

Anyway, here's my suggested edit

Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
   
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
       
    local ground = tile:getGround()
   
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
   
    if not isInArray(holeId, target.itemid) then
        return false
    end
   
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
   
    local thing = tile:getTopVisibleThing()
   
    if thing:isItem() and thing:getType():isMovable() then
        return thing:moveTo(toPosition:moveUpstairs())
    end
   
    if not thing:isCreature() then -- this section is the main edit.
        thing = tile:getTopCreature() -- we try to grab Any creature on the tile
        if not thing:isCreature() then
            local tileCreatures = tile:getCreatures() -- the above somehow fails, we try grabbing a list of All creatures on the tile
            if tileCreatures then
                thing = Creature(tileCreatures[1])
            end
            if not thing:isCreature() then
                return false
            end
        end
    end
       
    if not thing:isPlayer() then
        return thing:teleportTo(toPosition:moveUpstairs())
    end
   
    local playerId = thing:getId()
    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
            return true
        end
    else
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
   
    return false
end

This TFS pack is quite old and also includes some additions, I believe, that came from OTBR.

It worked when roping invisible creatures, but I got this error when trying to rope with nothing underneath.

Line 260: if not thing:isCreature() then

1662655494184.png
 
This TFS pack is quite old and also includes some additions, I believe, that came from OTBR.

It worked when roping invisible creatures, but I got this error when trying to rope with nothing underneath.

Line 260: if not thing:isCreature() then

View attachment 70413
change it into if not thing then
are you sure that is the line? because if thing was nil it would error on if thing:isItem() and thing:getType():isMovable() then
 
oh, i see, the newly overriden thing is nil.

small edit to Xikini's script, will also prioritize creatures over items
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
 
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
  
    local ground = tile:getGround()
 
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
 
    if not isInArray(holeId, target.itemid) then
        return false
    end
 
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    local thing = tile:getTopCreature()
    if not thing then
        thing = tile:getTopVisibleThing()
    end
 
    if thing:isItem() and thing:getType():isMovable() then
        return thing:moveTo(toPosition:moveUpstairs())
    end
  
    if not thing:isPlayer() then
        return thing:teleportTo(toPosition:moveUpstairs())
    end
 
    local playerId = thing:getId()
    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
            return true
        end
    else
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    return false
end

iirc getTopVisibleThing will return ground when the tile is empty, but getTopCreature will return nil
 
Last edited:
oh, i see, the newly overriden thing is nil.

small edit to Xikini's script, will also prioritize creatures over items
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
 
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
 
    local ground = tile:getGround()
 
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
 
    if not isInArray(holeId, target.itemid) then
        return false
    end
 
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    local thing = tile:getTopCreature()
    if not thing then
        thing = tile:getTopVisibleThing()
    end
 
    if thing:isItem() and thing:getType():isMovable() then
        return thing:moveTo(toPosition:moveUpstairs())
    end
 
    if not thing:isPlayer() then
        return thing:teleportTo(toPosition:moveUpstairs())
    end
 
    local playerId = thing:getId()
    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
            return true
        end
    else
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    return false
end

iirc getTopVisibleThing will return ground when the tile is empty, but getTopCreature will return nil

Line 262: return thing:teleportTo(toPosition:moveUpstairs())

1662658395300.png
 
Line 262: return thing:teleportTo(toPosition:moveUpstairs())

View attachment 70417
We need to account for unmoveable items like the ground it returns.
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
 
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
 
    local ground = tile:getGround()
 
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
 
    if not isInArray(holeId, target.itemid) then
        return false
    end
 
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    local thing = tile:getTopCreature()
    if not thing then
        thing = tile:getTopVisibleThing()
    end
    if thing:isItem() then
        if not thing:getType():isMovable() then
            player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
            return true
        end
        return thing:moveTo(toPosition:moveUpstairs())
    elseif thing:isPlayer() then
        local playerId = thing:getId()
        if ropeExhaust[playerId] and ropeExhaust[playerId] > os.time() then
            player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
            return true
        end
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
        end
        return true
    end
    //else its a creature
    return thing:teleportTo(toPosition:moveUpstairs())
end
 
Last edited:
Solution
We need to account for unmoveable items like the ground it returns.
Lua:
function onUseRope(player, item, fromPosition, target, toPosition, isHotkey)
    if toPosition.x == CONTAINER_POSITION then
        return false
    end
 
    local tile = Tile(toPosition)
    if not tile then
        return false
    end
 
    local ground = tile:getGround()
 
    if ground and isInArray(ropeSpots, ground.itemid) or tile:getItemById(14435) then
        player:teleportTo(toPosition:moveUpstairs())
        return true
    end
 
    if not isInArray(holeId, target.itemid) then
        return false
    end
 
    toPosition.z = toPosition.z + 1
    tile = Tile(toPosition)
    if not tile then
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    local thing = tile:getTopCreature()
    if not thing then
        thing = tile:getTopVisibleThing()
    end

    if thing:isItem() then
        if not thing:getType():isMovable() then
            player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
            return true
        end
        return thing:moveTo(toPosition:moveUpstairs())
    end
 
    if not thing:isPlayer() then
        return thing:teleportTo(toPosition:moveUpstairs())
    end
 
    local playerId = thing:getId()
    if not ropeExhaust[playerId] or ropeExhaust[playerId] < os.time() then
        if thing:teleportTo(toPosition:moveUpstairs()) then
            ropeExhaust[playerId] = os.time() + 1
            return true
        end
    else
        player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
        return true
    end
 
    return false
end
Work! Thank you! for @Xikini too!
 
Back
Top