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

Action Exercise Dummy for TFS 0.4 :o

change:
Lua:
local foundDummy = getThingfromPos(params.dummyPos, false)
for:
Lua:
local foundDummy = getThingFromPosition(params.dummyPos)
and change:
Lua:
params.dummyPos = dummyPosition
for:
Lua:
params.dummyPos = toPos
ready!
niceee workkk
100% works, you're the best!
 
this works perfectly to me, I just did tow adjusts to the script:
1) Validate if the item still with player...
- When throw the weapon away from BP, it continue training
2) Validate the vocation with item...
 
@Sarah Wesker it is not working for magic level:
Code:
[4:30:06.866] [Error - Action Interface] 
[4:30:06.866] data/actions/scripts/exercise_dummy.lua:onUse
[4:30:06.866] Description: 
[4:30:06.866] data/actions/scripts/exercise_dummy.lua:53: attempt to call global 'doPlayerAddManaSpent' (a nil value)
[4:30:06.866] stack traceback:
[4:30:06.866]     data/actions/scripts/exercise_dummy.lua:53: in function 'exerciseDummyTrainEvent'
[4:30:06.866]     data/actions/scripts/exercise_dummy.lua:114: in function <data/actions/scripts/exercise_dummy.lua:76>

exercise_dummy.lua
Code:
local storage = 9756
local mins = 60
local hours = 60 * 60
local days = 24 * 60 * 60
local time = 6 * hours
local timeNow = os.time()
---@ Create by Sarah Wesker | Tested Version: TFS 0.4
---@ list of training dummies.
local dummies = {
    [5777] = { skillRate = 1, skillSpeed = 1 },
    [5778] = { skillRate = 1, skillSpeed = 1 },
    [5787] = { skillRate = 1, skillSpeed = 1 },
    [5788] = { skillRate = 1, skillSpeed = 1 }
}
---@ Global training parameters of the system.
local staminaTries = 1 --# on minutes
local skillTries = 5 --# tries by blow
local skillSpent = function() return math.random(425, 575) end --# mana consumed by blow
local slotForUse = CONST_SLOT_AMMO
---@ list of weapons to train.
local weapons = {
    [2433] = { shootEffect = CONST_ME_HITAREA, shootDistEffect = CONST_ANI_CAKE, skillType = SKILL_MAGLEVEL }, -- magicLevel
    [2414] = { shootEffect = CONST_ME_HITAREA, shootDistEffect = CONST_ANI_SPEAR, skillType = SKILL_DISTANCE }, -- distance
    [2446] = { shootEffect = CONST_ME_HITAREA, skillType = SKILL_SWORD }, -- sword
    [2443] = { shootEffect = CONST_ME_HITAREA, skillType = SKILL_AXE }, -- axe
    [2444] = { shootEffect = CONST_ME_HITAREA, 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
                    doPlayerAddManaSpent(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)
    if timeNow - getPlayerStorageValue(cid, storage) < 0 then
        if getPlayerStorageValue(cid, storage)-timeNow > days then
         doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You must wait '.. math.ceil(((getPlayerStorageValue(cid, storage)) - timeNow)/days) ..' days to do it again.')
        elseif getPlayerStorageValue(cid, storage)-timeNow > hours then
         doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You must wait '.. math.ceil(((getPlayerStorageValue(cid, storage)) - timeNow)/hours) ..' hours to do it again.')
        else
         doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'You must wait '.. math.ceil(((getPlayerStorageValue(cid, storage)) - timeNow)/mins) ..' minutes to do it again.')
        end
        return true
    end
    local ammo = getPlayerSlotItem(cid, slotForUse)
    if ammo.uid ~= item.uid then
        return doPlayerSendCancel(cid, "The weapon must be located in your slot ammunition.")
    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) > 1 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.")
        setPlayerStorageValue(cid, storage, timeNow + time)
    else
        doPlayerSendCancel(cid, "You can not train")
    end
    return true
end
 
Seems to works fine. But when a player pull me, training stop. there's a way to prevent this?
 
Last edited:
Back
Top