EDIT FOR BETTER EXPLANATION
up i have modified the script and few things into my server now i have to errors in console the event start, i can enter to the teleport goes to the waiting room to be sent to the zombie arena, zombies are summoned, but when players get attacked they don't get kicked out of the event
i have enabled in events.xml
Lua:
<event class="Creature" method="onTargetCombat" enabled="1" />
my file data/events/scripts/creature.lua looks like this
Code:
function Creature:onChangeOutfit(outfit)
local onChangeMount = EventCallback.onChangeMount
if onChangeMount then
if not onChangeMount(self, outfit.lookMount) then
return false
end
end
local onChangeOutfit = EventCallback.onChangeOutfit
if onChangeOutfit then
return onChangeOutfit(self, outfit)
end
return true
end
function Creature:onAreaCombat(tile, isAggressive)
local onAreaCombat = EventCallback.onAreaCombat
if onAreaCombat then
return onAreaCombat(self, tile, isAggressive)
end
return RETURNVALUE_NOERROR
end
function Creature:onTargetCombat(target)
local onTargetCombat = EventCallback.onTargetCombat
if onTargetCombat then
return onTargetCombat(self, target)
end
return RETURNVALUE_NOERROR
end
my data/scripts/lib/event_callbacks.lua file looks like this
Code:
local unpack = unpack
local pack = table.pack
local EventCallbackData, callbacks, updateableParameters, autoID = {}, {}, {}, 0
-- This metatable creates an auto-configuration mechanism to create new types of EventCallbacks
local ec = setmetatable({}, { __newindex = function(self, key, value)
autoID = autoID + 1
callbacks[key] = autoID
local info, update = {}, {}
for k, v in pairs(value) do
if type(k) == "string" then
info[k] = v
else
update[k] = v
end
end
updateableParameters[autoID] = update
callbacks[autoID] = info
EventCallbackData[autoID] = {maxn = 0}
EVENT_CALLBACK_LAST = autoID
end})
--@ Definitions of valid EventCallback types to hook according to the given field name
--@ The fields within the assigned table, allow to save arbitrary information
-- Creature
ec.onChangeOutfit = {}
ec.onChangeMount = {}
ec.onAreaCombat = {returnValue=true}
ec.onTargetCombat = {returnValue=true}
ec.onHear = {}
ec.onChangeZone = {}
-- Party
ec.onJoin = {}
ec.onLeave = {}
ec.onDisband = {}
ec.onShareExperience = {}
ec.onInvite = {}
ec.onRevokeInvitation = {}
ec.onPassLeadership = {}
-- Player
ec.onBrowseField = {}
ec.onLook = {[5] = 1}
ec.onLookInBattleList = {[4] = 1}
ec.onLookInTrade = {[5] = 1}
ec.onLookInShop = {[4] = 1}
ec.onLookInMarket = {}
ec.onTradeRequest = {}
ec.onTradeAccept = {}
ec.onTradeCompleted = {}
ec.onMoveItem = {returnValue=true}
ec.onItemMoved = {}
ec.onMoveCreature = {}
ec.onReportRuleViolation = {}
ec.onReportBug = {}
ec.onTurn = {}
ec.onRotateItem = {}
ec.onGainExperience = {[3] = 1}
ec.onLoseExperience = {[2] = 1}
ec.onGainSkillTries = {[3] = 1}
ec.onWrapItem = {}
ec.onInventoryUpdate = {}
ec.onUpdateStorage = {}
-- Monster
ec.onDropLoot = {}
ec.onSpawn = {}
EventCallback = {
register = function (self, index)
if isScriptsInterface() then
local type, call = rawget(self, "type"), rawget(self, "call")
if type and call then
EventCallbackData[type][#EventCallbackData[type] + 1] = {call, tonumber(index) or 0}
table.sort(EventCallbackData[type], function (a, b) return a[2] < b[2] end)
return rawset(self, "type", nil) and rawset(self, "call", nil)
end
debugPrint("[Warning - EventCallback::register] is need to set up a callback before register.")
end
end,
clear = function (self)
EventCallbackData = {}
for i = 1, EVENT_CALLBACK_LAST do
EventCallbackData[i] = {}
end
end
}
setmetatable(EventCallback, {
__index = function (self) return self end,
__newindex = function (self, k, v)
if isScriptsInterface() then
local ecType = callbacks[k]
if ecType then
if type(v) == "function" then
return rawset(self, "type", ecType) and rawset(self, "call", v)
end
debugPrint(string.format("[Warning - EventCallback::%s] a function is expected.", k))
else
debugPrint(string.format("[Warning - EventCallback::%s] is not a valid callback.", k))
end
end
end,
__call = function (self, type, ...)
local eventTable, ret = EventCallbackData[type]
local args, events = table.pack(...), #eventTable
for k, ev in pairs(eventTable) do
ret = {ev[1](unpack(args))}
if k == events or (ret[1] ~= nil and (ret[1] == false or table.contains({EVENT_CALLBACK_ONAREACOMBAT, EVENT_CALLBACK_ONTARGETCOMBAT}, type) and ret[1] ~= RETURNVALUE_NOERROR)) then
return unpack(ret)
end
for k, v in pairs(auxargs[type] or {}) do args[k] = ret[v] end
end
end
})
-- can't be overwritten on reloads
EventCallback:clear()
the zombie.lua file looks like this
Code:
local function secondsToReadable(s)
local hours = math.floor(s / 3600)
local minutes = math.floor(math.fmod(s, 3600)/60)
local seconds = math.floor(math.fmod(s, 60))
return (hours > 0 and (hours .. ' hour' .. (hours > 1 and 's ' or ' ')) or '') ..
(minutes > 0 and (minutes .. ' minute' .. (minutes > 1 and 's ' or ' ')) or '') ..
(seconds > 0 and (seconds .. ' second' .. (seconds > 1 and 's ' or ' ')) or '')
end
local zombie = {}
-- keeps track of players & zombies
zombie.players = {}
zombie.zombies = {}
--#
zombie.config = {
startTime = '19:13:30', -- Hours:minutes:seconds
-- How many players needed to start the event.
minimumPlayers = 2,
-- How many players can enter at most.
maximumPlayers = 10,
-- %chance of a player dying from zombie attack
playerDeathChance = 20, -- %
-- How many zombies should spawn in the beginning?
zombieStartAmount = 2,
-- Name of the monster to be spawned
zombieName = 'zombski',
-- This is used to check if zombie event has started.
storageEventStarted = 191817,
-- Position for the teleport which is going..
-- ..to send players to the waiting room.
teleportSpawnPosition = Position(32340, 32218, 7),
waitingRoom = {
topLeft = Position(32231, 32182, 7),
bottomRight = Position(32243, 32191, 7)
},
-- How long players will wait in the waiting room.
waitingTime = 10, -- 10 seconds
teleportId = 1387, -- ID of teleport item
teleportActionId = 56783, -- action ID used on the teleport for detecting players
-- Zombie arena; Where players will try to survive
arena = {
topLeft = Position(32216, 32203, 8),
bottomRight = Position(32264, 32234, 8)
},
-- set to `true` if you want the rewards..
-- ..to be given randomly instead of all at once.
randomReward = false,
rewardBagId = 1987,
rewards = {
{2160, 1}, -- Crystal Coin
{2159, 2}--, -- Scarab Coin
-- {9020, 5} -- Vampire Token
}
}
--#
zombie.initEvent = function(self)
local teleportItem = Game.createItem(self.config.teleportId, 1, self.config.teleportSpawnPosition)
teleportItem:setActionId(self.config.teleportActionId)
Teleport(teleportItem.uid):setDestination(Position(
math.random(self.config.waitingRoom.topLeft.x, self.config.waitingRoom.bottomRight.x),
math.random(self.config.waitingRoom.topLeft.y, self.config.waitingRoom.bottomRight.y),
self.config.waitingRoom.topLeft.z
))
Game.broadcastMessage('Zombie event will begin in '.. secondsToReadable(self.config.waitingTime) ..', Hurry up!')
addEvent(function(z)
local tpTile = Tile(z.config.teleportSpawnPosition)
local tpItem = tpTile:getItemById(z.config.teleportId)
if tpItem then
tpItem:remove()
end
if z:countPlayers() < z.config.minimumPlayers then
Game.broadcastMessage('Zombie event shutting down... not enough players.', MESSAGE_STATUS_CONSOLE_RED)
z:kickPlayers()
return
end
z:startEvent()
end, self.config.waitingTime * 1000, self)
end
--#
zombie.startEvent = function(self)
Game.setStorageValue(self.config.storageEventStarted, 1)
Game.broadcastMessage('Zombie event has begun, Good luck!')
for _, player in pairs(self.players) do
if player then
player:teleportTo(Position(
math.random(self.config.arena.topLeft.x, self.config.arena.bottomRight.x),
math.random(self.config.arena.topLeft.y, self.config.arena.bottomRight.y),
self.config.arena.topLeft.z
))
end
end
for i = self.config.zombieStartAmount, 1, -1 do
self:spawnZombie(Position(
math.random(self.config.arena.topLeft.x, self.config.arena.bottomRight.x),
math.random(self.config.arena.topLeft.y, self.config.arena.bottomRight.y),
self.config.arena.topLeft.z
))
end
end
--#
zombie.stopEvent = function(self)
Game.setStorageValue(self.config.storageEventStarted, -1)
local winner = self:getWinner()
if not winner then return end
local depot = winner:getDepotChest(winner:getTown():getId(), true)
local bag = Game.createItem(self.config.rewardBagId, 1)
local itemId = nil
local itemCount = nil
if self.config.randomReward then
local randomRewardItem = self.config.rewards[math.random(1, #self.config.rewards)]
itemId = randomRewardItem[1]
itemCount = randomRewardItem[2]
bag:addItemEx(Game.createItem(itemId, itemCount), INDEX_WHEREEVER, FLAG_NOLIMIT)
depot:addItemEx(bag)
winner:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[Zombie] You have received a reward item. Check your depot.')
return
end
for _, reward in pairs(self.config.rewards) do
itemId = reward[1]
itemCount = reward[2]
bag:addItemEx(Game.createItem(itemId, itemCount), INDEX_WHEREEVER, FLAG_NOLIMIT)
end
depot:addItemEx(bag)
winner:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, '[Zombie] You have received reward items. Check your depot.')
Game.broadcastMessage(winner:getName() .. ' has won zombie event.')
zombie:kickPlayers()
zombie:clearZombies()
end
--#
zombie.addPlayer = function(self, p)
self.players[p:getId()] = p
end
--#
zombie.removePlayer = function(self, player)
self.players[player:getId()] = nil
player:teleportTo(player:getTown():getTemplePosition())
player:addHealth(player:getMaxHealth())
if self:countPlayers() == 1 then
self:stopEvent()
end
end
--#
zombie.countPlayers = function(self)
local n = 0
for _, player in pairs(self.players) do
if player then n = n + 1 end
end
return n
end
--#
zombie.kickPlayers = function(self)
for _, player in pairs(self.players) do
if player then
self:removePlayer(player)
end
end
self.players = {}
end
--#
zombie.getWinner = function(self)
for _, player in pairs(self.players) do
if player then
return player
end
end
return nil
end
--#
zombie.clearZombies = function(self)
for _, zombski in pairs(self.zombies) do
if zombski then
zombski:remove()
end
end
end
--#
zombie.spawnZombie = function(self, position)
local zombie = Game.createMonster(self.config.zombieName, position, false, true)
self.zombies[zombie:getId()] = zombie
position:sendMagicEffect(CONST_ME_MAGIC_RED)
end
--#
local ge = GlobalEvent('zombieStart')
function ge.onTime(interval)
local eventStorage = Game.getStorageValue(zombie.config.storageEventStarted)
local hasStarted = (eventStorage and (eventStorage == 1)) or false
if hasStarted then
print('[Error - ZombieEvent:onTime] The event has already started.')
return true
end
local tile = Tile(zombie.config.teleportSpawnPosition)
if not tile then
print('[Error - ZombieEvent:onTime] Could not create teleport, tile not found!')
return true
end
zombie:initEvent()
return true
end
ge:time(zombie.config.startTime)
ge:register()
--#
local enterZombie = MoveEvent('enterZombie')
function enterZombie.onStepIn(player, item, position, fromPosition)
if not item:getId() == zombie.config.teleportId then
return true
end
zombie:addPlayer(player)
Game.broadcastMessage(player:getName() .. ' has entered zombie event.', MESSAGE_STATUS_CONSOLE_RED)
if zombie:countPlayers() >= zombie.config.maximumPlayers then
Game.broadcastMessage('Zombie event will begin in a moment... Get ready!')
addEvent(function() zombie:startEvent() end, 3 * 1000)
end
return true
end
enterZombie:aid(zombie.config.teleportActionId)
enterZombie:register()
--#
local eventCallback = EventCallback
function eventCallback.onTargetCombat(creature, target)
if not creature or not target then
return RETURNVALUE_NOERROR
end
if (not creature:isMonster())
or (creature:getName():lower() ~= zombie.config.zombieName:lower())
or (not target:isPlayer()) then
return RETURNVALUE_NOERROR
end
local deathChance = zombie.config.playerDeathChance
math.randomseed(os.time())
if math.random(1, 100) <= deathChance then
local targetPos = target:getPosition()
targetPos:sendMagicEffect(CONST_ME_MORTAREA)
targetPos:sendMagicEffect(CONST_ME_BIGPLANTS)
target:sendTextMessage(MESSAGE_EVENT_ADVANCE, 'You have been killed by a zombie.')
zombie:spawnZombie(targetPos)
zombie:removePlayer(target)
return RETURNVALUE_NOERROR
end
target:say('!survived!', TALKTYPE_MONSTER_SAY)
target:getPosition():sendMagicEffect(CONST_ME_HOLYAREA)
return RETURNVALUE_NOERROR
end
eventCallback:register(1)
and zombski.lua like this:
local mType = Game.createMonsterType("Zombski")
local monster = {}
monster.description = "a zombski"
monster.experience = 1
monster.outfit = {
lookType = 311
}
monster.health = 100
monster.maxHealth = monster.health
monster.race = "undead"
monster.corpse = 9875
monster.speed = 200
monster.maxSummons = 0
monster.changeTarget = {
interval = 1000,
chance = 40
}
monster.flags = {
hostile = true,
summonable = false,
attackable = false,
convinceable = false,
illusionable = false,
canPushItems = true,
canPushCreatures = false,
targetDistance = 1,
staticAttackChance = 100
}
monster.voices = {
interval = 5000,
chance = 10,
{text = "KHGKHGKH", yell = false},
{text = "KHAAAA", yell = false}
}
monster.attacks = {
{name = "melee", attack = 1, skill = 1, effect = CONST_ME_DRAWBLOOD, interval = 1500}
}
monster.defenses = {
defense = 55,
armor = 55,
-- {name = "combat", type = COMBAT_HEALING, chance = 15, interval = 2*1000, minDamage = 180, maxDamage = 250, effect = CONST_ME_MAGIC_BLUE},
-- {name = "speed", chance = 15, interval = 2*1000, speed = 320, effect = CONST_ME_MAGIC_RED}
}
monster.elements = {
{type = COMBAT_PHYSICALDAMAGE, percent = 100},
{type = COMBAT_DEATHDAMAGE, percent = 100},
{type = COMBAT_ENERGYDAMAGE, percent = 100},
{type = COMBAT_EARTHDAMAGE, percent = 100},
{type = COMBAT_ICEDAMAGE, percent = 100},
{type = COMBAT_HOLYDAMAGE, percent = 100},
{type = COMBAT_POISONDAMAGE, percent = 100},
{type = COMBAT_FIREDAMAGE, percent = 100},
{type = COMBAT_DROWNDAMAGE, percent = 100},
{type = COMBAT_LIFEDRAIN, percent = 100}
}
monster.immunities = {
{type = "fire", combat = true, condition = true},
{type = "drown", condition = true},
{type = "lifedrain", combat = true},
{type = "paralyze", condition = true},
{type = "invisible", condition = true}
}
mType:register(monster)
as i said when player get attacked my zombie nothing happens players does not get kicked out of the event