• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

C++ exhuset manarune hootkey

Darius93

Active Member
Joined
Oct 16, 2022
Messages
88
Reaction score
27
Hello – I still have a problem with the manarune...
I don’t know what else to say – my goal is simple: I want to be able to use rune SD (spells) and UH/manarune (actions) at the same time. The code I have works almost perfectly, but there’s one problem — when I press the hotkey for the manarune twice very quickly, it heals me twice in a very short time.


It’s like it heals twice per second, even though I’ve set the exhaust to 1 second.


This is the bug I really want to fix — I’d even be willing to pay for help with it.
It really matters to me because I just can’t figure it out myself.

my function action.cppC:
C++:
bool Actions::useItemEx(Player* player, const Position& fromPos, const Position& toPos,
    uint8_t toStackPos, Item* item, bool isHotkey, Creature* creature/* = nullptr*/)
{
    // Mikro-delay dla mana-run (żeby zabić dwuklik), normalny delay dla reszty
    static constexpr uint16_t MANA_RUNE_IDS[] = { 2270, 2272 }; // dopisz tu inne ID jeśli masz
    const uint16_t id = item->getID();
    const bool isManaRune = std::find(std::begin(MANA_RUNE_IDS), std::end(MANA_RUNE_IDS), id) != std::end(MANA_RUNE_IDS);

    if (isManaRune) {
        // minimalny exhaust na poziomie C++, wystarczy by zablokować 2 pakiety „pod rząd”
        player->setNextAction(OTSYS_TIME() + 50); // 50 ms
    }
    else {
        player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::EX_ACTIONS_DELAY_INTERVAL));
    }

    player->stopWalk();

    Action* action = getAction(item);
    if (!action) {
        player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
        return false;
    }

    ReturnValue ret = action->canExecuteAction(player, toPos);
    if (ret != RETURNVALUE_NOERROR) {
        player->sendCancelMessage(ret);
        return false;
    }

    if (isHotkey) {
        showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), -1));
    }

    if (!action->executeUse(player, item, fromPos, action->getTarget(player, creature, toPos, toStackPos), toPos, isHotkey)) {
        if (!action->hasOwnErrorHandler()) {
            player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
        }
        return false;
    }
    return true;
}

manarune:
LUA:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    -- tylko na graczy
    if not target or not target:isPlayer() then
        return true
    end

    -- akceptowane ID runy (dopasuj do swoich)
    local itemId = item:getId()
    if itemId ~= 2270 and itemId ~= 2272 then
        return false
    end


    -- EXHAUST: najpierw sprawdź, jeśli jest - przerwij
    if player:getExhaustion(54328) > 0 then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_YOUAREEXHAUSTED))
        player:getPosition():sendMagicEffect(CONST_ME_POFF)
        return false
    end

    -- USTAW EXHAUST OD RAZU (np. 1s)
    player:setExhaustion(54328, 1)

    -- obliczenia
    local min, max = 0, 0
    local minHp, maxHp = 0, 0

    local function safeBonus(pl)
        local b1 = getPlayerStorageValue(pl, 2001) or 0
        if b1 < 0 then b1 = 0 end
        local b2 = getPlayerStatsAttribute(pl, "bonushealing") or 0
        return (b1 or 0) + (b2 or 0)
    end
  
        -- funkcja progów leczenia many jak potki z RL
    local function getStaticManaRange(pl)
        local level = pl:getLevel()
        local voc = getPlayerVocation(pl)

        -- domyślnie: mana potion (dla wszystkich)
        local minM, maxM = 70, 130

        -- strong mana potion od 50 lvla (ED/MS/RP)
        if level >= 50 and (voc == 1 or voc == 2 or voc == 3 or voc == 5 or voc == 6 or voc == 7) then
            minM, maxM = 110, 190
        end

        -- great mana potion od 80 lvla (ED/MS)
        if level >= 80 and (voc == 1 or voc == 2 or voc == 5 or voc == 6) then
            minM, maxM = 200, 300
        end

        return minM, maxM
    end


    local voc = getPlayerVocation(target)
    if voc == 1 or voc == 2 or voc == 5 or voc == 6 then -- ED / MS
        local minn  = (target:getMaxMana() / 100) * 66.5
        local maxx  = (target:getMaxMana() / 100) * 66.5
        local bonus = safeBonus(target)
        local flatBonus = (getPlayerStorageValue(player, 90001) > 0 and getPlayerStorageValue(player, 90001) or 0)
        min = minn + (minn / 100 * bonus) + flatBonus
        max = maxx + (maxx / 100 * bonus) + flatBonus

    elseif voc == 3 or voc == 7 then -- RP
        local minn  = (target:getMaxMana() / 100) * 66.5
        local maxx  = (target:getMaxMana() / 100) * 66.5
        local bonus = safeBonus(target)
        local flatBonus = (getPlayerStorageValue(player, 90001) > 0 and getPlayerStorageValue(player, 90001) or 0)
        min = minn + (minn / 100 * bonus) + flatBonus
        max = maxx + (maxx / 100 * bonus) + flatBonus

        local minnHp  = (target:getMaxHealth() / 100) * 66.80
        local maxxHp  = (target:getMaxHealth() / 100) * 66.30
        local bonusHp = safeBonus(target)
        local flatBonus = (getPlayerStorageValue(player, 90001) > 0 and getPlayerStorageValue(player, 90001) or 0)
        minHp = -(minnHp + (minnHp / 100 * bonusHp)) + flatBonus
        maxHp = -(maxxHp + (maxxHp / 100 * bonusHp)) + flatBonus

    elseif voc == 4 or voc == 8 then -- EK
        local minn  = (target:getMaxMana() / 100) * 66.8
        local maxx  = (target:getMaxMana() / 100) * 66.0
        local bonus = safeBonus(target)
        local flatBonus = (getPlayerStorageValue(player, 90001) > 0 and getPlayerStorageValue(player, 90001) or 0)
        min = minn + (minn / 100 * bonus) + flatBonus
        max = maxx + (maxx / 100 * bonus) + flatBonus
    end
  
       -- teraz sprawdzamy progi z potków
    local staticMin, staticMax = getStaticManaRange(target)
    local bonus = safeBonus(target)
    local flatBonus = (getPlayerStorageValue(player, 90001) > 0 and getPlayerStorageValue(player, 90001) or 0)

    -- dodajemy bonusy do wartości z potków
    staticMin = staticMin + (staticMin / 100 * bonus) + flatBonus
    staticMax = staticMax + (staticMax / 100 * bonus) + flatBonus

    -- jeśli obliczony % heal jest mniejszy niż próg, użyj progu
    if min < staticMin then
        min = staticMin
    end
    if max < staticMax then
        max = staticMax
    end

    -- leczenie/doładowanie many
    if target == player then
        if voc == 3 or voc == 7 then
            -- Jeśli chcesz, możesz włączyć również leczenie HP dla RP:
            -- doTargetCombatHealth(0, target, COMBAT_HEALING, minHp, maxHp, CONST_ME_MAGIC_BLUE)
        end
        doTargetCombatMana(0, target, min, max, CONST_ME_MAGIC_BLUE)
    else
        -- na innych: połowa efektu
        if not doTargetCombatMana(0, target, min / 2, max / 2, CONST_ME_MAGIC_BLUE) then
            return false
        end
    end

    -- liczniki/achievementy
    local cnt = getPlayerStorageValue(target, 3766)
    if cnt < 0 then cnt = 0 end
    cnt = cnt + 1
    setPlayerStorageValue(target, 3766, cnt)
    if cnt == 6999 then
        doPlayerAddAchievement(Player(target), 41)
    end

    target:say("Aaaah...", TALKTYPE_MONSTER_SAY)

    -- zużycie ładunku
    if getConfigInfo('removeChargesFromRunes') == true then
        item:remove(1)
    end

    return true
end



my config.lua
LUA:
timeBetweenActions = 200
timeBetweenExActions = 1000



Best regards.
 
It depends on how getExhaustion and setExhaustion work. I'm assuming they set storage values with the expire time or something, but if they're using os.time then the granularity is seconds which is too coarse. Here is the timeline for best and worst case scenarios then:
Code:
-- BEST CASE SCENARIO
0.000 use manarune + set storage to (os.time() + 1) -> (0 + 1) -> 1
1.000 manarune is usable again

-- WORST CASE SCENARIO
0.999 use manarune + set storage to (os.time() + 1) -> (0 + 1) -> 1
1.000 manarune is usable again

Keep in mind that os.time() truncates the current time to seconds and there is a large margin of error. The best alternative would be to have OTSYS_TIME exposed to scripts which has millisecond granularity.
 
It depends on how getExhaustion and setExhaustion work. I'm assuming they set storage values with the expire time or something, but if they're using os.time then the granularity is seconds which is too coarse. Here is the timeline for best and worst case scenarios then:
Code:
-- BEST CASE SCENARIO
0.000 use manarune + set storage to (os.time() + 1) -> (0 + 1) -> 1
1.000 manarune is usable again

-- WORST CASE SCENARIO
0.999 use manarune + set storage to (os.time() + 1) -> (0 + 1) -> 1
1.000 manarune is usable again

Keep in mind that os.time() truncates the current time to seconds and there is a large margin of error. The best alternative would be to have OTSYS_TIME exposed to scripts which has millisecond granularity.
I did it like this:

LUA:
local serverStart = os.mtime()

function now()
    return os.mtime() - serverStart
end

function Player.setExhaustion(self, id, seconds)
    local expire = now() + (seconds * 1000)
    self:setStorageValue(id, expire)
end

function Player.getExhaustion(self, id)
    local storage = self:getStorageValue(id)

    if not storage or storage <= 0 then
        return 0
    end

    local diff = storage - now()


    if diff < 0 or diff > 10 * 1000 then
        self:setStorageValue(id, 0)
        return 0
    end

    return diff / 1000
end

function Player:hasExhaustion(id)
    return self:getExhaustion(id) > 0
end

And overall, it works — would you do it differently?
I’m using TFS, and I used to have it written a bit differently before.
It worked fine on Windows, but not on Ubuntu.

I don’t think I have OTSYS_TIME, right?
I’m using TFS 1.2.
 
Exhaust is a condition, create it and add it to the player that used your action, check for it at the entry, and voila.
If you want to have a separate exhaust condition, add it using example that is already in your engine.

Alternatively, you could expose/wrap player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::EX_ACTIONS_DELAY_INTERVAL)); and add it to the bottom of your script, it will delay all itemEx usage.

PS: Using LLMs at this stage will only hinder your learning and progress.
It will gaslight you into thinking that "killing double click" is something you want to do lol
You can start using it when you know better.
 
Last edited:
So, you mentioned TFS 1.2 and I confirmed that os.mtime uses OTSYS_TIME underneath which wouldn't explain this behaviour. Then you said it worked fine on Windows which makes me think whether it could be a problem with OTSYS_TIME, but it uses std::chrono::system_time and it should have sub millisecond granularity so again, it wouldn't explain this behaviour.

I'd personally add some prints to Player.getExhaustion and see what shows up in the console.
Code:
function Player.getExhaustion(self, id)
    local storage = self:getStorageValue(id)
    if not storage then
        return 0
    end

    local t = now()
    local diff = storage - t
    print("STORAGE", storage, "NOW", t, "DIFF", diff)
    if diff <= 0 then
        self:setStorageValue(id, 0)
        return 0
    end

    local result = diff / 1000
    print("RESULT", result)
    return result
end
 
So, you mentioned TFS 1.2 and I confirmed that os.mtime uses OTSYS_TIME underneath which wouldn't explain this behaviour. Then you said it worked fine on Windows which makes me think whether it could be a problem with OTSYS_TIME, but it uses std::chrono::system_time and it should have sub millisecond granularity so again, it wouldn't explain this behaviour.

I'd personally add some prints to Player.getExhaustion and see what shows up in the console.
Code:
function Player.getExhaustion(self, id)
    local storage = self:getStorageValue(id)
    if not storage then
        return 0
    end

    local t = now()
    local diff = storage - t
    print("STORAGE", storage, "NOW", t, "DIFF", diff)
    if diff <= 0 then
        self:setStorageValue(id, 0)
        return 0
    end

    local result = diff / 1000
    print("RESULT", result)
    return result
end
windows:
Code:
STORAGE 51552   NOW     55206   DIFF    -3654
STORAGE 56206   NOW     56508   DIFF    -302
STORAGE 57508   NOW     57509   DIFF    -1
STORAGE 58509   NOW     57758   DIFF    751
RESULT  0.751
STORAGE 58509   NOW     57941   DIFF    568
RESULT  0.568
STORAGE 58509   NOW     58041   DIFF    468
RESULT  0.468
STORAGE 58509   NOW     58143   DIFF    366
RESULT  0.366
STORAGE 58509   NOW     58310   DIFF    199
RESULT  0.199
STORAGE 58509   NOW     58441   DIFF    68
RESULT  0.068
STORAGE 58509   NOW     58560   DIFF    -51


ubuntu:
Code:
2025-10-31 10:43:11 -  RESULT    29.21
2025-10-31 10:43:11 -  STORAGE    47173    NOW    18371    DIFF    28802
2025-10-31 10:43:11 -  RESULT    28.802
2025-10-31 10:43:11 -  STORAGE    47173    NOW    18781    DIFF    28392
2025-10-31 10:43:11 -  RESULT    28.392
2025-10-31 10:43:11 -  STORAGE    47173    NOW    19189    DIFF    27984
2025-10-31 10:43:11 -  RESULT    27.984
2025-10-31 10:43:11 -  STORAGE    47173    NOW    19599    DIFF    27574
2025-10-31 10:43:11 -  RESULT    27.574
2025-10-31 10:43:11 -  STORAGE    47173    NOW    20003    DIFF    27170
2025-10-31 10:43:11 -  RESULT    27.17
2025-10-31 10:43:11 -  STORAGE    47173    NOW    20409    DIFF    26764
2025-10-31 10:43:11 -  RESULT    26.764
2025-10-31 10:43:11 -  STORAGE    49430    NOW    20524    DIFF    28906
2025-10-31 10:43:11 -  RESULT    28.906
2025-10-31 10:43:11 -  STORAGE    47173    NOW    20818    DIFF    26355
2025-10-31 10:43:11 -  RESULT    26.355
2025-10-31 10:43:11 -  STORAGE    49430    NOW    21001    DIFF    28429
2025-10-31 10:43:11 -  RESULT    28.429
2025-10-31 10:43:11 -  STORAGE    47173    NOW    21223    DIFF    25950
2025-10-31 10:43:11 -  RESULT    25.95
2025-10-31 10:43:11 -  STORAGE    47173    NOW    21631    DIFF    25542
2025-10-31 10:43:11 -  RESULT    25.542
2025-10-31 10:43:11 -  STORAGE    49430    NOW    21988    DIFF    27442
2025-10-31 10:43:11 -  RESULT    27.442
2025-10-31 10:43:11 -  STORAGE    47173    NOW    22037    DIFF    25136
2025-10-31 10:43:11 -  RESULT    25.136
Generally, on Windows it heals, but on Ubuntu there’s such an exhaust that it’s impossible to use mr.
 
For some reason the value stored on linux is way higher that it's supposed to be? The timestamps on the left also look suspicious. Is that timer even running or is the output buffered and these are systemd timestamps?

Try printing the values inside now():
LUA:
function now()
    local t = os.mtime()
    local result = t - serverStart
    print("T", t, "SERVERSTART", serverStart, "RESULT", result)
    return result
end
 
Lua numerical values are stored as doubles, and thus they allow numbers approaching 64 bit integer limits like our current time in ms, and it will work untill year ~2250 without precision loss ... but you are trying to store them, and storage value is only int32_t.

Why do you guys keep hacking when an obvious solution is to create a separate cooldown condition?
You want fine granularity? check
You want the behavior to be consistent with the rest of cooldowns? check
 
Last edited:
For some reason the value stored on linux is way higher that it's supposed to be? The timestamps on the left also look suspicious. Is that timer even running or is the output buffered and these are systemd timestamps?

Try printing the values inside now():
LUA:
function now()
    local t = os.mtime()
    local result = t - serverStart
    print("T", t, "SERVERSTART", serverStart, "RESULT", result)
    return result
end
Code:
2025-11-05 08:51:40 -  T    1762329097864    SERVERSTART    1762329091215    RESULT    6649
2025-11-05 08:51:40 -  T    1762329097865    SERVERSTART    1762329091215    RESULT    6650
2025-11-05 08:51:40 -  T    1762329100362    SERVERSTART    1762329091215    RESULT    9147
2025-11-05 08:51:40 -  T    1762329100363    SERVERSTART    1762329091215    RESULT    9148
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593

Lua numerical values are stored as doubles, and thus they allow numbers approaching 64 bit integer limits like our current time in ms, and it will work untill year ~2250 without precision loss ... but you are trying to store them, and storage value is only int32_t.

Why do you guys keep hacking when an obvious solution is to create a separate cooldown condition?
You want fine granularity? check
You want the behavior to be consistent with the rest of cooldowns? check
How would you do it? What do you mean by creating a separate condition?
 
Code:
2025-11-05 08:51:40 -  T    1762329097864    SERVERSTART    1762329091215    RESULT    6649
2025-11-05 08:51:40 -  T    1762329097865    SERVERSTART    1762329091215    RESULT    6650
2025-11-05 08:51:40 -  T    1762329100362    SERVERSTART    1762329091215    RESULT    9147
2025-11-05 08:51:40 -  T    1762329100363    SERVERSTART    1762329091215    RESULT    9148
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593
In Lua memory, it's gonna be ok since it's kept in double (precise to 2^53), but when you setStorage, it is cast to int32, which cannot store more than 2,147,483,647, and 1,762,329,091,215 is bigger than that.

How would you do it? What do you mean by creating a separate condition?
There is a ton of conditions already in your engine, you just repeat the pattern and add a new one ... and you don't even have to add any logic, just the condition (and its enum) alone. Alternatively you can use subid's.
Then you create this condition, add it to the player when he casts the rune, and keep on checking if it's still there on script entry.
 
Last edited:
I gave it some thought and realized something. The script is computing an uptime with now() which is usually correct for timers, since you'd want to avoid integer overflow/truncation when converting to a storage value. But the issue is that these values are only really comparable on a single server "session". To illustrate, if you have the server running for a minute and set an exhaust, it will store something like 60000. If you then restart it, the exhaust will remain 60000 which translates to ~1 minute after startup. If you waited 1hr, you'd have an exhaust of 1hr after restart, and so on...

There are two solutions here: using conditions or storing timers in a table. I'm not gonna argue which one is better so you may want to test both and see which one works best for you. The one difference I can tell is that timers in a Lua table aren't persistent across server restarts, whilst condition ticks are, when using CONDITIONID_DEFAULT or CONDITIONID_COMBAT.

CONDITIONS:
LUA:
local exhaustConditions = {}

function Player.setExhaustion(self, id, seconds)
    local condition = exhaustConditions[id]
    if not condition then
        condition = Condition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT)
        condition:setParameter(CONDITION_PARAM_SUBID, id)
        exhaustConditions[id] = condition
    end

    condition:setParameter(CONDITION_PARAM_TICKS, (seconds * 1000))
    self:addCondition(condition)
end

function Player.hasExhaustion(self, id)
    return self:getCondition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT, id) ~= nil
end

TIMER TABLE:
LUA:
local exhaustTimers = {}

function Player.setExhaustion(self, id, seconds)
    if not exhaustTimers[self:getGuid()] then
        exhaustTimers[self:getGuid()] = {}
    end
    exhaustTimers[self:getGuid()][id] = (seconds * 1000) + os.mtime()
end

function Player.hasExhaustion(self, id)
    local exhaustion = exhaustTimers[self:getGuid()]
            and exhaustTimers[self:getGuid()][id]
    return ((exhaustion or 0) - os.mtime()) > 0
end
 
Code:
2025-11-05 08:51:40 -  T    1762329097864    SERVERSTART    1762329091215    RESULT    6649
2025-11-05 08:51:40 -  T    1762329097865    SERVERSTART    1762329091215    RESULT    6650
2025-11-05 08:51:40 -  T    1762329100362    SERVERSTART    1762329091215    RESULT    9147
2025-11-05 08:51:40 -  T    1762329100363    SERVERSTART    1762329091215    RESULT    9148
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593
2025-11-05 08:51:40 -  T    1762329100808    SERVERSTART    1762329091215    RESULT    9593


How would you do it? What do you mean by creating a separate condition?

LUA:
local exhaust = Condition(CONDITION_EXHAUST)

exhaust:setParameter(CONDITION_PARAM_TICKS, 4000)



if player:getCondition(CONDITION_EXHAUST)then

            player:sendTextMessage(MESSAGE_STATUS_SMALL, "You are exhausted.")

            player:getPosition():sendMagicEffect(CONST_ME_POFF)

            return true

        end



player:addCondition(exhaust)
 
I gave it some thought and realized something. The script is computing an uptime with now() which is usually correct for timers, since you'd want to avoid integer overflow/truncation when converting to a storage value. But the issue is that these values are only really comparable on a single server "session". To illustrate, if you have the server running for a minute and set an exhaust, it will store something like 60000. If you then restart it, the exhaust will remain 60000 which translates to ~1 minute after startup. If you waited 1hr, you'd have an exhaust of 1hr after restart, and so on...

There are two solutions here: using conditions or storing timers in a table. I'm not gonna argue which one is better so you may want to test both and see which one works best for you. The one difference I can tell is that timers in a Lua table aren't persistent across server restarts, whilst condition ticks are, when using CONDITIONID_DEFAULT or CONDITIONID_COMBAT.

CONDITIONS:
LUA:
local exhaustConditions = {}

function Player.setExhaustion(self, id, seconds)
    local condition = exhaustConditions[id]
    if not condition then
        condition = Condition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT)
        condition:setParameter(CONDITION_PARAM_SUBID, id)
        exhaustConditions[id] = condition
    end

    condition:setParameter(CONDITION_PARAM_TICKS, (seconds * 1000))
    self:addCondition(condition)
end

function Player.hasExhaustion(self, id)
    return self:getCondition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT, id) ~= nil
end

TIMER TABLE:
LUA:
local exhaustTimers = {}

function Player.setExhaustion(self, id, seconds)
    if not exhaustTimers[self:getGuid()] then
        exhaustTimers[self:getGuid()] = {}
    end
    exhaustTimers[self:getGuid()][id] = (seconds * 1000) + os.mtime()
end

function Player.hasExhaustion(self, id)
    local exhaustion = exhaustTimers[self:getGuid()]
            and exhaustTimers[self:getGuid()][id]
    return ((exhaustion or 0) - os.mtime()) > 0
end
Not sure why you're still trying to stand with the timer tables, which lack persistence, but well :P

Aside from not using correct syntax, there are a couple of issues with your code @fusion32
As it's not going to be a bottleneck, your cache is a premature optimization.
Additionally, you overcomplicate it with additional Sub IDs when it's not required,
Keep it simple ;)
Also, your code lacks granularity, which is exactly why we are here

Correct solution:
LUA:
local luaExhaustSid = 1
function Player:setExhaust(milis)
    condition = Condition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT)
    condition:setParameter(CONDITION_PARAM_SUBID, luaExhaustSid)
    condition:setParameter(CONDITION_PARAM_TICKS, milis)
    self:addCondition(condition)
end

function Player:getExhaust()
    return self:getCondition(CONDITION_EXHAUST_COMBAT, CONDITIONID_COMBAT, luaExhaustSid)
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
  if player:getExhaust() then
    player:sendTextMessage(MESSAGE_STATUS_SMALL, "You are exhausted.")
    return true
  end
 
  print("hello")
  player:setExhaust(1500)
end
 
Last edited:
Back
Top