• 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!

Help stamina training online

robertorb12

New Member
Joined
Jan 15, 2020
Messages
65
Reaction score
3
Hello, i want to implement that when attacking a monster (in this case training monk) give 1 min of stamina every 3 minutes hitting him

Can somebody help me? đź‘Ť
 
Solution
Here's the code if anyone want/needs it.
register to the creature only, not login.lua

data/monsters/training_monk.xml [under immunities]
XML:
<script>
    <event name="onStatsChange_staminaTraining"/>
</script>
data/creaturescripts/creaturescripts.xml
XML:
<event type="statschange" name="onStatsChange_staminaTraining" event="script" value="onStatsChange_staminaTraining.lua"/>
data/creaturescripts/scripts/onStatsChange_staminaTraining.lua
Lua:
local creatures = {}
local config = {
    timer = 180, -- time in seconds, before you gain stamina while hitting monster_name
    monster_name = "training monk",
    stamina_gain = 1, -- amount to gain after time elapse.
    threshold = 1000 -- how tight a timer before script...

I already tried it but I don't understand how this part should go:

Code:
--in the function--


Creature:onTargetCombat(target)

--under the last return true--

 if self:isPlayer() then
        if target and target:getName() == staminaBonus.target then
            local name = self:getName()
            if not staminaBonus.events[name] then
                staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
            end
        end
       end

How should that code be?
 
in data\events\scripts\creature.lua you should find
Lua:
function Creature:onTargetCombat(target)
then under it, at the end of the function it should be return true before this add
Lua:
 if self:isPlayer() then
        if target and target:getName() == staminaBonus.target then
            local name = self:getName()
            if not staminaBonus.events[name] then
                staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
            end
        end
       end
This is how it should look like, I added to main TFS creatue.lua
Lua:
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return RETURNVALUE_NOERROR
end

 -- HERE TRAINER ONLINE
local staminaBonus = {
    target ='TRAINER NAME',
    period = 180000, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end

function Creature:onTargetCombat(target)
 if self:isPlayer() then
        if target and target:getName() == staminaBonus.target then
            local name = self:getName()
            if not staminaBonus.events[name] then
                staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
            end
        end
       end
    return RETURNVALUE_NOERROR
end
 
Last edited:
in data\events\scripts\creature.lua you should find
Lua:
function Creature:onTargetCombat(target)
then under it, at the end of the function it should be return true before this add
Lua:
 if self:isPlayer() then
        if target and target:getName() == staminaBonus.target then
            local name = self:getName()
            if not staminaBonus.events[name] then
                staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
            end
        end
       end
This is how it should look like, I added to main TFS creatue.lua
Lua:
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return RETURNVALUE_NOERROR
end

-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='TRAINER NAME',
    period = 180000, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end

function Creature:onTargetCombat(target)
if self:isPlayer() then
        if target and target:getName() == staminaBonus.target then
            local name = self:getName()
            if not staminaBonus.events[name] then
                staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
            end
        end
       end
    return RETURNVALUE_NOERROR
end

[Warning - Events::load] Can not load script: creature.lua
data/events/scripts/creature.lua:153: <eof> expected near 'end'

there is my creature.lua;
Code:
__picif = {}
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return true
end
-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='Training Monk',
    period = 1, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end
-- Prey slots consumption
local function preyTimeLeft(player, slot)
    local timeLeft = player:getPreyTimeLeft(slot) / 60
    local monster = player:getPreyCurrentMonster(slot)
    if (timeLeft > 0) then
        local playerId = player:getId()
        local currentTime = os.time()
        local timePassed = currentTime - nextPreyTime[playerId][slot]
        if timePassed > 59 then
            timeLeft = timeLeft - 1
            nextPreyTime[playerId][slot] = currentTime + 60
        else
            timeLeft = 0
        end
        -- Expiring prey as there's no timeLeft
        if (timeLeft == 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
            player:setPreyCurrentMonster(slot, "")
        end
        -- Setting new timeLeft
        player:setPreyTimeLeft(slot, timeLeft * 60)
    else
        -- Expiring prey as there's no timeLeft
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
        player:setPreyCurrentMonster(slot, "")
    end
    return player:sendPreyData(slot)
end

local function removeCombatProtection(cid)
    local player = Player(cid)
    if not player then
        return true
    end

    local time = 0
    if player:isMage() then
        time = 10
    elseif player:isPaladin() then
        time = 20
    else
        time = 30
    end

    player:setStorageValue(Storage.combatProtectionStorage, 2)
    addEvent(function(cid)
        local player = Player(cid)
        if not player then
            return
        end

        player:setStorageValue(Storage.combatProtectionStorage, 0)
        player:remove()
    end, time * 1000, cid)
end

function Creature:onTargetCombat(target)
    if self:isPlayer() then
           if target and target:getName() == staminaBonus.target then
               local name = self:getName()
               if not staminaBonus.events[name] then
                   staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
               end
           end
          end
       return RETURNVALUE_NOERROR
   end

    if not __picif[target.uid] then
        if target:isMonster() then
            target:registerEvent("RewardSystemSlogan")
            __picif[target.uid] = {}
        end
    end

    if target:isPlayer() then
        if self:isMonster() then
            local protectionStorage = target:getStorageValue(Storage.combatProtectionStorage)

            if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
                if target:isPzLocked() then end
                if protectionStorage <= 0 then
                    addEvent(removeCombatProtection, 30 * 1000, target.uid)
                    target:setStorageValue(Storage.combatProtectionStorage, 1)
                elseif protectionStorage == 1 then
                    self:searchTarget()
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end

                return true
            end

            if protectionStorage >= os.time() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end

    if ((target:isMonster() and self:isPlayer() and target:getType():isPet() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getType():isPet() and self:getMaster() == target)) then
        return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
    end

    if PARTY_PROTECTION ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            local party = self:getParty()
            if party then
                local targetParty = target:getParty()
                if targetParty and targetParty == party then
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end
            end
        end
    end

    if ADVANCED_SECURE_MODE ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            if self:hasSecureMode() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end
    return true
end

function Creature:onDrainHealth(attacker, typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary)
    if (not self) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    if (not attacker) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    -- New prey => Bonus damage
    if (attacker:isPlayer()) then
        if (self:isMonster() and not self:getMaster()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (attacker:getPreyCurrentMonster(slot) == self:getName() and attacker:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_BOOST) then
                    damagePrimary = damagePrimary + math.floor(damagePrimary * (attacker:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    -- New prey => Damage reduction
    elseif (attacker:isMonster()) then
        if (self:isPlayer()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (self:getPreyCurrentMonster(slot) == attacker:getName() and self:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_REDUCTION) then
                    damagePrimary = damagePrimary - math.floor(damagePrimary * (self:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    end

    return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
end
 
Try this one
Lua:
__picif = {}
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return true
end
-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='Training Monk',
    period = 1, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end
-- Prey slots consumption
local function preyTimeLeft(player, slot)
    local timeLeft = player:getPreyTimeLeft(slot) / 60
    local monster = player:getPreyCurrentMonster(slot)
    if (timeLeft > 0) then
        local playerId = player:getId()
        local currentTime = os.time()
        local timePassed = currentTime - nextPreyTime[playerId][slot]
        if timePassed > 59 then
            timeLeft = timeLeft - 1
            nextPreyTime[playerId][slot] = currentTime + 60
        else
            timeLeft = 0
        end
        -- Expiring prey as there's no timeLeft
        if (timeLeft == 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
            player:setPreyCurrentMonster(slot, "")
        end
        -- Setting new timeLeft
        player:setPreyTimeLeft(slot, timeLeft * 60)
    else
        -- Expiring prey as there's no timeLeft
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
        player:setPreyCurrentMonster(slot, "")
    end
    return player:sendPreyData(slot)
end

local function removeCombatProtection(cid)
    local player = Player(cid)
    if not player then
        return true
    end

    local time = 0
    if player:isMage() then
        time = 10
    elseif player:isPaladin() then
        time = 20
    else
        time = 30
    end

    player:setStorageValue(Storage.combatProtectionStorage, 2)
    addEvent(function(cid)
        local player = Player(cid)
        if not player then
            return
        end

        player:setStorageValue(Storage.combatProtectionStorage, 0)
        player:remove()
    end, time * 1000, cid)
end

function Creature:onTargetCombat(target)
    if self then
    if self:isPlayer() then
           if target and target:getName() == staminaBonus.target then
               local name = self:getName()
               if not staminaBonus.events[name] then
                   staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
               end
           end
          end
          end
       return RETURNVALUE_NOERROR
   end

    if not __picif[target.uid] then
        if target:isMonster() then
            target:registerEvent("RewardSystemSlogan")
            __picif[target.uid] = {}
        end
    end

    if target:isPlayer() then
        if self:isMonster() then
            local protectionStorage = target:getStorageValue(Storage.combatProtectionStorage)

            if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
                if target:isPzLocked() then end
                if protectionStorage <= 0 then
                    addEvent(removeCombatProtection, 30 * 1000, target.uid)
                    target:setStorageValue(Storage.combatProtectionStorage, 1)
                elseif protectionStorage == 1 then
                    self:searchTarget()
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end

                return true
            end

            if protectionStorage >= os.time() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end

    if ((target:isMonster() and self:isPlayer() and target:getType():isPet() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getType():isPet() and self:getMaster() == target)) then
        return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
    end

    if PARTY_PROTECTION ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            local party = self:getParty()
            if party then
                local targetParty = target:getParty()
                if targetParty and targetParty == party then
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end
            end
        end
    end

    if ADVANCED_SECURE_MODE ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            if self:hasSecureMode() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    return true
end

function Creature:onDrainHealth(attacker, typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary)
    if (not self) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    if (not attacker) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    -- New prey => Bonus damage
    if (attacker:isPlayer()) then
        if (self:isMonster() and not self:getMaster()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (attacker:getPreyCurrentMonster(slot) == self:getName() and attacker:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_BOOST) then
                    damagePrimary = damagePrimary + math.floor(damagePrimary * (attacker:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    -- New prey => Damage reduction
    elseif (attacker:isMonster()) then
        if (self:isPlayer()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (self:getPreyCurrentMonster(slot) == attacker:getName() and self:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_REDUCTION) then
                    damagePrimary = damagePrimary - math.floor(damagePrimary * (self:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    end

    return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
end
 
Last edited:
Try this one
Lua:
__picif = {}
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return true
end
-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='Training Monk',
    period = 1, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end
-- Prey slots consumption
local function preyTimeLeft(player, slot)
    local timeLeft = player:getPreyTimeLeft(slot) / 60
    local monster = player:getPreyCurrentMonster(slot)
    if (timeLeft > 0) then
        local playerId = player:getId()
        local currentTime = os.time()
        local timePassed = currentTime - nextPreyTime[playerId][slot]
        if timePassed > 59 then
            timeLeft = timeLeft - 1
            nextPreyTime[playerId][slot] = currentTime + 60
        else
            timeLeft = 0
        end
        -- Expiring prey as there's no timeLeft
        if (timeLeft == 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
            player:setPreyCurrentMonster(slot, "")
        end
        -- Setting new timeLeft
        player:setPreyTimeLeft(slot, timeLeft * 60)
    else
        -- Expiring prey as there's no timeLeft
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
        player:setPreyCurrentMonster(slot, "")
    end
    return player:sendPreyData(slot)
end

local function removeCombatProtection(cid)
    local player = Player(cid)
    if not player then
        return true
    end

    local time = 0
    if player:isMage() then
        time = 10
    elseif player:isPaladin() then
        time = 20
    else
        time = 30
    end

    player:setStorageValue(Storage.combatProtectionStorage, 2)
    addEvent(function(cid)
        local player = Player(cid)
        if not player then
            return
        end

        player:setStorageValue(Storage.combatProtectionStorage, 0)
        player:remove()
    end, time * 1000, cid)
end

function Creature:onTargetCombat(target)
    if self:isPlayer() then
           if target and target:getName() == staminaBonus.target then
               local name = self:getName()
               if not staminaBonus.events[name] then
                   staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
               end
           end
          end
       return RETURNVALUE_NOERROR
   end

    if not __picif[target.uid] then
        if target:isMonster() then
            target:registerEvent("RewardSystemSlogan")
            __picif[target.uid] = {}
        end
    end

    if target:isPlayer() then
        if self:isMonster() then
            local protectionStorage = target:getStorageValue(Storage.combatProtectionStorage)

            if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
                if target:isPzLocked() then end
                if protectionStorage <= 0 then
                    addEvent(removeCombatProtection, 30 * 1000, target.uid)
                    target:setStorageValue(Storage.combatProtectionStorage, 1)
                elseif protectionStorage == 1 then
                    self:searchTarget()
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end

                return true
            end

            if protectionStorage >= os.time() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end

    if ((target:isMonster() and self:isPlayer() and target:getType():isPet() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getType():isPet() and self:getMaster() == target)) then
        return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
    end

    if PARTY_PROTECTION ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            local party = self:getParty()
            if party then
                local targetParty = target:getParty()
                if targetParty and targetParty == party then
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end
            end
        end
    end

    if ADVANCED_SECURE_MODE ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            if self:hasSecureMode() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    return true
end

function Creature:onDrainHealth(attacker, typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary)
    if (not self) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    if (not attacker) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    -- New prey => Bonus damage
    if (attacker:isPlayer()) then
        if (self:isMonster() and not self:getMaster()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (attacker:getPreyCurrentMonster(slot) == self:getName() and attacker:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_BOOST) then
                    damagePrimary = damagePrimary + math.floor(damagePrimary * (attacker:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    -- New prey => Damage reduction
    elseif (attacker:isMonster()) then
        if (self:isPlayer()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (self:getPreyCurrentMonster(slot) == attacker:getName() and self:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_REDUCTION) then
                    damagePrimary = damagePrimary - math.floor(damagePrimary * (self:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    end

    return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
end
Lua Script Error: [Event Interface]
data/events/scripts/creature.lua:Creature@onTargetCombat
data/events/scripts/creature.lua:88: attempt to index local 'self' (a nil value)
stack traceback:
[C]: in function '__index'
data/events/scripts/creature.lua:88: in function <data/events/scripts/creature.lua:87>


potions were not used with that
 
What error are you getting when using the potions? retry it I made small edit.
 
What error are you getting when using the potions? retry it I made small edit.

Lua Script Error: [Event Interface]
data/events/scripts/creature.lua
data/events/scripts/creature.lua:101: attempt to index global 'target' (a nil value)
stack traceback:
[C]: in function '__index'
data/events/scripts/creature.lua:101: in main chunk
[C]: in function 'reload'
...rometheus Server/data/scripts/talkactions/god/reload.lua:82: in function <...rometheus Server/data/scripts/talkactions/god/reload.lua:64>
[Warning - Events::load] Can not load script: creature.lua
data/events/scripts/creature.lua:153: <eof> expected near 'end'


it seems that it worked, but it gives me this error
 
Yeah otservbr is so modified, In main TFS it works properly.
I can still try to solve the issues you are getting but its all due to using modified/unclean TFS version.
Lua:
__picif = {}
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return true
end
-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='Training Monk',
    period = 1, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end
-- Prey slots consumption
local function preyTimeLeft(player, slot)
    local timeLeft = player:getPreyTimeLeft(slot) / 60
    local monster = player:getPreyCurrentMonster(slot)
    if (timeLeft > 0) then
        local playerId = player:getId()
        local currentTime = os.time()
        local timePassed = currentTime - nextPreyTime[playerId][slot]
        if timePassed > 59 then
            timeLeft = timeLeft - 1
            nextPreyTime[playerId][slot] = currentTime + 60
        else
            timeLeft = 0
        end
        -- Expiring prey as there's no timeLeft
        if (timeLeft == 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
            player:setPreyCurrentMonster(slot, "")
        end
        -- Setting new timeLeft
        player:setPreyTimeLeft(slot, timeLeft * 60)
    else
        -- Expiring prey as there's no timeLeft
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
        player:setPreyCurrentMonster(slot, "")
    end
    return player:sendPreyData(slot)
end

local function removeCombatProtection(cid)
    local player = Player(cid)
    if not player then
        return true
    end

    local time = 0
    if player:isMage() then
        time = 10
    elseif player:isPaladin() then
        time = 20
    else
        time = 30
    end

    player:setStorageValue(Storage.combatProtectionStorage, 2)
    addEvent(function(cid)
        local player = Player(cid)
        if not player then
            return
        end

        player:setStorageValue(Storage.combatProtectionStorage, 0)
        player:remove()
    end, time * 1000, cid)
end

function Creature:onTargetCombat(target)
    if self then
    if self:isPlayer() then
           if target and target:getName() == staminaBonus.target then
               local name = self:getName()
               if not staminaBonus.events[name] then
                   staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
               end
           end
          end
          end
       return RETURNVALUE_NOERROR
   end
       local player = Player(cid)
    if not player then
        return true
    end
    local target = player:getTarget()
    if not __picif[target.uid] then
        if target:isMonster() then
            target:registerEvent("RewardSystemSlogan")
            __picif[target.uid] = {}
        end
    end

    if target:isPlayer() then
        if self:isMonster() then
            local protectionStorage = target:getStorageValue(Storage.combatProtectionStorage)

            if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
                if target:isPzLocked() then end
                if protectionStorage <= 0 then
                    addEvent(removeCombatProtection, 30 * 1000, target.uid)
                    target:setStorageValue(Storage.combatProtectionStorage, 1)
                elseif protectionStorage == 1 then
                    self:searchTarget()
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end

                return true
            end

            if protectionStorage >= os.time() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end

    if ((target:isMonster() and self:isPlayer() and target:getType():isPet() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getType():isPet() and self:getMaster() == target)) then
        return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
    end

    if PARTY_PROTECTION ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            local party = self:getParty()
            if party then
                local targetParty = target:getParty()
                if targetParty and targetParty == party then
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end
            end
        end
    end

    if ADVANCED_SECURE_MODE ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            if self:hasSecureMode() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
            end
    return true
    end

function Creature:onDrainHealth(attacker, typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary)
    if (not self) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    if (not attacker) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    -- New prey => Bonus damage
    if (attacker:isPlayer()) then
        if (self:isMonster() and not self:getMaster()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (attacker:getPreyCurrentMonster(slot) == self:getName() and attacker:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_BOOST) then
                    damagePrimary = damagePrimary + math.floor(damagePrimary * (attacker:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    -- New prey => Damage reduction
    elseif (attacker:isMonster()) then
        if (self:isPlayer()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (self:getPreyCurrentMonster(slot) == attacker:getName() and self:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_REDUCTION) then
                    damagePrimary = damagePrimary - math.floor(damagePrimary * (self:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    end

    return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
end
 
Last edited:
Yeah otservbr is so modified, In main TFS it works properly.
I can still try to solve the issues you are getting but its all due to using modified/unclean TFS version.
For the target error line 101 try this one
Lua:
__picif = {}
function Creature:onChangeOutfit(outfit)
    return true
end

function Creature:onAreaCombat(tile, isAggressive)
    return true
end
-- HERE TRAINER ONLINE
local staminaBonus = {
    target ='Training Monk',
    period = 1, -- Period in milliseconds
    bonus = 1, -- gain stamina
    events = {}
}

local function addStamina(name)
    local player = Player(name)
    if not player then
        staminaBonus.events[name] = nil
    else
        local target = player:getTarget()
        if not target or target:getName() ~= staminaBonus.target then
            staminaBonus.events[name] = nil
        else
            player:setStamina(player:getStamina() + staminaBonus.bonus)
            staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
        end
    end
end
-- Prey slots consumption
local function preyTimeLeft(player, slot)
    local timeLeft = player:getPreyTimeLeft(slot) / 60
    local monster = player:getPreyCurrentMonster(slot)
    if (timeLeft > 0) then
        local playerId = player:getId()
        local currentTime = os.time()
        local timePassed = currentTime - nextPreyTime[playerId][slot]
        if timePassed > 59 then
            timeLeft = timeLeft - 1
            nextPreyTime[playerId][slot] = currentTime + 60
        else
            timeLeft = 0
        end
        -- Expiring prey as there's no timeLeft
        if (timeLeft == 0) then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
            player:setPreyCurrentMonster(slot, "")
        end
        -- Setting new timeLeft
        player:setPreyTimeLeft(slot, timeLeft * 60)
    else
        -- Expiring prey as there's no timeLeft
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Your %s's prey has expired.", monster:lower()))
        player:setPreyCurrentMonster(slot, "")
    end
    return player:sendPreyData(slot)
end

local function removeCombatProtection(cid)
    local player = Player(cid)
    if not player then
        return true
    end

    local time = 0
    if player:isMage() then
        time = 10
    elseif player:isPaladin() then
        time = 20
    else
        time = 30
    end

    player:setStorageValue(Storage.combatProtectionStorage, 2)
    addEvent(function(cid)
        local player = Player(cid)
        if not player then
            return
        end

        player:setStorageValue(Storage.combatProtectionStorage, 0)
        player:remove()
    end, time * 1000, cid)
end

function Creature:onTargetCombat(target)
    if self then
    if self:isPlayer() then
           if target and target:getName() == staminaBonus.target then
               local name = self:getName()
               if not staminaBonus.events[name] then
                   staminaBonus.events[name] = addEvent(addStamina, staminaBonus.period, name)
               end
           end
          end
          end
       return RETURNVALUE_NOERROR
   end
    local target = player:getTarget()
    if not __picif[target.uid] then
        if target:isMonster() then
            target:registerEvent("RewardSystemSlogan")
            __picif[target.uid] = {}
        end
    end

    if target:isPlayer() then
        if self:isMonster() then
            local protectionStorage = target:getStorageValue(Storage.combatProtectionStorage)

            if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
                if target:isPzLocked() then end
                if protectionStorage <= 0 then
                    addEvent(removeCombatProtection, 30 * 1000, target.uid)
                    target:setStorageValue(Storage.combatProtectionStorage, 1)
                elseif protectionStorage == 1 then
                    self:searchTarget()
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end

                return true
            end

            if protectionStorage >= os.time() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    end

    if ((target:isMonster() and self:isPlayer() and target:getType():isPet() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getType():isPet() and self:getMaster() == target)) then
        return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
    end

    if PARTY_PROTECTION ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            local party = self:getParty()
            if party then
                local targetParty = target:getParty()
                if targetParty and targetParty == party then
                    return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
                end
            end
        end
    end

    if ADVANCED_SECURE_MODE ~= 0 then
        if self:isPlayer() and target:isPlayer() then
            if self:hasSecureMode() then
                return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
            end
        end
    return true
end

function Creature:onDrainHealth(attacker, typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary)
    if (not self) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    if (not attacker) then
        return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
    end

    -- New prey => Bonus damage
    if (attacker:isPlayer()) then
        if (self:isMonster() and not self:getMaster()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (attacker:getPreyCurrentMonster(slot) == self:getName() and attacker:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_BOOST) then
                    damagePrimary = damagePrimary + math.floor(damagePrimary * (attacker:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    -- New prey => Damage reduction
    elseif (attacker:isMonster()) then
        if (self:isPlayer()) then
            for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
                if (self:getPreyCurrentMonster(slot) == attacker:getName() and self:getPreyBonusType(slot) == CONST_BONUS_DAMAGE_REDUCTION) then
                    damagePrimary = damagePrimary - math.floor(damagePrimary * (self:getPreyBonusValue(slot) / 100))
                    break
                end
            end
        end
    end

    return typePrimary, damagePrimary, typeSecondary, damageSecondary, colorPrimary, colorSecondary
end
and about the talkactions one you'll have to post your /data/scripts/talkactions/god/reload.lua
Lua Script Error: [Event Interface]
data/events/scripts/creature.lua
data/events/scripts/creature.lua:100: attempt to index global 'player' (a nil value)
stack traceback:
[C]: in function '__index'
data/events/scripts/creature.lua:100: in main chunk
[C]: in function 'reload'
...rometheus Server/data/scripts/talkactions/god/reload.lua:82: in function <...rometheus Server/data/scripts/talkactions/god/reload.lua:64>
[Warning - Events::load] Can not load script: creature.lua
data/events/scripts/creature.lua:153: <eof> expected near 'end'

it gives me something similar but with another line :/

there my reload.lua:
Code:
local talk = TalkAction("/reload")

local reloadTypes = {
    ["all"] = RELOAD_TYPE_ALL,

    ["action"] = RELOAD_TYPE_ACTIONS,
    ["actions"] = RELOAD_TYPE_ACTIONS,

    ["chat"] = RELOAD_TYPE_CHAT,
    ["channel"] = RELOAD_TYPE_CHAT,
    ["chatchannels"] = RELOAD_TYPE_CHAT,

    ["config"] = RELOAD_TYPE_CONFIG,
    ["configuration"] = RELOAD_TYPE_CONFIG,

    ["creaturescript"] = RELOAD_TYPE_CREATURESCRIPTS,
    ["creaturescripts"] = RELOAD_TYPE_CREATURESCRIPTS,

    ["events"] = RELOAD_TYPE_EVENTS,

    ["global"] = RELOAD_TYPE_GLOBAL,

    ["globalevent"] = RELOAD_TYPE_GLOBALEVENTS,
    ["globalevents"] = RELOAD_TYPE_GLOBALEVENTS,

    ["items"] = RELOAD_TYPE_ITEMS,

    ["module"] = RELOAD_TYPE_MODULES,
    ["modules"] = RELOAD_TYPE_MODULES,

    ["monster"] = RELOAD_TYPE_MONSTERS,
    ["monsters"] = RELOAD_TYPE_MONSTERS,

    ["mount"] = RELOAD_TYPE_MOUNTS,
    ["mounts"] = RELOAD_TYPE_MOUNTS,

    ["move"] = RELOAD_TYPE_MOVEMENTS,
    ["movement"] = RELOAD_TYPE_MOVEMENTS,
    ["movements"] = RELOAD_TYPE_MOVEMENTS,

    ["npc"] = RELOAD_TYPE_NPCS,
    ["npcs"] = RELOAD_TYPE_NPCS,

    ["quest"] = RELOAD_TYPE_QUESTS,
    ["quests"] = RELOAD_TYPE_QUESTS,

    ["raid"] = RELOAD_TYPE_RAIDS,
    ["raids"] = RELOAD_TYPE_RAIDS,

    ["spell"] = RELOAD_TYPE_SPELLS,
    ["spells"] =  RELOAD_TYPE_SPELLS,

    ["talk"] = RELOAD_TYPE_TALKACTIONS,
    ["talkaction"] = RELOAD_TYPE_TALKACTIONS,
    ["talkactions"] = RELOAD_TYPE_TALKACTIONS,

    ["weapon"] = RELOAD_TYPE_WEAPONS,
    ["weapons"] = RELOAD_TYPE_WEAPONS,

    ["scripts"] = RELOAD_TYPE_SCRIPTS,
    ["libs"] = RELOAD_TYPE_GLOBAL
}

function talk.onSay(player, words, param)
    if not player:getGroup():getAccess() or player:getAccountType() < ACCOUNT_TYPE_GOD then
        return true
    end

    if param == "" then
        player:sendCancelMessage("Command param required.")
        return false
    end

    logCommand(player, words, param)

    local reloadType = reloadTypes[param:lower()]
    if not reloadType then
        player:sendCancelMessage("Reload type not found.")
        return false
    end

    Game.reload(reloadType)
    player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("Reloaded %s.", param:lower()))
    return false
end

talk:separator(" ")
talk:register()


sorry for all this bro is that I can't fix it :c
 
I edited it above, try and post if you get other errors, Maybe you are using old version of otservbr because I think they are active solving the issues so you need to keep updated with their main distro.
 
so can you help ? to make it with effect? while player attack target the trainer for 3 minutes get +1 Min Stamina and got effect +1 after the 3 minutes left from attack target?
Basically you just need an onStatsChange script, along with these 2 functions.

getPlayerStamina(cid)
doPlayerSetStamina(cid, minutes)

But I've never used these functions, so without a server to test on, I can't make a perfect running script.
 
Here's the code if anyone want/needs it.
register to the creature only, not login.lua

data/monsters/training_monk.xml [under immunities]
XML:
<script>
    <event name="onStatsChange_staminaTraining"/>
</script>
data/creaturescripts/creaturescripts.xml
XML:
<event type="statschange" name="onStatsChange_staminaTraining" event="script" value="onStatsChange_staminaTraining.lua"/>
data/creaturescripts/scripts/onStatsChange_staminaTraining.lua
Lua:
local creatures = {}
local config = {
    timer = 180, -- time in seconds, before you gain stamina while hitting monster_name
    monster_name = "training monk",
    stamina_gain = 1, -- amount to gain after time elapse.
    threshold = 1000 -- how tight a timer before script cancels counting of timer. (2000 + (threshold of 1000) = need to hit blood every 3 seconds)
}


function onStatsChange(cid, attacker, type, combat, value)
    if type ~= STATSCHANGE_HEALTHLOSS then
        return true
    end

    if not isPlayer(attacker) then
        return true
    end
    if not isMonster(cid) then
        return true
    end
    if getCreatureName(cid):lower() ~= config.monster_name:lower() then
        return true
    end
 
    local current_time = os.mtime()
    if not creatures[cid] then
        creatures[cid] = {current_time, current_time} -- {start_time, last_hit_time}
        return true
    end

    -- check if too much time has elasped between last blood hit
    local time_difference = current_time - creatures[cid][2] -- between last hit and current time
    if time_difference > 2000 + config.threshold then
        creatures[cid] = {current_time, current_time}
        return true
    end
    creatures[cid][2] = current_time
 
    -- check if stamina timer has elasped
    time_difference = current_time - creatures[cid][1] -- time between first attack and current time.
    if time_difference < 1000 * config.timer then
        return true
    end
 
    -- give stamina and adjust timers for future stamina gain (2520 is max stamina)
    creatures[cid][1] = creatures[cid][1] + (1000 * config.timer)
 
 
    local stamina_to_add = getPlayerStamina(attacker) + config.stamina_gain
    if stamina_to_add >= 2520 then
        stamina_to_add = 2520 - getPlayerStamina(attacker)
    end
    if stamina_to_add <= 0 then -- stamina is already full
        return true
    end
     
    doPlayerSetStamina(attacker, stamina_to_add)
    doPlayerAddExperience(attacker, 1) -- neccesary to update client with new stamina information.
    addEvent(doPlayerAddExperience, 0, attacker, -1)
    return true
end
 
Last edited:
Solution
Here's the code if anyone want/needs it.
register to the creature only, not login.lua

data/monsters/training_monk.xml [under immunities]
XML:
<script>
    <event name="onStatsChange_staminaTraining"/>
</script>
data/creaturescripts/creaturescripts.xml
XML:
<event type="statschange" name="onStatsChange_staminaTraining" event="script" value="onStatsChange_staminaTraining.lua"/>
data/creaturescripts/scripts/onStatsChange_staminaTraining.lua
Lua:
local creatures = {}
local config = {
    timer = 180, -- time in seconds, before you gain stamina while hitting monster_name
    monster_name = "training monk",
    stamina_gain = 1, -- amount to gain after time elapse.
    threshold = 1000 -- how tight a timer before script cancels counting of timer. (2000 + (threshold of 1000) = need to hit blood every 3 seconds)
}


function onStatsChange(cid, attacker, type, combat, value)
    if type ~= STATSCHANGE_HEALTHLOSS then
        return true
    end

    if not isPlayer(attacker) then
        return true
    end
    if not isMonster(cid) then
        return true
    end
    if getCreatureName(cid):lower() ~= config.monster_name:lower() then
        return true
    end

    local current_time = os.mtime()
    if not creatures[cid] then
        creatures[cid] = {current_time, current_time} -- {start_time, last_hit_time}
        return true
    end

    -- check if too much time has elasped between last blood hit
    local time_difference = current_time - creatures[cid][2] -- between last hit and current time
    if time_difference > 2000 + config.threshold then
        creatures[cid] = {current_time, current_time}
        return true
    end
    creatures[cid][2] = current_time

    -- check if stamina timer has elasped
    time_difference = current_time - creatures[cid][1] -- time between first attack and current time.
    if time_difference < 1000 * config.timer then
        return true
    end

    -- give stamina and adjust timers for future stamina gain (2520 is max stamina)
    creatures[cid][1] = creatures[cid][1] + (1000 * config.timer)


    local stamina_to_add = getPlayerStamina(attacker) + config.stamina_gain
    if stamina_to_add >= 2520 then
        stamina_to_add = 2520 - getPlayerStamina(attacker)
    end
    if stamina_to_add <= 0 then -- stamina is already full
        return true
    end
    
    doPlayerSetStamina(attacker, stamina_to_add)
    doPlayerAddExperience(attacker, 1) -- neccesary to update client with new stamina information.
    addEvent(doPlayerAddExperience, 0, attacker, -1)
    return true
end

How can i add the script to this
Lua:
local mType = Game.createMonsterType("Training Machine")
local monster = {}
monster.description = "Training Machine"
monster.experience = 0
monster.outfit = {
    lookType = 1142
}

monster.health = 1000000
monster.maxHealth = monster.health
monster.race = "energy"
monster.corpse = 0
monster.speed = 0
monster.maxSummons = 0

monster.changeTarget = {
    interval = 1*1000,
    chance = 0
}

monster.flags = {
    summonable = false,
    attackable = true,
    hostile = true,
    convinceable = false,
    illusionable = false,
    canPushItems = true,
    canPushCreatures = true,
    targetDistance = 1,
    staticAttackChance = 100,
}

monster.summons = {
}

monster.voices = {
    interval = 5000,
    chance = 10,
    {text = "I hope you are enjoying your sparring Sir or Ma'am!", yell = false},
    {text = "Threat level rising!", yell = false},
    {text = "Engaging in hostile interaction!", yell = false},
    {text = "Rrrtttarrrttarrrtta", yell = false},
    {text = "Please feel free to hit me Sir or Ma'am!", yell = false},
    {text = "klonk klonk klonk", yell = false},
    {text = "Self-diagnosis running.", yell = false},
    {text = "Battle simulation proceeding.", yell = false},
    {text = "Repairs initiated!", yell = false}
}

monster.loot = {
}

monster.attacks = {
    {name = "melee", attack = 130, effect = CONST_ME_DRAWBLOOD, interval = 2*1000, minDamage = -1, maxDamage = -2}
}

monster.defenses = {
    defense = 1,
    armor = 1,
    {name = "combat", type = COMBAT_HEALING, chance = 15, interval = 2*1000, minDamage = 10000, maxDamage = 50000, effect = CONST_ME_MAGIC_BLUE}
}

monster.elements = {
}

monster.immunities = {
}

--[[
mType.onThink = function(monster, interval)
    print("I'm thinking")
end

mType.onAppear = function(monster, creature)
    if monster:getId() == creature:getId() then
        print(monster:getId(), creature:getId())
    end
end

mType.onDisappear = function(monster, creature)
    if monster:getId() == creature:getId() then
        print(monster:getId(), creature:getId())
    end
end

mType.onMove = function(monster, creature, fromPosition, toPosition)
    if monster:getId() == creature:getId() then
        print(monster:getId(), creature:getId(), fromPosition, toPosition)
    end
end

mType.onSay = function(monster, creature, type, message)
    print(monster:getId(), creature:getId(), type, message)
end
]]

mType:register(monster)
 
Back
Top