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

Lua Battlefield Event [latest TFS]

Sizaro

Advanced OT User
Joined
Aug 20, 2007
Messages
5,151
Solutions
5
Reaction score
210
Location
Sweden
GitHub
coldensjo
I salvaged this script from another datapack and I want to make it work perfectly but I need help.

What it does
How to start the event
  • Globalevent every 12:30 and 00:30 ingame.
  • Talkaction by tutor or higher with /btf
Entering the teleport
  • Puts you into a random team.
  • Sets your outfit to green or purple.
  • Puts you into an area where you have to prepare with your team.
  • After 10 minutes, the event starts and the walls that separates the teams is removed.
  • After 25 minutes, the event ends and teleports everyone to temple (untested).
  • If you die, you will spawn in temple and you don't lose anything.
  • If you logout, you will spawn in temple.
What it doesn't do
  • It's possible to change outfit inside >> it shouldn't be possible.
  • It doesn't spawn the teleport (maybe I configured it wrong?)
  • Friendly fire possible, but no damage is dealt (you will still get a skull) >> make it not possible to attack friendlies.
  • Possibly other things.
Feel free to test it yourself
TESTING MAP (script should be configured for it)
: battlefield.otbm
GitHub - otland/forgottenserver: A free and open-source MMORPG server emulator written in C++
cbBhVeW.jpg

(I might've forgotten something).

data\creaturescripts\creaturescripts.xml
XML:
<event type="preparedeath" name="BFPrepareDeath" script="events/battlefield.lua" />
<event type="healthchange" name="BFHealthChange" script="events/battlefield.lua" />
<event type="manachange" name="BFManaChange" script="events/battlefield.lua" />
<event type="logout" name="BFLogout" script="events/battlefield.lua" />

data\creaturescripts\scripts\events\battlefield.lua
Lua:
function onLogout(player)
    local info = Battlefield:findPlayer(player)
    if info then
        Battlefield:onLeave(player)
    end
    return true
end

function onPrepareDeath(player, killer)
    local info = Battlefield:findPlayer(player)
    if info then
        Battlefield:onDeath(player, killer)
    end
    return false
end

function onHealthChange(player, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if not attacker then
          return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
    local thisInfo = Battlefield:findPlayer(player)
    local otherInfo = Battlefield:findPlayer(attacker)
    if thisInfo and otherInfo and thisInfo.team == otherInfo.team then
        if primaryType ~= COMBAT_HEALING then
            return COMBAT_NONE, 0, COMBAT_NONE, 0
        end
    end
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

function onManaChange(player, attacker, manaChange, origin)
    if not attacker then
          return manaChange
    end
    local thisInfo = Battlefield:findPlayer(player)
    local otherInfo = Battlefield:findPlayer(attacker)
    if thisInfo and otherInfo and thisInfo.team == otherInfo.team then
        return 0
    end
    return manaChange
end

data\globalevents\globalevents.xml
XML:
<globalevent name="BF_01" time="13:00:00" script="events/bf_start.lua" />
<globalevent name="BF_02" time="00:30:00" script="events/bf_start.lua" />

data\globalevents\scripts\events\bf_start.lua
Lua:
local function warnEvent(i)
    Game.broadcastMessage("Battlefield event is about to commence!")
    if i > 1 then addEvent(warnEvent, 2 * 60 * 1000, i - 1) end
end

local function openBattlefield()
    Battlefield:Open()
end

local function closeBattlefield()
    Battlefield:Close()
end

function onTime(interval)
    Game.broadcastMessage("Battlefield event is about to commence!")
    createPortal(Battlefield.teleport.pos, 16, Battlefield.teleport.aid)
    addEvent(warnEvent, 2 * 60 * 1000, 4)
    addEvent(removePortal, 10 * 60 * 1000, Battlefield.teleport.pos, 16)
    addEvent(openBattlefield, 10 * 60 * 1000)
    addEvent(closeBattlefield, 25 * 60 * 1000)
    return true
end

data\movements\movements.xml
XML:
<movevent event="StepIn" actionid="45000" script="events/bf_tp.lua" />

data\movements\scripts\events\bf_tp.lua
Lua:
function onStepIn(creature, item, position, fromPosition)
    local player = Player(creature)
    if not player then return false end

    if player:getLevel() < Battlefield.minLevel then
        creature:teleportTo(fromPosition)
        creature:sendTextMessage(MESSAGE_INFO_DESCR, "You need level "..Battlefield.minLevel.."+ to enter.")
        return false
    end
  
    if Battlefield.maxPlayers <= Battlefield:getPlayersCount() then
        creature:teleportTo(fromPosition)
        creature:sendTextMessage(MESSAGE_INFO_DESCR, "Battlefield event is full.")
        return false
    end
  
    Battlefield:onJoin(creature)
    return true
end

data\talkactions\scripts\events\btf_start.lua
Lua:
local function warnEvent(i)
    Game.broadcastMessage("Battlefield event is about to commence!")
    if i > 1 then addEvent(warnEvent, 2 * 60 * 1000, i - 1) end
end

local function openBattlefield()
    Battlefield:Open()
end

local function closeBattlefield()
    Battlefield:Close()
end

function onSay(cid, words, param, channel)
    local player = Player(cid)
    if not player then return false end

    if not player:getGroup():getAccess() then
        return true
    end
  
    if player:getAccountType() <= ACCOUNT_TYPE_TUTOR then
        return true   
    end

    Game.broadcastMessage("Battlefield event is about to commence!")
    createPortal(Battlefield.teleport.pos, 16, Battlefield.teleport.aid)
    addEvent(warnEvent, 2 * 60 * 1000, 4)--4
    addEvent(removePortal, 10 * 60 * 1000, Battlefield.teleport.pos, 16)
    addEvent(openBattlefield, 10 * 60 * 1000)
    addEvent(closeBattlefield, 25 * 60 * 1000)
    return true
end

data\lib\libs.lua
Lua:
dofile('data/lib/events/libs.lua')

data\lib\events\libs.lua
Lua:
dofile('data/lib/battlefield.lua')

data\lib\events\battlefield.lua
Lua:
if not Battlefield then
    Battlefield = {
        open = false,

        wall = {
            id = 1037,

            pos = {
                Position(2109, 1845, 7),
                Position(2110, 1845, 7),
                Position(2111, 1845, 7),
                Position(2112, 1845, 7)
            }
        },

        rewards = {
            -- {itemid, quantity}
            {21399, 1},
        },

        minLevel = 100,
        minPlayers = 2, --min players to start event
        maxPlayers = 20, --max players in the event
        players = {},

        exit = Position(2078, 1844, 7), --temple

        teleport = {
            pos = Position(2097, 1847, 7),
            aid = 45000
        },

        teams = {
            [1] = {
                name = 'Purple',

                outfit = {
                    lookType = 138,
                    lookAddons = 0,
                    lookHead = 109,
                    lookLegs = 109,
                    lookBody = 109,
                    lookFeet = 109,
                },

                position = Position(2092, 1825, 7),

                players = {},
                kills = 0,
                size = 0,
            },

            [2] = {
                name = 'Green',

                outfit = {
                    lookType = 138,
                    lookAddons = 0,
                    lookHead = 82,
                    lookLegs = 82,
                    lookBody = 82,
                    lookFeet = 82,
                },

                position = Position(2129, 1866, 7),

                players = {},
                kills = 0,
                size = 0,
            },              
        },

        addPlayer = function (self, cid)
            local player = Player(cid)
            if player then
                self.players[player:getId()] = 1
            end
        end,

        removePlayer = function (self, cid)
            local player = Player(cid)
            if self.players[player:getId()] then
                self.players[player:getId()] = nil
            end
        end,

        getPlayers = function (self)
            return self.players
        end,

        getPlayer = function (self, cid)
            local player = Player(cid)
            if self.players[player:getId()] then
                return true
            else
                return false
            end
        end,

        getPlayersCount = function (self)
            local c = 0
            for _ in pairs(self.players) do c = c + 1 end
            return c
        end
    }

    function Battlefield:Open()
        if self.open then return false end
        self.open = true
        if Battlefield:getPlayersCount() < Battlefield.minPlayers then
            Battlefield:Close()
            return true
        end

        for i = 1, #Battlefield.wall.pos do
            local tile = Tile(Battlefield.wall.pos[i])
            if tile then
                local item = tile:getItemById(Battlefield.wall.id)
                if item then item:remove() end
            end
        end
        return true
    end

    function Battlefield:Close(winner)
        if not self.open then return false end
        self.open = false
        for i = 1, #Battlefield.wall.pos do
            local tile = Tile(Battlefield.wall.pos[i])
            if tile then
                local item = tile:getItemById(Battlefield.wall.id)
                if not item then
                    Game.createItem(Battlefield.wall.id, 1)
                end
            end
        end

        if not winner then
            if self.teams[1].kills > self.teams[2].kills then
                winner = 1
            elseif self.teams[1].kills < self.teams[2].kills then
                winner = 2
            end
        end

        if winner then
            Game.broadcastMessage(string.format("Team %s win the Battlefield Event!", self.teams[winner].name))
        else
            Game.broadcastMessage("There was a tie and nobody wins reward.")
        end

        for _, team in ipairs(self.teams) do
            for name, info in pairs(team.players) do
                local player = Player(name)
                if player then
                    self:onLeave(player)
                    if _ == winner then
                        for k, item in ipairs(self.rewards) do
                            player:addItem(item[1], item[2])
                        end
                    end
                end
            end
        end
        self.teams[1].players = {}
        self.teams[1].size = 0
        self.teams[1].kills = 0
        self.teams[2].players = {}
        self.teams[2].size = 0
        self.teams[2].kills = 0  
        return true
    end

    function Battlefield:findPlayer(player)
        local name = player:getName()
        return self.teams[1].players[name] or self.teams[2].players[name]
    end

    function Battlefield:onJoin(player)local team
        if self.teams[1].size == self.teams[2].size then
            team = math.random(1, 2)
        elseif self.teams[1].size > self.teams[2].size then
            team = 2
        else
            team = 1
        end

        player:setOutfit(self.teams[team].outfit)
        player:teleportTo(self.teams[team].position)

        local info = {name = player:getName(), team = team}
        self.teams[team].size = self.teams[team].size + 1
        self.teams[team].players[player:getName()] = info
        Battlefield:addPlayer(player)

        Game.broadcastMessage(string.format("%s entered the BattleField Event!", info.name))

        player:registerEvent("BFPrepareDeath")
        player:registerEvent("BFHealthChange")
        player:registerEvent("BFManaChange")
        player:registerEvent("BFLogout")

        return true
    end

    function Battlefield:onLeave(player)
        local info = self:findPlayer(player)
        if not info then return false end
        player:unregisterEvent("BFHealthChange")
        player:unregisterEvent("BFPrepareDeath")
        player:unregisterEvent("BFManaChange")
        player:unregisterEvent("BFLogout")

        Game.broadcastMessage(string.format("%s left the BattleField Event!", info.name))

        player:teleportTo(self.exit)
        self.teams[info.team].size = self.teams[info.team].size - 1
        self.teams[info.team].players[info.name] = nil

        player:addHealth(player:getMaxHealth())
        player:addMana(player:getMaxMana())
        player:removeCondition(CONDITION_INFIGHT)
        Battlefield:removePlayer(player)

        if self.teams[info.team].size == 0 then
            self:Close(info.team == 1 and 2 or 1)          
        end
        return true
    end

    function Battlefield:onDeath(player, killer)
        local info = self:findPlayer(player)
        if not info then return false end
        if killer and killer.getName then
            local killerInfo = self:findPlayer(killer)
            if killerInfo and killerInfo.team ~= info.team then
                local killerTeam = self.teams[killerInfo.team]
                killerTeam.kills = killerTeam.kills + 1
            end
        end
        self:onLeave(player)
        return true
    end

    function createPortal(pos, effect, aid)
        local tile = Tile(pos)
        if tile then
            local tp = tile:getItemById(1387)
            if tp == nil then
                local t = Game.createItem(1387, 1)
                t:setAttribute(ITEM_ATTRIBUTE_ACTIONID, aid)
                pos:sendMagicEffect(effect)
            end
        end
    end

    function removePortal(pos, effect)
        local tile = Tile(pos)
        if tile then
            local tp = tile:getItemById(1387)
            if tp then
                tp:remove()
            end
        end
    end
end
 
About the outfit thing, outfits aren't really a condition like manashield or a stat attribute they can be overwritten by the player using the outfit window. I don't know if this is intended behavior or a bug. Unless someone knows a way to suppress this?
 
What about skulls ? We got few types of skulls like yellow, red, black, orange and green. You could set one team skulls to red and the other one to green. After event end remove them.

But in this case we need to block players with skulls like red and black, so they can't enter the event, because they will use it to get rid of their skulls or you can allow them, but then you will need to somehow store their skulls and revert them after the event end.(storages should do the trick)

About friendly fire.
You can do it in events. "onTargetCombat"

Check the storage for player and target and if its the same, so they are in the same team then return false
 
Last edited:
About the skull thingy, couldn't I just make a movement that prevents the player from walking into the teleporter with a skull? Is there a function that checks player skull?
 
About the skull thingy, couldn't I just make a movement that prevents the player from walking into the teleporter with a skull? Is there a function that checks player skull?
Lua:
function onStepIn(creature, item, position, fromPosition)
   local player = creature:getPlayer()
   if not player then
       return true
   end
   
   local skulls = {SKULL_RED, SKULL_BLACK}
   if table.contains(skulls, player:getSkull()) then
       return true
   end

   player:teleportTo(Position(100, 100, 7))
   player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
   player:sendTextMessage(MESSAGE_EVENT_ADVANCE, 'You were teleported.')
   return true
end
 
Last edited:
Back
Top