• 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.3 potions.lua heal over time & toxicity

Michael Orsino

Premium User
Premium User
Support Team
Joined
Nov 15, 2007
Messages
854
Solutions
10
Reaction score
389
Location
Santiago, Chile (Australian)
Warning this script crashes the server if a player dies while a potion is healing them. I will update this if I find a solution.

Hi guys

I hate Tibia instant-heal potions and I think they are part of why the actual gameplay of Tibia sucks so bad.
I'd rather slit my wrists than mash potion hotkeys 24/7.

Anyway, I changed the potions.lua script to apply over time (5 times, immediately and then once every 2 seconds). This doesn't achieve anything in itself though, as people will still just spam their potions if they can. So I introduced "toxicity".
Each potion has a toxicity value that applies on use. If your toxicity reaches >= 100 you lose 5 max HP. Quick note, you can force other players to drink potions - so watch out for that ;)
Potion healing stacks. Toxicity reduces by 1 per second.
I've only done a very basic test to see that the script works in principal. Might be some issues, who knows ;D

actions\scripts\other\potions.lua
Lua:
local toxicity = 24036
local toxTime = 24037

local berserk = Condition(CONDITION_ATTRIBUTES)
berserk:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
berserk:setParameter(CONDITION_PARAM_SKILL_MELEE, 5)
berserk:setParameter(CONDITION_PARAM_SKILL_SHIELD, -10)
berserk:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local mastermind = Condition(CONDITION_ATTRIBUTES)
mastermind:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
mastermind:setParameter(CONDITION_PARAM_STAT_MAGICPOINTS, 3)
mastermind:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local bullseye = Condition(CONDITION_ATTRIBUTES)
bullseye:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
bullseye:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 5)
bullseye:setParameter(CONDITION_PARAM_SKILL_SHIELD, -10)
bullseye:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local potions = {
    [6558] = {transform = {7588, 7589}, toxicity = 1, effect = CONST_ME_DRAWBLOOD},
    [7439] = {condition = berserk, toxicity = 1, vocations = {4, 8}, effect = CONST_ME_MAGIC_RED, description = "Only knights may drink this potion.", text = "You feel stronger."},
    [7440] = {condition = mastermind, toxicity = 1, vocations = {1, 2, 5, 6}, effect = CONST_ME_MAGIC_BLUE, description = "Only sorcerers and druids may drink this potion.", text = "You feel smarter."},
    [7443] = {condition = bullseye, toxicity = 1, vocations = {3, 7}, effect = CONST_ME_MAGIC_GREEN, description = "Only paladins may drink this potion.", text = "You feel more accurate."},
    [7588] = {health = {50, 70}, toxicity = 2, vocations = {3, 4, 7, 8}, level = 50, flask = 7634, description = "Only knights and paladins of level 50 or above may drink this fluid."},
    [7589] = {mana = {23, 37}, toxicity = 2, vocations = {1, 2, 3, 5, 6, 7}, level = 50, flask = 7634, description = "Only sorcerers, druids and paladins of level 50 or above may drink this fluid."},
    [7590] = {mana = {30, 50}, toxicity = 3, vocations = {1, 2, 5, 6}, level = 80, flask = 7635, toxicity = 3, description = "Only druids and sorcerers of level 80 or above may drink this fluid."},
    [7591] = {health = {85, 115}, toxicity = 3, vocations = {4, 8}, level = 80, flask = 7635, description = "Only knights of level 80 or above may drink this fluid."},
    [7618] = {health = {25, 35}, toxicity = 1, flask = 7636},
    [7620] = {mana = {15, 25}, flask = 7636, toxicity = 1},
    [8472] = {health = {50, 70}, mana = {20, 40}, toxicity = 3, vocations = {3, 7}, level = 80, flask = 7635, description = "Only paladins of level 80 or above may drink this fluid."},
    [8473] = {health = {130, 170}, toxicity = 4, vocations = {4, 8}, level = 130, flask = 7635, description = "Only knights of level 130 or above may drink this fluid."},
    [8474] = {antidote = true, toxicity = 1, flask = 7636},
    [8704] = {health = {12, 18}, toxicity = 1, flask = 7636},
    [26029] = {mana = {85, 115}, toxicity = 4, vocations = {1, 2, 5, 6}, level = 130, flask = 7635, description = "Only druids and sorcerers of level 130 or above may drink this fluid."},
    [26030] = {health = {84, 116}, mana = {250, 350}, toxicity = 4, vocations = {3, 7}, level = 130, flask = 7635, description = "Only paladins of level 130 or above may drink this fluid."},
    [26031] = {health = {175, 225}, toxicity = 5, vocations = {4, 8}, level = 200, flask = 7635, description = "Only knights of level 200 or above may drink this fluid."}
}

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if type(target) == "userdata" and not target:isPlayer() then
        return false
    end

    if target:getStorageValue(toxTime) < 0 then
        target:setStorageValue(toxTime, 0)
    end

    local potion = potions[item:getId()]
    if potion.level and player:getLevel() < potion.level or potion.vocations and not table.contains(potion.vocations, player:getVocation():getId()) then
        player:say(potion.description, TALKTYPE_MONSTER_SAY)
        return true
    end

    if potion.condition then
        player:addCondition(potion.condition)
        player:say(potion.text, TALKTYPE_MONSTER_SAY)
        player:getPosition():sendMagicEffect(potion.effect)
    elseif potion.transform then
        item:transform(potion.transform[math.random(#potion.transform)])
        item:getPosition():sendMagicEffect(potion.effect)
        return true
    else

        local function healthOverTime()
            doTargetCombatHealth(0, target, COMBAT_HEALING, potion.health[1], potion.health[2])
        end

        if potion.health then
            target:setStorageValue(toxicity, player:getStorageValue(toxicity) + potion.toxicity)
            doTargetCombatHealth(0, target, COMBAT_HEALING, potion.health[1], potion.health[2])
            for i = 2, 8, 2 do
                addEvent(healthOverTime,i * 1000)
            end
        end

        local function manaOverTime()
            doTargetCombatMana(0, target, potion.mana[1], potion.mana[2])
        end

        if potion.mana then
            target:setStorageValue(toxicity, player:getStorageValue(toxicity) + potion.toxicity)
            doTargetCombatMana(0, target, potion.mana[1], potion.mana[2])
            for i = 2, 8, 2 do
                addEvent(manaOverTime,i * 1000)
            end
        end

        if potion.antidote then
            target:removeCondition(CONDITION_POISON)
        end

        if target:getStorageValue(toxicity) >= 0 then
            t1 = target:getStorageValue(toxTime)
            t2 = os.time()
            target:setStorageValue(toxicity, target:getStorageValue(toxicity) - os.difftime(t2, t1))
            if target:getStorageValue(toxicity) < 0 then
                target:setStorageValue(toxicity, potion.toxicity)
            end
            target:setStorageValue(toxTime, os.time())
        end

        if target:getStorageValue(toxicity) >= 50 and player:getStorageValue(toxicity) <= 74  then
            target:sendTextMessage(MESSAGE_INFO_DESCR, "WARNING HIGH TOXICITY LEVELS")
        elseif target:getStorageValue(toxicity) >= 75 and player:getStorageValue(toxicity) <= 99 then
            target:sendTextMessage(MESSAGE_INFO_DESCR, "WARNING DANGEROUS TOXICITY LEVELS!")
        elseif target:getStorageValue(toxicity) >= 100 then
            target:setMaxHealth(player:getMaxHealth() - 5)
            target:sendTextMessage(MESSAGE_INFO_DESCR, "TOXICITY LEVELS CRITICAL - 5 MAXIMUM HP LOST")
            target:getPosition():sendMagicEffect(CONST_ME_DRAWBLOOD)
        end

        player:addItem(potion.flask)
        target:say("Aaaah...", TALKTYPE_MONSTER_SAY)
        target:sendTextMessage(MESSAGE_STATUS_DEFAULT, "Toxicity level " .. player:getStorageValue(toxicity))
        target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE)
    end

    item:remove(1)
    return true
end

If anybody uses this or something like it in production, i'd love to see it!


EDIT:
If you want to stop players from using potions in protection zones (so that AFK players can't have their toxicity raised to the point they have 0 max hp and die forever) you can use a code like this:
Lua:
    if (getTilePzInfo(getCreaturePosition(target))) then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You cannot use potions in Protection Zones")
        return false
    end

Kind regards,
Michael
 
Last edited:
Warning this script crashes the server if a player dies while a potion is healing them. I will update this if I find a solution.

Hi guys

I hate Tibia instant-heal potions and I think they are part of why the actual gameplay of Tibia sucks so bad.
I'd rather slit my wrists than mash potion hotkeys 24/7.

Anyway, I changed the potions.lua script to apply over time (5 times, immediately and then once every 2 seconds). This doesn't achieve anything in itself though, as people will still just spam their potions if they can. So I introduced "toxicity".
Each potion has a toxicity value that applies on use. If your toxicity reaches >= 100 you lose 5 max HP. Quick note, you can force other players to drink potions - so watch out for that ;)
Potion healing stacks. Toxicity reduces by 1 per second.
I've only done a very basic test to see that the script works in principal. Might be some issues, who knows ;D

actions\scripts\other\potions.lua
Lua:
local toxicity = 24036
local toxTime = 24037

local berserk = Condition(CONDITION_ATTRIBUTES)
berserk:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
berserk:setParameter(CONDITION_PARAM_SKILL_MELEE, 5)
berserk:setParameter(CONDITION_PARAM_SKILL_SHIELD, -10)
berserk:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local mastermind = Condition(CONDITION_ATTRIBUTES)
mastermind:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
mastermind:setParameter(CONDITION_PARAM_STAT_MAGICPOINTS, 3)
mastermind:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local bullseye = Condition(CONDITION_ATTRIBUTES)
bullseye:setParameter(CONDITION_PARAM_TICKS, 10 * 60 * 1000)
bullseye:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 5)
bullseye:setParameter(CONDITION_PARAM_SKILL_SHIELD, -10)
bullseye:setParameter(CONDITION_PARAM_BUFF_SPELL, true)

local potions = {
    [6558] = {transform = {7588, 7589}, toxicity = 1, effect = CONST_ME_DRAWBLOOD},
    [7439] = {condition = berserk, toxicity = 1, vocations = {4, 8}, effect = CONST_ME_MAGIC_RED, description = "Only knights may drink this potion.", text = "You feel stronger."},
    [7440] = {condition = mastermind, toxicity = 1, vocations = {1, 2, 5, 6}, effect = CONST_ME_MAGIC_BLUE, description = "Only sorcerers and druids may drink this potion.", text = "You feel smarter."},
    [7443] = {condition = bullseye, toxicity = 1, vocations = {3, 7}, effect = CONST_ME_MAGIC_GREEN, description = "Only paladins may drink this potion.", text = "You feel more accurate."},
    [7588] = {health = {50, 70}, toxicity = 2, vocations = {3, 4, 7, 8}, level = 50, flask = 7634, description = "Only knights and paladins of level 50 or above may drink this fluid."},
    [7589] = {mana = {23, 37}, toxicity = 2, vocations = {1, 2, 3, 5, 6, 7}, level = 50, flask = 7634, description = "Only sorcerers, druids and paladins of level 50 or above may drink this fluid."},
    [7590] = {mana = {30, 50}, toxicity = 3, vocations = {1, 2, 5, 6}, level = 80, flask = 7635, toxicity = 3, description = "Only druids and sorcerers of level 80 or above may drink this fluid."},
    [7591] = {health = {85, 115}, toxicity = 3, vocations = {4, 8}, level = 80, flask = 7635, description = "Only knights of level 80 or above may drink this fluid."},
    [7618] = {health = {25, 35}, toxicity = 1, flask = 7636},
    [7620] = {mana = {15, 25}, flask = 7636, toxicity = 1},
    [8472] = {health = {50, 70}, mana = {20, 40}, toxicity = 3, vocations = {3, 7}, level = 80, flask = 7635, description = "Only paladins of level 80 or above may drink this fluid."},
    [8473] = {health = {130, 170}, toxicity = 4, vocations = {4, 8}, level = 130, flask = 7635, description = "Only knights of level 130 or above may drink this fluid."},
    [8474] = {antidote = true, toxicity = 1, flask = 7636},
    [8704] = {health = {12, 18}, toxicity = 1, flask = 7636},
    [26029] = {mana = {85, 115}, toxicity = 4, vocations = {1, 2, 5, 6}, level = 130, flask = 7635, description = "Only druids and sorcerers of level 130 or above may drink this fluid."},
    [26030] = {health = {84, 116}, mana = {250, 350}, toxicity = 4, vocations = {3, 7}, level = 130, flask = 7635, description = "Only paladins of level 130 or above may drink this fluid."},
    [26031] = {health = {175, 225}, toxicity = 5, vocations = {4, 8}, level = 200, flask = 7635, description = "Only knights of level 200 or above may drink this fluid."}
}

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if type(target) == "userdata" and not target:isPlayer() then
        return false
    end

    if target:getStorageValue(toxTime) < 0 then
        target:setStorageValue(toxTime, 0)
    end

    local potion = potions[item:getId()]
    if potion.level and player:getLevel() < potion.level or potion.vocations and not table.contains(potion.vocations, player:getVocation():getId()) then
        player:say(potion.description, TALKTYPE_MONSTER_SAY)
        return true
    end

    if potion.condition then
        player:addCondition(potion.condition)
        player:say(potion.text, TALKTYPE_MONSTER_SAY)
        player:getPosition():sendMagicEffect(potion.effect)
    elseif potion.transform then
        item:transform(potion.transform[math.random(#potion.transform)])
        item:getPosition():sendMagicEffect(potion.effect)
        return true
    else

        local function healthOverTime()
            doTargetCombatHealth(0, target, COMBAT_HEALING, potion.health[1], potion.health[2])
        end

        if potion.health then
            target:setStorageValue(toxicity, player:getStorageValue(toxicity) + potion.toxicity)
            doTargetCombatHealth(0, target, COMBAT_HEALING, potion.health[1], potion.health[2])
            for i = 2, 8, 2 do
                addEvent(healthOverTime,i * 1000)
            end
        end

        local function manaOverTime()
            doTargetCombatMana(0, target, potion.mana[1], potion.mana[2])
        end

        if potion.mana then
            target:setStorageValue(toxicity, player:getStorageValue(toxicity) + potion.toxicity)
            doTargetCombatMana(0, target, potion.mana[1], potion.mana[2])
            for i = 2, 8, 2 do
                addEvent(manaOverTime,i * 1000)
            end
        end

        if potion.antidote then
            target:removeCondition(CONDITION_POISON)
        end

        if target:getStorageValue(toxicity) >= 0 then
            t1 = target:getStorageValue(toxTime)
            t2 = os.time()
            target:setStorageValue(toxicity, target:getStorageValue(toxicity) - os.difftime(t2, t1))
            if target:getStorageValue(toxicity) < 0 then
                target:setStorageValue(toxicity, potion.toxicity)
            end
            target:setStorageValue(toxTime, os.time())
        end

        if target:getStorageValue(toxicity) >= 50 and player:getStorageValue(toxicity) <= 74  then
            target:sendTextMessage(MESSAGE_INFO_DESCR, "WARNING HIGH TOXICITY LEVELS")
        elseif target:getStorageValue(toxicity) >= 75 and player:getStorageValue(toxicity) <= 99 then
            target:sendTextMessage(MESSAGE_INFO_DESCR, "WARNING DANGEROUS TOXICITY LEVELS!")
        elseif target:getStorageValue(toxicity) >= 100 then
            target:setMaxHealth(player:getMaxHealth() - 5)
            target:sendTextMessage(MESSAGE_INFO_DESCR, "TOXICITY LEVELS CRITICAL - 5 MAXIMUM HP LOST")
            target:getPosition():sendMagicEffect(CONST_ME_DRAWBLOOD)
        end

        player:addItem(potion.flask)
        target:say("Aaaah...", TALKTYPE_MONSTER_SAY)
        target:sendTextMessage(MESSAGE_STATUS_DEFAULT, "Toxicity level " .. player:getStorageValue(toxicity))
        target:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE)
    end

    item:remove(1)
    return true
end

If anybody uses this or something like it in production, i'd love to see it!


EDIT:
If you want to stop players from using potions in protection zones (so that AFK players can't have their toxicity raised to the point they have 0 max hp and die forever) you can use a code like this:
Lua:
    if (getTilePzInfo(getCreaturePosition(target))) then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You cannot use potions in Protection Zones")
        return false
    end

Kind regards,
Michael

in
Code:
healthOverTime
Check if player exist before execute rest of the function :)
 
in
Code:
healthOverTime
Check if player exist before execute rest of the function :)
Still will crash. Correct behaviour is to pass creature id and recreate userdata in function
 
I haven't had a chance to work on this yet, but Nekiro provided support for me on this on the premium support board.
With Nekiro's advice I was able to eliminate the crash issue, but never got around to fixing an additional error it throws after.
I'll try make time to fix it and update this thread soon.

The advice to fix the crash: Your target variable isnt defined in the function scope, if its invalid it will crash, you need to pass it as parameter to the function via addEvent
The advice to fix the error that occurs: Use creature id instead of userdata in event function and reconstruct the creature using local target = Creature(creatureId)
 
Back
Top