• 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.3] manual moving boat

Sun

Knowledge is power - France is bacon
Joined
Jan 26, 2015
Messages
333
Solutions
22
Reaction score
243
Made this on request of a client that turned out to be a scammer, so I've decided to release it to the public.

You've probably seen limos moving boat that moves automatically on a predefined route.
this is rather different.

This moving boat gives more freedom to the player.
It moves in the direction you turn and can move on any ID you define in the config.
In other words you can edit so it moves on swamp, tar, water or whatever you want.
vtIgB51.gif


It comes with anti-collision, so there's pretty much nothing to worry about.
Have in mind tho, that because of the anti-collision this boat is no good at moving in narrow areas (this also makes it harder for the boat to trap itself). Although more difficult, it can still get trapped in some narrow areas, make sure to test first.

It can only be docked where there's 3 identical horizontal or vertical borders next to each-other
the exception is docks & beaches since there's no "walk blocking" border.
jZPIRXC.gif


Actions
make sure the actionid in xml is the same as in the config.

actions/actions.xml
Code:
<action actionid="6900" script="moving_boat.lua"/>
actions/scripts/moving_boat.lua
Lua:
local fight = createConditionObject(CONDITION_INFIGHT)
setConditionParam(fight, CONDITION_PARAM_TICKS, -1)

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if player:getCondition(CONDITION_INFIGHT) ~= nil then
        return player:sendCancelMessage("You can't travel while in combat.")
    else
        player:addCondition(fight)
    end
    player:teleportTo(toPosition)
    return true
end

Events
events/events.xml
Code:
<event class="Player" method="onTurn" enabled="1" />
events/scripts/player.lua
find & edit
function Player:eek:nTurn(direction)
Lua:
function Player:onTurn(direction)

    if mbc.isOnBoat(self:getId()) then
        mbc.moveBoat(self:getId(), direction, self:getPosition())
    end
    return true
end
if you're using [Event] Walkthrough everything Ctrl + Arrow keys [TFS 1.X]
Lua:
function Player:onTurn(direction)

    if mbc.isOnBoat(self:getId()) then
        mbc.moveBoat(self:getId(), direction, self:getPosition())
    else
        if self:getStorageValue(mbc.storage) < 1 then
            if self:getGroup():getAccess() and self:getDirection() == direction then
                local nextPosition = self:getPosition()
                nextPosition:getNextPosition(direction)

                self:teleportTo(nextPosition, true)
            end
        end
    end

    return true
end

Lib
lib/lib.lua
add
Lua:
-- Custom functions
dofile('data/lib/custom/custom.lua')

lib/custom/custom.lua
Lua:
dofile('data/lib/custom/moving_boat.lua')
lib/custom/moving_boat.lua
Lua:
mbc = { -- moving boat config
    water = {4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4664, 4665, 4666},
    borders = {
        [4644] = "south",
        [4645] = "west",
        [4646] = "north",
        [4647] = "east",
    },
    boats = {
        horizontal = {3592,3594,3596},
        vertical = {3587,3589,3591}
    },
    speed = 100,
    storage = 36901,
    actionid = 6900,

    isOnBoat = function(cid)
        local player = Player(cid)

        if player:getStorageValue(mbc.storage) > 0 then
            return false
        end

        local check = 0
        local tile = Tile(player:getPosition())

        if tile:getItems() == nil or tile:getGround() == nil then
            return false
        end
        if isInArray(mbc.water, tile:getGround():getId()) then
            check = check + 1
        end
        for k,v in pairs(tile:getItems()) do
            if mbc["borders"][v:getId()] ~= nil then
                check = check + 1
            end
            if v:getId() == mbc.boats.horizontal[2] or v:getId() == mbc.boats.vertical[2] then
                check = check + 1
            end
            if check == 2 then
                player:setStorageValue(mbc.storage, 1)
                local function setStorage(cid, key, value)
                    Player(cid):setStorageValue(key,value)
                end
                addEvent(setStorage, mbc.speed, cid, mbc.storage, 0)
                return true
            end
        end

        return false
    end,

    createBoat = function(pos, boat)

        local i = 1
        if boat[1] == mbc.boats.vertical[1] then
            for y = pos.y-1,pos.y+1 do
                local p = {x = pos.x, y = y, z = pos.z}
                local create = Game.createItem(boat[i], 1, p)
                if i == 2 then create:setActionId(mbc.actionid) end
                i = i + 1
            end
        else
            for x = pos.x-1,pos.x+1 do
                local p = {x = x, y = pos.y, z = pos.z}
                local create = Game.createItem(boat[i], 1, p)
                if i == 2 then create:setActionId(mbc.actionid) end
                i = i + 1
            end
        end

    end,

    removeBoat = function(pos)

        local t = Tile(pos)
        local ho = mbc.boats.horizontal
        local ve = mbc.boats.vertical

        if t:getItemById(ve[2]) ~= nil then
            for y = pos.y-1,pos.y+1 do
                p = {x = pos.x, y = y, z = pos.z}
                if Tile(p) ~= nil then
                    for k,v in pairs(ve) do
                        local item = (Tile(p):getItemById(v) ~= nil and Tile(p):getItemById(v) or nil)
                        if item ~= nil then
                            item:remove()
                        end
                    end
                end
            end
        elseif t:getItemById(ho[2]) ~= nil then
            for x = pos.x-1,pos.x+1 do
                p = {x = x, y = pos.y, z = pos.z}
                if Tile(p) ~= nil then
                    for k,v in pairs(ho) do
                        local item = Tile(p):getItemById(v)
                        if item ~= nil then
                            item:remove()
                        end
                    end
                end
            end
        end
    end,

    isBorder = function(pos, id)
        local b = mbc["borders"]
        local check = 0
        local function checkForBorder(tile, itemid)
            local border = false
            for k,v in pairs(tile:getItems()) do
                if b[v:getId()] ~= nil then
                    border = true
                end
                if v:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) and b[v:getId()] == nil then
                    return 0
                end
            end
            if border then
                return 1
            end
            return 0
        end

        if b[id] == "north" then
            for x = pos.x-1,pos.x+1 do
                local p = {x = x, y = pos.y, z = pos.z}
                local tile = Tile(p)
                if tile ~= nil and tile:getItems() ~= nil then
                    check = check + checkForBorder(tile, id)
                end
            end
        elseif b[id] == "east" then
            for y = pos.y-1,pos.y+1 do
                local p = {x = pos.x, y = y, z = pos.z}
                local tile = Tile(p)
                if tile ~= nil and tile:getItems() ~= nil then
                    check = check + checkForBorder(tile, id)
                end
            end
        elseif b[id] == "south" then
            for x = pos.x-1,pos.x+1 do
                local p = {x = x, y = pos.y, z = pos.z}
                local tile = Tile(p)
                if tile ~= nil and tile:getItems() ~= nil then
                    check = check + checkForBorder(tile, id)
                end
            end
        elseif b[id] == "west" then
            for y = pos.y-1,pos.y+1 do
                local p = {x = pos.x, y = y, z = pos.z}
                local tile = Tile(p)
                if tile ~= nil and tile:getItems() ~= nil then
                    check = check + checkForBorder(tile, id)
                end
            end
        end
        if check == 3 then
            return true
        end
        return false
    end,

    moveBoat = function(cid, dir, pos)
        local player = Player(cid)
        local b = nil -- boat

        local nextPos = {
            [1] = {{x = pos.x, y = pos.y-1, z = pos.z}, {x = pos.x, y = pos.y-2, z = pos.z}, 3587},
            [2] = {{x = pos.x+1, y = pos.y, z = pos.z}, {x = pos.x+2, y = pos.y, z = pos.z}, 3596},
            [3] = {{x = pos.x, y = pos.y+1, z = pos.z}, {x = pos.x, y = pos.y+2, z = pos.z}, 3591},
            [4] = {{x = pos.x-1, y = pos.y, z = pos.z}, {x = pos.x-2, y = pos.y, z = pos.z}, 3592}
        }
       
        local np = nextPos[dir+1]
        local tile = Tile(np[1])
        local tile_2 = Tile(np[2])
        local isBorder = false

        if tile ~= nil and tile:getItems() ~= nil then
            for k,v in pairs(tile:getItems()) do
                if mbc["borders"][v:getId()] ~= nil then
                    if mbc.isBorder(np[1], v:getId()) then
                        isBorder = true
                        if dir%2 == 0 then
                            b = mbc.boats.horizontal
                        else
                            b = mbc.boats.vertical
                        end
                    else
                        return
                    end
                    break
                elseif v:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) or v:getId() ~= np[3] then
                    return
                end
            end
        end

        if tile_2 ~= nil and tile_2:getItems() ~= nil and (not isBorder) then
            for k,v in pairs(tile_2:getItems()) do
                if mbc["borders"][v:getId()] ~= nil then
                    if mbc.isBorder(np[2], v:getId()) then
                        isBorder = true
                        break
                    else
                        return
                    end
                elseif v:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) or (isInArray(mbc.boats.horizontal, v:getId())) or (isInArray(mbc.boats.vertical, v:getId())) then
                    return
                end
            end
        end

        if b == nil then
            if dir%2 == 0 then
                b = mbc.boats.vertical
            else
                b = mbc.boats.horizontal
            end
        end

        if tile ~= nil and (isInArray(mbc.water, tile:getGround():getId()) or isBorder) then
            mbc.removeBoat(pos)
            player:teleportTo(np[1])
            mbc.createBoat(np[1], b)
        end

    end,
}

Movements
make sure it's the same action id as in the config
movements/movements.xml
Code:
<movevent event="stepOut" actionid="6900" script="moving_boat.lua"/>
movements/scripts/moving_boat.lua
Lua:
function onStepOut(creature, item, position, fromPosition)

    if not creature:isPlayer() then return true end
    if creature:getCondition(CONDITION_INFIGHT) ~= nil then
        local function removeFight(cid)
            local player = Player(cid)
            if (not mbc.isOnBoat(cid)) and player:getStorageValue(mbc.storage) < 1 then
                player:removeCondition(CONDITION_INFIGHT)
            end
        end
        addEvent(removeFight, mbc.speed, creature:getId())
    end
    return true
end
 
test and tell us if any problem, btw why not use 1.3 on your server? there is not much work to change from 1.2 to 1.3 (1.2 is 6 years old already)

Thanks. I will test soon, and post or result.
I'm using Nostalrius which is based on TFs 1.2. I don't believe I have enough knowledge to perform this upgrade. But I will definitely seek to know.
 
Back
Top