johnsamir
Advanced OT User
As title says player don't get attacked or kicked out after the zombie has aproached the player
get thsi error in the console:
this is the script
this is my data/events/scripts/creature.lua ontargetcombat code
this is the line 50
this is my eventscallback
get thsi error in the console:
LUA:
Lua Script Error: [Event Interface]
data/events/scripts/creature.lua:Creature@onTargetCombat
data/events/scripts/creature.lua:50: attempt to call global 'hasEventCallback' (a nil value)
stack traceback:
data/events/scripts/creature.lua:50: in function <data/events/scripts/creature.lua:40>
this is the script
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 = {
time = '23:08:00', -- Hours:minutes:seconds
days = { -- set to "false" to disable specific days
["monday"] = true,
["tuesday"] = true,
["wednesday"] = true,
["thursday"] = true,
["friday"] = true,
["saturday"] = true,
["sunday"] = true,
},
},
-- 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({x = 1000, y = 1000, z = 7})
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 currentDay = os.date("%A"):lower()
if not zombie.config.startTime.days[currentDay] then
return true
end
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.time)
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)
this is my data/events/scripts/creature.lua ontargetcombat code
Code:
function Creature:onTargetCombat(target)
local player = Player(self)
if player and target and CTF_STATUS == 1 then
if isGreenTeam(player:getName()) and isGreenTeam(target:getName()) then
return false
elseif isRedTeam(player:getName()) and isRedTeam(target:getName()) then
return false
end
end
if hasEventCallback(EVENT_CALLBACK_ONTARGETCOMBAT) then
return EventCallback(EVENT_CALLBACK_ONTARGETCOMBAT, self, target)
else
return RETURNVALUE_NOERROR
end
end
Code:
if hasEventCallback(EVENT_CALLBACK_ONTARGETCOMBAT) then
this is my eventscallback
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, triggerIndex)
if isScriptsInterface() then
local eventType = rawget(self, 'eventType')
local callback = rawget(self, 'callback')
if not eventType or not callback then
debugPrint("[Warning - EventCallback::register] need to setup a callback before you can register.")
return
end
local eventData = EventCallbackData[eventType]
eventData.maxn = #eventData + 1
eventData[eventData.maxn] = {
callback = callback,
triggerIndex = tonumber(triggerIndex) or 0
}
table.sort(eventData, function(ecl, ecr) return ecl.triggerIndex < ecr.triggerIndex end)
self.eventType = nil
self.callback = nil
end
end,
clear = function(self)
EventCallbackData = {}
for i = 1, EVENT_CALLBACK_LAST do
EventCallbackData[i] = {maxn = 0}
end
end
}
setmetatable(EventCallback, {
__newindex = function(self, key, callback)
if not isScriptsInterface() then
return
end
local eventType = callbacks[key]
if not eventType then
debugPrint(string.format("[Warning - EventCallback::%s] is not a valid callback.", key))
return
end
if type(callback) ~= "function" then
debugPrint(string.format("[Warning - EventCallback::%s] a function is expected.", key))
return
end
rawset(self, 'eventType', eventType)
rawset(self, 'callback', callback)
end,
__index = function(self, key)
local callback = callbacks[key]
if not callback then
if not isScriptsInterface() then
return
end
return rawget(self, key)
end
local eventData = EventCallbackData[callback]
local maxn = eventData.maxn
if maxn == 0 then
return
end
return function(...)
local results, args, info = {}, pack(...), callbacks[callback]
for index = 1, maxn do
repeat
results = {eventData[index].callback(unpack(args))}
local output = results[1]
-- If the call returns nil then we continue with the next call
if output == nil then
break
end
-- If the call returns false then we exit the loop
if not output then
return false
end
-- If the call of type returnvalue returns noerror then we continue the loop
if info.returnValue then
if output == RETURNVALUE_NOERROR then
break
end
return output
end
-- We left the loop why have we reached the end
if index == eventData.maxn then
return unpack(results)
end
until true
-- Update the results for the next call
for index, value in pairs(updateableParameters[callback]) do
args[index] = results[value]
end
end
end
end
})