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

Advanced Task NPC

nowitsky

Member
Joined
Jun 26, 2016
Messages
88
Solutions
2
Reaction score
12
I tested it on TFS 1.3.

Some bugs:
If u don't say "Bye" to npc he is always in talk with you everywhere,
I finish Rats task, if i was trying to start Troll task it take me back co Rats task.
 

Naimad4

Premium User
Premium User
Joined
Jul 27, 2018
Messages
14
Reaction score
1
Converted to Modal Windows

Creaturescript.xml
Code:
<event type="modalwindow" name="TaskSystemWindow" script="TaskSystemWindow.lua" />
<event type="kill" name="TaskSystemKill" script="TaskSystemKill.lua" />

add creaturescript: TaskSystemWindow.lua
Code:
local npcMissions = {
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [1] = {name = "Rat Killer", -- Kill monsters only
        arrayName = {"Rat", "rat", "Rats", "rats", "Pest", "pest", "Pests", "pests", "rat killer", "Rat killer", "Rat Killer"},
        storageMission = 43000, -- Mission storage should be unique even in different NPC files.
        storageRequired = nil, -- Use this to require different tasks to be done complete before this task can be started.
        messageTaskInfo = "I need you to kill 10 rats and 10 cave rats.", -- This message is said to the player when he starts the task.
        messageTaskComplete = "Thank you! Those pests have ruined my store. unfortunately they will be back. The rats aren't the main {problem}", -- This message is said to the player when he finishs the task.
        windowMsg = "Kill rats in the basement.", -- This text is shown under the title of the modal window
        monsters = { -- Monster task
            [1] = {name = "Rat", amount = 10, storage = 41000}, -- Monster storages should be unique even in different NPC files.
            [2] = {name = "Cave Rat", amount = 10, storage = 41001}
        },
        --Rewards--
        exp = 1000, -- Exp given to the player for completing the task.
        rewardItems = { -- Items given to the player for completing the task.
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = nil -- Use this to set any storages you want to when the player completes the task excluding storageNpc and storageMission
    },
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [2] = {name = "Troll Hunter",
        arrayName = {"troll hunter", "Troll Hunter", "Troll", "troll", "Trolls", "trolls"},
        storageMission = 43001,
        storageRequired = {43000},
        messageTaskInfo = "I need you to kill 20 trolls.",
        messageTaskComplete = "You are truley a legend. There is one more thing I need. Could you {help} me one more time?",
        windowMsg = "Kill trolls in the forst to the east. Also, collect x items",
        monsters = {
            [1] = {name = "Troll", amount = 20, storage = 41002},
        },
        collectItems = { -- Collect Items task
            [1] = {itemid = 1111, amount = 1}
        },
        --Rewards--
        exp = 5000,
        rewardItems = {
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = {
            [1] = {41532, 1}
        }
    },
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [3] = {name = "The Collector", -- Collect Items only
        arrayName = {"collector", "Collector", "collect", "Collect", "cheese", "Cheese"},
        storageMission = 43003,
        storageRequired = {43001, 43002},
        messageTaskInfo = "I need you to collect 10 cheese.",
        messageTaskComplete = "You are truley a legend. I do not need anymore help.",
        windowMsg = "Collect x items",
        collectItems = { -- Collect Items task
            [1] = {itemid = 1111, amount = 1}
        },
        --Rewards--
        exp = 5000,
        rewardItems = {
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = nil
    }
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
}

function onModalWindow(player, modalWindowId, buttonId, choiceId)
    if modalWindowId == 0x10 then
        if buttonId == 0x01 then
            local TASK = npcMissions[choiceId]
           
            if not TASK then print('Internal Error finding Task') return false end
            if player:getStorageValue(TASK.storageMission) == 2 then
                local window = ModalWindow(0x12, TASK.name, TASK.windowMsg)
                window:addChoice(0x00, "You have already completed this task.")
                window:addButton(0x00, "Exit")
                window:setDefaultEnterButton(0x00)
                window:sendToPlayer(player)
                return true
            elseif player:getStorageValue(TASK.storageMission) == 1 then
                local window = ModalWindow(0x12, TASK.name, TASK.windowMsg)
                local count = 1
                if TASK.monsters then
                    for i = 1, #TASK.monsters do
                        window:addChoice(count, "("..player:getStorageValue(TASK.monsters[i].storage).."/"..TASK.monsters[i].amount.." "..TASK.monsters[i].name..".")
                        count = count + 1
                    end
                end
               
                if TASK.collectItems then
                    for i = 1, #TASK.collectItems do
                        window:addChoice(count, "("..player:getItemCount(TASK.collectItems[i].itemid).."/"..TASK.collectItems[i].amount.." "..ItemType(TASK.collectItems[i].itemid):getName()..".")
                        count = count + 1
                    end
                end
               
                window:addButton(0x00, "Exit")
                window:addButton(choiceId, "Turn-In")
                window:setDefaultEnterButton(0x01)
                window:sendToPlayer(player)
                return true
               
            elseif player:getStorageValue(TASK.storageMission) == -1 then
                local window = ModalWindow(0x11, TASK.name, TASK.windowMsg)
                local count = 1
                if TASK.monsters then
                    for i = 1, #TASK.monsters do
                        window:addChoice(count, "Kill: "..TASK.monsters[i].amount.." "..TASK.monsters[i].name..".")
                        count = count + 1
                    end
                end
               
                if TASK.collectItems then
                    for i = 1, #TASK.collectItems do
                        window:addChoice(count, "Collect: "..TASK.collectItems[i].amount.." "..ItemType(TASK.collectItems[i].itemid):getName()..".")
                        count = count + 1
                    end
                end
               
                window:addButton(0x00, "Exit")
                window:addButton(choiceId, "Accept")
                window:setDefaultEnterButton(0x01)
                window:sendToPlayer(player)
                return true
            end
            return true
        end
   
    elseif modalWindowId == 0x11 then
            local TASK = npcMissions[buttonId]
       
            if not TASK then print('Internal Error finding Task') return false end
       
            player:setStorageValue(TASK.storageMission, 1)
       
            if TASK.monsters then
                for i = 1, #TASK.monsters do
                    player:setStorageValue(TASK.monsters[i].storage, 0)
                end
            end
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You have started: "..TASK.name.."!")
            return true
           
    elseif modalWindowId == 0x12 then
            local TASK = npcMissions[buttonId]
           
            if not TASK then print('Internal Error finding Task') return false end
           
            local canTurnIn = true
           
            if TASK.monsters then
                for i = 1, #TASK.monsters do
                    if player:getStorageValue(TASK.monsters[i].storage) < TASK.monsters[i].amount then
                        canTurnIn = false
                    end
                end
            end
           
            if TASK.collectItems then
                for i = 1, #TASK.collectItems do
                    if player:getItemCount(TASK.collectItems[i].itemid) < TASK.collectItems[i].amount then
                        canTurnIn = false
                    end
                end
            end
           
            if canTurnIn then
                if TASK.monsters then
                    for i = 1, #TASK.monsters do
                        player:setStorageValue(TASK.monsters[i].storage, -1)
                    end
                end
           
                if TASK.collectItems then
                    for i = 1, #TASK.collectItems do
                        player:removeItem(TASK.collectItems[i].itemid, TASK.collectItems[i].amount)
                    end
                end
               
                player:setStorageValue(TASK.storageMission, 2)
               
                if TASK.exp then
                    player:addExperience(TASK.exp)
                end
               
                if TASK.rewardItems then
                    for i = 1, #TASK.rewardItems do
                        player:addItem(TASK.rewardItems[i].itemid, TASK.rewardItems[i].amount, true)
                    end
                end
               
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You have completed: "..TASK.name.."!")
            else
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You are not ready to turn in this task.")
            end
        end
    return true
end

add creaturescript: TaskSystemKill.lua
Code:
local missions = { -- Use missionStorage to link the monsters to each mission. It is set up this way so multiple missions can have the same monsters.
    [1] = {name = "Rat", amount = 10, missionStorage = 43000, storage = 41000},
    [2] = {name = "Cave Rat", amount = 10, missionStorage = 43000, storage = 41001},
    [3] = {name = "Troll", amount = 10, missionStorage = 43001, storage = 41002}
}

function onKill(creature, target)
    if isPlayer(creature) and isMonster(target) then
        for i = 1, #missions do
            if target:getName() == missions[i].name then
                if creature:getStorageValue(missions[i].missionStorage) == 1 then
                    if creature:getStorageValue(missions[i].storage) < missions[i].amount then
                        creature:setStorageValue(missions[i].storage, creature:getStorageValue(missions[i].storage) + 1)
                        creature:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You have killed "..creature:getStorageValue(missions[i].storage).."/"..missions[i].amount..") "..missions[i].name.."('s)")
                    end
                end
            end
        end
    end
    return true
end

NPC file
Code:
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

npcHandler:addModule(FocusModule:new())

local npcMissions = {
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [1] = {name = "Rat Killer", -- Kill monsters only
        arrayName = {"Rat", "rat", "Rats", "rats", "Pest", "pest", "Pests", "pests", "rat killer", "Rat killer", "Rat Killer"},
        storageMission = 43000, -- Mission storage should be unique even in different NPC files.
        storageRequired = nil, -- Use this to require different tasks to be done complete before this task can be started.
        messageTaskInfo = "I need you to kill 10 rats and 10 cave rats.", -- This message is said to the player when he starts the task.
        messageTaskComplete = "Thank you! Those pests have ruined my store. unfortunately they will be back. The rats aren't the main {problem}", -- This message is said to the player when he finishs the task.
        windowMsg = "Kill rats in the basement.", -- This text is shown under the title of the modal window
        monsters = { -- Monster task
            [1] = {name = "Rat", amount = 10, storage = 41000}, -- Monster storages should be unique even in different NPC files.
            [2] = {name = "Cave Rat", amount = 10, storage = 41001}
        },
        --Rewards--
        exp = 1000, -- Exp given to the player for completing the task.
        rewardItems = { -- Items given to the player for completing the task.
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = nil -- Use this to set any storages you want to when the player completes the task excluding storageNpc and storageMission
    },
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [2] = {name = "Troll Hunter",
        arrayName = {"troll hunter", "Troll Hunter", "Troll", "troll", "Trolls", "trolls"},
        storageMission = 43001,
        storageRequired = {43000},
        messageTaskInfo = "I need you to kill 20 trolls.",
        messageTaskComplete = "You are truley a legend. There is one more thing I need. Could you {help} me one more time?",
        windowMsg = "Kill trolls in the forst to the east. Also, collect x items",
        monsters = {
            [1] = {name = "Troll", amount = 20, storage = 41002},
        },
        collectItems = { -- Collect Items task
            [1] = {itemid = 1111, amount = 1}
        },
        --Rewards--
        exp = 5000,
        rewardItems = {
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = {
            [1] = {41532, 1}
        }
    },
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    [3] = {name = "The Collector", -- Collect Items only
        arrayName = {"collector", "Collector", "collect", "Collect", "cheese", "Cheese"},
        storageMission = 43003,
        storageRequired = {43001, 43002},
        messageTaskInfo = "I need you to collect 10 cheese.",
        messageTaskComplete = "You are truley a legend. I do not need anymore help.",
        windowMsg = "Collect x items",
        collectItems = { -- Collect Items task
            [1] = {itemid = 1111, amount = 1}
        },
        --Rewards--
        exp = 5000,
        rewardItems = {
            [1] = {itemid = 2390, amount = 1}
        },
        setStorage = nil
    }
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
    --------------------------------------------------------------------------------------------------------------------------------
}

local npcStory = { -- This story is told when the player first talks to the npc.
    [1] = "Not now adventurer. I have to deal with these pests.",
    [2] = "Honey! Get my broom, these things are everywhere. They aren't even scared of me!?",
    [3] = "If this continues we will have to close down our business!",
    [4] = "Please god send us some {help}!"
}

local MESSAGES_GREET = { -- Messages are based on the npcStorage for the player. This table handles all greeting interaction between the npc and player.
  --Storage / message
  -- The player gets his storage for the npc set as soon as he talks to the npc
  -- The players stoarge is set to 0. This table is accessed by MESSAGES[player:getStorageValue(npcStorage) - 1]
  -- Everytime a player accepts and completes one of the tasks/missions his npcStorage is increased by 1. That is how the code keeps track of how the npc should respond to the player.
    [1] = "Hello again |PLAYERNAME|. Do you want to {help} me yet?",
    [2] = "I am glad you decided to help. Are those {rats} giving you a problem?",
    [3] = "Thanks for killing those rats. I have another {task} I need {help} with.",
    [4] = "The trolls are powerful. Be sure to take strong gear with you.",
    [5] = "Thank you for all your help."
}

local MESSAGES_GOODBYE = { -- This works the same as MESSAGES_GREET. Depending on how many tasks the player has done for the npc. The npc will say different things when he says goodbye to the player.
    [1] = "Thanks for nothing |PLAYERNAME|.",
    [2] = "Thank you for your help. Goodbye.",
    [3] = "You have helped so much. I will be sure to tell other of you."
}

local arrayGreetings = {"hi", "Hi", "hello", "Hello", "hey", "Hey", "oi", "Oi", "hola", "Hola"}
local arrayFarewell = {"bye", "Bye", "goodbye", "Goodbye", "good-bye", "Good-Bye", "Good-bye", "cya", "adios", "Adios"}

local messageHearStoryAgain = "story"
local messageCheckTasks = {"help", "Help", "task", "Task", "tasks", "Tasks"}
local messageShowTasks = "Here is what I need help with."

local messageCompletedAllTasks = "Thank you for all you have done. I dont need anymore help."
local taskWindowTitle = "Title of Modal Window"
local taskWindowText = "Tasks"

local npcStorage = 45000

function onCreatureSay(cid, type, msg)
    local player = Player(cid)
    local playerGreetMessage = MESSAGES_GREET[player:getStorageValue(npcStorage)]
    local playerGoodbyeMessage = MESSAGES_GOODBYE[player:getStorageValue(npcStorage)]

    if isInArray(arrayGreetings, msg) and not npcHandler:isFocused(cid) and player:getStorageValue(npcStorage) == -1 then
        npcHandler:addFocus(cid)
        npcHandler:say(npcStory, player:getId(), false, true, 4000)
        player:setStorageValue(npcStorage, 1)

    elseif isInArray(arrayGreetings, msg) and not npcHandler:isFocused(cid) then
        npcHandler:addFocus(cid)
        if string.find(playerGreetMessage, "|PLAYERNAME|") then
            local newMsg = string.gsub(playerGreetMessage, "|PLAYERNAME|", player:getName())
            selfSay(newMsg, cid)
        else
            selfSay(playerGreetMessage, cid)
        end
    
    elseif isInArray(arrayFarewell, msg) and npcHandler:isFocused(cid) then
        if string.find(playerGoodbyeMessage, "|PLAYERNAME|") then
            local newMsg = string.gsub(playerGoodbyeMessage, "|PLAYERNAME|", player:getName())
            selfSay(newMsg, cid)
        else
            selfSay(playerGoodbyeMessage, cid)
        end
        player:setStorageValue(npcStorage, -1)
        npcHandler:releaseFocus(cid)
    
    elseif isInArray(messageCheckTasks, msg) and npcHandler:isFocused(cid) then
        local text = messageShowTasks
        local window = ModalWindow(0x10, taskWindowTitle, taskWindowText)
        local hasMissions = false
        for i = 1, #npcMissions do
            if player:getStorageValue(npcMissions[i].storageMission) < 2 then
                if npcMissions[i].storageRequired then
                local showTask = true
                    for x = 1, #npcMissions[i].storageRequired do
                        if player:getStorageValue(npcMissions[i].storageRequired[x]) ~= 2 then
                            showTask = false
                            break
                        end
                    end
                
                    if showTask then
                        window:addChoice(i, npcMissions[i].name)
                        hasMissions = true
                    end
                else
                    window:addChoice(i, npcMissions[i].name)
                    hasMissions = true
                end
            end
        end
    
        if hasMissions then
            window:addButton(0x00, "Exit")
            window:addButton(0x01, "Select")
            window:setDefaultEnterButton(0x01)
            window:sendToPlayer(player)
            return true
        else
            selfSay(messageCompletedAllTasks, cid)
            return true
        end
    end
return true
end

I have added everything as in this quote from you
I added the 2 scripts into creaturescripts\scripts and put the 2 lines into .xml

also I have taken NPC script from you which is working untill:

18:12 Jester: Hello again Gamemaster. Do you want to help me yet?

When I write 'help', following error appears in console

Lua Script Error: [Npc interface]
data/npc/scripts/test.lua:eek:nCreatureSay
data/npc/scripts/test.lua:153: attempt to call global 'ModalWindow' (a nil value)
stack traceback:
[C]: in function 'ModalWindow'
data/npc/scripts/test.lua:153: in function <data/npc/scripts/test.lua:122>

errors when I run the server:

[Error - CreatureEvent::configureEvent] Invalid type for creature event: TaskSystemWindow
[Warning - BaseEvents::loadFromXml] Failed to configure event

I am using TFS 1.3 from Nekiro 8.6 downgrade!
I saw that you're saying it's working on 1.3. That's why I was confused why it didnt work for me :S
 
OP
Itutorial

Itutorial

Premium User
Premium User
Joined
Dec 23, 2014
Messages
1,876
Solutions
50
Reaction score
594
Okay guys. I want to update this but I need to know exactly what people need the code to do. There is too much to try to put into one npc file for all of this. PM me here on otland and I can create the exact NPC you are looking for.
 

Evil Puncker

prolonged absenteeism
TFS Developer
Joined
May 30, 2009
Messages
7,675
Solutions
182
Reaction score
3,466
I am using TFS 1.3 from Nekiro 8.6 downgrade!
I saw that you're saying it's working on 1.3. That's why I was confused why it didnt work for me :S
modal windows doesn't exist in 8.6 client, that is why you get errors
 

Dip Set

Well-Known Member
Joined
Dec 27, 2007
Messages
129
Solutions
1
Reaction score
68
Tested Modal Windows conversion on TFS 1.3+, npc responds to hi, task, loads modal window, with Rat Killer, but after that you can't select anything. Also he does not lose focus on the player until you say bye.
1591100729963.png
to clarify, upon hitting "Select" the window disappears, same as with Exit.
 

oualid6496

Well-Known Member
Joined
Aug 24, 2014
Messages
408
Solutions
4
Reaction score
77
Location
Dordrecht, The Netherlands
Tested Modal Windows conversion on TFS 1.3+, npc responds to hi, task, loads modal window, with Rat Killer, but after that you can't select anything. Also he does not lose focus on the player until you say bye.
View attachment 46241
to clarify, upon hitting "Select" the window disappears, same as with Exit.
Same problem
 

Dip Set

Well-Known Member
Joined
Dec 27, 2007
Messages
129
Solutions
1
Reaction score
68
I'll try to take a look at it if I get time, honestly forgot about it
 

Zodia

Member
Joined
Feb 21, 2020
Messages
154
Reaction score
6
Converter I tried for the Nostalrius 7.7 tfs 1.2 server still without success. Does anyone give a light?
 
OP
Itutorial

Itutorial

Premium User
Premium User
Joined
Dec 23, 2014
Messages
1,876
Solutions
50
Reaction score
594
Remember modal windows doesn't exist until 9.6+ i believe
 

nowitsky

Member
Joined
Jun 26, 2016
Messages
88
Solutions
2
Reaction score
12
with modal windows i have a problem, if i push Select window gone.
with no modal windows, rats are not counted.
 
Top