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:
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:
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:
Thank you!
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!