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

TFS 1.X+ Event erro

jel

Member
Joined
Mar 22, 2014
Messages
209
Reaction score
8
--------------------------------------------------------------------------------
---------------------------------- # CONFIG # ----------------------------------
--------------------------------------------------------------------------------
local WaveEvent = {
MAX_WAVES = 3,
----------------------------
STATE_CLOSED = -1,
STATE_STARTED = 1,
STATE_WAITING = 2,
----------------------------
STATE_STORAGE = 101192,
WAVE_ROUND_STORAGE = 101193,
PLAYERS_JOINED = 101194,
DMG_OVERFLOW = 101195,
REWARD_CHEST_USED = 101196,
REWARD_DIFFICULTY = 101197,
-----------------------------
WAITING_TIME = 1 * 10 * 1000,
MIN_REQ_PLAYERS = 1,
----------------------------
NEXT_WAVE_DELAY = 10 * 1000,
BOSS_SPAWN_DELAY = 5 * 1000,
BOSS_SPAWN_TRIES = 5,
----------------------------
FINAL_BOSS = 'Zugurosh',
mobsPerPlayer = 2,
----------------------------
EXP_REWARD_FACTOR = 1.05, -- 5%
REWARD_CHEST_AID = 10129,
REWARDS = {
[1] = { -- easy
-- {itemid, count, chance}
{2160, 10, 100},
{2159, 5, 5}
},
[2] = { -- medium
{2392, 1, 25},
{2645, 1, 32}
},
[3] = { -- hard
{2520, 1, 100},
{2470, 1, 100}
}
},
MONSTERS = {
HP_INCREMENT = 1.05, -- +5%
DMG_INCREMENT = 1.05, -- +5%
INITIAL_COUNT = 3,
monsterList = {
'armenius','barbaria','thalas'
--'orc warrior'
-- 'rat','snake','orc','rotworm','troll','slime','skeleton','orc warrior','wyvern',
-- 'carrion worm','cyclops','cyclops drone','orc shaman','orc spearman','vampire',
-- 'orc warlord','orc berserker','dragon','fire elemental','energy elemental','wyrm',
-- 'cyclops smith','plaguesmith'
}
},
Arena = {
TOP_LEFT = Position(47, 399, 7),
BOTTOM_RIGHT = Position(61, 409, 7),
monsters = {} -- leave this empty
},
WaitingRoom = {
TOP_LEFT = Position(52, 395, 7),
BOTTOM_RIGHT = Position(55, 397, 7)
},
RewardRoom = Position(58, 397, 7)
}
local function countMonstersInEvent()
local counter = 0
for cid, monster in pairs(WaveEvent.Arena.monsters) do
if monster then
counter = counter + 1
end
end
return counter
end
local function getRandomPosition(conf)
return Position(
math.random(conf.TOP_LEFT.x, conf.BOTTOM_RIGHT.x),
math.random(conf.TOP_LEFT.y, conf.BOTTOM_RIGHT.y),
conf.TOP_LEFT.z
)
end
local function secondsToReadable(s)
local minutes = math.floor(math.mod(s, 3600)/60)
local seconds = math.floor(math.mod(s, 60))
return (minutes > 0 and (minutes .. ' minutes ') or '') ..
(seconds > 0 and (seconds .. ' seconds ') or '')
end
local function ordinal_number(n)
-- How to to add "th" or "rd" to the date (https://stackoverflow.com/a/20726654)
last_digit = n % 10
if last_digit == 1 and n ~= 11
then return 'st'
elseif last_digit == 2 and n ~= 12
then return 'nd'
elseif last_digit == 3 and n ~= 13
then return 'rd'
else
return 'th'
end
end
--------------------------------------------------------------------------------
-------------------------------- # TALKACTION # --------------------------------
--------------------------------------------------------------------------------
local ta = TalkAction('!joinwave')
function ta.onSay(player, words, param)
local waveEventState = Game.getStorageValue(WaveEvent.STATE_STORAGE)
if not waveEventState or waveEventState == WaveEvent.STATE_CLOSED then
player:sendTextMessage(MESSAGE_STATUS_SMALL, 'The event hasn\'t started.')
return false
end
if waveEventState == WaveEvent.STATE_STARTED then
player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You are late. Catch the train next time.')
return false
end
if player:getZone() ~= ZONE_PROTECTION then
player:sendTextMessage(MESSAGE_STATUS_SMALL, 'Go to a safe zone first.')
return false
end
player:setStorageValue(WaveEvent.REWARD_CHEST_USED, 0)
player:teleportTo(getRandomPosition(WaveEvent.WaitingRoom))
local playersJoined = (Game.getStorageValue(WaveEvent.PLAYERS_JOINED) or 0) + 1
Game.broadcastMessage(
player:getName() .. ' has joined the wave event. ('.. playersJoined ..'/'.. WaveEvent.MIN_REQ_PLAYERS ..')',
MESSAGE_STATUS_CONSOLE_BLUE
)
Game.setStorageValue(WaveEvent.PLAYERS_JOINED, playersJoined)
return false
end
ta:separator(' ')
ta:register()
--------------------------------------------------------------------------------
-------------------------------- # GLOBALEVENT # -------------------------------
--------------------------------------------------------------------------------
local function closeEvent()
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, 0)
Game.setStorageValue(WaveEvent.PLAYERS_JOINED, 0)
for cid, creature in pairs(WaveEvent.Arena.monsters) do
creature:remove()
end
WaveEvent.Arena.monsters = {}
end
local function isInEvent(player)
local playerPos = player:getPosition()
if (playerPos.x >= WaveEvent.Arena.TOP_LEFT.x and playerPos.x <= WaveEvent.Arena.BOTTOM_RIGHT.x)
and (playerPos.y >= WaveEvent.Arena.TOP_LEFT.y and playerPos.y <= WaveEvent.Arena.BOTTOM_RIGHT.y) then
return true
end
return false
end
local function getPlayersInEvent()
local onlinePlayers = Game.getPlayers()
local playersInEvent = {}
for i, player in pairs(onlinePlayers) do
if isInEvent(player) then
table.insert(playersInEvent, i, player)
end
end
return playersInEvent
end
local function spawnBoss(effect_rounds)
if not effect_rounds then
addEvent(spawnBoss, 1000, WaveEvent.BOSS_SPAWN_TRIES)
return
end
local pos = getRandomPosition(WaveEvent.Arena)
if effect_rounds == 0 then
local m = Game.createMonster(WaveEvent.FINAL_BOSS, getRandomPosition(WaveEvent.Arena), false, true)
m:say('GROOAAAAAR! <dramatic msg here>', TALKTYPE_MONSTER_SAY)
pos:sendMagicEffect(CONST_ME_TELEPORT)
return
end
pos:sendMagicEffect(CONST_ME_TELEPORT)
pos:sendMagicEffect(CONST_ME_POFF)
addEvent(spawnBoss, 1000, effect_rounds - 1)
end
local function handleMonsterCreation(m, wave_n, playerAmount)
local mType = MonsterType(m)
if not mType then
return print('[Warning - WaveEvent::spawnMonsters] Unknown monster type ' .. m)
end
local mPos = getRandomPosition(WaveEvent.Arena)
local monster = Game.createMonster(m, mPos, false, true)
if not monster then
return print('[Warning - WaveEvent::spawnMonsters] Could not create monster ' .. m)
end
monster:setMaxHealth(math.floor((monster:getMaxHealth() * (playerAmount + 1) * WaveEvent.MONSTERS.HP_INCREMENT) / 2))
monster:setHealth(monster:getMaxHealth())
mPos:sendMagicEffect(CONST_ME_TELEPORT)
WaveEvent.Arena.monsters[monster:getId()] = monster
end
local function initWave(wave_n, playerAmount)
if wave_n > WaveEvent.MAX_WAVES then
local mType = MonsterType(WaveEvent.FINAL_BOSS)
if not mType then
print('[Error - WaveEvent::initWave] Could not create final boss. Unknown monster type ('.. WaveEvent.FINAL_BOSS ..')')
-- kick players
return
end
spawnBoss()
return
end
local monsterCount = (wave_n * 2) + WaveEvent.MONSTERS.INITIAL_COUNT
for i = 1, monsterCount do
local m = WaveEvent.MONSTERS.monsterList[math.random(1, #WaveEvent.MONSTERS.monsterList)]
handleMonsterCreation(m, wave_n, playerAmount)
end
end
local function teleportPlayersToArena()
local playersFound = 0
local z = WaveEvent.WaitingRoom.TOP_LEFT.z
for x = WaveEvent.WaitingRoom.TOP_LEFT.x, WaveEvent.WaitingRoom.BOTTOM_RIGHT.x do
for y = WaveEvent.WaitingRoom.TOP_LEFT.y, WaveEvent.WaitingRoom.BOTTOM_RIGHT.y do
local tile = Tile(x, y, z)
local tileCreatures = tile:getCreatures()
if tileCreatures then
for _, creature in pairs(tileCreatures) do
creature:teleportTo(getRandomPosition(WaveEvent.Arena))
playersFound = playersFound + 1
end
end
end
end
if playersFound == 0 then
Game.broadcastMessage('[WaveEvent] Nobody joined the wave event. Closing.', MESSAGE_STATUS_CONSOLE_BLUE)
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
return
end
if playersFound < WaveEvent.MIN_REQ_PLAYERS then
Game.broadcastMessage('[WaveEvent] Not enough players. Closing.', MESSAGE_STATUS_CONSOLE_BLUE)
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
return
end
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_STARTED)
Game.broadcastMessage(
'[WaveEvent] Starting with ' .. playersFound .. ' player'
.. (playersFound > 1 and 's' or '')
.. '. Good luck!',
MESSAGE_STATUS_CONSOLE_BLUE
)
Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, 1)
initWave(1, playersFound)
end
local ge = GlobalEvent('WaveEvent')
function ge.onTime(interval)
local eventState = Game.getStorageValue(WaveEvent.STATE_STORAGE)
if eventState == WaveEvent.STATE_STARTED
or eventState == WaveEvent.STATE_WAITING then
print('[Error - WaveEvent::eek:nTime] Event state not closed. StorageKey -> '.. WaveEvent.STATE_STORAGE)
return true
end
Game.broadcastMessage(
'WaveEvent has started. You have '
.. secondsToReadable(WaveEvent.WAITING_TIME / 1000)
.. ' to join. !joinwave',
MESSAGE_STATUS_CONSOLE_BLUE
)
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_WAITING)
addEvent(teleportPlayersToArena, WaveEvent.WAITING_TIME)
end
ge:time('03:49:30')
ge:register()
--------------------------------------------------------------------------------
-------------------------------- # CREATURESCRIPT # ----------------------------
--------------------------------------------------------------------------------
local cs = CreatureEvent('WaveEventPrepareDeath')
function cs.onPrepareDeath(player, killer)
if Game.getStorageValue(WaveEvent.STATE_STORAGE) == WaveEvent.STATE_CLOSED then
return true
end
if isInEvent(player) then
player:teleportTo(player:getTown():getTemplePosition())
player:setHealth(player:getMaxHealth())
player:setMana(player:getMaxMana())
Game.broadcastMessage('[WaveEvent] ' .. player:getName() .. ' was killed by a monster.')
end
local isEventClosed = Game.getStorageValue(WaveEvent.STATE_STORAGE) ~= WaveEvent.STATE_CLOSED
if #getPlayersInEvent() == 0 and not isEventClosed then
Game.broadcastMessage('[WaveEvent] Nobody has completed the wave event. Closing ...')
closeEvent()
end
return true
end
cs:register()
local csx = CreatureEvent('WaveEventMonsterDeath')
function csx.onKill(player, target)
if Game.getStorageValue(WaveEvent.STATE_STORAGE) == WaveEvent.STATE_CLOSED
or not isInEvent(player)
or target:getMaster() then
return true
end
if target:getName():lower() == WaveEvent.FINAL_BOSS:lower() then
Game.broadcastMessage('[WaveEvent] The final boss has been killed. Congratulations!')
Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
local pie = getPlayersInEvent()
-- What was the difficulty ?
local joined = Game.getStorageValue(WaveEvent.PLAYERS_JOINED)
local diff = math.abs(#pie - joined)
if diff <= math.floor(joined * 0.33) then diff = 1
elseif diff <= math.floor(joined * 0.66) then diff = 2
else diff = 3 end
Game.setStorageValue(WaveEvent.REWARD_DIFFICULTY, diff)
for _, p in pairs(pie) do
p:teleportTo(WaveEvent.RewardRoom)
end
closeEvent()
return true
end
WaveEvent.Arena.monsters[target:getId()] = nil
if countMonstersInEvent() > 0 then
return true
end
local n = Game.getStorageValue(WaveEvent.WAVE_ROUND_STORAGE) or 1
local bcMsg = ordinal_number(n) ..' wave has been cleared.'
if n < WaveEvent.MAX_WAVES then
bcMsg = bcMsg .. ' Prepare for the next wave. ('.. secondsToReadable(WaveEvent.NEXT_WAVE_DELAY / 1000).. ')'
else
bcMsg = bcMsg .. ' Prepare for the final boss!'
end
local playersInEvent = getPlayersInEvent()
for _, player in pairs(playersInEvent) do
player:say('+EXP', TALKTYPE_MONSTER_SAY)
player:addExperience(4200 * player:getLevel() * WaveEvent.EXP_REWARD_FACTOR) -- meh
end
Game.broadcastMessage(bcMsg)
Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, n + 1)
addEvent(initWave, WaveEvent.NEXT_WAVE_DELAY, n + 1, #playersInEvent)
return true
end
csx:register()
local csy = CreatureEvent('WaveEventPHC')
function csy.onHealthChange(player, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
if (primaryType == COMBAT_HEALING)
or (not isInEvent(player))
or (player:getStorageValue(WaveEvent.DMG_OVERFLOW) == 1) then
player:setStorageValue(WaveEvent.DMG_OVERFLOW, -1)
return primaryDamage, primaryType, secondaryDamage, secondaryType
end
return primaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
primaryType,
secondaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
secondaryType
end
csy:register()
local csz = CreatureEvent('WaveEventPMC')
function csz.onManaChange(player, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
if (primaryType == COMBAT_HEALING) or (not isInEvent(player)) then
return primaryDamage, primaryType, secondaryDamage, secondaryType
end
local dmgTotal = primaryDamage + secondaryDamage
if dmgTotal > player:getMana() then
player:setStorageValue(WaveEvent.DMG_OVERFLOW, 1)
end
return primaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
primaryType,
secondaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
secondaryType
end
csz:register()
--------------------------------------------------------------------------------
------------------------------------ # ACTION # --------------------------------
--------------------------------------------------------------------------------
local action = Action()
function action.onUse(player, item, fromPosition, itemEx, toPosition, isHotkey)
local hasUsed = player:getStorageValue(WaveEvent.REWARD_CHEST_USED)
if hasUsed == 1 then
player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You have already obtained the reward.')
player:getPosition():sendMagicEffect(CONST_ME_POFF)
return true
end
local diff = Game.getStorageValue(WaveEvent.REWARD_DIFFICULTY)
local rewards = WaveEvent.REWARDS[diff]
local items = ''
for _, rewardItem in pairs(rewards) do
local chance = rewardItem[3]
if math.random(1, 100) <= chance then
items = items .. (#items > 0 and ', ' or '')
local itemId = rewardItem[1]
local count = rewardItem[2]
local itemX = Game.createItem(itemId, count)
local depot = player:getDepotChest(player:getTown():getId(), true)
depot:addItemEx(itemX, INDEX_WHEREEVER, FLAG_NOLIMIT)
items = items .. '('.. count ..'x ' .. itemX:getName() .. (count > 1 and 's' or '') .. ')'
end
end
items = items .. '.'
player:setStorageValue(WaveEvent.REWARD_CHEST_USED, 1)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, '[WaveEvent] You have received ' .. items)
player:teleportTo(player:getTown():getTemplePosition())
return true
end
action:aid(WaveEvent.REWARD_CHEST_AID)
action:register()

[2021-08-06 17:09:00.437] [error] Lua script error: /home/servidor/data/scripts/custom/monsterwavelib.lua:callback
[2021-08-06 17:09:00.438] [error] /home/servidor/data/scripts/custom/monsterwavelib.lua:86: attempt to call field 'mod' (a nil value)
stack traceback:
[C]: in function 'mod'
/home/servidor/data/scripts/custom/monsterwavelib.lua:86: in function 'secondsToReadable'
/home/servidor/data/scripts/custom/monsterwavelib.lua:258: in function </home/servidor/data/scripts/custom/monsterwavelib.lua:249>

hello, I have this error in this function what can it be?
 

Loney

🇲🇽
Senator
Premium User
Joined
Jul 23, 2012
Messages
1,994
Solutions
23
Reaction score
203
Location
MX
Replace:
Lua:
local minutes = math.floor(math.mod(s, 3600)/60)
local seconds = math.floor(math.mod(s, 60))
with:
Lua:
local minutes = math.floor(math.fmod(s, 3600)/60)
local seconds = math.floor(math.fmod(s, 60))
 
Top