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

Insert party task count (custom system)

_M4G0_

Well-Known Member
Joined
Feb 6, 2016
Messages
504
Solutions
16
Reaction score
98
how i can insert this solution on the script
tfs 1.2
Lua:
local MonstersTask = {}

for k, v in pairs(TASK.Tasks) do
    for mob, count in pairs(v.Monsters) do
        if not MonstersTask[mob] then
            MonstersTask[mob] = {}
        end
        table.insert(MonstersTask[mob], k)
    end
end

function onLogin(player)
    player:registerEvent("TaskKill")
    return true
end

function onKill(player, target)
    local mob = target:getName()
    if not MonstersTask[mob] then
        return true
    end

    for k, v in pairs(player:getTasks().progress) do
        local TaskMobCount = TASK.Tasks[k].Monsters[mob]
        local KillCount = v[mob]
        if KillCount and isInArray(MonstersTask[mob], k) and KillCount < TaskMobCount then
            KillCount = KillCount+1
            player:setProgressTaskCount(k, mob, KillCount)
            if KillCount < TaskMobCount then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, string.format("Task >> [%s]: Kill [%s/%s] %s%s.", k, KillCount, TaskMobCount, mob, (TaskMobCount > 1 and "s" or "")))
            elseif KillCount == TaskMobCount then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, string.format("Task >> [%s]: Kill [%s/%s] %s%s Completed!", k, KillCount, TaskMobCount, mob, (TaskMobCount > 1 and "s" or "")))
                local completed = true
                for iTaskMob, iTaskCount in pairs(v) do
                    if iTaskCount < TASK.Tasks[k].Monsters[iTaskMob] then
                        completed = false
                    end
                end
                if completed then
                    player:sendTextMessage(MESSAGE_STATUS_WARNING, string.format("Task >> [%s]: Completed!", k))
                end
            end
        end
    end
    return true
end
 
Solution
I won't give you the solution but I'll tell you what you should pay attention to.

OnKill is a callback that can be called twice each time a creature is killed.
This happens specially if the death has two attackers and the last hit was not delivered by the same attacker that did most damage.

This can be mitigated by expanding your callback to have a third parameter to say if the person was the last hit or not, and checking for that.


One might feel tempted to just go to your script and put to iterate on each party member, this needs to have extra checks to guarantee people are within the same screen as monster and this script of yours is not even particulary checking if...
I won't give you the solution but I'll tell you what you should pay attention to.

OnKill is a callback that can be called twice each time a creature is killed.
This happens specially if the death has two attackers and the last hit was not delivered by the same attacker that did most damage.

This can be mitigated by expanding your callback to have a third parameter to say if the person was the last hit or not, and checking for that.


One might feel tempted to just go to your script and put to iterate on each party member, this needs to have extra checks to guarantee people are within the same screen as monster and this script of yours is not even particulary checking if the monster is a summon. In fact it's not even checking if it's a monster, I could create a character named Demon and finish a task by killing it.


Take a look at how I did my task system, for instance (some of those checks can be optimized with the use of monstro:isSummon() that didn't existed back then.

Lua:
dofile('data/lib/tasklib.lua')
local config = {
    countForParty = true, -- a kill contara para todos os membros da party?
    showName = true,
    maxDist = 7 -- se a distancia do player para o monstro for maior que esse valor, a task nao conta pra ele.
}

function onKill(player, monstro, lasthit)
    if not lasthit or not Player(player.uid) or not Monster(monstro.uid) then return true end
    local target = Monster(monstro.uid)
    if type(target:getMaster()) ~= 'nil' then return true end

    local killers = {}
    local tpos = target:getPosition()

    if config.countForParty then
        local party = player:getParty()
        if party and party:isSharedExperienceActive() and party:getMembers() then
            for i, creature in pairs(party:getMembers()) do
                local pos = creature:getPosition()
                if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                    killers[#killers + 1] = creature.uid
                end
            end
            local pos = party:getLeader():getPosition()
            if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                killers[#killers + 1] = party:getLeader().uid
            end
        else
            killers[1] = player.uid
        end
    else
        killers[1] = player.uid
    end

    for i = 1, #killers do
        local player = Player(killers[i])
        for _, v in ipairs(Task_storages) do
            if player:getStorageValue(v.task) and player:getStorageValue(v.task) > 0 then
                if Tasks[player:getStorageValue(v.task)] and isInArray(Tasks[player:getStorageValue(v.task)].creatures, target:getName()) then
                    local actualTask = Tasks[player:getStorageValue(v.task)]
                    local killed = player:getStorageValue(v.count)
                    if killed < actualTask.count then
                        killed = killed + 1
                        player:setStorageValue(v.count, killed)
                        if killed == actualTask.count then
                            local answer = player:getTaskMessage(Tasks, player:getStorageValue(v.task), "Complete")
                            if answer then
                                message = answer
                            else
                                message = "You finished your task."
                            end
                            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
                        elseif killed < actualTask.count then
                            --player:sendTextMessage(type, text[, position, primaryValue = 0, primaryColor = TEXTCOLOR_NONE[, secondaryValue = 0, secondaryColor = TEXTCOLOR_NONE]])
                            player:say(((config.showName and Tasks[player:getStorageValue(v.task)].name) and (Tasks[player:getStorageValue(v.task)].name) or '') .." ["..killed .."/"..actualTask.count.."]", TALKTYPE_MONSTER_YELL, false, player, tpos)
                            --player:sendTextMessage(MESSAGE_STATUS_DEFAULT, "Killed ".. ((config.showName and Tasks[player:getStorageValue(v.task)].name) and (Tasks[player:getStorageValue(v.task)].name) or '') .." ["..killed .."/"..actualTask.count.."]")
                        end
                    end
                end
            end
        end
    end

return true
end
 
Solution
I won't give you the solution but I'll tell you what you should pay attention to.

OnKill is a callback that can be called twice each time a creature is killed.
This happens specially if the death has two attackers and the last hit was not delivered by the same attacker that did most damage.

This can be mitigated by expanding your callback to have a third parameter to say if the person was the last hit or not, and checking for that.


One might feel tempted to just go to your script and put to iterate on each party member, this needs to have extra checks to guarantee people are within the same screen as monster and this script of yours is not even particulary checking if the monster is a summon. In fact it's not even checking if it's a monster, I could create a character named Demon and finish a task by killing it.


Take a look at how I did my task system, for instance (some of those checks can be optimized with the use of monstro:isSummon() that didn't existed back then.

Lua:
dofile('data/lib/tasklib.lua')
local config = {
    countForParty = true, -- a kill contara para todos os membros da party?
    showName = true,
    maxDist = 7 -- se a distancia do player para o monstro for maior que esse valor, a task nao conta pra ele.
}

function onKill(player, monstro, lasthit)
    if not lasthit or not Player(player.uid) or not Monster(monstro.uid) then return true end
    local target = Monster(monstro.uid)
    if type(target:getMaster()) ~= 'nil' then return true end

    local killers = {}
    local tpos = target:getPosition()

    if config.countForParty then
        local party = player:getParty()
        if party and party:isSharedExperienceActive() and party:getMembers() then
            for i, creature in pairs(party:getMembers()) do
                local pos = creature:getPosition()
                if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                    killers[#killers + 1] = creature.uid
                end
            end
            local pos = party:getLeader():getPosition()
            if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                killers[#killers + 1] = party:getLeader().uid
            end
        else
            killers[1] = player.uid
        end
    else
        killers[1] = player.uid
    end

    for i = 1, #killers do
        local player = Player(killers[i])
        for _, v in ipairs(Task_storages) do
            if player:getStorageValue(v.task) and player:getStorageValue(v.task) > 0 then
                if Tasks[player:getStorageValue(v.task)] and isInArray(Tasks[player:getStorageValue(v.task)].creatures, target:getName()) then
                    local actualTask = Tasks[player:getStorageValue(v.task)]
                    local killed = player:getStorageValue(v.count)
                    if killed < actualTask.count then
                        killed = killed + 1
                        player:setStorageValue(v.count, killed)
                        if killed == actualTask.count then
                            local answer = player:getTaskMessage(Tasks, player:getStorageValue(v.task), "Complete")
                            if answer then
                                message = answer
                            else
                                message = "You finished your task."
                            end
                            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message)
                        elseif killed < actualTask.count then
                            --player:sendTextMessage(type, text[, position, primaryValue = 0, primaryColor = TEXTCOLOR_NONE[, secondaryValue = 0, secondaryColor = TEXTCOLOR_NONE]])
                            player:say(((config.showName and Tasks[player:getStorageValue(v.task)].name) and (Tasks[player:getStorageValue(v.task)].name) or '') .." ["..killed .."/"..actualTask.count.."]", TALKTYPE_MONSTER_YELL, false, player, tpos)
                            --player:sendTextMessage(MESSAGE_STATUS_DEFAULT, "Killed ".. ((config.showName and Tasks[player:getStorageValue(v.task)].name) and (Tasks[player:getStorageValue(v.task)].name) or '') .." ["..killed .."/"..actualTask.count.."]")
                        end
                    end
                end
            end
        end
    end

return true
end
thanks for attention, i think using your example i have solved and add the verifications.
getting like this
Lua:
-- <event type="kill" name="TaskKill" script="NPC Task Creaturescript.lua" />
-- <event type="login" name="TaskKillLogin" script="NPC Task Creaturescript.lua" />
local config = {
    countForParty = true, -- a kill contara para todos os membros da party?
    showName = true,
    maxDist = 7 -- se a distancia do player para o monstro for maior que esse valor, a task nao conta pra ele.
}
local MonstersTask = {}

for k, v in pairs(TASK.Tasks) do
    for mob, count in pairs(v.Monsters) do
        if not MonstersTask[mob] then
            MonstersTask[mob] = {}
        end
        table.insert(MonstersTask[mob], k)
    end
end

function onLogin(player)
    player:registerEvent("TaskKill")
    return true
end

  
function onKill(player, target, lasthit)
    if (isSummon(target) or isPlayer(target)) then
        return false
    end   
    local mob = target:getName()
    if not MonstersTask[mob] then
        return true
    end
    local killers = {}
    local tpos = target:getPosition()

    if config.countForParty then
        local party = player:getParty()
        if party and party:isSharedExperienceEnabled() and party:getMembers() then
            for i, creature in pairs(party:getMembers()) do
                local pos = creature:getPosition()
                if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                    killers[#killers + 1] = creature.uid
                end
            end
            local pos = party:getLeader():getPosition()
            if pos.z == tpos.z and pos:getDistance(tpos) <= config.maxDist then
                killers[#killers + 1] = party:getLeader().uid
            end
        else
            killers[1] = player.uid
        end
    else
        killers[1] = player.uid
    end
    for i = 1, #killers do
    local player = Player(killers[i])
        print(player:getName())
        for k, v in pairs(player:getTasks().progress) do
            local TaskMobCount = TASK.Tasks[k].Monsters[mob]
            local KillCount = v[mob]
            if KillCount and isInArray(MonstersTask[mob], k) and KillCount < TaskMobCount then
                KillCount = KillCount+1
                player:setProgressTaskCount(k, mob, KillCount)
                if KillCount < TaskMobCount then
                    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, string.format("Task >> [%s]: Kill [%s/%s] %s%s.", k, KillCount, TaskMobCount, mob, (TaskMobCount > 1 and "s" or "")))
                elseif KillCount == TaskMobCount then
                    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, string.format("Task >> [%s]: Kill [%s/%s] %s%s Completed!", k, KillCount, TaskMobCount, mob, (TaskMobCount > 1 and "s" or "")))
                    local completed = true
                    for iTaskMob, iTaskCount in pairs(v) do
                        if iTaskCount < TASK.Tasks[k].Monsters[iTaskMob] then
                            completed = false
                        end
                    end
                    if completed then
                        player:sendTextMessage(MESSAGE_STATUS_WARNING, string.format("Task >> [%s]: Completed!", k))
                    end
                end
            end
        end
    end
    return true
end
 
You forgot to check if lastHit and ideally you shouldn't use return false.

I don't remember exactly the consequence of a return false for the onKill callback but I think it ignore frags
 
@Night Wolf can u share your task system? i looking for it
It's huge and I can't post here at otland due limit of characters.
Essentially this is the logic, the tasklib is just a few more functions and a lot of tables:


Lua:
dofile('data/lib/tasklib.lua')

local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

-- OTServ event handling functions start
function onCreatureAppear(cid)              npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid)           npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg)  npcHandler:onCreatureSay(cid, type, msg) end
function onThink()                      npcHandler:onThink() end
function onPlayerCloseChannel(cid) npcHandler:onPlayerCloseChannel(cid) end

local skillNames = {
    [1] = "Fist",
    [2] = "Club",
    [3] = "Sword",
    [4] = "Axe",
    [5] = "Distance",
    [6] = "Shield",
    [7] = "Fishing",
}

-- pre-processing to use in ordered task iterator
local config = {}
local first = 14020 -- first task
local last = first
for i in pairs(Tasks) do
    if i > last then
        last = i
    end
end
config.first = first
config.last = last

function Player:giveRewards(task)
    local taskname = Tasks[task].name and Tasks[task].name or Tasks[task].creatures[1]
    local reply = "For the ".. taskname .." task you have received:\n\n"
    local rewards = Tasks[task].rewards
    local count = 0
    for _ in pairs(rewards) do count = count + 1 end -- easist solution for the message problem.
    local ncount = count
    for option, value in pairs(rewards) do
        count = count - 1
        if option == 'addons' then -- Addons
            for _, v in ipairs(value) do
                local tpe = self:getSex() == 0 and v.female or v.male
                self:addOutfitAddon(tpe[1], tpe[2])
            end
            reply = reply.."- a new addon\n"
        elseif option == 'outfits' then -- Outfits
            for _, v in ipairs(value) do
                local tpe = self:getSex() == 0 and v.female or v.male
                self:addOutfit(tpe)
            end
            reply = reply.."- a new outfit\n"
        elseif option == 'storages' then -- Storages
            for _, v in ipairs(value) do
                self:setStorageValue(v.storage, v.value and v.value or 1)
            end
            reply = reply.."- new missions unblocked\n"
        elseif option == 'mounts' then -- Mounts
            for _, v in ipairs(value) do
                self:addMount(v)
            end
            reply = reply.."- a new mount\n"
        elseif option == 'skills' then -- Skills
            for _, v in ipairs(value) do
                self:addSkillTries(v.skillid, v.value)
            end
            reply = reply.."- "..v.value.." points of "..skillNames[v.skillid]:lower().." skill\n"
        elseif option == 'experience' then -- Experience
            local quantity = 1
            if type(value) == 'number' then
                quantity = value
            elseif value.relative then
                local t_task = Tasks[task]
                local mob = MonsterType(string.lower(t_task.creatures[1]))
                if mob then
                    quantity = mob:getExperience()
                else
                    print(t_task.creatures[1].. " is not determined in the game.")
                end
                quantity = quantity * t_task.count
                if value.stages then
                    local level = self:getLevel()
                    local experience = self:getExperience()
                    local nextLevelExperience = getExperienceForLevel(level + 1)
                    if experience > nextLevelExperience then
                        nextLevelExperience = experience
                    end
                    level = level + (experience/nextLevelExperience)
                    local multiplier = getMultiplier(level, Game.getExperienceStage(self:getLevel()), 1)
                    quantity = quantity * multiplier
                    if value.percent then
                        quantity = math.ceil((quantity * value.percent)/100)
                    end
                end
            end
            self:addExperience(quantity, true)
            reply = reply.."- "..quantity.." points of experience\n"
        elseif option == 'items' then -- Items
            reply = reply.."- The follow item"..(#value > 1 and 's' or '').." sent to mailbox:\n"
            local parcel = Container(doCreateItemEx(value.container and value.container or 2596))
            if value.random then
                local v = value[math.random(1, #value)]
                local newItem = nil
                if type(v[1]) == 'number'  then
                    newItem = Item(doCreateItemEx(v[1], v[2] or 1))
                else
                    local item = ItemType(v[1])
                    if item then
                        newItem = Item(doCreateItemEx(item:getId(), v[2] or 1))
                    end
                end
                if v.actionid then
                    newItem:setActionId(v.actionid)
                end
                reply = reply.."--> "..(v[2] > 1 and v[2] or "").." "..ItemType(v[1]):getName()..'\n'
                parcel:addItemEx(newItem)
            else
                for i, v in ipairs(value) do
                    if v.chance and v.chance < math.random(1, 100) then goto continue end
                    if v.vocation and v.vocation ~= self:getVocation():getId() then goto continue end
                    local newItem = nil
                    if type(v[1]) == 'number' then
                        newItem = Item(doCreateItemEx(v[1], v[2] or 1))
                    else -- if the name is written as string
                        local item = ItemType(v[1])
                        if item then
                            newItem = Item(doCreateItemEx(item:getId(), v[2] or 1))
                        end
                    end
                    if v.actionid then
                        newItem:setActionId(v.actionid)
                    end
                    local itemcount = v[2] and v[2] or 1
                    reply = reply.."--> "..(itemcount > 1 and itemcount.." "..ItemType(v[1]):getPluralName() or ItemType(v[1]):getName()).."\n"
                    parcel:addItemEx(newItem)
                    ::continue::
                end
            end
            local packagename = (taskname):lower()..' task package'
            parcel:setAttribute(ITEM_ATTRIBUTE_NAME, packagename)

            local inbox = self:getInbox()
            inbox:addItemEx(parcel, INDEX_WHEREEVER, FLAG_NOLIMIT)
        elseif option == 'choose' then
        end
    end
    local answer = self:getTaskMessage(Tasks, task, "Deliver")
    if answer then
        reply = reply.."\n"..answer
    else
        reply = reply.."\nEnjoy your ".. (ncount > 1 and 'prizes' or 'prize') .."!"
    end
    return reply
end

function Player:meetRequirements (i)
    if Tasks[i] and self:getLevel() >= Tasks[i].level and (not self:getStorageValue(i) or self:getStorageValue(i) < 0) then
        if Tasks[i].requirements then
            for i, k in ipairs(Tasks[i].requirements) do
                if k.storage and self:getStorageValue(k.storage) and self:getStorageValue(k.storage) < (k.value and k.value or 1) then
                    return false
                end
            end
        end
        return true
    end
    return false
end

function Player:updateStorages(task, sttask)
    self:setStorageValue(task, 1) -- set task as complete
    self:setStorageValue(Task_storages.ranking, math.max(self:getStorageValue(Task_storages.ranking), 0) + 1) -- Ranking on site
    self:setStorageValue(sttask.task, -1) -- clear storage task
    self:setStorageValue(sttask.count, 0) -- clear storage count
    local ttype = Tasks[task].type
    if self:getStorageValue(TaskTypes[ttype].storage) < 0 then
        self:setStorageValue(TaskTypes[ttype].storage, 0) -- set as 0 the storage of tasktype (meaning we already cleared at least one of the tasks, allowing us to proceed)
    end
    return true
end

function Player:getInProgressTasks()
    local doing = {}
    for i, v in ipairs(Task_storages) do
        if self:getStorageValue(v.task) > 0 then
            doing[#doing + 1] = {self:getStorageValue(v.task), i}
        end
    end
    return doing
end

function Player:getFreeSlot()
    for i, v in ipairs(Task_storages) do
        if not self:getStorageValue(v.task) or self:getStorageValue(v.task) <= 0 then
            return i
        end
    end
    return false
end

function creatureSayCallback(cid, typee, msg)
    if (not npcHandler:isFocused(cid)) then
        return false
    end

    local player = Player(cid)
    local window = ModalWindow {}

    window:addButton('Cancel')
    window:setDefaultEscapeButton('Cancel')

    if (msgcontains(msg, 'task') or msgcontains(msg, 'hunting')) then
        local maxTasks = #Task_storages
        local doing = player:getInProgressTasks()

        if #doing < maxTasks then
            local challenges = 0
            for ttype, tb in ipairs(TaskTypes) do
                local i = 1
                repeat
                    if tb.tasks[i] then
                        local task = tb.tasks[i]
                        if player:meetRequirements(task) then
                            local choice = window:addChoice(tb.name)
                            choice.correct = tb.tasks
                            challenges = challenges + 1
                            i = -1
                        end
                    end
                    i = i + 1
                until (i == 0 or i > (config.last - config.first))
            end
            -- Check if at least one task is available
            if challenges > 0 then
                local npc = Npc(getNpcCid())
                window.title = 'Choosing the task group'
                window.message = 'Which group of tasks are you interested to see?'

                local function ExpandTaskType(button1, choice1)
                    local NewWindow = ModalWindow {
                        title = 'Choosing the task',
                        message = "Inside the ".. choice1.text .." group there are this options. \nChoose the one that fits you better."
                    }
                    NewWindow:addButton('Cancel',
                        function(button2, choice2)
                            npc:say("No interest in making a task? Ok then.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                        end
                    )
                    NewWindow:setDefaultEscapeButton('Cancel')

                    NewWindow:addButton('Back',
                        function(button2, choice2)
                            window:sendToPlayer(player)
                            npc:say("You are back to the group selection screen.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                        end
                    )

                    NewWindow:addButton('Choose',
                        function(button2, choice2)
                            local taskid = choice2.correct
                            local freeSlot = player:getFreeSlot()
                            if freeSlot then
                                player:setStorageValue(Task_storages[freeSlot].task, taskid)
                                player:setStorageValue(Task_storages[freeSlot].count, 0)
                                player:setStorageValue(taskid, 0)
                                -- Trigger accepted messages
                                local answer = player:getTaskMessage(Tasks, choice2.correct, "Accept")
                                if answer then
                                    npc:say(answer, TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                                else
                                    npc:say("You have choosen {".. choice2.text.. "} task and I want you to kill {".. Tasks[taskid].count .."} of them. Come talk to me again once you have finished it.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                                end
                                local reply = "The following creatures will count towards your task count:\n\n"
                                for i, mob in pairs(Tasks[taskid].creatures) do
                                    reply = reply.."- "..mob.."\n"
                                end
                                reply = reply.."\nAny of these creatures will count when killed. If you're in party with shared exp active and in the same screen of the killed creatured it will count regardless of who in the party did the last blow."
                                player:showTextDialog(13831, reply)
                            end
                        end
                    )
                    NewWindow:setDefaultEnterButton('Choose')

                    local tasks = choice1.correct
                    local doing = player:getInProgressTasks()

                    for _, t in ipairs(tasks) do
                        if player:meetRequirements(t) then
                            local name = Tasks[t].name and Tasks[t].name or Tasks[t].creatures[1]
                            local choice = NewWindow:addChoice(name)
                            choice.correct = t
                        end
                    end

                    NewWindow:sendToPlayer(player)
                    npc:say("In this group I have the following tasks.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                    return true
                end

                window:addButton('Select', ExpandTaskType)
                window:setDefaultEnterButton('Select')
                window:setDefaultCallback(
                    function(button, choice)
                        npc:say("Not interest in starting a task? It's fine, I know this isn't for everyone...", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                    end
                )
                window:sendToPlayer(player)
                npcHandler:say("I have many kinds of tasks, choose the group that fits you best.", cid)
            else
                npcHandler:say("Actually things are going pretty calm these days and I don't really need your help in any hunt.", cid)
            end
        else
            npcHandler:say("As I told you before, you can have only {".. maxTasks .."} active "..(maxTasks > 1 and 'tasks' or 'task').." at time. Tell me if you need to {cancel} one.", cid)
        end
    ---------- cancel ------------
    elseif msgcontains(msg, 'cancel') then
        local doing = player:getInProgressTasks()
        if #doing == 0 then
            npcHandler:say("You are not doing any task and therefore can't cancel a task, why don't you start one? (say {task} to begin)", cid)
        else
            local npc = Npc(getNpcCid())
            window.title = 'Cancel Task'
            window.message = 'Which task do you want to cancel?'

            for _, t in ipairs(doing) do
                local task = t[1]
                local name = Tasks[task].name and Tasks[task].name or Tasks[task].creatures[1]
                local choice = window:addChoice(name)
                choice.correct = t
            end

            local function MakeSure(button1, choice1)
                local task = choice1.correct[1]
                local sttask = Task_storages[choice1.correct[2]]
                --player:updateStorages(task, sttask)
                local NewWindow = ModalWindow {
                    title = 'Cancel Task',
                    message = "Are you sure you want to cancel ".. choice1.text .." task?"
                }
                NewWindow:addButton('Cancel',
                    function(button2, choice2)
                        npc:say("Ok then, we can do this later.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                    end
                )
                NewWindow:setDefaultEscapeButton('Cancel')

                NewWindow:addButton('Yes',
                    function(button2, choice2)
                        player:setStorageValue(task, -1)
                        player:setStorageValue(sttask.task, -1)
                        player:setStorageValue(sttask.count, -1)
                        npc:say("You are no longer doing the ".. choice1.text.." task.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                    end
                )
                NewWindow:setDefaultEnterButton('Yes')

                NewWindow:sendToPlayer(player)
                npc:say("Please confirm your will.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
            end

            window:addButton('Choose', MakeSure)
            window:setDefaultEnterButton('Choose')
            window:setDefaultCallback(
                function(button, choice)
                    npc:say("Ok then, we can do this later.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                end
            )
            window:sendToPlayer(player)
            npcHandler:say("Choose the task you want to cancel and press \"Choose\" button.", cid)
        end
    ---------- rewards ------------
    elseif msgcontains(msg, 'reward') then
        local doing = player:getInProgressTasks()

        if #doing == 0 then
            npcHandler:say("You are not even doing any task... If you are so avid for a reward, let's start one!", cid)
        else
            local finished = {}
            for i = 1, #doing do
                if player:getStorageValue(Task_storages[doing[i][2]].count) >= Tasks[doing[i][1]].count then
                    finished[#finished + 1] = doing[i]
                end
            end
            if #finished == 0 then
                npcHandler:say("You didn't finished any task yet, check your questlog for more details on your progress.", cid)
            else
                local npc = Npc(getNpcCid())
                window.title = 'Collect Rewards'
                window.message = 'For which task do you want to collect your rewards?'

                for _, t in ipairs(finished) do
                    local task = t[1]
                    local name = Tasks[task].name and Tasks[task].name or Tasks[task].creatures[1]
                    local choice = window:addChoice(name)
                    choice.correct = t
                end

                local function ProcessCompletion(button, choice)
                    local task = choice.correct[1]
                    local sttask = Task_storages[choice.correct[2]]
                    player:updateStorages(task, sttask)
                    local reply = player:giveRewards(task)
                    player:showTextDialog(2596, reply)
                    npc:say("Here's your prize!", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                end

                window:addButton('Claim', ProcessCompletion)
                window:setDefaultCallback(
                    function(button, choice)
                        npc:say("Ok then, we can do this later.", TALKTYPE_PRIVATE_NP, false, player, npc:getPosition())
                    end
                )
                window:setDefaultEnterButton('Claim')
                window:sendToPlayer(player)
                npcHandler:say("Choose the task you want to finish.", cid)
            end
        end
    end
    return true
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())
 
Back
Top