Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Credits: Sarah Wesker
- Version: 1.1
- Compat: TFS 1.3
- Create: December 2020
- ]]--
- local config = {
- miscellaneous = {
- name = "Dream Of Gold", -- event name
- talkaction = "!dream", -- Talkaction words
- -->> These two functions are compatible with newer versions of TFS Eyes o.o <<-
- canPushPlayers = false, -- Allow players within the event to push each other?
- },
- start = {
- time = "20:02:10", -- time to start event each day
- waiting = '60s', -- wait player to enter event, examples: 10s -> 10 seconds | 2m -> 2 minutes
- ending = '2m' -- 5 minutes finish event
- },
- area = {
- fromPos = Position(3093, 1880, 7), -- Upper left corner
- toPos = Position(3125, 1906, 7), -- Lower right corner
- waitZone = Position(3078, 1904, 7) -- Waiting room
- },
- players = {
- min = 2, -- min required
- max = 10, -- max players in the evento
- storage = 7777, -- storage, to remove players from the event in case they get trapped! (it should never happen)
- speed = 250 -- speed at which players must move in the event
- },
- state = {
- type = 'stoped', -- no edit!
- debug = false -- not use in production
- },
- gold = { -- Properties in the event
- id = 2148, -- gold coin ID
- aid = 7777, -- cambia este valor si ya tienes en uso este Action ID
- chestId = 5675, -- chestId
- chestAid = 7778, -- cambia este valor si ya tienes en uso este Action ID
- chestChance = 2, -- chance for create chest on area
- chestValues = {500,800} -- chance of gain 500 to 800 gold when use the chest
- },
- rewardBag = 1992, -- Reward bag id
- rewards = { -- In this table, you can add the rewards, as are the example:
- { itemId = 2160, count = 100, chance = 100 },
- { itemId = 7591, count = 100, chance = 70 },
- { itemId = 7590, count = 100, chance = 70 }
- },
- cache = { -- This table should not be modified for anything
- eventIds = {},
- players = {},
- tiles = {},
- tileCount = 0
- }
- }
- --Check if your Server is compatible
- if not EventCallback or not Container.getItems then
- print("------------------------DREAM EVENT------------------------\nWARNING: YOUR SERVER IS NOT COMPATIBLE WITH THIS EVENT\nREQUIREMENTS: TFS 1.3\nhttps://github.com/otland/forgottenserver/pull/2867\nhttps://github.com/otland/forgottenserver/pull/3160\n-------------------------------------------------------------")
- config = nil
- else
- _DGE = {}
- function _DGE.isWalkable(x, y, z)
- local tile = Tile(x, y, z)
- if not tile or tile:hasFlag(TILESTATE_FLOORCHANGE) then
- return false
- end
- local ground = tile:getGround()
- if not ground or ground:hasProperty(CONST_PROP_BLOCKSOLID) then
- return false
- end
- local items = tile:getItems()
- for i = 1, tile:getItemCount() do
- local item = items[i]
- local itemType = item:getType()
- if itemType:getType() ~= ITEM_TYPE_MAGICFIELD and not itemType:isMovable() and item:hasProperty(CONST_PROP_BLOCKSOLID) then
- return false
- end
- end
- return tile
- end
- local function loadTiles()
- config.cache.tiles = {}
- config.cache.tileCount = 0
- for x = config.area.fromPos.x, config.area.toPos.x do
- for y = config.area.fromPos.y, config.area.toPos.y do
- local tile = _DGE.isWalkable(x, y, config.area.fromPos.z)
- if tile then
- local ground = tile:getGround()
- ground:setAttribute(ITEM_ATTRIBUTE_ACTIONID, config.gold.aid)
- config.cache.tileCount = config.cache.tileCount +1
- ground:setCustomAttribute('tileIndex', config.cache.tileCount)
- table.insert(config.cache.tiles, tile)
- end
- end
- end
- end
- local function formatTime(seconds)
- if seconds <= 0 then return '0s' end
- local days = math.floor(seconds / 86400)
- seconds = (seconds % 86400)
- local hours = math.floor(seconds / 3600)
- seconds = (seconds % 3600)
- local minutes = math.floor(seconds / 60)
- seconds = (seconds % 60)
- local result = ''
- if days >= 1 then result = string.format("%s%u days", result, days) end
- if hours >= 1 then result = string.format("%s%s%u hours", result, (days > 0 and ' ' or ''), hours) end
- if minutes >= 1 then result = string.format("%s%s%u minutes", result, (hours > 0 and ' ' or ''), minutes) end
- if seconds >= 1 then result = string.format("%s%s%u seconds", result, (minutes > 0 and ' ' or ''), seconds) end
- return result
- end
- local function getTime(str)
- local seconds = str:match('(%d+)s') or 0
- local minutes = str:match('(%d+)m') or 0
- local hours = str:match('(%d+)h') or 0
- return seconds, minutes, hours
- end
- function _DGE.debug(message)
- print(string.format("[%s - Debug] %s", config.miscellaneous.name, message))
- end
- function _DGE.eventSay(message)
- Game.broadcastMessage(string.format("%s says:\n%s", config.miscellaneous.name, message), MESSAGE_EVENT_ADVANCE)
- end
- function _DGE.sayToPlayers(message)
- for _, p in pairs(config.cache.players) do
- local player = Player(p.id)
- if player then
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("%s says:\n%s", config.miscellaneous.name, message))
- end
- end
- end
- function _DGE.removeCachePlayer(player)
- local playerId = player:getId()
- for index, p in pairs(config.cache.players) do
- if p.id == playerId then
- table.remove(config.cache.players, index)
- return true
- end
- end
- return false
- end
- function _DGE.finish()
- if #config.cache.players > 1 then
- table.sort(config.cache.players, function (p1, p2) return p1.score > p2.score end)
- else
- _DGE.close()
- return
- end
- local winner = Player(config.cache.players[1].id)
- if winner then
- winner:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Congratulations, you are the winner!")
- _DGE.eventSay(string.format("The player %s is the winner!", winner:getName()))
- _DGE.sendRewards(winner)
- end
- _DGE.close()
- end
- function _DGE.sendRewards(winner)
- local bag = Game.createItem(config.rewardBag, 1)
- if bag then
- for _, reward in pairs(config.rewards) do
- if reward.chance >= math.random(1, 100) then
- bag:addItem(reward.itemId, reward.count, INDEX_WHEREEVER, FLAG_NOLIMIT)
- end
- end
- local inbox = winner:getInbox()
- if inbox then
- local description, items = "You rewards: ", bag:getItems()
- for _, item in pairs(items) do
- description = string.format("%s%d %s%s", description, item:getCount(), item:getName(), (_ == #items and '.' or ', '))
- end
- inbox:addItemEx(bag, INDEX_WHEREEVER, FLAG_NOLIMIT)
- winner:sendTextMessage(MESSAGE_INFO_DESCR, description..'\nCheck your depot inbox.')
- end
- end
- end
- function _DGE.resetPlayer(player)
- _DGE.changeSpeedTo(player, true)
- player:setMovementBlocked(false)
- player:setStorageValue(config.players.storage, -1)
- local town = player:getTown()
- if not town then town = Town(1) end
- player:getPosition():sendMagicEffect(CONST_ME_POFF)
- local townPos = town:getTemplePosition()
- player:teleportTo(townPos)
- townPos:sendMagicEffect(CONST_ME_TELEPORT)
- end
- function _DGE.changeSpeedTo(player, remove)
- local speed = player:getSpeed()
- if remove then
- local index = _DGE.isPlayerExist(player)
- if index then
- local base = config.cache.players[index].speed
- if speed > base then
- local diff = base - speed
- player:changeSpeed(diff)
- elseif speed < base then
- local diff = speed - base
- player:changeSpeed(math.abs(diff))
- end
- end
- return
- end
- if speed > config.players.speed then
- local diff = config.players.speed - speed
- player:changeSpeed(diff)
- elseif speed < config.players.speed then
- local diff = speed - config.players.speed
- player:changeSpeed(math.abs(diff))
- end
- end
- function _DGE.checkSpeedPlayers()
- for _, p in pairs(config.cache.players) do
- local player = Player(p.id)
- if player then
- _DGE.changeSpeedTo(player)
- end
- end
- config.cache.eventIds['speed'] = addEvent(_DGE.checkSpeedPlayers, 1000)
- end
- function _DGE.clean(withoutCreatures, exactlyTile)
- local function clean(tile)
- local gold = tile:getItemById(config.gold.id)
- while gold do
- gold:remove()
- gold = tile:getItemById(config.gold.id)
- end
- local chest = tile:getItemById(config.gold.chestId)
- while chest do
- chest:remove()
- chest = tile:getItemById(config.gold.chestId)
- end
- end
- if exactlyTile then
- clean(config.cache.tiles[exactlyTile])
- return
- end
- for _, tile in pairs(config.cache.tiles) do
- clean(tile)
- if not withoutCreatures then
- local creatures = tile:getCreatures()
- for _, creature in pairs(creatures) do
- if creature:isPlayer() then
- _DGE.resetPlayer(creature)
- end
- end
- end
- end
- end
- function _DGE.fill()
- _DGE.clean(true)
- for _, tile in pairs(config.cache.tiles) do
- local tilePos = tile:getPosition()
- if math.random(1, 100) <= config.gold.chestChance then
- local chest = Game.createItem(config.gold.chestId, 1, tilePos)
- if chest then
- chest:setAttribute(ITEM_ATTRIBUTE_ACTIONID, config.gold.chestAid)
- end
- else
- for i = 1, 3 do
- local gold = Game.createItem(config.gold.id, math.random(10, 80), tilePos)
- if gold then
- gold:setAttribute(ITEM_ATTRIBUTE_ACTIONID, config.gold.chestAid)
- end
- end
- end
- end
- end
- function _DGE.refill(refillInterval, count)
- if count == 0 then
- return
- end
- _DGE.showScores()
- _DGE.fill()
- config.cache.eventIds['refill'] = addEvent(_DGE.refill, refillInterval, refillInterval, count -1)
- end
- function _DGE.showScores()
- if #config.cache.players > 1 then
- table.sort(config.cache.players, function (p1, p2) return p1.score > p2.score end)
- else
- _DGE.close()
- return
- end
- local count = 0
- local description = "~ Scores ~\n\n"
- local playerCount = #config.cache.players
- for _, p in pairs(config.cache.players) do
- count = count +1
- local player = Player(p.id)
- if player then
- description = string.format("%s%d) %s - %d coins%s", description, _, player:getName(), p.score, (_ == playerCount and '' or '\n'))
- end
- if count >= 5 then
- break
- end
- end
- _DGE.sayToPlayers(description)
- end
- function _DGE.checkWaiting()
- if #config.cache.players >= config.players.min then
- _DGE.eventPreparing()
- return
- end
- config.state.type = "stoped"
- _DGE.eventSay("The event has been closed due to lack of participants.")
- _DGE.close()
- end
- function _DGE.kickPlayers()
- for _, p in pairs(config.cache.players) do
- local player = Player(p.id)
- if player then
- _DGE.resetPlayer(player)
- end
- end
- config.cache.players = {}
- end
- function _DGE.kickPlayer(player)
- local index = _DGE.isPlayerExist(player)
- if not index then
- return false
- end
- _DGE.resetPlayer(player)
- table.remove(config.cache.players, index)
- return true
- end
- function _DGE.isPlayerExist(player)
- local playerId = player:getId()
- for _, p in pairs(config.cache.players) do
- if playerId == p.id then
- return _
- end
- end
- return false
- end
- function _DGE.joinPlayer(player)
- table.insert(config.cache.players, { id = player:getId(), score = 0, speed = player:getSpeed() })
- player:setStorageValue(config.players.storage, 1)
- player:getPosition():sendMagicEffect(CONST_ME_POFF)
- player:teleportTo(config.area.waitZone)
- config.area.waitZone:sendMagicEffect(CONST_ME_TELEPORT)
- if #config.cache.players >= config.players.max then
- local waitingEventId = config.cache.eventIds['waiting']
- if waitingEventId then
- stopEvent(waitingEventId)
- config.cache.eventIds['waiting'] = nil
- end
- _DGE.stopAdvertising()
- _DGE.eventPreparing()
- end
- return true
- end
- function _DGE.eventPreparing()
- _DGE.fill()
- local alreadyTile = {}
- for _, p in pairs(config.cache.players) do
- local player = Player(p.id)
- if player then
- local rNumber = math.random(1, config.cache.tileCount)
- if not table.contains(alreadyTile, rNumber) then
- table.insert(alreadyTile, rNumber)
- _DGE.clean(nil, rNumber)
- player:setMovementBlocked(true)
- _DGE.changeSpeedTo(player)
- player:teleportTo(config.cache.tiles[rNumber]:getPosition())
- end
- end
- end
- _DGE.eventSay("We are ready to start, get ready...")
- config.state.type = "preparing"
- config.cache.eventIds['counterStart'] = addEvent(_DGE.counterStart, 1000, 5)
- end
- function _DGE.sendNumber(player, number, color)
- player:sendTextMessage(MESSAGE_EXPERIENCE_OTHERS, text, player:getPosition(), number, color, 0, TEXTCOLOR_NONE)
- end
- function _DGE.addScore(player, count)
- local index = _DGE.isPlayerExist(player)
- if index then
- config.cache.players[index].score = config.cache.players[index].score +count
- return true
- end
- return false
- end
- function _DGE.counterStart(seconds)
- local started = seconds == 0
- for _, p in pairs(config.cache.players) do
- local player = Player(p.id)
- if player then
- if started then
- player:setMovementBlocked(false)
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Gogogogog!")
- else
- _DGE.sendNumber(player, seconds, TEXTCOLOR_RED)
- end
- end
- end
- if not started then
- config.cache.eventIds['counterStart'] = addEvent(_DGE.counterStart, 1000, seconds -1)
- else
- _DGE.checkSpeedPlayers()
- config.state.type = "started"
- local s, m ,h = getTime(config.start.ending)
- local tseconds = s+(m*60)+(h*60*60)
- config.cache.eventIds['ending'] = addEvent(_DGE.finish, tseconds * 1000)
- local refillInterval = math.ceil(tseconds/3) * 1000
- config.cache.eventIds['refill'] = addEvent(_DGE.refill, refillInterval, refillInterval, 2)
- end
- end
- function _DGE.stopAdvertising()
- local s, m ,h = getTime(config.start.waiting)
- local tseconds = s+(m*60)+(h*60*60)
- local advertisings = math.floor(tseconds / 60)
- if advertisings > 0 then
- for i = 1, advertisings do
- stopEvent(config.cache.eventIds['advertisings'..i])
- end
- end
- end
- function _DGE.init()
- if config.cache.tileCount == 0 then
- loadTiles()
- if config.state.debug then
- _DGE.debug(string.format("loaded %d tiles.", config.cache.tileCount))
- end
- end
- _DGE.clean()
- local s, m ,h = getTime(config.start.waiting)
- local tseconds = s+(m*60)+(h*60*60)
- _DGE.eventSay(string.format("The event will start in %s, use the command %s to enter.", formatTime(tseconds), config.miscellaneous.talkaction))
- config.cache.eventIds['waiting'] = addEvent(_DGE.checkWaiting, tseconds * 1000)
- config.state.type = "open"
- local advertisings = math.floor(tseconds / 60)
- if advertisings > 0 then
- for i = 1, advertisings do
- config.cache.eventIds['advertisings'..i] = addEvent(function (tseconds, talk)
- _DGE.eventSay(string.format("The event will start in %s, use the command %s to enter.", formatTime(tseconds), talk))
- end, (30 * 1000)*i, tseconds-30, config.miscellaneous.talkaction)
- end
- end
- return true
- end
- function _DGE.close()
- for _, eventId in pairs(config.cache.eventIds) do
- stopEvent(eventId)
- end
- config.cache.eventIds = {}
- _DGE.kickPlayers()
- config.state.type = "close"
- end
- local global = GlobalEvent("DreamOfGold")
- global.onTime = _DGE.init
- global:time(config.start.time)
- global:register()
- local talk = TalkAction(config.miscellaneous.talkaction)
- function talk.onSay(player, words, param)
- if player:getGroup():getAccess() then
- if param == "open" then
- if table.contains({'open', 'started', 'preparing'}, config.state.type) then
- player:sendCancelMessage("The event is now open.")
- else
- _DGE.init()
- end
- return false
- elseif param == "close" then
- if table.contains({'closing', 'stoped'}, config.state.type) then
- player:sendCancelMessage("The event is already closed.")
- else
- _DGE.close()
- end
- return false
- end
- end
- if table.contains({'back', 'exit'}, param:lower()) then
- if table.contains({'started', 'preparing'}, config.state.type) then
- player:sendCancelMessage("Sorry, the event has already started.")
- return false
- end
- if not _DGE.kickPlayer(player) then
- player:sendCancelMessage("Sorry, but you are not at the event.")
- else
- player:sendCancelMessage("You have left the event.")
- end
- return false
- end
- if _DGE.isPlayerExist(player) then
- player:sendCancelMessage("Sorry, you're already inside the event.")
- return false
- end
- if config.state.type == "open" then
- if not _DGE.joinPlayer(player) then
- player:sendCancelMessage("Sorry, there are no more spaces.")
- end
- elseif table.contains({'closing', 'stoped'}, config.state.type) then
- player:sendCancelMessage("Sorry, but the event is closed.")
- else
- player:sendCancelMessage("Sorry, but the event is running.")
- end
- return false
- end
- talk:separator(" ")
- talk:register()
- local cEvent = CreatureEvent("DreamOfGold")
- function cEvent.onLogin(player)
- if player:getStorageValue(config.players.storage) == 1 then
- _DGE.resetPlayer(player)
- end
- return true
- end
- cEvent:register()
- local cEvent = CreatureEvent("DreamOfGoldLogout")
- function cEvent.onLogout(player)
- if player:getStorageValue(config.players.storage) == 1 then
- player:sendCancelMessage("You cannot logout, because you are at the event.")
- return false
- end
- return true
- end
- cEvent:register()
- local move = MoveEvent("DreamOfGold")
- function move.onStepIn(creature, ground, position, fromPosition)
- local player = creature:getPlayer()
- if not player then
- return true
- end
- local tile = config.cache.tiles[ground:getCustomAttribute('tileIndex')]
- if not tile then
- return true
- end
- local playerId = player:getId()
- local items = tile:getItems()
- for _, item in pairs(items) do
- if item:getId() == config.gold.id then
- local count = player:getSpeed() > config.players.speed and item:getCount()/2 or item:getCount()
- if _DGE.addScore(player, count) then
- _DGE.sendNumber(player, count, TEXTCOLOR_YELLOW)
- item:remove()
- end
- break
- end
- end
- return true
- end
- move:aid(config.gold.aid)
- move:register()
- local action = Action()
- function action.onUse(player, item, fromPos, target, toPos, isHotkey)
- if item:getId() == config.gold.chestId then
- local count = math.random(config.gold.chestValues[1], config.gold.chestValues[2])
- count = player:getSpeed() > config.players.speed and count/2 or count
- if _DGE.addScore(player, count) then
- _DGE.sendNumber(player, count, TEXTCOLOR_YELLOW)
- item:remove()
- end
- end
- return true
- end
- action:aid(config.gold.chestAid)
- action:register()
- local ec = EventCallback
- function ec.onMoveCreature(player, creature, fromPosition, toPosition)
- if not player:getGroup():getAccess() then
- if not config.miscellaneous.canPushPlayers then
- if player:getStorageValue(config.players.storage) == 1 then
- player:sendCancelMessage("It is not allowed to move players in the event.")
- return false
- end
- end
- end
- return true
- end
- ec:register(-1)
- local ec = EventCallback
- function ec.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
- if not player:getGroup():getAccess() then
- if toPosition.x ~= CONTAINER_POSITION or fromPosition.x ~= CONTAINER_POSITION then
- if player:getStorageValue(config.players.storage) == 1 then
- player:sendCancelMessage("It is not allowed to move items in the event.")
- return false
- end
- end
- end
- return true
- end
- ec:register(-1)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement