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

No move dummy

carlinhous1996

New Member
Joined
Apr 14, 2022
Messages
54
Reaction score
3
could someone help me with this script?
when the player moves the training stops, I wanted the same to happen with the dummy, when someone pushes the dummy the training also ends. it's possible ?
Lua:
---@ Create by Sarah Wesker | Tested Version: TFS 0.4
---@ list of training dummies.
local dummies = {
    [9653] = { skillRate = 0.8, skillSpeed = 2 },
    [1476] = { skillRate = 0.7, skillSpeed = 3 },
    [1477] = { skillRate = 0.7, skillSpeed = 3 },
    [1478] = { skillRate = 0.7, skillSpeed = 3 },
    [1442] = { skillRate = 0.7, skillSpeed = 3 },
    [5787] = { skillRate = 0.5, skillSpeed = 3 }
}

---@ Global training parameters of the system.
local staminaTries = 1 --# on minutes
local skillTries = 1 --# tries by blow
local skillSpent = function() return math.random(425, 575) end --# mana consumed by blow
local slotForUse = CONST_SLOT_LEFT

---@ list of weapons to train.
local weapons = {
    [7754] = { shootDistEffect = CONST_ANI_FIRE, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2426] = { shootDistEffect = CONST_ANI_SPEAR, skillType = SKILL_DISTANCE }, -- distance
    [7744] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7750] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7758] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB }, -- club
    [7879] = { shootDistEffect = CONST_ANI_ENERGY, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2404] = { shootDistEffect = CONST_ANI_THROWINGKNIFE, skillType = SKILL_DISTANCE }, -- distance
    [7869] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7875] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7883] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB } -- club
}

---@ EDTE is the global event table to control the system correctly.
if not EDTE then EDTE = {} end

---@ functions to assign or obtain the training status of a player.
function getPlayerExerciseTrain(cid) return EDTE[cid] or false end
function setPlayerExerciseTrain(cid, status) EDTE[cid] = status return status end

---@ local training function.
local function exerciseDummyTrainEvent(params, weapon)
    if isPlayer(params.cid) then
        local item = getPlayerSlotItem(params.cid, slotForUse)
        local playerPosition = getCreaturePosition(params.cid)
        if getDistanceBetween(playerPosition, params.currentPos) == 0 and item.itemid == params.itemid then
            local weaponCharges = getItemAttribute(item.uid, "charges") or getItemInfo(params.itemid).charges
            local reloadMs = getVocationInfo(getPlayerVocation(params.cid)).attackSpeed * params.dummy.skillSpeed
            if weaponCharges >= 1 then
                doItemSetAttribute(item.uid, "charges", weaponCharges -1)
                if weapon.shootDistEffect then doSendDistanceShoot(playerPosition, params.dummyPos, weapon.shootDistEffect) end
                if weapon.shootEffect then doSendMagicEffect(params.dummyPos, weapon.shootEffect) end
                if weapon.skillType == SKILL_MAGLEVEL then
                    doPlayerAddSpentMana(params.cid, (skillSpent() * params.dummy.skillRate) * getConfigValue("rateMagic"))
                else
                    doPlayerAddSkillTry(params.cid, weapon.skillType, (skillTries * params.dummy.skillRate) * getConfigValue("rateSkill"))
                end
                local currentStamina = getPlayerStamina(params.cid)
                doPlayerSetStamina(params.cid, currentStamina + staminaTries)
                if weaponCharges <= 1 then
                    exerciseDummyTrainEvent(params, weapon)
                else
                    setPlayerExerciseTrain(params.cid, addEvent(exerciseDummyTrainEvent, reloadMs, params, weapon))
                end
                return true
            else
                doRemoveItem(item.uid)
                doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "Your exercise weapon has expired, therefore your training too.")
            end
        else
            doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "You have finished your training.")
        end
    end
    return setPlayerExerciseTrain(params.cid, nil)
end

function onUse(cid, item, fromPos, target, toPos, isHotkey)
    local ammo = getPlayerSlotItem(cid, slotForUse)
    if ammo.uid ~= item.uid then
        return doPlayerSendCancel(cid, "The weapon must be located in your left hand.")
    end
    if not target then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTPOSSIBLE)
    end
    local playerPosition = getCreaturePosition(cid)
    if not getTileInfo(playerPosition).protection then
        return doPlayerSendCancel(cid, "You can only train in protection zone.")
    end
    local dummy = dummies[target.itemid]
    local weapon = weapons[item.itemid]
    if not weapon or not dummy then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_CANNOTUSETHISOBJECT)
    end
    local dummyPosition = getThingPosition(target.uid)
    if getDistanceBetween(playerPosition, dummyPosition) > 6 then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_THEREISNOWAY)
    end
    if not getPlayerExerciseTrain(cid) then
        local params = {}
        params.cid = cid
        params.currentPos = playerPosition
        params.dummyPos = dummyPosition
        params.itemid = item.itemid
        params.dummy = dummy
        exerciseDummyTrainEvent(params, weapon)
        doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, "You have started training with dummy.")
    else
        doPlayerSendCancel(cid, "You can not train")
    end
    return true
end
 
Test:
Lua:
---@ Create by Sarah Wesker | Tested Version: TFS 0.4
---@ list of training dummies.
local dummies = {
    [9653] = { skillRate = 0.8, skillSpeed = 2 },
    [1476] = { skillRate = 0.7, skillSpeed = 3 },
    [1477] = { skillRate = 0.7, skillSpeed = 3 },
    [1478] = { skillRate = 0.7, skillSpeed = 3 },
    [1442] = { skillRate = 0.7, skillSpeed = 3 },
    [5787] = { skillRate = 0.5, skillSpeed = 3 }
}

---@ Global training parameters of the system.
local staminaTries = 1 --# on minutes
local skillTries = 1 --# tries by blow
local skillSpent = function() return math.random(425, 575) end --# mana consumed by blow
local slotForUse = CONST_SLOT_LEFT

---@ list of weapons to train.
local weapons = {
    [7754] = { shootDistEffect = CONST_ANI_FIRE, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2426] = { shootDistEffect = CONST_ANI_SPEAR, skillType = SKILL_DISTANCE }, -- distance
    [7744] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7750] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7758] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB }, -- club
    [7879] = { shootDistEffect = CONST_ANI_ENERGY, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2404] = { shootDistEffect = CONST_ANI_THROWINGKNIFE, skillType = SKILL_DISTANCE }, -- distance
    [7869] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7875] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7883] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB } -- club
}

local DPOSS = {}

---@ local training function.
local function exerciseDummyTrainEvent(params)
    if isPlayer(params.cid) then
        local dummyThing = getTileItemById(params.dummyPos, params.dummyId)
        if dummyThing.uid == 0 then
            doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "You have finished your training.")
            DPOSS[params.cid] = nil
            return false
        end

        local dummy = dummies[params.dummyId]
        local weapon = weapons[params.itemid]
        local item = getPlayerSlotItem(params.cid, slotForUse)
        local playerPosition = getCreaturePosition(params.cid)
        if getDistanceBetween(playerPosition, params.currentPos) == 0 and item.itemid == params.itemid then
            local weaponCharges = getItemAttribute(item.uid, "charges") or getItemInfo(params.itemid).charges
            local reloadMs = getVocationInfo(getPlayerVocation(params.cid)).attackSpeed * dummy.skillSpeed
            if weaponCharges >= 1 then
                doItemSetAttribute(item.uid, "charges", weaponCharges -1)
                if weapon.shootDistEffect then doSendDistanceShoot(playerPosition, params.dummyPos, weapon.shootDistEffect) end
                if weapon.shootEffect then doSendMagicEffect(params.dummyPos, weapon.shootEffect) end
                if weapon.skillType == SKILL_MAGLEVEL then
                    doPlayerAddSpentMana(params.cid, (skillSpent() * dummy.skillRate) * getConfigValue("rateMagic"))
                else
                    doPlayerAddSkillTry(params.cid, weapon.skillType, (skillTries * dummy.skillRate) * getConfigValue("rateSkill"))
                end
                doPlayerSetStamina(params.cid, getPlayerStamina(params.cid) + staminaTries)
                params.eventId = addEvent(exerciseDummyTrainEvent, reloadMs, params)
                return true
            else
                doRemoveItem(item.uid)
                doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "Your exercise weapon has expired, therefore your training too.")
            end
        else
            doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "You have finished your training.")
        end
    end

    DPOSS[params.cid] = nil
    return false
end

function onUse(cid, item, fromPos, target, toPos, isHotkey)
    local ammo = getPlayerSlotItem(cid, slotForUse)
    if ammo.uid ~= item.uid then
        return doPlayerSendCancel(cid, "The weapon must be located in your left hand.")
    end
    if not target then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTPOSSIBLE)
    end
    local playerPosition = getCreaturePosition(cid)
    if not getTileInfo(playerPosition).protection then
        return doPlayerSendCancel(cid, "You can only train in protection zone.")
    end
    local dummy = dummies[target.itemid]
    local weapon = weapons[item.itemid]
    if not weapon or not dummy then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_CANNOTUSETHISOBJECT)
    end
    local dummyPosition = getThingPosition(target.uid)
    if getDistanceBetween(playerPosition, dummyPosition) > 6 then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_THEREISNOWAY)
    end
    if not DPOSS[cid] then
        local params = {
            cid = cid,
            itemid = item.itemid,
            dummyPos = dummyPosition,
            currentPos = playerPosition,
            dummyId = target.itemid
        }

        DPOSS[cid] = params
        exerciseDummyTrainEvent(params)
        doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, "You have started training with dummy.")
    else
        doPlayerSendCancel(cid, "You can not train")
    end
    return true
end
 
Last edited:
Here I made a modification, I'm not sure if it's the best, but the truth is that I haven't touched such an old server for many years
With this change now if the dummy is not in the same position the training is canceled the next time it is verified:
Obviously it will also be canceled for all players who are training with this same dummy.
Lua:
---@ Create by Sarah Wesker | Tested Version: TFS 0.4
---@ list of training dummies.
local dummies = {
    [9653] = { skillRate = 0.8, skillSpeed = 2 },
    [1476] = { skillRate = 0.7, skillSpeed = 3 },
    [1477] = { skillRate = 0.7, skillSpeed = 3 },
    [1478] = { skillRate = 0.7, skillSpeed = 3 },
    [1442] = { skillRate = 0.7, skillSpeed = 3 },
    [5787] = { skillRate = 0.5, skillSpeed = 3 }
}

---@ Global training parameters of the system.
local staminaTries = 1 --# on minutes
local skillTries = 1 --# tries by blow
local skillSpent = function() return math.random(425, 575) end --# mana consumed by blow
local slotForUse = CONST_SLOT_LEFT

---@ list of weapons to train.
local weapons = {
    [7754] = { shootDistEffect = CONST_ANI_FIRE, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2426] = { shootDistEffect = CONST_ANI_SPEAR, skillType = SKILL_DISTANCE }, -- distance
    [7744] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7750] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7758] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB }, -- club
    [7879] = { shootDistEffect = CONST_ANI_ENERGY, skillType = SKILL_MAGLEVEL }, -- magicLevel Sor
    [2404] = { shootDistEffect = CONST_ANI_THROWINGKNIFE, skillType = SKILL_DISTANCE }, -- distance
    [7869] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_SWORD }, -- sword
    [7875] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_AXE }, -- axe
    [7883] = { shootEffect = CONST_ME_BLOCKHIT, skillType = SKILL_CLUB } -- club
}

local DPOSS = {}

local function setDPOSS(pos, params)
    local key = string.format("%d:%d:%d", pos.x, pos.y, pos.z)
    local dposs = DPOSS[key]
    if not dposs then
        dposs = {}
        DPOSS[key] = dposs
    end
    dposs[params.cid] = params
    return true
end

local function getDPOSS(pos)
    local key = string.format("%d:%d:%d", pos.x, pos.y, pos.z)
    local dposs = DPOSS[key]
    if not dposs then
        dposs = {}
        DPOSS[key] = dposs
    end
    return dposs
end

---@ local training function.
local function exerciseDummyTrainEvent(params, weapon)
    if isPlayer(params.cid) then
        local dummy = getTileItemById(params.dummyPos, params.dummyId)
        if dummy.uid == 0 then
            local dposs = getDPOSS(params.dummyPos)
            if dposs then
                local toRemove = {}
                for cid, param in pairs(dposs) do
                    stopEvent(param.eventId)
                    doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, "You have finished your training.")
                    toRemove[#toRemove + 1] = cid
                end
                for _, cid in pairs(toRemove) do dposs[cid] = nil end
            end
            return false
        end

        local item = getPlayerSlotItem(params.cid, slotForUse)
        local playerPosition = getCreaturePosition(params.cid)
        if getDistanceBetween(playerPosition, params.currentPos) == 0 and item.itemid == params.itemid then
            local weaponCharges = getItemAttribute(item.uid, "charges") or getItemInfo(params.itemid).charges
            local reloadMs = getVocationInfo(getPlayerVocation(params.cid)).attackSpeed * params.dummy.skillSpeed
            if weaponCharges >= 1 then
                doItemSetAttribute(item.uid, "charges", weaponCharges -1)
                if weapon.shootDistEffect then doSendDistanceShoot(playerPosition, params.dummyPos, weapon.shootDistEffect) end
                if weapon.shootEffect then doSendMagicEffect(params.dummyPos, weapon.shootEffect) end
                if weapon.skillType == SKILL_MAGLEVEL then
                    doPlayerAddSpentMana(params.cid, (skillSpent() * params.dummy.skillRate) * getConfigValue("rateMagic"))
                else
                    doPlayerAddSkillTry(params.cid, weapon.skillType, (skillTries * params.dummy.skillRate) * getConfigValue("rateSkill"))
                end
                doPlayerSetStamina(params.cid, getPlayerStamina(params.cid) + staminaTries)
                params.eventId = addEvent(exerciseDummyTrainEvent, reloadMs, params, weapon)
                return true
            else
                local dposs = getDPOSS(params.dummyPos)
                if dposs then
                    dposs[params.cid] = nil
                end
                doRemoveItem(item.uid)
                doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "Your exercise weapon has expired, therefore your training too.")
            end
        else
            local dposs = getDPOSS(params.dummyPos)
            if dposs then
                dposs[params.cid] = nil
            end
            doPlayerSendTextMessage(params.cid, MESSAGE_EVENT_ADVANCE, "You have finished your training.")
        end
    end
    return false
end

function onUse(cid, item, fromPos, target, toPos, isHotkey)
    local ammo = getPlayerSlotItem(cid, slotForUse)
    if ammo.uid ~= item.uid then
        return doPlayerSendCancel(cid, "The weapon must be located in your left hand.")
    end
    if not target then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTPOSSIBLE)
    end
    local playerPosition = getCreaturePosition(cid)
    if not getTileInfo(playerPosition).protection then
        return doPlayerSendCancel(cid, "You can only train in protection zone.")
    end
    local dummy = dummies[target.itemid]
    local weapon = weapons[item.itemid]
    if not weapon or not dummy then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_CANNOTUSETHISOBJECT)
    end
    local dummyPosition = getThingPosition(target.uid)
    if getDistanceBetween(playerPosition, dummyPosition) > 6 then
        return doPlayerSendDefaultCancel(cid, RETURNVALUE_THEREISNOWAY)
    end
    local dposs = getDPOSS(dummyPosition)
    if not dposs[cid] then
        local params = {
            cid = cid,
            itemid = item.itemid,
            dummy = dummy,
            dummyPos = dummyPosition,
            currentPos = playerPosition,
            dummyId = target.itemid
        }
        setDPOSS(dummyPosition, params)
        exerciseDummyTrainEvent(params, weapon)
        doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, "You have started training with dummy.")
    else
        doPlayerSendCancel(cid, "You can not train")
    end
    return true
end


when you move the dummy that tries to attack again this comes out
help me please


[Error - Action Interface]
In a timer event called from:
data/actions/scripts/drummy.lua:eek:nUse
Description:
data/actions/scripts/drummy.lua:57: attempt to index local 'params' (a function value)
stack traceback:
data/actions/scripts/drummy.lua:57: in function <data/actions/scripts/drummy.lua:56>
 
when you move the dummy that tries to attack again this comes out
help me please


[Error - Action Interface]
In a timer event called from:
data/actions/scripts/drummy.lua:eek:nUse
Description:
data/actions/scripts/drummy.lua:57: attempt to index local 'params' (a function value)
stack traceback:
data/actions/scripts/drummy.lua:57: in function <data/actions/scripts/drummy.lua:56>
Try to copy the code again, I have modified it: HERE
 
Back
Top