• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

TFS 1.X+ Last Man Standing Event

X X X

Newb
Joined
Jul 26, 2015
Messages
110
Reaction score
10
Hello,

Having trouble with an event I'm trying to create. I've modified the script here (GlobalEvent - [TFS 1.2] Zombie Arena (https://otland.net/threads/tfs-1-2-zombie-arena.258250/)) to be a "Last Man Standing" style event. All of the beginning stuff works; I can start the event with the talkaction, the portal appears, players enter the waiting room, it sends them into the arena, it summons monsters, etc etc.

I'm stuck at the very end; that is, when there's only 1 person left, the event does not end, and they don't get the reward. I have been messing with this script for about 10 hours and cannot get it to work. Sometimes I can get it to when the last player dies, the winner gets the reward but the loser gets the reward also. Here is my modified script:

Lua:
debug = true

-- Config
zombieArena = {
    config = {
        minPlayers = 2,  -- Minimum players for the event to begin
        monsters   = 20, -- Total monsters to kill
        monster    = "Hero",
      
        -- Time between starts
        -- This gets called recursively until event is started
        minutesBetweenStart = 0.5,

        -- How many seconds between each zombie spawned
        secondsBetweenZombies = 10,
    },
    storages  = {
        eventOpened    = 670000,
        eventStarted   = 670001,
        eventFinished  = 670002,
        monstersLeft   = 670003,
        playerOnEvent  = 670004, -- Singular
        playersOnEvent = 670005, -- Global
    },
    positions = {
        waitingRoom = {
            center = Position(765, 662, 7),

            -- Radius is how many squares from center
            -- Do NOT count walls in radius
            radius = 2,
        },
        arena = {
            [1] = {
            center = Position(749, 675, 7),
            radius = 15,
        },
            [2] = {
            center = Position(749, 675,6),
            radius = 15,
        },
            [3] = {
              center = Position(749, 675, 5),
            radius = 15,
        },   
    },

        -- Where to spawn teleport to waiting room
        teleport = Position(770, 662, 7),
    },
    messages = {
        eventOpened   = "Zombie arena portal is now open!",
        eventStarted  = "Zombie arena event has started!",
        eventFinished = "All zombies have been slain! Zombie arena completed.",
        eventFailed   = "The zombies won by killing every single player...",
    },
    rewards = {
        [1] = {
            name   = "crystal coin",
            itemid = 2160,
            count  = 50,
        },
        [2] = {
            name   = "magic sword",
            itemid = 2400,
            count  = 1,
        },
--      [3] = {
--          name   = "example item",
--          itemid = 666,
--          count  = 1,
--      },
    },
}


zombieArena.__index = zombieArena


function zombieArena:autoStart()
    local function start()
        zombieArena:start()
    end

    -- Checks if event has been started recursively,
    -- if not tries again until start
    local function check()
        if not zombieArena:isStarted() then
            zombieArena:autoStart()
        end
    end

    addEvent(start, zombieArena.config.minutesBetweenStart * 60 * 1000)
    addEvent(check, zombieArena.config.minutesBetweenStart * 60 * 1000 + 5)
end

-- Main function to start event
function zombieArena:start()
    if zombieArena:isStarted() then
        zombieArena:debug("Event was already started.")
        return false
    end

    if not zombieArena:teleportPlayers() then
        return false
    end

    zombieArena:removeTeleport()
    zombieArena:summonMonsters()

    Game.broadcastMessage(zombieArena.messages.eventStarted, MESSAGE_STATUS_WARNING)
    Game.setStorageValue(zombieArena.storages.monstersLeft, zombieArena.config.monsters)
    Game.setStorageValue(zombieArena.storages.eventStarted, 1)
    return true
end


function zombieArena:openEvent()   
  
    if Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        zombieArena:debug("Event is already open.")
        return false
    end

    if zombieArena:isStarted() then
        zombieArena:debug("Event has already started.")
        return false
    end

    -- Open event
    Game.broadcastMessage(zombieArena.messages.eventOpened, MESSAGE_STATUS_WARNING)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.eventFinished, 0)
    Game.setStorageValue(zombieArena.storages.eventOpened, 1)
    zombieArena:debug("Event opened.")
    zombieArena:createTeleport()
    print(Game.getStorageValue(zombieArena.storages.playersOnEvent))
    return true
end


-- Creates the teleport to the waiting room
function zombieArena:createTeleport()
    local tp = Game.createItem(1387, 1, zombieArena.positions.teleport)
    if not tp:isTeleport() then
        tp:remove()
        return false
    end

    tp:setDestination(zombieArena.positions.waitingRoom.center)
    zombieArena:debug("Teleport created.")
    return true
end


-- Removes the teleport to the waiting room
function zombieArena:removeTeleport()

    if not Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        zombieArena:debug("Event is not opened.")
        return false
    end

    Game.setStorageValue(zombieArena.storages.eventOpened, 0)
    zombieArena:debug("Event closed for new players.")

    -- Remove teleport
    local tp = Tile(zombieArena.positions.teleport)
    if tp:getItemById(1387):isTeleport() then
        tp:getItemById(1387):remove()
        zombieArena:debug("Teleport removed.")
        return true
    end
end

function zombieArena:checkWaitingRoom()
    local center = zombieArena.positions.waitingRoom.center
    local radius = zombieArena.positions.waitingRoom.radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)
  
    if #players == 0 then
        zombieArena:debug("No players in waiting room.")
        return nil
    end

    if #players < zombieArena.config.minPlayers then
        local message = string.format("%d players required to start. Currently %d player(s) found. ", zombieArena.config.minPlayers, #players)
        zombieArena:messageGroup(players, message)
        zombieArena:debug(message)
        return players
    end
    return players
end

-- Clears all zombies from arena
function zombieArena:clear()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local monsters = Game.getSpectators(center, false, false, radius, radius, radius, radius)

    if monsters == nil then
        return false
    end

    if #monsters < 0 then
        return false
    end

    for i = 1, #monsters do
        monster = Creature(monsters[i])
        monster:remove()
    end
    zombieArena:debug("Zombie arena cleared.")
    return true
end


-- If there's more players than the required minimum,
-- teleport all players from waiting room to the arena.
function zombieArena:teleportPlayers()
    players = zombieArena:checkWaitingRoom()
    if players ~= nil then
      
        -- Not enough players
        if #players < zombieArena.config.minPlayers then
            return false
        end

        -- Teleport players
        for i = 1, #players do
            local player = Player(players[i])
            player:teleportTo(zombieArena.positions.arena[1].center)
            zombieArena:debug(player:getName() .. " was teleported to arena.")
            zombieArena:addPlayer(player)
        end
        return true
    end
end

-- Adds player to the event
function zombieArena:addPlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 1)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() + 1)
    zombieArena:debug(player:getName() .. " was added to event.")
    print(Game.getStorageValue(zombieArena.storages.playersOnEvent))
end

-- Removes player from the event
function zombieArena:removePlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() - 1)
    zombieArena:debug(player:getName() .. " was removed from event.")
    players = zombieArena:getPlayersLeft()
    print(Game.getStorageValue(zombieArena.storages.playersOnEvent))
    print(players)
    if players == 1 then
        for i = 1, #players do
            local player = Player(players[i])
                zombieArena:reward(player)
            end

        -- Ends the event
        zombieArena:finish(true)
        return true
    end
end

-- Gets all players on event
function zombieArena:getPlayersLeft()
    return Game.getStorageValue(zombieArena.storages.playersOnEvent)
end


-- Message a group of people
function zombieArena:messageGroup(players, message)
    for i = 1, #players do
        local player = Player(players[i])
        player:sendTextMessage(MESSAGE_STATUS_WARNING, message)
    end
end

-- Spawns a monster randomly within the radius provided in positions
function zombieArena:createMonster(i)

    -- Purposely written this way instead of using the table directly,
    -- since tables are pass by reference.
    local radius = zombieArena.positions.arena[1].radius
    local x = zombieArena.positions.arena[1].center.x
    local y = zombieArena.positions.arena[1].center.y
    local z = zombieArena.positions.arena[1].center.z
    x = math.random(x - radius, x + radius)
    y = math.random(y - radius, y + radius)
  
    local function create()
        -- Create monster
        if zombieArena:isStarted() then
            if Game.createMonster(zombieArena.config.monster, Position(x, y, z)) then
                Position(x, y, z):sendMagicEffect(CONST_ME_POFF)
                local message = string.format("%s created at position {x = %d, y = %d, z = %d}", zombieArena.config.monster, x, y, z)
                zombieArena:debug(message)
                return true
            end
        end
    end

    if addEvent(create, i * zombieArena.config.secondsBetweenZombies * 1000) then
        return true
    end
  
    -- Something went wrong
    local message = string.format("Unexpected error: couldn't create %s at position {x = %d, y = %d, z = %d}", monster, x, y, z)
    zombieArena:debug(message)
    return false
end

-- Summon x monsters provided in config
function zombieArena:summonMonsters()
    for i = 1, zombieArena.config.monsters do
            zombieArena:createMonster(i)
    end
    local message = string.format("%d monsters will be summoned.", zombieArena.config.monsters)
    zombieArena:debug(message)
end

-- Gets how many monsters there left in arena
function zombieArena:getMonstersLeft()
    return Game.getStorageValue(zombieArena.storages.monstersLeft)
end

function zombieArena:finish(playersWon)

    if playersWon then
        Game.broadcastMessage(zombieArena.messages.eventFinished, MESSAGE_STATUS_WARNING)
        zombieArena:debug(zombieArena.messages.eventFinished)
    else
        Game.broadcastMessage(zombieArena.messages.eventFailed, MESSAGE_STATUS_WARNING)
    zombieArena:debug(zombieArena.messages.eventFailed)
    end

    Game.setStorageValue(zombieArena.storages.eventStarted, 0)
    Game.setStorageValue(zombieArena.storages.eventFinished, 1)
end

-- Give the players who survived the event a reward
-- and teleport to hometown
function zombieArena:reward(player)
    for i = 1, #zombieArena.rewards do
        player:addItem(zombieArena.rewards[i].itemid, zombieArena.rewards[i].count)

        local message = string.format("You received a %s.", zombieArena.rewards[i].name)
        player:sendTextMessage(MESSAGE_STATUS_WARNING, message)
        zombieArena:debug(player:getName() .. " received a " .. zombieArena.rewards[i].name)

    end
    player:teleportTo(player:getTown():getTemplePosition())
    zombieArena:debug(player:getName() .. " got teleported to " .. player:getTown():getName() .. ".")

    zombieArena:removePlayer(player)
    return true
end

-- Checks if event is finished
-- returns either true or false
function zombieArena:isFinished()
    if Game.getStorageValue(zombieArena.storages.eventFinished) == 1 then
        return true
    end
    return false
end

-- Checks if event has started
-- returns either true or false
function zombieArena:isStarted()
    if Game.getStorageValue(zombieArena.storages.eventStarted) == 1 then
        return true
    end
    return false
end

-- Checks if event is opened
-- returns either true or false
function zombieArena:isOpened()
    if Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        return true
    end
    return false
end


-- Check if player is doing event
-- returns either true or false
function zombieArena:isPlayerOnEvent(player)
    if player:getStorageValue(zombieArena.storages.playerOnEvent) == 1 then
        return true
    end
    return false
end


-- Toggle debug on/off on top off this file
function zombieArena:debug(message)
    if debug then
        message = "[ZOMBIEARENA] " .. message
        print(message)
    end
end

Because the original post was supposed to be a "Zombie Killing Event," it only checked to see if the event was over when the number of total zombies hit zero. Since I want to do a last man standing, I want the event to be over when it checks and sees there is only 1 player left with the storage value for zombieArena.storages.playersOnEvent. So, I decided to use the "removePlayer" function to check how many players were left. Here is my console output for the entire event:

Code:
GOD has logged in.
[ZOMBIEARENA] Event opened.
[ZOMBIEARENA] Teleport created.
0
Player 1 has logged in.
Player 2 has logged in.
[ZOMBIEARENA] 2 players required to start. Currently 1 player(s) found.
[ZOMBIEARENA] Player 1 was teleported to arena.
[ZOMBIEARENA] Player 1 was added to event.
1
[ZOMBIEARENA] Player 2 was teleported to arena.
[ZOMBIEARENA] Player 2 was added to event.
2
[ZOMBIEARENA] Event closed for new players.
[ZOMBIEARENA] Teleport removed.
[ZOMBIEARENA] 20 monsters will be summoned.
[ZOMBIEARENA] Hero created at position {x = 746, y = 661, z = 7}
[ZOMBIEARENA] Hero created at position {x = 742, y = 687, z = 7}
[ZOMBIEARENA] Hero created at position {x = 760, y = 667, z = 7}
[ZOMBIEARENA] Hero created at position {x = 738, y = 686, z = 7}
[ZOMBIEARENA] Hero created at position {x = 736, y = 667, z = 7}
[ZOMBIEARENA] Hero created at position {x = 736, y = 660, z = 7}
[ZOMBIEARENA] Hero created at position {x = 743, y = 663, z = 7}
[ZOMBIEARENA] Player 1 was removed from event.
1
1

Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/zombie_arena/death.lua:onPrepareDeath
data/lib/event/zombie_arena.lua:257: attempt to get length of global 'players' (a number value)
[ZOMBIEARENA] Hero created at position {x = 763, y = 674, z = 7}
[ZOMBIEARENA] Hero created at position {x = 737, y = 682, z = 7}
[ZOMBIEARENA] Hero created at position {x = 759, y = 668, z = 7}
[ZOMBIEARENA] Hero created at position {x = 761, y = 672, z = 7}
[ZOMBIEARENA] Hero created at position {x = 752, y = 690, z = 7}

I can see from my print that players does indeed equal 1, but the error thinks I'm comparing a string to a number? If I remove that line completely (if player == 1 then) there are no errors, but the last player is still stuck in the arena.

Also, here is my death.lua script as well for reference:

Lua:
-- When player dies in Zombie Arena
function onPrepareDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    
    if zombieArena:isStarted() and zombieArena:isPlayerOnEvent(player) then
        player:addHealth(player:getMaxHealth())
        player:addMana(player:getMaxMana())
        player:teleportTo(player:getTown():getTemplePosition())
        zombieArena:removePlayer(player)
        zombieArena:debug(player:getName() .. " got teleported to " .. player:getTown():getName() .. ".")
        
        return false
    end
    return true
end

Thank you!
 
Solution
Several things are wrong, the comparison you're doing is trying to compare memory to a number. First, I see for some reason the checkArena function is missing from yours. I'm guessing you removed it trying to change the event. Add this back in:

Lua:
function zombieArena:checkArena()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)

    if zombieArena:getPlayersLeft() == 0 then
        zombieArena:finish(false)   
        if zombieArena:clear() then
            zombieArena:debug("All players died.")
        end
        return nil
    end
    return players
end

If you want to check...

Crevasse

惡名昭彰
Joined
Jan 13, 2017
Messages
116
Solutions
9
Reaction score
63
Location
Washington, D.C.
Several things are wrong, the comparison you're doing is trying to compare memory to a number. First, I see for some reason the checkArena function is missing from yours. I'm guessing you removed it trying to change the event. Add this back in:

Lua:
function zombieArena:checkArena()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)

    if zombieArena:getPlayersLeft() == 0 then
        zombieArena:finish(false)   
        if zombieArena:clear() then
            zombieArena:debug("All players died.")
        end
        return nil
    end
    return players
end

If you want to check players left each time a player is removed and then end the event when there's only 1 player left, you are correct that this can be done in the removePlayer function, but you should do it like this:

Lua:
-- Removes player from the event
function zombieArena:removePlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() - 1)
    zombieArena:debug(player:getName() .. " was removed from event.")
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    players = zombieArena:checkArena()
    
    if zombieArena:getPlayersLeft() == 1 then
        for i = 1, #players do
            local player = Player(players[i])
            zombieArena:reward(player)
        end

        -- Ends the event
        zombieArena:finish(true)
        return true
    end
end

Then you should clean up other spots in the code that you don't need...checking how many monsters are left etc. since that doesn't matter.
 
Solution

Unknow Name

Banned User
Joined
Jun 23, 2022
Messages
8
Reaction score
0
GitHub
Abdala
Thank you that worked! Yes, I will clean up the other stuff that is not needed now that I have the core function done!!
Can you send me this script After your modifications, please
I also want monster xml zombie
I know the solution is here but I got errors so I would like to ask you for help with that
Thank you in advance
----------------------
 

Unknow Name

Banned User
Joined
Jun 23, 2022
Messages
8
Reaction score
0
GitHub
Abdala
Several things are wrong, the comparison you're doing is trying to compare memory to a number. First, I see for some reason the checkArena function is missing from yours. I'm guessing you removed it trying to change the event. Add this back in:

Lua:
function zombieArena:checkArena()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)

    if zombieArena:getPlayersLeft() == 0 then
        zombieArena:finish(false)  
        if zombieArena:clear() then
            zombieArena:debug("All players died.")
        end
        return nil
    end
    return players
end

If you want to check players left each time a player is removed and then end the event when there's only 1 player left, you are correct that this can be done in the removePlayer function, but you should do it like this:

Lua:
-- Removes player from the event
function zombieArena:removePlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() - 1)
    zombieArena:debug(player:getName() .. " was removed from event.")
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    players = zombieArena:checkArena()
   
    if zombieArena:getPlayersLeft() == 1 then
        for i = 1, #players do
            local player = Player(players[i])
            zombieArena:reward(player)
        end

        -- Ends the event
        zombieArena:finish(true)
        return true
    end
end

Then you should clean up other spots in the code that you don't need...checking how many monsters are left etc. since that doesn't matter.
I did everything you said I got it wrong in line 274
Event Work Fine But the players die and the first one to die gets the prize and the event ends
After the first player dies, he takes the rest kick
The other problem is that in this event they did not publish the monster zombie xml file
I took it from somewhere else
There is a problem with reading this
Lua:
in monsterxml>>>>...   <event name="zombie_arena"/>
look at zombie.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<monster name="Zombie" nameDescription="a zombie" race="undead" experience="0" speed="150" manacost="0">
    <health now="10000" max="10000" />
    <look type="100" corpse="0" />
    <targetchange interval="4000" chance="10" />
    <flags>
        <flag summonable="0" />
        <flag attackable="0" />
        <flag hostile="1" />
        <flag illusionable="0" />
        <flag convinceable="0" />
        <flag pushable="0" />
        <flag canpushitems="1" />
        <flag canpushcreatures="1" />
        <flag targetdistance="1" />
        <flag staticattack="90" />
        <flag runonhealth="0" />
    </flags>
    <attacks>
        <attack name="melee" interval="1000" min="0" max="-10000000" />
    </attacks>
    <defenses armor="15" defense="15" />
    <elements>
        <element firePercent="50" />
    </elements>
    <immunities>
        <immunity death="1" />
        <immunity energy="1" />
        <immunity ice="1" />
        <immunity earth="1" />
        <immunity drown="1" />
        <immunity drunk="1" />
        <immunity lifedrain="1" />
        <immunity paralyze="1" />
    </immunities>
    <voices interval="5000" chance="10">
        <voice sentence="Mst.... klll...." />
        <voice sentence="Whrrrr... ssss.... mmm.... grrrrl" />
        <voice sentence="Dnnnt... cmmm... clsrrr...." />
        <voice sentence="Httt.... hmnnsss..." />
    </voices>
    <script>
        <event name="zombie_arena"/>
    </script>
</monster>
Look At My Event Script
Code:
debug = true

-- Config
zombieArena = {
    config = {
        minPlayers = 2,  -- Minimum players for the event to begin
        monsters   = 20, -- Total monsters to kill
        monster    = "Zombie",
      
        -- Time between starts
        -- This gets called recursively until event is started
        minutesBetweenStart = 0.5,

        -- How many seconds between each zombie spawned
        secondsBetweenZombies = 5,
    },
    storages  = {
        eventOpened    = 670000,
        eventStarted   = 670001,
        eventFinished  = 670002,
        monstersLeft   = 670003,
        playerOnEvent  = 670004, -- Singular
        playersOnEvent = 670005, -- Global
    },
    positions = {
        waitingRoom = {
            center = Position(677, 1078, 6),

            -- Radius is how many squares from center
            -- Do NOT count walls in radius
            radius = 2,
        },
        arena = {
            [1] = {
            center = Position(1016, 908, 7),
            radius = 10,
        },
            [2] = {
            center = Position(1013, 908,7),
            radius = 10,
        },
            [3] = {
              center = Position(1018, 909, 7),
            radius = 10,
        },   
    },

        -- Where to spawn teleport to waiting room
        teleport = Position(867, 1537, 14),
    },
    messages = {
        eventOpened   = "Zombie arena portal is now open!",
        eventStarted  = "Zombie arena event has started!",
        eventFinished = "All zombies have been slain! Zombie arena completed.",
        eventFailed   = "The zombies won by killing every single player...",
    },
    rewards = {
        [1] = {
            name   = "crystal coin",
            itemid = 2160,
            count  = 25,
        },
        [2] = {
            name   = "magic sword",
            itemid = 2159,
            count  = 25,
        },
--      [3] = {
--          name   = "example item",
--          itemid = 666,
--          count  = 1,
--      },
    },
}


zombieArena.__index = zombieArena


function zombieArena:autoStart()
    local function start()
        zombieArena:start()
    end

    -- Checks if event has been started recursively,
    -- if not tries again until start
    local function check()
        if not zombieArena:isStarted() then
            zombieArena:autoStart()
        end
    end

    addEvent(start, zombieArena.config.minutesBetweenStart * 60 * 1000)
    addEvent(check, zombieArena.config.minutesBetweenStart * 60 * 1000 + 5)
end

-- Main function to start event
function zombieArena:start()
    if zombieArena:isStarted() then
        zombieArena:debug("Event was already started.")
        return false
    end

    if not zombieArena:teleportPlayers() then
        return false
    end

    zombieArena:removeTeleport()
    zombieArena:summonMonsters()

    Game.broadcastMessage(zombieArena.messages.eventStarted, MESSAGE_STATUS_WARNING)
    Game.setStorageValue(zombieArena.storages.monstersLeft, zombieArena.config.monsters)
    Game.setStorageValue(zombieArena.storages.eventStarted, 1)
    return true
end


function zombieArena:openEvent()   
 
    if Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        zombieArena:debug("Event is already open.")
        return false
    end

    if zombieArena:isStarted() then
        zombieArena:debug("Event has already started.")
        return false
    end

    -- Open event
    Game.broadcastMessage(zombieArena.messages.eventOpened, MESSAGE_STATUS_WARNING)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.eventFinished, 0)
    Game.setStorageValue(zombieArena.storages.eventOpened, 1)
    zombieArena:debug("Event opened.")
    zombieArena:createTeleport()
    print(Game.getStorageValue(zombieArena.storages.playersOnEvent))
    return true
end


-- Creates the teleport to the waiting room
function zombieArena:createTeleport()
    local tp = Game.createItem(1387, 1, zombieArena.positions.teleport)
    if not tp:isTeleport() then
        tp:remove()
        return false
    end

    tp:setDestination(zombieArena.positions.waitingRoom.center)
    zombieArena:debug("Teleport created.")
    return true
end


-- Removes the teleport to the waiting room
function zombieArena:removeTeleport()

    if not Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        zombieArena:debug("Event is not opened.")
        return false
    end

    Game.setStorageValue(zombieArena.storages.eventOpened, 0)
    zombieArena:debug("Event closed for new players.")

    -- Remove teleport
    local tp = Tile(zombieArena.positions.teleport)
    if tp:getItemById(1387):isTeleport() then
        tp:getItemById(1387):remove()
        zombieArena:debug("Teleport removed.")
        return true
    end
end

function zombieArena:checkWaitingRoom()
    local center = zombieArena.positions.waitingRoom.center
    local radius = zombieArena.positions.waitingRoom.radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)
 
    if #players == 0 then
        zombieArena:debug("No players in waiting room.")
        return nil
    end

    if #players < zombieArena.config.minPlayers then
        local message = string.format("%d players required to start. Currently %d player(s) found. ", zombieArena.config.minPlayers, #players)
        zombieArena:messageGroup(players, message)
        zombieArena:debug(message)
        return players
    end
    return players
end

function zombieArena:checkArena()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local players = Game.getSpectators(center, false, true, radius, radius, radius, radius)

    if zombieArena:getPlayersLeft() == 0 then
        zombieArena:finish(false)   
        if zombieArena:clear() then
            zombieArena:debug("All players died.")
        end
        return nil
    end
    return players
end

-- Clears all zombies from arena
function zombieArena:clear()
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    local monsters = Game.getSpectators(center, false, false, radius, radius, radius, radius)

    if monsters == nil then
        return false
    end

    if #monsters < 0 then
        return false
    end

    for i = 1, #monsters do
        monster = Creature(monsters[i])
        monster:remove()
    end
    zombieArena:debug("Zombie arena cleared.")
    return true
end


-- If there's more players than the required minimum,
-- teleport all players from waiting room to the arena.
function zombieArena:teleportPlayers()
    players = zombieArena:checkWaitingRoom()
    if players ~= nil then
      
        -- Not enough players
        if #players < zombieArena.config.minPlayers then
            return false
        end

        -- Teleport players
        for i = 1, #players do
            local player = Player(players[i])
            player:teleportTo(zombieArena.positions.arena[1].center)
            zombieArena:debug(player:getName() .. " was teleported to arena.")
            zombieArena:addPlayer(player)
        end
        return true
    end
end

-- Adds player to the event
function zombieArena:addPlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 1)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() + 1)
    zombieArena:debug(player:getName() .. " was added to event.")
    print(Game.getStorageValue(zombieArena.storages.playersOnEvent))
end

-- Removes player from the event
function zombieArena:removePlayer(player)
    player:setStorageValue(zombieArena.storages.playerOnEvent, 0)
    Game.setStorageValue(zombieArena.storages.playersOnEvent, zombieArena:getPlayersLeft() - 1)
    zombieArena:debug(player:getName() .. " was removed from event.")
    local center = zombieArena.positions.arena[1].center
    local radius = zombieArena.positions.arena[1].radius
    players = zombieArena:checkArena()
    
    if zombieArena:getPlayersLeft() == 1 then
        for i = 1, #players do
            local player = Player(players[i])
            zombieArena:reward(player)
        end

        -- Ends the event
        zombieArena:finish(true)
        return true
    end
end

-- Gets all players on event
function zombieArena:getPlayersLeft()
    return Game.getStorageValue(zombieArena.storages.playersOnEvent)
end


-- Message a group of people
function zombieArena:messageGroup(players, message)
    for i = 1, #players do
        local player = Player(players[i])
        player:sendTextMessage(MESSAGE_STATUS_WARNING, message)
    end
end

-- Spawns a monster randomly within the radius provided in positions
function zombieArena:createMonster(i)

    -- Purposely written this way instead of using the table directly,
    -- since tables are pass by reference.
    local radius = zombieArena.positions.arena[1].radius
    local x = zombieArena.positions.arena[1].center.x
    local y = zombieArena.positions.arena[1].center.y
    local z = zombieArena.positions.arena[1].center.z
    x = math.random(x - radius, x + radius)
    y = math.random(y - radius, y + radius)
 
    local function create()
        -- Create monster
        if zombieArena:isStarted() then
            if Game.createMonster(zombieArena.config.monster, Position(x, y, z)) then
                Position(x, y, z):sendMagicEffect(CONST_ME_POFF)
                local message = string.format("%s created at position {x = %d, y = %d, z = %d}", zombieArena.config.monster, x, y, z)
                zombieArena:debug(message)
                return true
            end
        end
    end

    if addEvent(create, i * zombieArena.config.secondsBetweenZombies * 1000) then
        return true
    end
 
    -- Something went wrong
    local message = string.format("Unexpected error: couldn't create %s at position {x = %d, y = %d, z = %d}", monster, x, y, z)
    zombieArena:debug(message)
    return false
end

-- Summon x monsters provided in config
function zombieArena:summonMonsters()
    for i = 1, zombieArena.config.monsters do
            zombieArena:createMonster(i)
    end
    local message = string.format("%d monsters will be summoned.", zombieArena.config.monsters)
    zombieArena:debug(message)
end

-- Gets how many monsters there left in arena
function zombieArena:getMonstersLeft()
    return Game.getStorageValue(zombieArena.storages.monstersLeft)
end

function zombieArena:finish(playersWon)

    if playersWon then
        Game.broadcastMessage(zombieArena.messages.eventFinished, MESSAGE_STATUS_WARNING)
        zombieArena:debug(zombieArena.messages.eventFinished)
    else
        Game.broadcastMessage(zombieArena.messages.eventFailed, MESSAGE_STATUS_WARNING)
    zombieArena:debug(zombieArena.messages.eventFailed)
    end

    Game.setStorageValue(zombieArena.storages.eventStarted, 0)
    Game.setStorageValue(zombieArena.storages.eventFinished, 1)
end

-- Give the players who survived the event a reward
-- and teleport to hometown
function zombieArena:reward(player)
    for i = 1, #zombieArena.rewards do
        player:addItem(zombieArena.rewards[i].itemid, zombieArena.rewards[i].count)

        local message = string.format("You received a %s.", zombieArena.rewards[i].name)
        player:sendTextMessage(MESSAGE_STATUS_WARNING, message)
        zombieArena:debug(player:getName() .. " received a " .. zombieArena.rewards[i].name)

    end
    player:teleportTo(player:getTown():getTemplePosition())
    zombieArena:debug(player:getName() .. " got teleported to " .. player:getTown():getName() .. ".")

    zombieArena:removePlayer(player)
    return true
end

-- Checks if event is finished
-- returns either true or false
function zombieArena:isFinished()
    if Game.getStorageValue(zombieArena.storages.eventFinished) == 1 then
        return true
    end
    return false
end

-- Checks if event has started
-- returns either true or false
function zombieArena:isStarted()
    if Game.getStorageValue(zombieArena.storages.eventStarted) == 1 then
        return true
    end
    return false
end

-- Checks if event is opened
-- returns either true or false
function zombieArena:isOpened()
    if Game.getStorageValue(zombieArena.storages.eventOpened) == 1 then
        return true
    end
    return false
end


-- Check if player is doing event
-- returns either true or false
function zombieArena:isPlayerOnEvent(player)
    if player:getStorageValue(zombieArena.storages.playerOnEvent) == 1 then
        return true
    end
    return false
end


-- Toggle debug on/off on top off this file
function zombieArena:debug(message)
    if debug then
        message = "[ZOMBIEARENA] " .. message
        print(message)
    end
end
How do I solve this and thank you for all the fixes you've made
This event has more than one problem, and you simplified it ♥♥♥
 
Top