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

CreatureEvent [TFS 1.2] Task System

rwxsu

Computer Engineer
Joined
Mar 31, 2018
Messages
121
Solutions
5
Reaction score
169
GitHub
rwxsu
Task System For TFS 1.2


Features:
* You can add as many tasks as you want
* You can add as many rewards as you want for each task
* You can add multiple monsters to a task, so it registers the kill on different monsters (e.g. dragon and dragon lord)
* You can change the name of the task
* You can choose what the NPC will tell the player for each task


See How Here:






7 simple steps


Add the NPC: data/npc/Tarr.xml
XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Tarr" script="Task.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="430" head="114" body="132" legs="95" feet="132" addons="1" />
    <parameters>
        <parameter key="message_greet" value="|PLAYERNAME|, need a task?" />
        <parameter key="message_walkaway" value="COME BACK WHEN YOU ARE PREPARED!" />
        <parameter key="message_farewell" value="COME BACK WHEN YOU ARE PREPARED!" />
    </parameters>
</npc>



Add the NPC script: data/npc/scripts/Task.lua
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

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 creatureSayCallback(cid, type, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end
   
    local player = Player(cid)

    if msgcontains(msg, 'task') or msgcontains(msg, 'mission') then
        task:new(player, npcHandler)
    end

    if msgcontains(msg, 'reset') then
        task:reset(player, npcHandler)
    end

    return true
end

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



Add the lib: data/lib/custom/task.lua
Lua:
------------------------------------------------------
--                   Firestorm by rwxsu             --
------------------------------------------------------
--               License: do as you please          --
------------------------------------------------------

debug = true -- Debug mode for developers
reset = true -- Reset tasks by saying 'reset' to npc


task = {
    storage = {
        onTask         = 6522000,
        monstersLeft = 6522001,
        completed    = 6522002,
        getFinished  = 6522003,
    },
    tasks = { -- You can add as many tasks as you want
        [1] = {
            name = "Slimy Worms", -- Name of Task
            description = "The slimy rotworms in the sewers are destroying the city. Please kill some of them for me.", -- What the NPC tells the player to do
            monsters = { -- You can add as many monsters as you want
                "Rotworm",
                "Carrion Worm",
            },
            toKill = 4, -- How many monsters the player needs to kill
            rewards = {    -- You can add as many rewards as you want
                [1] = {
                    name = "crystal coin",
                    itemid = 2160,
                    count = 3,
                },
                [2] = {
                    name = "magic sword",
                    itemid = 2400,
                    count = 1,
                },
            },
        },
        [2] = {
            name = "Firebreathers",
            description = "Dragons.. dragons.. dragons...", 
            monsters = {
                "Dragon",
                "Dragon Lord",
            },
            toKill = 3,
            rewards = {
                [1] = {
                    name = "crystal coin",
                    itemid = 2160,
                    count = 10,
                },
            },
        },
        [3] = {
            name = "Demonz",
            description = "Big, red and magical.", 
            monsters = {
                "Demon",
            },
            toKill = 1,
            rewards = {
                [1] = {
                    name = "crystal coin",
                    itemid = 2160,
                    count = 50,
                },
            },
        },
    },
}

task.__index = task

-- Finds out what the last task the player did was, if any,
-- and gives the player a new task
function task:new(player, npcHandler) 
    if task:getCompleted(player) > 0 then
        task:reward(player, npcHandler)
        task:set(player, 0)
        return false
    end

    if task:onTask(player) > 0 then
        npcHandler:say("You already have a task.", player:getId())
        task:debug(player:getName() .. " is already on a task " .. task.tasks[task:onTask(player)].name  .. ".")
        return false
    end

    local lastFinished = task:getFinished(player)
    if lastFinished == #task.tasks then
        npcHandler:say("You have completed all the tasks!", player:getId())
        return false
    end

    local newTask = lastFinished + 1
    task:set(player, newTask)
    npcHandler:say(task.tasks[newTask].description, player:getId())
    return true
end

-- Sets the task provided 't' to the player provided
function task:set(player, t)
    if player:setStorageValue(task.storage.onTask, t) then       
        if t == 0 then
            task:debug(player:getName() .. " is no longer on task.")
            return false
        end
        task:debug(player:getName() .. " started task " .. task.tasks[t].name .. ".")
       
        if player:setStorageValue(task.storage.monstersLeft, task.tasks[t].toKill) then
            return true
        end
    end   
    return false
end

function task:setCompleted(player, t)
    if player:setStorageValue(task.storage.completed, t) then
        if t == 0 then
            return true
        end
        return true
    end
    return false
end

function task:getCompleted(player)
    return player:getStorageValue(task.storage.completed)
end

function task:getMonstersLeft(player)
    return player:getStorageValue(task.storage.monstersLeft)
end

-- Checks if the player is currently doing a task
-- And returns the task the player is doing
function task:onTask(player)
    for i = 1, #task.tasks do
        if player:getStorageValue(task.storage.onTask) == i then
            return i
        end
    end
    return 0
end

function task:setFinished(player, t)
    if player:setStorageValue(task.storage.getFinished, t) then
        task:debug(player:getName() .. " finished task " .. task.tasks[t].name)
        return true
    end
    return false
end

-- Checks if the player has finished a task
-- And returns the task that is finished
function task:getFinished(player)
    for i = 1, #task.tasks do
        if player:getStorageValue(task.storage.getFinished) == i then
            return i
        end
    end
    return 0
end

-- Checks if the monster killed was a task monster
function task:onKill(player, target)
    currentTask = task:onTask(player)
    for i = 1, #task.tasks[currentTask].monsters do
        if string.lower(target:getName()) == string.lower(task.tasks[currentTask].monsters[i]) then
           
            if task:getMonstersLeft(player) < 1 then
                return false
            end

            player:setStorageValue(task.storage.monstersLeft, task:getMonstersLeft(player) - 1)
            if task:getMonstersLeft(player) == 0 then
                if task:setCompleted(player, currentTask) then
                    player:sendTextMessage(MESSAGE_STATUS_WARNING, "You have completed your task.")
                    task:debug(string.format("%s has completed %s.", player:getName(), task.tasks[currentTask].name))
                    return true
                end
            end

            player:sendTextMessage(MESSAGE_STATUS_WARNING, "You killed a " .. string.lower(target:getName()) .. ". Only " .. task:getMonstersLeft(player) .. " left to kill!")
            task:debug(player:getName() .. " killed a " .. string.lower(target:getName()) .. ". " .. task:getMonstersLeft(player) .. " monsters left.") 
            return true
        end
    end
    return false
end

function task:reward(player, npcHandler)
    local t = task:onTask(player)
    for i = 1, #task.tasks[t].rewards do
        player:addItem(task.tasks[t].rewards[i].itemid, task.tasks[t].rewards[i].count)
        player:sendTextMessage(MESSAGE_STATUS_WARNING, string.format("You received %dx %s(s).", task.tasks[t].rewards[i].count, task.tasks[t].rewards[i].name))
        task:debug(string.format(player:getName() .. " received %dx %s(s).", task.tasks[t].rewards[i].count, task.tasks[t].rewards[i].name))
    end

    npcHandler:say("Here you go!", player:getId())

    task:onTask(player, 0)
    task:setCompleted(player, 0)
    task:setFinished(player, t)
    return true
end

-- Toggle true/false at the top of this lua file
-- Resets the tasks for the provided player
function task:reset(player, npcHandler)
    if reset then
        player:setStorageValue(task.storage.onTask, 0)
        player:setStorageValue(task.storage.monstersLeft, 0)
        player:setStorageValue(task.storage.completed, 0)
        player:setStorageValue(task.storage.getFinished, 0)
        npcHandler:say("You have reseted all the tasks.", player:getId())
        task:debug(player:getName() .. " reseted his tasks.")
    end
end

-- Toggle true/false at the top of this lua file
function task:debug(string)
    if debug then
        string = "[TASK] " .. string
        print(string)
    end
end




Remember to add this in data/lib/lib.lua
Lua:
dofile('data/lib/custom/task.lua')



Add the onKill in data/creaturescripts/scripts/task.lua
Code:
function onKill(player, target, lastHit)
    if not (task:onTask(player) > 0) then
        return false
    end

    if not player:isPlayer() then
        return false
    end

    task:onKill(player, target)
    return true 
end



Link it with your xml: data/creaturescripts/creaturescripts.xml
XML:
<event type="kill" name="Task" script="task.lua" />



Lastly don't forget to register the event in data/creaturescripts/scripts/login.lua
Lua:
player:registerEvent("Task")




That's it! Hope you enjoy it,
rwxsu
 
Sadly, when i utevo res a monster it counts as a task monster. :/
 
i'd still be inefficient to kill your summons to progress.

~ mana used vs progress.
 
Sadly, when i utevo res a monster it counts as a task monster. :/


Replace the code in data/creaturescripts/scripts/task.lua with this:
Lua:
function onKill(player, target, lastHit)
    if not (task:onTask(player) > 0) then
        return false
    end

    if not player:isPlayer() then
        return false
    end

    if target:getMaster() ~= nil then
        return false
    end

    task:onKill(player, target)
    return true 
end


The only difference is:
Lua:
if target:getMaster() ~= nil then return false end

Thank you for your feedback,
rwxsu
 


Replace the code in data/creaturescripts/scripts/task.lua with this:
Lua:
function onKill(player, target, lastHit)
    if not (task:onTask(player) > 0) then
        return false
    end

    if not player:isPlayer() then
        return false
    end

    if target:getMaster() ~= nil then
        return false
    end

    task:onKill(player, target)
    return true 
end


The only difference is:
Lua:
if target:getMaster() ~= nil then return false end

Thank you for your feedback,
rwxsu

Sweet, Thank you :)

/Nixez
 
Hi!

how can i reward with experience or storage?
It's not implemented in this script, but you can do it like this:

- Under reward, set itemid to 0 and set the count to how much experience you want the player to get
- Then in the task:reward() function's for-loop, you do a check to see if itemid is 0, and if it is reward the player with count experience and return the function.
 
Hi, is it possible to change a bit code in files to let players decide which task they want to do?
 
Hello, is there any way to connect this to the Quest log in TFS 1.2?

If my 1st task is rotworms, 2nd orcs, 3rd dargons.......

I want my quest log to say something like:
Tasks
Mission 1: Rots (Completed)
Mission 2: Orcs (Completed)
Mission 3: Dragons

The storagevalues now seems to be reused of what i can make sense of in the code.

Hope you understand what i am trying to say :rolleyes:
 
I made a reset enhancement so that the player doesn't reset missions infinitely.

in task lib
Code:
task = {
    storage = {
        onTask         = 6522000,
        monstersLeft = 6522001,
        completed    = 6522002,
        getFinished  = 6522003,
        resetTime  = 6522004, -- Reset Storage
    },

in lib fuctions task:reset add
Code:
function task:reset(player, npcHandler)
    if player:getStorageValue(task.storage.resetTime) - os.time() <= 0 then
        if reset then
            player:setStorageValue(task.storage.resetTime, os.time() + 3600) -- 3600 seconds = 1 hour to reset
            player:setStorageValue(task.storage.onTask, 0)
            player:setStorageValue(task.storage.monstersLeft, 0)
            player:setStorageValue(task.storage.completed, 0)
            player:setStorageValue(task.storage.getFinished, 0)
            npcHandler:say("You have reseted all the tasks, wait 12 hours to reset again.", player:getId())
            task:debug(player:getName() .. " reseted his tasks.")
        end
    else
    player:sendTextMessage(MESSAGE_STATUS_WARNING,"[TASK] Wait 1 hour to be able to reset mission.")
    end
en
 
I made a reset enhancement so that the player doesn't reset missions infinitely.

in task lib
Code:
task = {
    storage = {
        onTask         = 6522000,
        monstersLeft = 6522001,
        completed    = 6522002,
        getFinished  = 6522003,
        resetTime  = 6522004, -- Reset Storage
    },

in lib fuctions task:reset add
Code:
function task:reset(player, npcHandler)
    if player:getStorageValue(task.storage.resetTime) - os.time() <= 0 then
        if reset then
            player:setStorageValue(task.storage.resetTime, os.time() + 3600) -- 3600 seconds = 1 hour to reset
            player:setStorageValue(task.storage.onTask, 0)
            player:setStorageValue(task.storage.monstersLeft, 0)
            player:setStorageValue(task.storage.completed, 0)
            player:setStorageValue(task.storage.getFinished, 0)
            npcHandler:say("You have reseted all the tasks, wait 12 hours to reset again.", player:getId())
            task:debug(player:getName() .. " reseted his tasks.")
        end
    else
    player:sendTextMessage(MESSAGE_STATUS_WARNING,"[TASK] Wait 1 hour to be able to reset mission.")
    end
en



Which file should I add this (below) code to?
Also to data/lib/custom/task.lua ?

Lua:
function task:reset(player, npcHandler)
    if player:getStorageValue(task.storage.resetTime) - os.time() <= 0 then
        if reset then
            player:setStorageValue(task.storage.resetTime, os.time() + 3600) -- 3600 seconds = 1 hour to reset
            player:setStorageValue(task.storage.onTask, 0)
            player:setStorageValue(task.storage.monstersLeft, 0)
            player:setStorageValue(task.storage.completed, 0)
            player:setStorageValue(task.storage.getFinished, 0)
            npcHandler:say("You have reseted all the tasks, wait 12 hours to reset again.", player:getId())
            task:debug(player:getName() .. " reseted his tasks.")
        end
    else
    player:sendTextMessage(MESSAGE_STATUS_WARNING,"[TASK] Wait 1 hour to be able to reset mission.")
    end
end
 
Replace Second First code for Second in task lib
Which file should I add this (below) code to?
Also to data/lib/custom/task.lua ?

Lua:
function task:reset(player, npcHandler)
    if player:getStorageValue(task.storage.resetTime) - os.time() <= 0 then
        if reset then
            player:setStorageValue(task.storage.resetTime, os.time() + 3600) -- 3600 seconds = 1 hour to reset
            player:setStorageValue(task.storage.onTask, 0)
            player:setStorageValue(task.storage.monstersLeft, 0)
            player:setStorageValue(task.storage.completed, 0)
            player:setStorageValue(task.storage.getFinished, 0)
            npcHandler:say("You have reseted all the tasks, wait 12 hours to reset again.", player:getId())
            task:debug(player:getName() .. " reseted his tasks.")
        end
    else
    player:sendTextMessage(MESSAGE_STATUS_WARNING,"[TASK] Wait 1 hour to be able to reset mission.")
    end
end
 
[TASK] playername killed a monster, 100 monster left, appears on the console, can I have it removed?
 
Back
Top