• 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.2 Ani lever do not reset

henkas

Well-Known Member
Joined
Jul 8, 2015
Messages
1,055
Solutions
5
Reaction score
62
Any ideas why when time passes lever do not reset to 1945, so basically it always stays with cooldown
LUA:
local config = {
    duration = 30, -- time till reset, in minutes
    level_req = 10, -- minimum level to do quest
    min_players = 4, -- minimum players to join quest
    lever_id = 1945, -- id of lever before pulled
    pulled_id = 1946 -- id of lever after pulled
}

local player_positions = {
    [1] = {fromPos = Position(543, 716, 7), toPos = Position(539, 762, 8)},
    [2] = {fromPos = Position(539, 717, 7), toPos = Position(554, 762, 8)},
    [3] = {fromPos = Position(547, 717, 7), toPos = Position(569, 762, 8)},
    [4] = {fromPos = Position(543, 721, 7), toPos = Position(585, 762, 8)}
}

local monsters = {
    [1] = {pos = Position(539, 772, 8), name = "Fighter 1"},
    [2] = {pos = Position(554, 772, 8), name = "Fighter 2"},
    [3] = {pos = Position(569, 772, 8), name = "Fighter 3"},
    [4] = {pos = Position(585, 772, 8), name = "Fighter 4"},
    [5] = {pos = Position(537, 802, 8), name = "Fighter 5"},
    [6] = {pos = Position(552, 802, 8), name = "Fighter 6"},
    [7] = {pos = Position(567, 802, 8), name = "Fighter 7"},
    [8] = {pos = Position(583, 802, 8), name = "Fighter 8"}
}

function doResetAnnihilator(uid)
    local item = Item(uid)
    if not item then
        return
    end

    local monster_names = {}
    for key, value in pairs(monsters) do
        if not isInArray(monster_names, value.name) then
            monster_names[monster_names + 1] = value.name
        end
    end

    for i = 1, #monsters do
        local creatures = Tile(monsters[i].pos):getCreatures()
        for key, creature in pairs(creatures) do
            if isInArray(monster_names, creature:getName()) then
                creature:remove()
            end
        end
    end

    for i = 1, #player_positions do
        local creatures = Tile(player_positions[i].toPos):getCreatures()
        for key, creature in pairs(creatures) do
            if isInArray(monster_names, creature:getName()) then
                creature:remove()
            end
        end
    end

    item:transform(config.lever_id)
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.itemid ~= config.lever_id then
        return player:sendCancelMessage("The quest is currently in use. Cooldown is " .. config.duration .. " minutes.")
    end

    local participants, pull_player = {}, false
    for i = 1, #player_positions do
        local fromPos = player_positions[i].fromPos
        local tile = Tile(fromPos)
        if not tile then
            print(">> ERROR: Annihilator tile does not exist for Position(" .. fromPos.x .. ", " .. fromPos.y .. ", " .. fromPos.z .. ").")
            return player:sendCancelMessage("There is an issue with this quest. Please contact an administrator.")
        end

        local creature = tile:getBottomCreature()
        if creature then
            local participant = creature:getPlayer()
            if not participant then
                return player:sendCancelMessage(participant:getName() .. " is not a valid participant.")
            end

            if participant:getLevel() < config.level_req then
                return player:sendCancelMessage(participant:getName() .. " is not the required level.")
            end

            if participant.uid == player.uid then
                pull_player = true
            end

            participants[#participants + 1] = {participant = participant, toPos = player_positions[i].toPos}
        end
    end

    if #participants < config.min_players then
        return player:sendCancelMessage("You do not have the required amount of participants.")
    end

    if not pull_player then
        return player:sendCancelMessage("You are in the wrong position.")
    end

    for i = 1, #monsters do
        local toPos = monsters[i].pos
        if not Tile(toPos) then
            print(">> ERROR: Annihilator tile does not exist for Position(" .. toPos.x .. ", " .. toPos.y .. ", " .. toPos.z .. ").")
            return player:sendCancelMessage("There is an issue with this quest. Please contact an administrator.")
        end
        Game.createMonster(monsters[i].name, monsters[i].pos, false, true)
    end

    for i = 1, #participants do
        participants[i].participant:teleportTo(participants[i].toPos)
        participants[i].toPos:sendMagicEffect(CONST_ME_TELEPORT)
    end

    item:transform(config.pulled_id)
    addEvent(doResetAnnihilator, config.duration * 60 * 1000, item.uid)
    return true
end
 
Solution
Try my latest fix at the bottom of this thread. Thanks for pointing out the bug.
Try my latest fix at the bottom of this thread. Thanks for pointing out the bug.
 
Solution
Try my latest fix at the bottom of this thread. Thanks for pointing out the bug.
Thanks. Can i not use local quest_range and local exit_position because its really useless stuff for me and makes it more complicated.
 
Yeah just compare my changes for the fix and update your version.
Did it. Guess the part i dont need is , everything else updated.
58 end
59 end
60
61 for key, cid in pairs(cid_array) do
62 local participant = Player(cid)
63 if participant and isInRange(participant:getPosition(), quest_range.fromPos, quest_range.toPos) then
64 participant:teleportTo(exit_position)
65 exit_position:sendMagicEffect(CONST_ME_TELEPORT)
 
You misunderstand how to get an item userdata inside an addEvent. Passing uids doesn't work because that uid is unique only to where it's being executed, after the main function is finished executing (onUse here) the uid can't be reused since the reference is gone.
Inside doResetAnnihilator you need to use this:
LUA:
function doResetAnnihilator(pos)
    local item = Tile(pos):getItemById(config.pulled_id)
    if not item then
        return
    end

Then for your addEvent you need to pass position parameter to this callback like so:
LUA:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)
 
You misunderstand how to get an item userdata inside an addEvent. Passing uids doesn't work because that uid is unique only to where it's being executed, after the main function is finished executing (onUse here) the uid can't be reused since the reference is gone.
Inside doResetAnnihilator you need to use this:
LUA:
function doResetAnnihilator(pos)
    local item = Tile(pos):getItemById(config.pulled_id)
    if not item then
        return
    end

Then for your addEvent you need to pass position parameter to this callback like so:
LUA:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)
Doesnt work either.
 
Of course it doesn't work. I didn't give you code to just copy/paste, I told you how to get the item in your callback.
What you do with the item is up to you.
You mean like
LUA:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, 100,100,7)
?
 
You mean like
LUA:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, 100,100,7)
?
No, that part you could fully copypaste, I used toPosition there for a reason.
The callback you just need to replace getting the local item variable with what I gave and transform the item that way.
 
No, that part you could fully copypaste, I used toPosition there for a reason.
The callback you just need to replace getting the local item variable with what I gave and transform the item that way.
So like Apollos said
LUA:
function doResetAnnihilator(position, cid_array)
    local tile = Tile(position)
    local item = tile and tile:getItemById(config.pulled_id)
    if not item then
        return
    end
it doesnt work
 
Are you actually reading the code or do you just ignore it until someone gives you something that works instantly? It is programmed in english so if you know how to read english you should be able to figure out what is going on.

Code:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)

addEvent(event, duration, [params])

is used to call a separate function at a specific time that you chose. That is why the lever doesn't reset instantly. So thats why that is there.

doResetAnnihilator <--- that is the function that is being called after the duration time.

config.duration <-- that is used in the local values that you set for minutes to reset the lever

* 60 * 1000 turns the time into minutes. 1 minute = 60000 miliseconds. So 60 * 1000 = 60000miliseconds = 1 minute.

toPosition is called when the function is started

Code:
function onUse(player, item, target, fromPosition, toPosition)

See the toPosition there? So the onUse sets the toPosition as soon as it is called. That is why you can use it and it reads as a position.

toPosition = {x = 1000, y = 1000, z = 7} <--- thats what is pretty much being read by the code when you use toPosition.

So again, because you clearly don't like to learn, I will explain it one more time.

Code:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)

This calls doResetAnnihilator after the amount of time you put config.duration * 60 * 1000 with the parameter of toPosition

So now you have to make the function doResetAnnihilator.

When you make it

Code:
function doResetAnnihilator(toPosition)
end

You can put toPosition because you put it in the addEvent before. So the information is passed through to the function.

(thank god TFS developers did all the hard work because you don't understand even the simplest parts)

So now we know the function doResetAnnihilator know the POSITION OF THE LEVER because the position of the lever was set in toPosition.

Now just because the function knows a position doesn't mean it is going to do anything.

So then we tell it what to do with the position

Code:
function doResetAnnihilator(toPosition)
local item = Tile(toPosition):getItemById(itemIdOfLever)
end

Now you see we added a new line. So read what it is doing.....

Tile()

This is used to call a tiles data. Now the code doesn't know which tile. So because we saved the toPosition before we will use that position to tell
it what tile to call.

Tile(toPosition)

That tells the code what tile it is supposed to be doing what you want on. If you dont tell it IT DOESN'T KNOW.

Tile(toPosition):getItemId()

that is used to find an item on a tiles position. If the ITEM IS NOT ON THE TILE it will return false.

Since levers cannot be moved and cannot move on there own it isn't actually nessacary to make sure its there but we do anyway
because if for some reason the lever is removed we don't want an error in the console so we add:

Code:
function doResetAnnihilator(toPosition)
local item = Tile(toPosition):getItemById(itemIdOfLever)
if not item then return false end
end

so the line: if not item then return false end makes sure the item you specified by its itemid is there. Otherwise it just ends the code and doesn't throw an error.

That is how far people got you. Your code knows:
-Start the new function after the correct time -> doResetAnnihilator
-Send the correct information needed to find the lever -> toPosition
-Find the item in the new function
-Make sure the item exists so there are no errors

ALL YOU HAVE TO DO IS TELL THE ITEM TO TRANSFORM INTO THE ITEMID OF THE RESET LEVER....

I will give you a hint....

item:transform()
 
Are you actually reading the code or do you just ignore it until someone gives you something that works instantly? It is programmed in english so if you know how to read english you should be able to figure out what is going on.

Code:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)

addEvent(event, duration, [params])

is used to call a separate function at a specific time that you chose. That is why the lever doesn't reset instantly. So thats why that is there.

doResetAnnihilator <--- that is the function that is being called after the duration time.

config.duration <-- that is used in the local values that you set for minutes to reset the lever

* 60 * 1000 turns the time into minutes. 1 minute = 60000 miliseconds. So 60 * 1000 = 60000miliseconds = 1 minute.

toPosition is called when the function is started

Code:
function onUse(player, item, target, fromPosition, toPosition)

See the toPosition there? So the onUse sets the toPosition as soon as it is called. That is why you can use it and it reads as a position.

toPosition = {x = 1000, y = 1000, z = 7} <--- thats what is pretty much being read by the code when you use toPosition.

So again, because you clearly don't like to learn, I will explain it one more time.

Code:
addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition)

This calls doResetAnnihilator after the amount of time you put config.duration * 60 * 1000 with the parameter of toPosition

So now you have to make the function doResetAnnihilator.

When you make it

Code:
function doResetAnnihilator(toPosition)
end

You can put toPosition because you put it in the addEvent before. So the information is passed through to the function.

(thank god TFS developers did all the hard work because you don't understand even the simplest parts)

So now we know the function doResetAnnihilator know the POSITION OF THE LEVER because the position of the lever was set in toPosition.

Now just because the function knows a position doesn't mean it is going to do anything.

So then we tell it what to do with the position

Code:
function doResetAnnihilator(toPosition)
local item = Tile(toPosition):getItemById(itemIdOfLever)
end

Now you see we added a new line. So read what it is doing.....

Tile()

This is used to call a tiles data. Now the code doesn't know which tile. So because we saved the toPosition before we will use that position to tell
it what tile to call.

Tile(toPosition)

That tells the code what tile it is supposed to be doing what you want on. If you dont tell it IT DOESN'T KNOW.

Tile(toPosition):getItemId()

that is used to find an item on a tiles position. If the ITEM IS NOT ON THE TILE it will return false.

Since levers cannot be moved and cannot move on there own it isn't actually nessacary to make sure its there but we do anyway
because if for some reason the lever is removed we don't want an error in the console so we add:

Code:
function doResetAnnihilator(toPosition)
local item = Tile(toPosition):getItemById(itemIdOfLever)
if not item then return false end
end

so the line: if not item then return false end makes sure the item you specified by its itemid is there. Otherwise it just ends the code and doesn't throw an error.

That is how far people got you. Your code knows:
-Start the new function after the correct time -> doResetAnnihilator
-Send the correct information needed to find the lever -> toPosition
-Find the item in the new function
-Make sure the item exists so there are no errors

ALL YOU HAVE TO DO IS TELL THE ITEM TO TRANSFORM INTO THE ITEMID OF THE RESET LEVER....

I will give you a hint....

item:transform()
So i need to add item:transform(config.lever_id) above addEvent? Isnt it?
 
So i need to add item:transform(config.lever_id) above addEvent? Isnt it?
No. It can't be explained any better than what has already been done so I won't even try. Besides what they are explaining is what I have already updated in my original thread.

Make sure you use the most recent post I made on my thread (scroll to the complete bottom). Also make sure you have the configs lever_id set to the item id of BEFORE it is pulled. Then make sure the configs pulled_id is set to the item id of AFTER it is pulled. If you've done all this correctly then there is no reason this shouldn't work for you.
 
No. It can't be explained any better than what has already been done so I won't even try. Besides what they are explaining is what I have already updated in my original thread.

Make sure you use the most recent post I made on my thread (scroll to the complete bottom). Also make sure you have the configs lever_id set to the item id of BEFORE it is pulled. Then make sure the configs pulled_id is set to the item id of AFTER it is pulled. If you've done all this correctly then there is no reason this shouldn't work for you.
Ofc everything is same like in your latest update
LUA:
local config = {
    duration = 5, -- time till reset, in minutes
    level_req = 300, -- minimum level to do quest
    min_players = 4, -- minimum players to join quest
    lever_id = 1945, -- id of lever before pulled
    pulled_id = 1946 -- id of lever after pulled
}

local player_positions = {
    [1] = {fromPos = Position(543, 716, 7), toPos = Position(539, 762, 8)},
    [2] = {fromPos = Position(539, 717, 7), toPos = Position(554, 762, 8)},
    [3] = {fromPos = Position(547, 717, 7), toPos = Position(569, 762, 8)},
    [4] = {fromPos = Position(543, 721, 7), toPos = Position(585, 762, 8)}
}

local monsters = {
    [1] = {pos = Position(539, 772, 8), name = "Demon"},
    [2] = {pos = Position(554, 772, 8), name = "Demon"},
    [3] = {pos = Position(569, 772, 8), name = "Demon"},
    [4] = {pos = Position(585, 772, 8), name = "Demon"},
    [5] = {pos = Position(537, 802, 8), name = "Demon"},
    [6] = {pos = Position(552, 802, 8), name = "Demon"},
    [7] = {pos = Position(567, 802, 8), name = "Demon"},
    [8] = {pos = Position(583, 802, 8), name = "Demon"}
}

function doResetAnnihilator(position, cid_array)
    local tile = Tile(position)
    local item = tile and tile:getItemById(config.pulled_id)
    if not item then
        return
    end

    local monster_names = {}
    for key, value in pairs(monsters) do
        if not isInArray(monster_names, value.name) then
            monster_names[monster_names + 1] = value.name
        end
    end

    for i = 1, #monsters do
        local creatures = Tile(monsters[i].pos):getCreatures()
        for key, creature in pairs(creatures) do
            if isInArray(monster_names, creature:getName()) then
                creature:remove()
            end
        end
    end

    for i = 1, #player_positions do
        local creatures = Tile(player_positions[i].toPos):getCreatures()
        for key, creature in pairs(creatures) do
            if isInArray(monster_names, creature:getName()) then
                creature:remove()
            end
        end
    end

    item:transform(config.lever_id)
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.itemid ~= config.lever_id then
        return player:sendCancelMessage("The quest is currently in use. Cooldown is " .. config.duration .. " minutes.")
    end

    local participants, pull_player = {}, false
    for i = 1, #player_positions do
        local fromPos = player_positions[i].fromPos
        local tile = Tile(fromPos)
        if not tile then
            print(">> ERROR: Annihilator tile does not exist for Position(" .. fromPos.x .. ", " .. fromPos.y .. ", " .. fromPos.z .. ").")
            return player:sendCancelMessage("There is an issue with this quest. Please contact an administrator.")
        end

        local creature = tile:getBottomCreature()
        if creature then
            local participant = creature:getPlayer()
            if not participant then
                return player:sendCancelMessage(participant:getName() .. " is not a valid participant.")
            end

            if participant:getLevel() < config.level_req then
                return player:sendCancelMessage(participant:getName() .. " is not the required level.")
            end

            if participant.uid == player.uid then
                pull_player = true
            end

            participants[#participants + 1] = {participant = participant, toPos = player_positions[i].toPos}
        end
    end

    if #participants < config.min_players then
        return player:sendCancelMessage("You do not have the required amount of participants.")
    end

    if not pull_player then
        return player:sendCancelMessage("You are in the wrong position.")
    end

    for i = 1, #monsters do
        local toPos = monsters[i].pos
        if not Tile(toPos) then
            print(">> ERROR: Annihilator tile does not exist for Position(" .. toPos.x .. ", " .. toPos.y .. ", " .. toPos.z .. ").")
            return player:sendCancelMessage("There is an issue with this quest. Please contact an administrator.")
        end
        Game.createMonster(monsters[i].name, monsters[i].pos, false, true)
    end

    local cid_array = {}
    for i = 1, #participants do
        participants[i].participant:teleportTo(participants[i].toPos)
        participants[i].toPos:sendMagicEffect(CONST_ME_TELEPORT)
        cid_array[#cid_array + 1] = participants[i].participant.uid
    end

    item:transform(config.pulled_id)
    addEvent(doResetAnnihilator, config.duration * 60 * 1000, toPosition, cid_array)
    return true
end
 

Similar threads

Replies
1
Views
169
Back
Top