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

Lua [TFS 1.2] Task System - Players still get kill count even if they left area

Eldora

Banned User
Joined
Oct 19, 2009
Messages
604
Reaction score
26
I need this code to stop giving kill count for players if they have not been in combat the latest 5 minutes.
Right now, players get kill counts as long as they stay in the party.
They can even stand in the depot, getting kill counts from their friends monster kills, as long as they stay in the party.

Using TFS 1.2

Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end

local function applyStorages(player, info)
    local storageValue = player:getStorageValue(info.storage)
    local howMany = storageValue + 1
    if player:getStorageValue(info.missionstorage) == 1 then
        if storageValue >= info.count then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have already killed " .. info.count .. " " .. info.plural .. ". Report back to Tusker.")
        else
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have killed [" .. howMany .. "/" .. info.count .. "] " .. info.plural .. ".")
        end
        player:setStorageValue(info.storage, storageValue + 1)
    end
end

function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end

    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                applyStorages(member, info)
            end
        else
            applyStorages(obj, info)
        end
    end
    return true
end
 
Last edited:
In your function getObjs(creature) do a check to see if the player is within like 30 tiles of the dying creature.
If they are out of range, don't give them any storage.

Lua:
if creaturePosition:getDistance(playerPosition) <= 30 then
    -- give credit
end
 
You can add on your inside lib/core/player.lua
Lua:
function Player:getLastCombatTime()
    local lastCombatTime = self:getStorageValue(LAST_COMBAT_TIME)
    if lastCombatTime == -1 then
        return os.time()
    else
        return lastCombatTime
    end
end

and then modify your code to:
Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks and attacker:getLastCombatTime() + 300 >= os.time() then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end

local function applyStorages(player, info)
    local storageValue = player:getStorageValue(info.storage)
    local howMany = storageValue + 1
    if player:getStorageValue(info.missionstorage) == 1 then
        if storageValue >= info.count then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have already killed " .. info.count .. " " .. info.plural .. ". Report back to Tusker.")
        else
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have killed [" .. howMany .. "/" .. info.count .. "] " .. info.plural .. ".")
        end
        player:setStorageValue(info.storage, storageValue + 1)
    end
end

function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end

    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                applyStorages(member, info)
            end
        else
            applyStorages(obj, info)
        end
    end
    return true
end
And remember to add a one storage to your list of storages or add in global.lua this:

Lua:
local LAST_COMBAT_TIME = 61398

It's just a suggestion, I'm not an expert in this LUA thing.

Greetings!.

The previous solution is also good so it doesn't tell them unless they are at the right distance
 
In your function getObjs(creature) do a check to see if the player is within like 30 tiles of the dying creature.
If they are out of range, don't give them any storage.

Lua:
if creaturePosition:getDistance(playerPosition) <= 30 then
    -- give credit
end
How can I add this to "local function getObjs(creature)" properly?

Here is the code:
Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end
Post automatically merged:

You can add on your inside lib/core/player.lua
Lua:
function Player:getLastCombatTime()
    local lastCombatTime = self:getStorageValue(LAST_COMBAT_TIME)
    if lastCombatTime == -1 then
        return os.time()
    else
        return lastCombatTime
    end
end

and then modify your code to:
Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks and attacker:getLastCombatTime() + 300 >= os.time() then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end

local function applyStorages(player, info)
    local storageValue = player:getStorageValue(info.storage)
    local howMany = storageValue + 1
    if player:getStorageValue(info.missionstorage) == 1 then
        if storageValue >= info.count then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have already killed " .. info.count .. " " .. info.plural .. ". Report back to Tusker.")
        else
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have killed [" .. howMany .. "/" .. info.count .. "] " .. info.plural .. ".")
        end
        player:setStorageValue(info.storage, storageValue + 1)
    end
end

function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end

    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                applyStorages(member, info)
            end
        else
            applyStorages(obj, info)
        end
    end
    return true
end
And remember to add a one storage to your list of storages or add in global.lua this:

Lua:
local LAST_COMBAT_TIME = 61398

It's just a suggestion, I'm not an expert in this LUA thing.

Greetings!.

The previous solution is also good so it doesn't tell them unless they are at the right distance
What is the time required being in combat before losing the KillCount?
 
Last edited:
What is the time required being in combat before losing the KillCount?
Like has you said. 5 minutes, has added on the line 7:

Lua:
if attacker and timeNow - cb.ticks <= inFightTicks and attacker:getLastCombatTime() + 300 >= os.time() then

on this part:

Lua:
attacker:getLastCombatTime() + 300 >= os.time()

300 seconds = 5 minutes
 
@Xikini

1678040664365.png
Post automatically merged:

@NvSo

How can I add this:

Lua:
if creaturePosition:getDistance(playerPosition) <= 30 then
    -- give credit
end

into this:

Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end


it says that 'creaturePosition" is a nil value, so I think it is not correct for TFS 1.2?
Post automatically merged:

You can add on your inside lib/core/player.lua
Lua:
function Player:getLastCombatTime()
    local lastCombatTime = self:getStorageValue(LAST_COMBAT_TIME)
    if lastCombatTime == -1 then
        return os.time()
    else
        return lastCombatTime
    end
end

and then modify your code to:
Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks and attacker:getLastCombatTime() + 300 >= os.time() then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end

local function applyStorages(player, info)
    local storageValue = player:getStorageValue(info.storage)
    local howMany = storageValue + 1
    if player:getStorageValue(info.missionstorage) == 1 then
        if storageValue >= info.count then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have already killed " .. info.count .. " " .. info.plural .. ". Report back to Tusker.")
        else
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have killed [" .. howMany .. "/" .. info.count .. "] " .. info.plural .. ".")
        end
        player:setStorageValue(info.storage, storageValue + 1)
    end
end

function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end

    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                applyStorages(member, info)
            end
        else
            applyStorages(obj, info)
        end
    end
    return true
end
And remember to add a one storage to your list of storages or add in global.lua this:

Lua:
local LAST_COMBAT_TIME = 61398

It's just a suggestion, I'm not an expert in this LUA thing.

Greetings!.

The previous solution is also good so it doesn't tell them unless they are at the right distance
This did not work, tried it and nothing changed.
 
Last edited:
@Xikini

View attachment 73886
Post automatically merged:

@NvSo

How can I add this:

Lua:
if creaturePosition:getDistance(playerPosition) <= 30 then
    -- give credit
end

into this:

Lua:
local function getObjs(creature)
    local objs = {}
    local timeNow = os.mtime()
    local inFightTicks = configManager.getNumber(configKeys.PZ_LOCKED)
    for uid, cb in pairs(creature:getDamageMap()) do
        local attacker = Player(uid)
        if attacker and timeNow - cb.ticks <= inFightTicks then
            local party = attacker:getParty()
            if party then
                local lid = party:getLeader():getId()
                if not objs[lid] then
                    objs[lid] = party
                end
            else
                objs[attacker:getId()] = attacker
            end
        end
    end
    return objs
end


it says that 'creaturePosition" is a nil value, so I think it is not correct for TFS 1.2?
Post automatically merged:


This did not work, tried it and nothing changed.
Sorry, I thought your getObjs was getting a list of all the creatures, but I was mistaken.

Add it to the main function.

Lua:
function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end
    
    local creaturePosition = creature:getPosition()
    
    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                if creaturePosition:getDistance(member:getPosition()) <= 30 then
                    applyStorages(member, info)
                end
            end
        else
            if creaturePosition:getDistance(obj:getPosition()) <= 30 then
                applyStorages(obj, info)
            end
        end
    end
    return true
end
 
Sorry, I thought your getObjs was getting a list of all the creatures, but I was mistaken.

Add it to the main function.

Lua:
function onKill(player, creature)
    local info = config[creature:getName():lower()]
    if not info or creature:getMaster() then
        return true
    end
   
    local creaturePosition = creature:getPosition()
   
    for _, obj in pairs(getObjs(creature)) do
        if getmetatable(obj) == Party then
            for _, member in pairs({obj:getLeader(), unpack(obj:getMembers())}) do
                if creaturePosition:getDistance(member:getPosition()) <= 30 then
                    applyStorages(member, info)
                end
            end
        else
            if creaturePosition:getDistance(obj:getPosition()) <= 30 then
                applyStorages(obj, info)
            end
        end
    end
    return true
end

Thank you @Xikini ,

It seems like when you say "stop" to pause a task, it will not keep your progression (amount of kills) for later if you pick it up again.
It will basically remove your progression completely and you have to start from 0, any idea how to maintain the progression for later?

Note: I searched for "stop" in this code and could find two rows that seem to handle that part? Any ideas @Xikini

Lua:
function creatureSayCallback(cid, type, msg)

     local player, cmsg = Player(cid), msg:gsub("(%a)([%w_']*)", Cptl)
     if not npcHandler:isFocused(cid) then
         if msg == "hi" or msg == "hello" then
             npcHandler:addFocus(cid)
             if player:getStorageValue(storage) == -1 then
                 local text, n = "",  0
                 for k, x in pairs(monsters) do
                     if player:getStorageValue(x.mstorage) < x.amount then
                         n = n + 1
                         text = text .. ", "
                         text = text .. ""..x.amount.." {"..k.."}"
                     end
                 end
                 if n > 1 then
                     npcHandler:say("I have several tasks for you to kill monsters"..text..", which one do you choose? I can also show you a {list} with rewards and you can {stop} a task if you want.", cid)
                     npcHandler.topic[cid] = 1
                     xmsg[cid] = msg
                 elseif n == 1 then
                     npcHandler:say("I have one last task for you"..text..".", cid)
                     npcHandler.topic[cid] = 1
                 else
                     npcHandler:say("You already did all tasks, I have nothing for you to do anymore, good job though.", cid)
                 end
             elseif player:getStorageValue(storage) == 1 then
                 for k, x in pairs(monsters) do
                     if player:getStorageValue(x.storage) == 1 then
                         npcHandler:say("Did you kill "..x.amount.." "..k.."?", cid)
                         npcHandler.topic[cid] = 2
                         xmsg[cid] = k
                     end
                 end
             end
         else
             return false
         end
     elseif monsters[cmsg] and npcHandler.topic[cid] == 1 then
         if player:getStorageValue(monsters[cmsg].storage) == -1 then
             npcHandler:say("Good luck, come back when you killed "..monsters[cmsg].amount.." "..cmsg..".", cid)
             player:setStorageValue(storage, 1)
             player:setStorageValue(monsters[cmsg].storage, 1)
         player:setStorageValue(monsters[cmsg].mstorage, 0)
         else
             npcHandler:say("You already did the "..cmsg.." mission.", cid)
         end
         npcHandler.topic[cid] = 0
     elseif msgcontains(msg, "yes") and npcHandler.topic[cid] == 2 then
         local x = monsters[xmsg[cid]]
         if player:getStorageValue(x.mstorage) >= x.amount then
             npcHandler:say("Good job, here is your reward, "..getItemsFromTable(x.items)..".", cid)
             for g = 1, #x.items do
                 player:addItem(x.items[g].id, x.items[g].count)
             end
             player:addExperience(x.exp)
             player:setStorageValue(x.storage, 2)
             player:setStorageValue(storage, -1)
             npcHandler.topic[cid] = 3
         else
             npcHandler:say("You didn't kill them all, you still need to kill "..x.amount -(player:getStorageValue(x.mstorage)).." "..xmsg[cid]..".", cid)
         end
     elseif msgcontains(msg, "task") and npcHandler.topic[cid] == 3 then
         local text, n = "",  0
         for k, x in pairs(monsters) do
             if player:getStorageValue(x.mstorage) < x.amount then
                 n = n + 1
                 text = text .. (n == 1 and "" or ", ")
                 text = text .. "{"..k.."}"
             end
         end
         if text ~= "" then
             npcHandler:say("Want to do another task? You can choose "..text..".", cid)
             npcHandler.topic[cid] = 1
         else
             npcHandler:say("You already did all tasks.", cid)
         end
     elseif msgcontains(msg, "no") and npcHandler.topic[cid] == 1 then
         npcHandler:say("Ok then.", cid)
         npcHandler.topic[cid] = 0
     elseif msgcontains(msg, "stop") then
         local text, n = "",  0
         for k, x in pairs(monsters) do
             if player:getStorageValue(x.mstorage) < x.amount then
                 n = n + 1
                 text = text .. (n == 1 and "" or ", ")
                 text = text .. "{"..k.."}"
                 if player:getStorageValue(x.storage) == 1 then
                      player:setStorageValue(x.storage, -1)
                 end
             end
         end
         if player:getStorageValue(storage) == 1 then
             npcHandler:say("Alright, let me know if you want to continue an other task, you can still choose "..text..".", cid)
         else
             npcHandler:say("You didn't start any new task yet, if you want to start one, you can choose "..text..".", cid)
         end
         player:setStorageValue(storage, -1)
         npcHandler.topic[cid] = 1
     elseif msgcontains(msg, "list") then
         local text = "Tasks\n\n"
         for k, x in pairs(monsters) do
             if player:getStorageValue(x.mstorage) < x.amount then
                 text = text ..k .." ["..(player:getStorageValue(x.mstorage) < 1 and 0 or player:getStorageValue(x.mstorage)).."/"..x.amount.."]:\n  Rewards:\n  "..getItemsFromTable(x.items).."\n  "..x.exp.." experience \n\n"
             else
                 text = text .. k .." [DONE]\n"
             end
         end
         player:showTextDialog(1949, "" .. text)
         npcHandler:say("Here you are.", cid)
     elseif msgcontains(msg, "bye") then
         npcHandler:say("Bye.", cid)
         npcHandler:releaseFocus(cid)
     else
         npcHandler:say("Please tell me which creature you want to take a task for. You can also ask me to {list} your current status for each task. ", cid)
     end
     return true
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
 
Back
Top