TFS 1.X+ TFS 1.3 Timer for quest lever

SorketROrk

Member
Joined
Oct 14, 2020
Messages
95
Solutions
1
Reaction score
24
Location
Sweden
Hey!

I would like to ask for some help with this script from @Sarah Wesker:
Lua:
local configQuest = {
    actionId = 901,
    players = { -- Positions where players are standing to enter
        Tile(3051, 1828, 8),
        Tile(3051, 1829, 8),
        Tile(3051, 1830, 8),
        Tile(3051, 1831, 8),
        Tile(3051, 1832, 8),
        Tile(3051, 1833, 8),
        Tile(3051, 1834, 8)
    },
    minPlayers = 1, -- Minimum number of players that can enter. in this case 1 or more
    destination = Position(3056, 1831, 8), -- Position where the players will be teleported when entering the room
    requirements = {
        level = 2000, -- level required to enter the room
        storages = {} -- if you need some storage to be able to enter or several storages
    },
    room = {
        centerPos = Position(3068, 1831, 8), -- center of the room
        fromPos = Position(3055, 1812, 8), -- the upper left corner of the room
        toPos = Position(3084, 1844, 8) -- the lower right corner of the room
    },
    boss = {
        name = "Demon", -- boss name
        spawnPos = Position(3068, 1831, 8), -- spawn boss position
        exitIn = 1 -- minutes to get out of the room
    },
    debug = {
        enabled = false, -- for testing with /reload scripts
        exitPos = Position(3051, 1826, 8), -- Position to which players will be sent off after a while
        leverIds = {1945, 1946}, -- lever on / lever off
        admins = false -- detect administrators in the room
    }
}

local function getPlayersInQuest()
    local spectators = Game.getSpectators(configQuest.room.centerPos, false, true, configQuest.radius.x, configQuest.radius.x, configQuest.radius.y, configQuest.radius.y)
    local players = {}
    for _, spectator in pairs(spectators) do
        if spectator:getGroup():getId() == 1 or configQuest.debug.admins then
            players[#players +1] = spectator
        end
    end
    return players
end

local function closeQuest()
    local ground = configQuest.players[1]:getGround()
    for _, p in pairs(getPlayersInQuest()) do
        p:teleportTo(configQuest.debug.exitPos)
    end
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        boss:remove()
    end
    ground:removeCustomAttribute("evId")
end

local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not configQuest.radius then
        configQuest.radius = {
            x = math.ceil((configQuest.room.toPos.x - configQuest.room.fromPos.x) / 2),
            y = math.ceil((configQuest.room.toPos.y - configQuest.room.fromPos.y) / 2)
        }
    end
    local leverCanUse = false
    local playerPosition = player:getPosition()
    for _, tile in pairs(configQuest.players) do
        leverCanUse = playerPosition == tile:getPosition()
        if leverCanUse then
            break
        end
    end
    if not leverCanUse then
        return false
    end
    local questPlayers = getPlayersInQuest()
    for _, p in pairs(questPlayers) do
        if configQuest.debug.enabled then
            p:teleportTo(configQuest.debug.exitPos)
        end
    end
    if configQuest.debug.enabled then
        configQuest.debug.exitPos:sendMagicEffect(CONST_ME_TELEPORT)
    end
    local ground = configQuest.players[1]:getGround()
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        if configQuest.debug.enabled or #questPlayers == 0 then
            boss:remove()
            stopEvent(ground:getCustomAttribute("evId"))
            ground:removeCustomAttribute("evId")
        else
            player:sendCancelMessage(string.format("You must wait for the boss to be defeated or wait %d seconds.", ground:getCustomAttribute("now") - os.time()))
            return true
        end
    end
    local players = {}
    for _, tile in pairs(configQuest.players) do
        local p = tile:getTopCreature()
        if p and p:isPlayer() then
            if p:getLevel() < configQuest.requirements.level then
                player:sendCancelMessage(string.format("%s must be level %d or higher.", p:getName(), configQuest.requirements.level))
                p:getPosition():sendMagicEffect(CONST_ME_POFF)
                return true
            end
            for _, storage in pairs(configQuest.requirements.storages) do
                if p:getStorageValue(storage) == -1 then
                    player:sendCancelMessage(string.format("%s still cannot face this boss.", p:getName()))
                    p:getPosition():sendMagicEffect(CONST_ME_POFF)
                    return true
                end
            end
            players[#players +1] = p
        end
    end
    if #players < configQuest.minPlayers then
        player:sendCancelMessage(string.format("Sorry, only groups of %d or more players are allowed.", configQuest.minPlayers))
        return true
    end
    for _, p in pairs(players) do
        p:getPosition():sendMagicEffect(CONST_ME_POFF)
        p:teleportTo(configQuest.destination)
    end
    configQuest.destination:sendMagicEffect(CONST_ME_TELEPORT)
    boss = Game.createMonster(configQuest.boss.name, configQuest.boss.spawnPos)
    if boss then
        ground:setCustomAttribute("bossId", boss:getId())
        ground:setCustomAttribute("evId", addEvent(closeQuest, configQuest.boss.exitIn * 60 * 1000))
        ground:setCustomAttribute("now", os.time() + (configQuest.boss.exitIn * 60))
    end
    item:transform(item:getId() == configQuest.debug.leverIds[1] and configQuest.debug.leverIds[2] or configQuest.debug.leverIds[1])
    return true
end

action:aid(configQuest.actionId)
action:register()

Script is working nicely, I do however need to add some type of timer on the lever.

Any ideas on how to go about if I would like something like:
Once the player/team uses lever, it starts a timer that will pervent players from using the lever to teleport inside quest for the next 30 minutes?

Right now It is only checking to see if boss is alive, and if not it will let players in if I am correct.

All help is greatly appreciated

Yours,
SRO
 
Solution
Well, if you don't mind not using revscripts, here is oldschool action scrip that I use :p Never had any issue, very simple one.
And I guess it is not a problem to convert it to revscript also...

Lua:
local bossConfig = {
        [50040] = {  -- ActionID
        requiredLevel = 250,
        minPlayersRequired = 1,

        boss = "The Dread Maiden",
        bossGlobalStorage = 60069,
        playerStorage = 60070, -- storage counting the time, number of hours between fights
        playerQuestStorage = 60084, --storage of a mission required to enter
        teleportPosition = Position(1832, 1640, 13),
        centerRoomPosition = Position(1833, 1629, 13),
        northRange = 15, eastRange = 15, southRange = 15, westRange = 15,
        exit...

Unknown Soldier

Mapping a map
Joined
Oct 30, 2010
Messages
160
Solutions
9
Reaction score
274
In your config {} add line where you specify global storage for the lever, and desired delay time in minutes.

Lua:
bossGlobalStorage = 12345,
delayTime = 30

then inside your function which checks all the requirements players must meet, add this code, which will check the global storage.

Lua:
if (getGlobalStorageValue(configQuest.bossGlobalStorage) > 0) then
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
      return true
end

And in the part of your script that teleports all players inside the room and summons a boss, add lines, that will set global storage to value 1, and an event, that will change global storage again to 0 after your desired time (delayTime in this case)

Lua:
setGlobalStorageValue(configQuest.bossGlobalStorage, 1)
addEvent(setGlobalStorageValue, configQuest.delayTime * 60 * 1000, configQuest.bossGlobalStorage, 0)

Hope that helps, I didn't edit your script, because i suck at scripting and I would have to check it on my TFS... and I'm not able to do this now.

@edit
If I were to try... I would do this...
Lua:
local configQuest = {
    actionId = 901,
    bossGlobalStorage = 12345,
    delayTime = 30,
    players = { -- Positions where players are standing to enter
        Tile(3051, 1828, 8),
        Tile(3051, 1829, 8),
        Tile(3051, 1830, 8),
        Tile(3051, 1831, 8),
        Tile(3051, 1832, 8),
        Tile(3051, 1833, 8),
        Tile(3051, 1834, 8)
    },
    minPlayers = 1, -- Minimum number of players that can enter. in this case 1 or more
    destination = Position(3056, 1831, 8), -- Position where the players will be teleported when entering the room
    requirements = {
        level = 2000, -- level required to enter the room
        storages = {} -- if you need some storage to be able to enter or several storages
    },
    room = {
        centerPos = Position(3068, 1831, 8), -- center of the room
        fromPos = Position(3055, 1812, 8), -- the upper left corner of the room
        toPos = Position(3084, 1844, 8) -- the lower right corner of the room
    },
    boss = {
        name = "Demon", -- boss name
        spawnPos = Position(3068, 1831, 8), -- spawn boss position
        exitIn = 1 -- minutes to get out of the room
    },
    debug = {
        enabled = false, -- for testing with /reload scripts
        exitPos = Position(3051, 1826, 8), -- Position to which players will be sent off after a while
        leverIds = {1945, 1946}, -- lever on / lever off
        admins = false -- detect administrators in the room
    }
}

local function getPlayersInQuest()
    local spectators = Game.getSpectators(configQuest.room.centerPos, false, true, configQuest.radius.x, configQuest.radius.x, configQuest.radius.y, configQuest.radius.y)
    local players = {}
    for _, spectator in pairs(spectators) do
        if spectator:getGroup():getId() == 1 or configQuest.debug.admins then
            players[#players +1] = spectator
        end
    end
    return players
end

local function closeQuest()
    local ground = configQuest.players[1]:getGround()
    for _, p in pairs(getPlayersInQuest()) do
        p:teleportTo(configQuest.debug.exitPos)
    end
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        boss:remove()
    end
    ground:removeCustomAttribute("evId")
end

local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not configQuest.radius then
        configQuest.radius = {
            x = math.ceil((configQuest.room.toPos.x - configQuest.room.fromPos.x) / 2),
            y = math.ceil((configQuest.room.toPos.y - configQuest.room.fromPos.y) / 2)
        }
    end
    local leverCanUse = false
    local playerPosition = player:getPosition()
    for _, tile in pairs(configQuest.players) do
        leverCanUse = playerPosition == tile:getPosition()
        if leverCanUse then
            break
        end
    end
    if not leverCanUse then
        return false
    end
    local questPlayers = getPlayersInQuest()
    for _, p in pairs(questPlayers) do
        if configQuest.debug.enabled then
            p:teleportTo(configQuest.debug.exitPos)
        end
    end
    if configQuest.debug.enabled then
        configQuest.debug.exitPos:sendMagicEffect(CONST_ME_TELEPORT)
    end
    
    if (getGlobalStorageValue(configQuest.bossGlobalStorage) > 0) then
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
      return true
    end

    local ground = configQuest.players[1]:getGround()
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        if configQuest.debug.enabled or #questPlayers == 0 then
            boss:remove()
            stopEvent(ground:getCustomAttribute("evId"))
            ground:removeCustomAttribute("evId")
        else
            player:sendCancelMessage(string.format("You must wait for the boss to be defeated or wait %d seconds.", ground:getCustomAttribute("now") - os.time()))
            return true
        end
    end
    local players = {}
    for _, tile in pairs(configQuest.players) do
        local p = tile:getTopCreature()
        if p and p:isPlayer() then
            if p:getLevel() < configQuest.requirements.level then
                player:sendCancelMessage(string.format("%s must be level %d or higher.", p:getName(), configQuest.requirements.level))
                p:getPosition():sendMagicEffect(CONST_ME_POFF)
                return true
            end
            for _, storage in pairs(configQuest.requirements.storages) do
                if p:getStorageValue(storage) == -1 then
                    player:sendCancelMessage(string.format("%s still cannot face this boss.", p:getName()))
                    p:getPosition():sendMagicEffect(CONST_ME_POFF)
                    return true
                end
            end
            players[#players +1] = p
        end
    end
    if #players < configQuest.minPlayers then
        player:sendCancelMessage(string.format("Sorry, only groups of %d or more players are allowed.", configQuest.minPlayers))
        return true
    end
    for _, p in pairs(players) do
        p:getPosition():sendMagicEffect(CONST_ME_POFF)
        p:teleportTo(configQuest.destination)
    end
    setGlobalStorageValue(configQuest.bossGlobalStorage, 1)
    addEvent(setGlobalStorageValue, configQuest.delayTime * 60 * 1000, configQuest.bossGlobalStorage, 0)
    configQuest.destination:sendMagicEffect(CONST_ME_TELEPORT)
    boss = Game.createMonster(configQuest.boss.name, configQuest.boss.spawnPos)
    if boss then
        ground:setCustomAttribute("bossId", boss:getId())
        ground:setCustomAttribute("evId", addEvent(closeQuest, configQuest.boss.exitIn * 60 * 1000))
        ground:setCustomAttribute("now", os.time() + (configQuest.boss.exitIn * 60))
    end
    item:transform(item:getId() == configQuest.debug.leverIds[1] and configQuest.debug.leverIds[2] or configQuest.debug.leverIds[1])
    return true
end

action:aid(configQuest.actionId)
action:register()
 
Last edited:
OP
SorketROrk

SorketROrk

Member
Joined
Oct 14, 2020
Messages
95
Solutions
1
Reaction score
24
Location
Sweden
In your config {} add line where you specify global storage for the lever, and desired delay time in minutes.

Lua:
bossGlobalStorage = 12345,
delayTime = 30

then inside your function which checks all the requirements players must meet, add this code, which will check the global storage.

Lua:
if (getGlobalStorageValue(configQuest.bossGlobalStorage) > 0) then
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
      return true
end

And in the part of your script that teleports all players inside the room and summons a boss, add lines, that will set global storage to value 1, and an event, that will change global storage again to 0 after your desired time (delayTime in this case)

Lua:
setGlobalStorageValue(configQuest.bossGlobalStorage, 1)
addEvent(setGlobalStorageValue, configQuest.delayTime * 60 * 1000, configQuest.bossGlobalStorage, 0)

Hope that helps, I didn't edit your script, because i suck at scripting and I would have to check it on my TFS... and I'm not able to do this now.

@edit
If I were to try... I would do this...
Lua:
local configQuest = {
    actionId = 901,
    bossGlobalStorage = 12345,
    delayTime = 30,
    players = { -- Positions where players are standing to enter
        Tile(3051, 1828, 8),
        Tile(3051, 1829, 8),
        Tile(3051, 1830, 8),
        Tile(3051, 1831, 8),
        Tile(3051, 1832, 8),
        Tile(3051, 1833, 8),
        Tile(3051, 1834, 8)
    },
    minPlayers = 1, -- Minimum number of players that can enter. in this case 1 or more
    destination = Position(3056, 1831, 8), -- Position where the players will be teleported when entering the room
    requirements = {
        level = 2000, -- level required to enter the room
        storages = {} -- if you need some storage to be able to enter or several storages
    },
    room = {
        centerPos = Position(3068, 1831, 8), -- center of the room
        fromPos = Position(3055, 1812, 8), -- the upper left corner of the room
        toPos = Position(3084, 1844, 8) -- the lower right corner of the room
    },
    boss = {
        name = "Demon", -- boss name
        spawnPos = Position(3068, 1831, 8), -- spawn boss position
        exitIn = 1 -- minutes to get out of the room
    },
    debug = {
        enabled = false, -- for testing with /reload scripts
        exitPos = Position(3051, 1826, 8), -- Position to which players will be sent off after a while
        leverIds = {1945, 1946}, -- lever on / lever off
        admins = false -- detect administrators in the room
    }
}

local function getPlayersInQuest()
    local spectators = Game.getSpectators(configQuest.room.centerPos, false, true, configQuest.radius.x, configQuest.radius.x, configQuest.radius.y, configQuest.radius.y)
    local players = {}
    for _, spectator in pairs(spectators) do
        if spectator:getGroup():getId() == 1 or configQuest.debug.admins then
            players[#players +1] = spectator
        end
    end
    return players
end

local function closeQuest()
    local ground = configQuest.players[1]:getGround()
    for _, p in pairs(getPlayersInQuest()) do
        p:teleportTo(configQuest.debug.exitPos)
    end
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        boss:remove()
    end
    ground:removeCustomAttribute("evId")
end

local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not configQuest.radius then
        configQuest.radius = {
            x = math.ceil((configQuest.room.toPos.x - configQuest.room.fromPos.x) / 2),
            y = math.ceil((configQuest.room.toPos.y - configQuest.room.fromPos.y) / 2)
        }
    end
    local leverCanUse = false
    local playerPosition = player:getPosition()
    for _, tile in pairs(configQuest.players) do
        leverCanUse = playerPosition == tile:getPosition()
        if leverCanUse then
            break
        end
    end
    if not leverCanUse then
        return false
    end
    local questPlayers = getPlayersInQuest()
    for _, p in pairs(questPlayers) do
        if configQuest.debug.enabled then
            p:teleportTo(configQuest.debug.exitPos)
        end
    end
    if configQuest.debug.enabled then
        configQuest.debug.exitPos:sendMagicEffect(CONST_ME_TELEPORT)
    end
   
    if (getGlobalStorageValue(configQuest.bossGlobalStorage) > 0) then
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
      return true
    end

    local ground = configQuest.players[1]:getGround()
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        if configQuest.debug.enabled or #questPlayers == 0 then
            boss:remove()
            stopEvent(ground:getCustomAttribute("evId"))
            ground:removeCustomAttribute("evId")
        else
            player:sendCancelMessage(string.format("You must wait for the boss to be defeated or wait %d seconds.", ground:getCustomAttribute("now") - os.time()))
            return true
        end
    end
    local players = {}
    for _, tile in pairs(configQuest.players) do
        local p = tile:getTopCreature()
        if p and p:isPlayer() then
            if p:getLevel() < configQuest.requirements.level then
                player:sendCancelMessage(string.format("%s must be level %d or higher.", p:getName(), configQuest.requirements.level))
                p:getPosition():sendMagicEffect(CONST_ME_POFF)
                return true
            end
            for _, storage in pairs(configQuest.requirements.storages) do
                if p:getStorageValue(storage) == -1 then
                    player:sendCancelMessage(string.format("%s still cannot face this boss.", p:getName()))
                    p:getPosition():sendMagicEffect(CONST_ME_POFF)
                    return true
                end
            end
            players[#players +1] = p
        end
    end
    if #players < configQuest.minPlayers then
        player:sendCancelMessage(string.format("Sorry, only groups of %d or more players are allowed.", configQuest.minPlayers))
        return true
    end
    for _, p in pairs(players) do
        p:getPosition():sendMagicEffect(CONST_ME_POFF)
        p:teleportTo(configQuest.destination)
    end
    setGlobalStorageValue(configQuest.bossGlobalStorage, 1)
    addEvent(setGlobalStorageValue, configQuest.delayTime * 60 * 1000, configQuest.bossGlobalStorage, 0)
    configQuest.destination:sendMagicEffect(CONST_ME_TELEPORT)
    boss = Game.createMonster(configQuest.boss.name, configQuest.boss.spawnPos)
    if boss then
        ground:setCustomAttribute("bossId", boss:getId())
        ground:setCustomAttribute("evId", addEvent(closeQuest, configQuest.boss.exitIn * 60 * 1000))
        ground:setCustomAttribute("now", os.time() + (configQuest.boss.exitIn * 60))
    end
    item:transform(item:getId() == configQuest.debug.leverIds[1] and configQuest.debug.leverIds[2] or configQuest.debug.leverIds[1])
    return true
end

action:aid(configQuest.actionId)
action:register()
Thank you for taking your time to explain, I haven't had the opportunity to play around with timers so I had no clue on how to apply it.

I'll be testing the script when I get home! 😃👍
 

Unknown Soldier

Mapping a map
Joined
Oct 30, 2010
Messages
160
Solutions
9
Reaction score
274
Hmmm.. not working and no errors :eek:
Check for typos, if there is everything ok then try placing the two last parts of the code in different places in the script. It should work, I am using this code in a script and it works for me. TFS 1.3.

You can also use os.time for that

Lua:
local config = {
    delayglobal = 60032, -- global storage, that blocks entrance to the boss for "FIGHTTIME" minutes (example: fighttime is 10 min, somebody enters tp and leaves boss room after 1 minute, tp will be blocked for 9 minutes more anyway)
    fighttime = 5*60*1000,  -- (10 * 60 * 1000 = ten minutes)
}

if getGlobalStorageValue(config.delayglobal) <= os.time() then  
      setGlobalStorageValue(config.delayglobal, os.time() + (config.fighttime / 1000))
else
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must wait few minutes for the boss to regenerate.")
end

You can for example wrap part of your code, which teleport players inside the room, spawn bosses etc in the "if" that I've pasted. Something like...

Lua:
if getGlobalStorageValue(config.delayglobal) <= os.time() then  
      setGlobalStorageValue(config.delayglobal, os.time() + (config.fighttime / 1000))
      ...
      YOUR CODE
      ...
else
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must wait few minutes for the boss to regenerate.")
end
 
Last edited:
OP
SorketROrk

SorketROrk

Member
Joined
Oct 14, 2020
Messages
95
Solutions
1
Reaction score
24
Location
Sweden
Check for typos, if there is everything ok then try placing the two last parts of the code in different places in the script. It should work, I am using this code in a script and it works for me. TFS 1.3.

You can also use os.time for that

Lua:
local config = {
    delayglobal = 60032, -- global storage, that blocks entrance to the boss for "FIGHTTIME" minutes (example: fighttime is 10 min, somebody enters tp and leaves boss room after 1 minute, tp will be blocked for 9 minutes more anyway)
    fighttime = 5*60*1000,  -- (10 * 60 * 1000 = ten minutes)
}

if getGlobalStorageValue(config.delayglobal) <= os.time() then 
      setGlobalStorageValue(config.delayglobal, os.time() + (config.fighttime / 1000))
else
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must wait few minutes for the boss to regenerate.")
end

You can for example wrap part of your code, which teleport players inside the room, spawn bosses etc in the "if" that I've pasted. Something like...

Lua:
if getGlobalStorageValue(config.delayglobal) <= os.time() then 
      setGlobalStorageValue(config.delayglobal, os.time() + (config.fighttime / 1000))
      ...
      YOUR CODE
      ...
else
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must wait few minutes for the boss to regenerate.")
end

I should get some type of error if there are typos right? Im not getting any errors.

I understand the code you are using and how it works, the problem is trying to make everything work together with it.


Right now the lever cant be used while the new lines are in action, does someone know why? or maybe if there is another way to achieve what im looking for? :(
 

Unknown Soldier

Mapping a map
Joined
Oct 30, 2010
Messages
160
Solutions
9
Reaction score
274
I should get some type of error if there are typos right? Im not getting any errors.

I understand the code you are using and how it works, the problem is trying to make everything work together with it.


Right now the lever cant be used while the new lines are in action, does someone know why? or maybe if there is another way to achieve what im looking for? :(
So you are saying this script works nicely, but it doesn't work at all in my case. First fix the script, then add modifications :p
 

Unknown Soldier

Mapping a map
Joined
Oct 30, 2010
Messages
160
Solutions
9
Reaction score
274
Well, if you don't mind not using revscripts, here is oldschool action scrip that I use :p Never had any issue, very simple one.
And I guess it is not a problem to convert it to revscript also...

Lua:
local bossConfig = {
        [50040] = {  -- ActionID
        requiredLevel = 250,
        minPlayersRequired = 1,

        boss = "The Dread Maiden",
        bossGlobalStorage = 60069,
        playerStorage = 60070, -- storage counting the time, number of hours between fights
        playerQuestStorage = 60084, --storage of a mission required to enter
        teleportPosition = Position(1832, 1640, 13),
        centerRoomPosition = Position(1833, 1629, 13),
        northRange = 15, eastRange = 15, southRange = 15, westRange = 15,
        exit = Position(1854, 1630, 13),
        bossPosition = Position(1833, 1629, 13),
        time = 15, --in minutes, 0.1 = 6 seconds
        delayTime = 15 + 3, --fight time from line above, plus reserved delay time for reward chest to disappear, making free reward chest impossible

        playerPositions = {
            [1] = Position(1858, 1630, 13),
            [2] = Position(1859, 1630, 13),
            [3] = Position(1860, 1630, 13),
            [4] = Position(1861, 1630, 13),
            [5] = Position(1862, 1630, 13)
        }
    }
}

local function resetBoss_the_dread_maiden(bossConfig, bossId)
local monster = Monster(bossId)
if monster then
    monster:remove()
end
local spectators = Game.getSpectators(bossConfig.centerRoomPosition, false, true, bossConfig.westRange, bossConfig.eastRange, bossConfig.northRange, bossConfig.southRange)
for i = 1, #spectators do
    spectators[i]:teleportTo(bossConfig.exit)
end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)


    if item.itemid == 1946 then
        local bossConfig = bossConfig[item:getActionId()]
        if not bossConfig then
            return false
        end

        if (getGlobalStorageValue(bossConfig.bossGlobalStorage) > 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
            return true
        end

        local errorMsg
        local rPlayers = {}
       
        for index, ipos in pairs(bossConfig.playerPositions) do
            local playerTile = Tile(ipos):getTopCreature()
            if playerTile then
                if playerTile:isPlayer() then
                    if playerTile:getLevel() >= bossConfig.requiredLevel then
                        if playerTile:getStorageValue(bossConfig.playerStorage) <= os.time() then
                            if playerTile:getStorageValue(bossConfig.playerQuestStorage) >= 1 then
                                table.insert(rPlayers, playerTile:getId())
                            else
                                errorMsg = 'One or more players have not acomplished required quest progress yet.'
                                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                                return false
                            end
                        else
                            errorMsg = 'One or more players have already entered in the last 20 hours.'
                            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                            return false
                        end
                    else
                        errorMsg = 'All the players need to be level '.. bossConfig.requiredLevel ..' or higher.'
                        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                        return false
                    end
                end
            end
        end

        if (#rPlayers >= bossConfig.minPlayersRequired) then
            for _, pid in pairs(rPlayers) do
                local rplayer = Player(pid)
                if rplayer:isPlayer() then
                    rplayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, ('You have ' ..bossConfig.time.. ' minutes to kill ' ..bossConfig.boss..'.'))
                    for j=1,5 do
                    bossConfig.playerPositions[j]:sendMagicEffect(CONST_ME_POFF)
                    end
                    rplayer:teleportTo(bossConfig.teleportPosition)
                    rplayer:setStorageValue(bossConfig.playerStorage, os.time() + (20 * 60 * 60)) --should be 20*60*60 for 20 hours
                    bossConfig.teleportPosition:sendMagicEffect(CONST_ME_ENERGYAREA)
                    rplayer:setDirection(DIRECTION_NORTH)
                end
            end
            setGlobalStorageValue(bossConfig.bossGlobalStorage, 1)
            addEvent(setGlobalStorageValue, bossConfig.delayTime * 60 * 1000, bossConfig.bossGlobalStorage, 0)
            local monster = Game.createMonster(bossConfig.boss, bossConfig.bossPosition)
            addEvent(resetBoss_the_dread_maiden, bossConfig.time * 60 * 1000, bossConfig, monster and monster.uid or 0)
        else
            if not errorMsg then
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, ("You need at least %u player."):format(bossConfig.minPlayersRequired))
            else
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
            end
            return true
        end

    end

item:transform(item.itemid == 1946 and 1945 or 1946)

return true
end
 
Solution
OP
SorketROrk

SorketROrk

Member
Joined
Oct 14, 2020
Messages
95
Solutions
1
Reaction score
24
Location
Sweden
Well, if you don't mind not using revscripts, here is oldschool action scrip that I use :p Never had any issue, very simple one.
And I guess it is not a problem to convert it to revscript also...

Lua:
local bossConfig = {
        [50040] = {  -- ActionID
        requiredLevel = 250,
        minPlayersRequired = 1,

        boss = "The Dread Maiden",
        bossGlobalStorage = 60069,
        playerStorage = 60070, -- storage counting the time, number of hours between fights
        playerQuestStorage = 60084, --storage of a mission required to enter
        teleportPosition = Position(1832, 1640, 13),
        centerRoomPosition = Position(1833, 1629, 13),
        northRange = 15, eastRange = 15, southRange = 15, westRange = 15,
        exit = Position(1854, 1630, 13),
        bossPosition = Position(1833, 1629, 13),
        time = 15, --in minutes, 0.1 = 6 seconds
        delayTime = 15 + 3, --fight time from line above, plus reserved delay time for reward chest to disappear, making free reward chest impossible

        playerPositions = {
            [1] = Position(1858, 1630, 13),
            [2] = Position(1859, 1630, 13),
            [3] = Position(1860, 1630, 13),
            [4] = Position(1861, 1630, 13),
            [5] = Position(1862, 1630, 13)
        }
    }
}

local function resetBoss_the_dread_maiden(bossConfig, bossId)
local monster = Monster(bossId)
if monster then
    monster:remove()
end
local spectators = Game.getSpectators(bossConfig.centerRoomPosition, false, true, bossConfig.westRange, bossConfig.eastRange, bossConfig.northRange, bossConfig.southRange)
for i = 1, #spectators do
    spectators[i]:teleportTo(bossConfig.exit)
end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)


    if item.itemid == 1946 then
        local bossConfig = bossConfig[item:getActionId()]
        if not bossConfig then
            return false
        end

        if (getGlobalStorageValue(bossConfig.bossGlobalStorage) > 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There is already a team inside or the boss is regenerating. Please wait for your turn.")
            return true
        end

        local errorMsg
        local rPlayers = {}
      
        for index, ipos in pairs(bossConfig.playerPositions) do
            local playerTile = Tile(ipos):getTopCreature()
            if playerTile then
                if playerTile:isPlayer() then
                    if playerTile:getLevel() >= bossConfig.requiredLevel then
                        if playerTile:getStorageValue(bossConfig.playerStorage) <= os.time() then
                            if playerTile:getStorageValue(bossConfig.playerQuestStorage) >= 1 then
                                table.insert(rPlayers, playerTile:getId())
                            else
                                errorMsg = 'One or more players have not acomplished required quest progress yet.'
                                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                                return false
                            end
                        else
                            errorMsg = 'One or more players have already entered in the last 20 hours.'
                            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                            return false
                        end
                    else
                        errorMsg = 'All the players need to be level '.. bossConfig.requiredLevel ..' or higher.'
                        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
                        return false
                    end
                end
            end
        end

        if (#rPlayers >= bossConfig.minPlayersRequired) then
            for _, pid in pairs(rPlayers) do
                local rplayer = Player(pid)
                if rplayer:isPlayer() then
                    rplayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, ('You have ' ..bossConfig.time.. ' minutes to kill ' ..bossConfig.boss..'.'))
                    for j=1,5 do
                    bossConfig.playerPositions[j]:sendMagicEffect(CONST_ME_POFF)
                    end
                    rplayer:teleportTo(bossConfig.teleportPosition)
                    rplayer:setStorageValue(bossConfig.playerStorage, os.time() + (20 * 60 * 60)) --should be 20*60*60 for 20 hours
                    bossConfig.teleportPosition:sendMagicEffect(CONST_ME_ENERGYAREA)
                    rplayer:setDirection(DIRECTION_NORTH)
                end
            end
            setGlobalStorageValue(bossConfig.bossGlobalStorage, 1)
            addEvent(setGlobalStorageValue, bossConfig.delayTime * 60 * 1000, bossConfig.bossGlobalStorage, 0)
            local monster = Game.createMonster(bossConfig.boss, bossConfig.bossPosition)
            addEvent(resetBoss_the_dread_maiden, bossConfig.time * 60 * 1000, bossConfig, monster and monster.uid or 0)
        else
            if not errorMsg then
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, ("You need at least %u player."):format(bossConfig.minPlayersRequired))
            else
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, errorMsg)
            end
            return true
        end

    end

item:transform(item.itemid == 1946 and 1945 or 1946)

return true
end
I don't mind, cant wait to get home and try it!! 🙂🙂
 

Xikini

I whore myself out for likes
Support Team
Joined
Nov 17, 2010
Messages
5,407
Solutions
361
Reaction score
3,514
Hey!

I would like to ask for some help with this script from @Sarah Wesker:
Lua:
local configQuest = {
    actionId = 901,
    players = { -- Positions where players are standing to enter
        Tile(3051, 1828, 8),
        Tile(3051, 1829, 8),
        Tile(3051, 1830, 8),
        Tile(3051, 1831, 8),
        Tile(3051, 1832, 8),
        Tile(3051, 1833, 8),
        Tile(3051, 1834, 8)
    },
    minPlayers = 1, -- Minimum number of players that can enter. in this case 1 or more
    destination = Position(3056, 1831, 8), -- Position where the players will be teleported when entering the room
    requirements = {
        level = 2000, -- level required to enter the room
        storages = {} -- if you need some storage to be able to enter or several storages
    },
    room = {
        centerPos = Position(3068, 1831, 8), -- center of the room
        fromPos = Position(3055, 1812, 8), -- the upper left corner of the room
        toPos = Position(3084, 1844, 8) -- the lower right corner of the room
    },
    boss = {
        name = "Demon", -- boss name
        spawnPos = Position(3068, 1831, 8), -- spawn boss position
        exitIn = 1 -- minutes to get out of the room
    },
    debug = {
        enabled = false, -- for testing with /reload scripts
        exitPos = Position(3051, 1826, 8), -- Position to which players will be sent off after a while
        leverIds = {1945, 1946}, -- lever on / lever off
        admins = false -- detect administrators in the room
    }
}

local function getPlayersInQuest()
    local spectators = Game.getSpectators(configQuest.room.centerPos, false, true, configQuest.radius.x, configQuest.radius.x, configQuest.radius.y, configQuest.radius.y)
    local players = {}
    for _, spectator in pairs(spectators) do
        if spectator:getGroup():getId() == 1 or configQuest.debug.admins then
            players[#players +1] = spectator
        end
    end
    return players
end

local function closeQuest()
    local ground = configQuest.players[1]:getGround()
    for _, p in pairs(getPlayersInQuest()) do
        p:teleportTo(configQuest.debug.exitPos)
    end
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        boss:remove()
    end
    ground:removeCustomAttribute("evId")
end

local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    if not configQuest.radius then
        configQuest.radius = {
            x = math.ceil((configQuest.room.toPos.x - configQuest.room.fromPos.x) / 2),
            y = math.ceil((configQuest.room.toPos.y - configQuest.room.fromPos.y) / 2)
        }
    end
    local leverCanUse = false
    local playerPosition = player:getPosition()
    for _, tile in pairs(configQuest.players) do
        leverCanUse = playerPosition == tile:getPosition()
        if leverCanUse then
            break
        end
    end
    if not leverCanUse then
        return false
    end
    local questPlayers = getPlayersInQuest()
    for _, p in pairs(questPlayers) do
        if configQuest.debug.enabled then
            p:teleportTo(configQuest.debug.exitPos)
        end
    end
    if configQuest.debug.enabled then
        configQuest.debug.exitPos:sendMagicEffect(CONST_ME_TELEPORT)
    end
    local ground = configQuest.players[1]:getGround()
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        if configQuest.debug.enabled or #questPlayers == 0 then
            boss:remove()
            stopEvent(ground:getCustomAttribute("evId"))
            ground:removeCustomAttribute("evId")
        else
            player:sendCancelMessage(string.format("You must wait for the boss to be defeated or wait %d seconds.", ground:getCustomAttribute("now") - os.time()))
            return true
        end
    end
    local players = {}
    for _, tile in pairs(configQuest.players) do
        local p = tile:getTopCreature()
        if p and p:isPlayer() then
            if p:getLevel() < configQuest.requirements.level then
                player:sendCancelMessage(string.format("%s must be level %d or higher.", p:getName(), configQuest.requirements.level))
                p:getPosition():sendMagicEffect(CONST_ME_POFF)
                return true
            end
            for _, storage in pairs(configQuest.requirements.storages) do
                if p:getStorageValue(storage) == -1 then
                    player:sendCancelMessage(string.format("%s still cannot face this boss.", p:getName()))
                    p:getPosition():sendMagicEffect(CONST_ME_POFF)
                    return true
                end
            end
            players[#players +1] = p
        end
    end
    if #players < configQuest.minPlayers then
        player:sendCancelMessage(string.format("Sorry, only groups of %d or more players are allowed.", configQuest.minPlayers))
        return true
    end
    for _, p in pairs(players) do
        p:getPosition():sendMagicEffect(CONST_ME_POFF)
        p:teleportTo(configQuest.destination)
    end
    configQuest.destination:sendMagicEffect(CONST_ME_TELEPORT)
    boss = Game.createMonster(configQuest.boss.name, configQuest.boss.spawnPos)
    if boss then
        ground:setCustomAttribute("bossId", boss:getId())
        ground:setCustomAttribute("evId", addEvent(closeQuest, configQuest.boss.exitIn * 60 * 1000))
        ground:setCustomAttribute("now", os.time() + (configQuest.boss.exitIn * 60))
    end
    item:transform(item:getId() == configQuest.debug.leverIds[1] and configQuest.debug.leverIds[2] or configQuest.debug.leverIds[1])
    return true
end

action:aid(configQuest.actionId)
action:register()

Script is working nicely, I do however need to add some type of timer on the lever.

Any ideas on how to go about if I would like something like:
Once the player/team uses lever, it starts a timer that will pervent players from using the lever to teleport inside quest for the next 30 minutes?

Right now It is only checking to see if boss is alive, and if not it will let players in if I am correct.

All help is greatly appreciated

Yours,
SRO
Just figured I'd pop in and give a solution to the original request, even though an alternative solution was suggested.
Lua:
local configQuest = {
    actionId = 901,
    players = { -- Positions where players are standing to enter
        Tile(3051, 1828, 8),
        Tile(3051, 1829, 8),
        Tile(3051, 1830, 8),
        Tile(3051, 1831, 8),
        Tile(3051, 1832, 8),
        Tile(3051, 1833, 8),
        Tile(3051, 1834, 8)
    },
    minPlayers = 1, -- Minimum number of players that can enter. in this case 1 or more
    destination = Position(3056, 1831, 8), -- Position where the players will be teleported when entering the room
    requirements = {
        level = 2000, -- level required to enter the room
        storages = {} -- if you need some storage to be able to enter or several storages
    },
    room = {
        centerPos = Position(3068, 1831, 8), -- center of the room
        fromPos = Position(3055, 1812, 8), -- the upper left corner of the room
        toPos = Position(3084, 1844, 8) -- the lower right corner of the room
    },
    boss = {
        name = "Demon", -- boss name
        spawnPos = Position(3068, 1831, 8), -- spawn boss position
        exitIn = 1 -- minutes to get out of the room
    },
    debug = {
        enabled = false, -- for testing with /reload scripts
        exitPos = Position(3051, 1826, 8), -- Position to which players will be sent off after a while
        leverIds = {1945, 1946}, -- lever on / lever off
        admins = false -- detect administrators in the room
    },
    -- Xikini edit start
    leverRestrictionTime = 30, -- in minutes
    leverRestrictionStorage = 45001 -- global storage
    -- Xikini edit finish
}

local function getPlayersInQuest()
    local spectators = Game.getSpectators(configQuest.room.centerPos, false, true, configQuest.radius.x, configQuest.radius.x, configQuest.radius.y, configQuest.radius.y)
    local players = {}
    for _, spectator in pairs(spectators) do
        if spectator:getGroup():getId() == 1 or configQuest.debug.admins then
            players[#players +1] = spectator
        end
    end
    return players
end

local function closeQuest()
    local ground = configQuest.players[1]:getGround()
    for _, p in pairs(getPlayersInQuest()) do
        p:teleportTo(configQuest.debug.exitPos)
    end
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        boss:remove()
    end
    ground:removeCustomAttribute("evId")
end

local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
    -- Xikini edit start
    if Game.getStorageValue(configQuest.leverRestrictionStorage) > os.time() then
        player:sendCancelMessage(string.format("Lever is on cooldown. You must wait %d seconds.", Game.getStorageValue(configQuest.leverRestrictionStorage) - os.time()))
        return true
    end
    -- Xikini edit finish
    if not configQuest.radius then
        configQuest.radius = {
            x = math.ceil((configQuest.room.toPos.x - configQuest.room.fromPos.x) / 2),
            y = math.ceil((configQuest.room.toPos.y - configQuest.room.fromPos.y) / 2)
        }
    end
    local leverCanUse = false
    local playerPosition = player:getPosition()
    for _, tile in pairs(configQuest.players) do
        leverCanUse = playerPosition == tile:getPosition()
        if leverCanUse then
            break
        end
    end
    if not leverCanUse then
        return false
    end
    local questPlayers = getPlayersInQuest()
    for _, p in pairs(questPlayers) do
        if configQuest.debug.enabled then
            p:teleportTo(configQuest.debug.exitPos)
        end
    end
    if configQuest.debug.enabled then
        configQuest.debug.exitPos:sendMagicEffect(CONST_ME_TELEPORT)
    end
    local ground = configQuest.players[1]:getGround()
    local boss = Monster(ground:getCustomAttribute("bossId"))
    if boss then
        if configQuest.debug.enabled or #questPlayers == 0 then
            boss:remove()
            stopEvent(ground:getCustomAttribute("evId"))
            ground:removeCustomAttribute("evId")
        else
            player:sendCancelMessage(string.format("You must wait for the boss to be defeated or wait %d seconds.", ground:getCustomAttribute("now") - os.time()))
            return true
        end
    end
    local players = {}
    for _, tile in pairs(configQuest.players) do
        local p = tile:getTopCreature()
        if p and p:isPlayer() then
            if p:getLevel() < configQuest.requirements.level then
                player:sendCancelMessage(string.format("%s must be level %d or higher.", p:getName(), configQuest.requirements.level))
                p:getPosition():sendMagicEffect(CONST_ME_POFF)
                return true
            end
            for _, storage in pairs(configQuest.requirements.storages) do
                if p:getStorageValue(storage) == -1 then
                    player:sendCancelMessage(string.format("%s still cannot face this boss.", p:getName()))
                    p:getPosition():sendMagicEffect(CONST_ME_POFF)
                    return true
                end
            end
            players[#players +1] = p
        end
    end
    if #players < configQuest.minPlayers then
        player:sendCancelMessage(string.format("Sorry, only groups of %d or more players are allowed.", configQuest.minPlayers))
        return true
    end
    for _, p in pairs(players) do
        p:getPosition():sendMagicEffect(CONST_ME_POFF)
        p:teleportTo(configQuest.destination)
    end
    configQuest.destination:sendMagicEffect(CONST_ME_TELEPORT)
    boss = Game.createMonster(configQuest.boss.name, configQuest.boss.spawnPos)
    if boss then
        ground:setCustomAttribute("bossId", boss:getId())
        ground:setCustomAttribute("evId", addEvent(closeQuest, configQuest.boss.exitIn * 60 * 1000))
        ground:setCustomAttribute("now", os.time() + (configQuest.boss.exitIn * 60))
    end
    item:transform(item:getId() == configQuest.debug.leverIds[1] and configQuest.debug.leverIds[2] or configQuest.debug.leverIds[1])
    -- Xikini edit start
    Game.setStorageValue(configQuest.leverRestrictionStorage, os.time() + (configQuest.leverRestrictionTime * 60))
    -- Xikini edit finish
    return true
end

action:aid(configQuest.actionId)
action:register()
 
Top