• 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+ how to optimize

ZeroSkyer

Member
Joined
May 17, 2019
Messages
62
Reaction score
9
Location
EEUU
Hello, I just launched the Valentine's Day event and almost the entire server uses exercise, the fact is that up to 40% of the cpu is used with that script, can someone help me optimize it? thanks in advance

Lua:
local skills = {
    [32384] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32385] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32386] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32387] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32388] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32389] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [32124] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32125] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32126] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32127] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32128] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32129] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40114] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40115] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40116] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40117] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40118] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40119] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40120] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40121] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40122] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40123] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40124] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40125] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE} -- SORCERER
}

local houseDummies = {32143, 32144, 32145, 32146, 32147, 32148}
local freeDummies = {32142, 32149}
local skillRateDefault = configManager.getNumber(configKeys.RATE_SKILL)
local magicRateDefault = configManager.getNumber(configKeys.RATE_MAGIC)

local function start_train(pid,start_pos,itemid,fpos, bonusDummy, dummyId)
    local player = Player(pid)
    if player ~= nil then
    if Tile(fpos):getItemById(dummyId) then
        local pos_n = player:getPosition()
        if start_pos:getDistance(pos_n) == 0 then
            if player:getItemCount(itemid) >= 1 then
                local exercise = player:getItemById(itemid,true)
                if exercise:isItem() then
                    if exercise:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                        local charges_n = exercise:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                        if charges_n > 1 then
                            --exercise:setAttribute(ITEM_ATTRIBUTE_CHARGES,(charges_n-1))

                            local voc = player:getVocation()

                            if skills[itemid].id == SKILL_MAGLEVEL then
                                local magicRate = getRateFromTable(magicLevelStages, player:getMagicLevel(), magicRateDefault)
                                if not bonusDummy then
                                    player:addManaSpent(math.ceil(500*magicRate))
                                else
                                    player:addManaSpent(math.ceil(500*magicRate)*1.1) -- 10%
                                end
                            else
                                local skillRate = getRateFromTable(skillsStages, player:getEffectiveSkillLevel(skills[itemid].id), skillRateDefault)
                                if not bonusDummy then
                                    player:addSkillTries(skills[itemid].id, 7*skillRate)
                                else
                                    player:addSkillTries(skills[itemid].id, (7*skillRate)*1.1) -- 10%
                                end
                            end
                                fpos:sendMagicEffect(CONST_ME_HITAREA)
                            if skills[itemid].range then
                                pos_n:sendDistanceEffect(fpos, skills[itemid].range)
                            end
                            local training = addEvent(start_train, voc:getAttackSpeed(), pid,start_pos,itemid,fpos,bonusDummy,dummyId)
                            player:setStorageValue(Storage.isTraining,1)
                        else
                            exercise:remove(1)
                            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training weapon vanished.")
                            stopEvent(training)
                            player:setStorageValue(Storage.isTraining,0)
                        end
                    end
                end
            end
        else
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
            stopEvent(training)
            player:setStorageValue(Storage.isTraining,0)
        end
    else
    stopEvent(training)
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
            player:setStorageValue(Storage.isTraining, 0)
            end
            else
        stopEvent(training)
        if player then
            player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
            player:setStorageValue(Storage.isTraining,0)
        end
    end
 
    return true
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local start_pos = player:getPosition()
    if player:getStorageValue(Storage.isTraining) == 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You are already training.")
        return false
    end
    if target:isItem() then
        if isInArray(houseDummies,target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(training)
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(player:getId(),start_pos,item.itemid,target:getPosition(), true, target:getId())
        elseif isInArray(freeDummies, target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(training)
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(player:getId(),start_pos,item.itemid,target:getPosition(), false, target:getId())
        end
    end
    return true
end
 
I'm not gonna re-write the whole script for you as I would honestly just start from scratch and I don't have your dummies on the map or any of that, which would require a whole bunch of work to test that it even works, but if you want to edit that for optimizations here are my suggestions.

1. stop using addevent. There is zero point in using it in this script as far as I can see.... instead use the custom function you already have and an onThink creaturescript to take care of ending it when its the correct time. This I believe would be your biggest consumer of cpu I do believe, having looked at this script.

2. Organize it to become more clear as to what is actually happening in each chunk. What I mean is, with all those else, elseif's you have, its hard to follow exactly whats going on so for example lets say you want to only execute certain code if this, else execute. You can take care of the first if, and then the next if, and the next all separately utilizing return, and then whatever is the last possible outcome on the if check, then that will only be reached if none of the other if's took place, example


Lua:
local config = {exit = 21212}

    function stepOff.onStepOut(player, item, position, fromPosition)
        if not player:isPlayer() then
            return true --- we returned when its not a player, rest doesn't execute
        end

        if not item:getUniqueId() == config.exit then
            return true --- we returned because the tile didn't have our unique id assigned
        end
      
        position:sendMagicEffect(CONST_ME_GREEN_RINGS) -- here it executes without the need of else, because we are still reading from the script
        return true
    end

Otherwise, every single time your script runs, it runs all the way thru, doing more checks that have nothing to do with it, when it could have ended already, if that makes sense.

3.Utilize feeding situational data from table to loops. These things are godsend when used correctly

4. Stop Using addevent and stopevent, pretty sure I said this already but I want to make sure if you took the time to read the whole thing, you understand my seriousness about using it, would be so much more "optimized" without that hogging up your resources with sooo many running, actual events are better than addevents...

TL:DR
Specifically line 68 is probably the major reason for your cpu, it starts another call for the function that its currently executing , and where it does it and how it does it, causes it to repeatedly create because there is nothing stopping it from doing so before it gets to that point, pretty sure its an infinite loop, but it kind of has to be there, because of the else's, need to re-write using oranization like I described above, see sample lua
 
Last edited:
I'm not gonna re-write the whole script for you as I would honestly just start from scratch and I don't have your dummies on the map or any of that, which would require a whole bunch of work to test that it even works, but if you want to edit that for optimizations here are my suggestions.

1. stop using addevent. There is zero point in using it in this script as far as I can see.... instead use the custom function you already have and an onThink creaturescript to take care of ending it when its the correct time. This I believe would be your biggest consumer of cpu I do believe, having looked at this script.

2. Organize it to become more clear as to what is actually happening in each chunk. What I mean is, with all those else, elseif's you have, its hard to follow exactly whats going on so for example lets say you want to only execute certain code if this, else execute. You can take care of the first if, and then the next if, and the next all separately utilizing return, and then whatever is the last possible outcome on the if check, then that will only be reached if none of the other if's took place, example


Lua:
local config = {exit = 21212}

    function stepOff.onStepOut(player, item, position, fromPosition)
        if not player:isPlayer() then
            return true --- we returned when its not a player, rest doesn't execute
        end

        if not item:getUniqueId() == config.exit then
            return true --- we returned because the tile didn't have our unique id assigned
        end
     
        position:sendMagicEffect(CONST_ME_GREEN_RINGS) -- here it executes without the need of else, because we are still reading from the script
        return true
    end

Otherwise, every single time your script runs, it runs all the way thru, doing more checks that have nothing to do with it, when it could have ended already, if that makes sense.

3.Utilize feeding situational data from table to loops. These things are godsend when used correctly

4. Stop Using addevent and stopevent, pretty sure I said this already but I want to make sure if you took the time to read the whole thing, you understand my seriousness about using it, would be so much more "optimized" without that hogging up your resources with sooo many running, actual events are better than addevents...

TL:DR
Specifically line 68 is probably the major reason for your cpu, it starts another call for the function that its currently executing , and where it does it and how it does it, causes it to repeatedly create because there is nothing stopping it from doing so before it gets to that point, pretty sure its an infinite loop, but it kind of has to be there, because of the else's, need to re-write using oranization like I described above, see sample lua
Thanks for your answer, i think someone was using wpe to make it fast and it was causing lag, i added a 10 second exhaust to re-train and the lag spikes went away but the cpu consumption is still high, i'm going to add the feature of tibia to limit the people who can train on a dummy so it is less common to use a lot of CPU. Ii don't think i can optimize it on my own right now since I don't have much knowledge, but I'm still learning, thanks!
 
I checked the script and there was no mechanism to stop the events, so I fixed it for you.
I'm still not sure if it fixes your CPU problem, I don't really understand why you suffer from this problem, but at least they will no longer be able to take advantage of the bug you had

Lua:
local skills = {
    [32384] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32385] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32386] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32387] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32388] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32389] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [32124] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32125] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32126] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32127] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32128] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32129] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40114] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40115] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40116] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40117] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40118] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40119] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40120] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40121] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40122] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40123] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40124] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40125] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE} -- SORCERER
}

local houseDummies = {32143, 32144, 32145, 32146, 32147, 32148}
local freeDummies = {32142, 32149}
local skillRateDefault = configManager.getNumber(configKeys.RATE_SKILL)
local magicRateDefault = configManager.getNumber(configKeys.RATE_MAGIC)
local eventIDs = {}

local function start_train(pid,start_pos,itemid,fpos, bonusDummy, dummyId)
    local player = Player(pid)
    if not player then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        return
    end

    if not Tile(fpos):getItemById(dummyId) then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        player:setStorageValue(Storage.isTraining, 0)
        return
    end

    local pos_n = player:getPosition()
    if start_pos:getDistance(pos_n) > 0 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:setStorageValue(Storage.isTraining,0)
        return
    end

    if player:getItemCount(itemid) >= 1 then
        local exercise = player:getItemById(itemid,true)
        if exercise:isItem() then
            if exercise:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local charges_n = exercise:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if charges_n > 1 then
                    --exercise:setAttribute(ITEM_ATTRIBUTE_CHARGES,(charges_n-1))
                    local voc = player:getVocation()
                    if skills[itemid].id == SKILL_MAGLEVEL then
                        local magicRate = getRateFromTable(magicLevelStages, player:getMagicLevel(), magicRateDefault)
                        if not bonusDummy then
                            player:addManaSpent(math.ceil(500*magicRate))
                        else
                            player:addManaSpent(math.ceil(500*magicRate)*1.1) -- 10%
                        end
                    else
                        local skillRate = getRateFromTable(skillsStages, player:getEffectiveSkillLevel(skills[itemid].id), skillRateDefault)
                        if not bonusDummy then
                            player:addSkillTries(skills[itemid].id, 7*skillRate)
                        else
                            player:addSkillTries(skills[itemid].id, (7*skillRate)*1.1) -- 10%
                        end
                    end
                        fpos:sendMagicEffect(CONST_ME_HITAREA)
                    if skills[itemid].range then
                        pos_n:sendDistanceEffect(fpos, skills[itemid].range)
                    end
                    eventIDs[pid] = addEvent(start_train, voc:getAttackSpeed(), pid,start_pos,itemid,fpos,bonusDummy,dummyId)
                    player:setStorageValue(Storage.isTraining,1)
                else
                    exercise:remove(1)
                    player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training weapon vanished.")
                    stopEvent(eventIDs[pid])
                    eventIDs[pid] = nil
                    player:setStorageValue(Storage.isTraining,0)
                end
            end
        end
    end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local start_pos = player:getPosition()
    if player:getStorageValue(Storage.isTraining) == 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You are already training.")
        return false
    end

    if target:isItem() then
        local pid = player:getId()
        if isInArray(houseDummies,target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), true, target:getId())
        elseif isInArray(freeDummies, target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), false, target:getId())
        end
    end
    return true
end
 
I checked the script and there was no mechanism to stop the events, so I fixed it for you.
I'm still not sure if it fixes your CPU problem, I don't really understand why you suffer from this problem, but at least they will no longer be able to take advantage of the bug you had

Lua:
local skills = {
    [32384] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32385] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32386] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32387] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32388] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32389] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [32124] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32125] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32126] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32127] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32128] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32129] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40114] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40115] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40116] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40117] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40118] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40119] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40120] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40121] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40122] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40123] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40124] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40125] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE} -- SORCERER
}

local houseDummies = {32143, 32144, 32145, 32146, 32147, 32148}
local freeDummies = {32142, 32149}
local skillRateDefault = configManager.getNumber(configKeys.RATE_SKILL)
local magicRateDefault = configManager.getNumber(configKeys.RATE_MAGIC)
local eventIDs = {}

local function start_train(pid,start_pos,itemid,fpos, bonusDummy, dummyId)
    local player = Player(pid)
    if not player then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        return
    end

    if not Tile(fpos):getItemById(dummyId) then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        player:setStorageValue(Storage.isTraining, 0)
        return
    end

    local pos_n = player:getPosition()
    if start_pos:getDistance(pos_n) > 0 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:setStorageValue(Storage.isTraining,0)
        return
    end

    if player:getItemCount(itemid) >= 1 then
        local exercise = player:getItemById(itemid,true)
        if exercise:isItem() then
            if exercise:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local charges_n = exercise:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if charges_n > 1 then
                    --exercise:setAttribute(ITEM_ATTRIBUTE_CHARGES,(charges_n-1))
                    local voc = player:getVocation()
                    if skills[itemid].id == SKILL_MAGLEVEL then
                        local magicRate = getRateFromTable(magicLevelStages, player:getMagicLevel(), magicRateDefault)
                        if not bonusDummy then
                            player:addManaSpent(math.ceil(500*magicRate))
                        else
                            player:addManaSpent(math.ceil(500*magicRate)*1.1) -- 10%
                        end
                    else
                        local skillRate = getRateFromTable(skillsStages, player:getEffectiveSkillLevel(skills[itemid].id), skillRateDefault)
                        if not bonusDummy then
                            player:addSkillTries(skills[itemid].id, 7*skillRate)
                        else
                            player:addSkillTries(skills[itemid].id, (7*skillRate)*1.1) -- 10%
                        end
                    end
                        fpos:sendMagicEffect(CONST_ME_HITAREA)
                    if skills[itemid].range then
                        pos_n:sendDistanceEffect(fpos, skills[itemid].range)
                    end
                    eventIDs[pid] = addEvent(start_train, voc:getAttackSpeed(), pid,start_pos,itemid,fpos,bonusDummy,dummyId)
                    player:setStorageValue(Storage.isTraining,1)
                else
                    exercise:remove(1)
                    player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training weapon vanished.")
                    stopEvent(eventIDs[pid])
                    eventIDs[pid] = nil
                    player:setStorageValue(Storage.isTraining,0)
                end
            end
        end
    end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local start_pos = player:getPosition()
    if player:getStorageValue(Storage.isTraining) == 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You are already training.")
        return false
    end

    if target:isItem() then
        local pid = player:getId()
        if isInArray(houseDummies,target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), true, target:getId())
        elseif isInArray(freeDummies, target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), false, target:getId())
        end
    end
    return true
[/QUOTE]
Thanks, I'll test it tomorrow on the online server
 
I checked the script and there was no mechanism to stop the events, so I fixed it for you.
I'm still not sure if it fixes your CPU problem, I don't really understand why you suffer from this problem, but at least they will no longer be able to take advantage of the bug you had

Lua:
local skills = {
    [32384] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32385] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32386] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32387] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32388] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32389] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [32124] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [32125] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [32126] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [32127] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [32128] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [32129] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40114] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40115] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40116] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40117] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40118] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40119] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE}, -- SORCERER
    [40120] = {id=SKILL_SWORD,voc=4}, -- KNIGHT
    [40121] = {id=SKILL_AXE,voc=4}, -- KNIGHT
    [40122] = {id=SKILL_CLUB,voc=4}, -- KNIGHT
    [40123] = {id=SKILL_DISTANCE,voc=3,range=CONST_ANI_SIMPLEARROW}, -- PALADIN
    [40124] = {id=SKILL_MAGLEVEL,voc=2,range=CONST_ANI_SMALLICE}, -- DRUID
    [40125] = {id=SKILL_MAGLEVEL,voc=1,range=CONST_ANI_FIRE} -- SORCERER
}

local houseDummies = {32143, 32144, 32145, 32146, 32147, 32148}
local freeDummies = {32142, 32149}
local skillRateDefault = configManager.getNumber(configKeys.RATE_SKILL)
local magicRateDefault = configManager.getNumber(configKeys.RATE_MAGIC)
local eventIDs = {}

local function start_train(pid,start_pos,itemid,fpos, bonusDummy, dummyId)
    local player = Player(pid)
    if not player then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        return
    end

    if not Tile(fpos):getItemById(dummyId) then
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        player:setStorageValue(Storage.isTraining, 0)
        return
    end

    local pos_n = player:getPosition()
    if start_pos:getDistance(pos_n) > 0 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training has stopped.")
        stopEvent(eventIDs[pid])
        eventIDs[pid] = nil
        player:setStorageValue(Storage.isTraining,0)
        return
    end

    if player:getItemCount(itemid) >= 1 then
        local exercise = player:getItemById(itemid,true)
        if exercise:isItem() then
            if exercise:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then
                local charges_n = exercise:getAttribute(ITEM_ATTRIBUTE_CHARGES)
                if charges_n > 1 then
                    --exercise:setAttribute(ITEM_ATTRIBUTE_CHARGES,(charges_n-1))
                    local voc = player:getVocation()
                    if skills[itemid].id == SKILL_MAGLEVEL then
                        local magicRate = getRateFromTable(magicLevelStages, player:getMagicLevel(), magicRateDefault)
                        if not bonusDummy then
                            player:addManaSpent(math.ceil(500*magicRate))
                        else
                            player:addManaSpent(math.ceil(500*magicRate)*1.1) -- 10%
                        end
                    else
                        local skillRate = getRateFromTable(skillsStages, player:getEffectiveSkillLevel(skills[itemid].id), skillRateDefault)
                        if not bonusDummy then
                            player:addSkillTries(skills[itemid].id, 7*skillRate)
                        else
                            player:addSkillTries(skills[itemid].id, (7*skillRate)*1.1) -- 10%
                        end
                    end
                        fpos:sendMagicEffect(CONST_ME_HITAREA)
                    if skills[itemid].range then
                        pos_n:sendDistanceEffect(fpos, skills[itemid].range)
                    end
                    eventIDs[pid] = addEvent(start_train, voc:getAttackSpeed(), pid,start_pos,itemid,fpos,bonusDummy,dummyId)
                    player:setStorageValue(Storage.isTraining,1)
                else
                    exercise:remove(1)
                    player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training weapon vanished.")
                    stopEvent(eventIDs[pid])
                    eventIDs[pid] = nil
                    player:setStorageValue(Storage.isTraining,0)
                end
            end
        end
    end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local start_pos = player:getPosition()
    if player:getStorageValue(Storage.isTraining) == 1 then
        player:sendTextMessage(MESSAGE_INFO_DESCR, "You are already training.")
        return false
    end

    if target:isItem() then
        local pid = player:getId()
        if isInArray(houseDummies,target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), true, target:getId())
        elseif isInArray(freeDummies, target:getId()) then
            if not skills[item.itemid].range and (start_pos:getDistance(target:getPosition()) > 1) then
                player:sendTextMessage(MESSAGE_INFO_DESCR, "Get closer to the dummy.")
                stopEvent(eventIDs[pid])
                eventIDs[pid] = nil
                return true
            end
            player:sendTextMessage(MESSAGE_INFO_DESCR, "You started training.")
            start_train(pid,start_pos,item.itemid,target:getPosition(), false, target:getId())
        end
    end
    return true
end
These last days I have seen that the onStorageUpdate function of player.lua has been higher than normal so I added a logger to the function to know which players used it the most and all are using exercise or used exercise recently (as if it were a loop ). Do you know what it could be?
 
Back
Top