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

NPC Collecting items and monster missions

Hey very nice script! I will use it, but I want to make serval missions for different kind of items. Is it possible in this script?
For example i go and collect chicken feather minotaur leather.
I go to the NPC and say "chicken feather" and he will give me reward for chicken feather
But its not the "next" quest, I want to do parallel.

/bump
 
Last edited by a moderator:
Supports both monsters and items in the same task.
Credit goes to @Xagul for modifications

Code:
-- Collecting items and monster missions by Limos (Modified by Xagul to support both monsters and items in the same task)
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

local missions = {
   [1] = {
     items = {
       {id = 5890, count = 12},
       {id = 5878, count = 20},
       {id = 5894, count = 8}
     },
    monsters = {
       {name = "Chickens", count = 20, storage = 21905},
       {name = "Bats", count = 30, storage = 21906},
       {name = "Minotaurs", count = 40, storage = 21907}
     },
     message = "Great, for your first mission you need to...",
     level = 15, -- minimum level voor this mission
     rewarditems = {
       {id = 2160, count = 1},
       {id = 2152, count = 1}
     },
     rewardexp = 15000
   },
   [2] = {
     monsters = {
       {name = "Rats", count = 20, storage = 21900},
       {name = "Rotworms", count = 26, storage = 21901}
     },
     message = "Thanks, for your next mission...",
     level = 30,
     rewarditems = {
       {id = 2160, count = 5}
     },
     rewardexp = 40000
   },
   [3] = {
     items = {
       {id = 5920, count = 45},
       {id = 5877, count = 22}
     },
     message = "Awesome, now...",
     level = 50,
     rewarditems = {
       {id = 2160, count = 15}
     },
     rewardexp = 100000
   },
   [4] = {
     monsters = {
       {name = "Dragon Lords", count = 25, storage = 21902}
     },
     message = "Good job, now...",
     level = 70,
     rewarditems = {
       {id = 2160, count = 25}
     },
     rewardexp = 200000
   },
   [5] = {
     items = {
       {id = 5906, count = 35},
       {id = 5882, count = 42},
       {id = 4850, count = 1}
     },
     message = "Good, now for your final mission!",
     level = 100,
     rewarditems = {
       {id = 2160, count = 50}
     },
     rewardexp = 450000
   }
}

local storage = 45551

local function getItemsMonstersFromTable(imtable, imtype)
     local text = ""
     for v = 1, #imtable do
         local ret = ", "
         if v == 1 then
             ret = ""
         elseif v == #imtable then
             ret = " and "
         end
         text = text .. ret
         count = imtable[v].count
         if imtable[v].id then
             info = ItemType(imtable[v].id)
             text = text .. (count > 1 and count or info:getArticle()).." "..(count > 1 and info:getPluralName() or info:getName())
         else
             text = text .. count .." "..imtable[v].name
         end
     end

    if(text ~= "") then
        text = ((imtype == "monsters" and "Kill: ") or "Collect: ") .. text
    end
     return text
end

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

     local player = Player(cid)
     local x = missions[player:getStorageValue(storage)]

     if msgcontains(msg, 'mission') or msgcontains(msg, 'quest') then
         if player:getStorageValue(storage) == -1 then
             selfSay("I have several missions for you, do you accept the challenge?", cid)
             npcHandler.topic[cid] = 1
         elseif x then
             if player:getLevel() >= x.level then
                local missionstr = ""
              if(x.monsters) then
                   missionstr = getItemsMonstersFromTable(x.monsters, "monsters")
                end
                if(x.items) then
                   missionstr = missionstr .. ((missionstr ~= "" and "\n") or "") .. getItemsMonstersFromTable(x.items, "items")
                end
                 selfSay("Did you complete my task?\n".. missionstr, cid)
                 npcHandler.topic[cid] = 1
             else
                 selfSay("The mission I gave you is for level "..x.level..", come back later.", cid)
             end
         else
             selfSay("You already did all the missions, great job though.", cid)
             npcHandler:releaseFocus(cid)
         end
     elseif msgcontains(msg, 'yes') and npcHandler.topic[cid] == 1 then
         if player:getStorageValue(storage) == -1 then
             player:setStorageValue(storage, 1)
             local x = missions[player:getStorageValue(storage)]
      
            local missionstr = ""
            if(x.monsters) then
                missionstr = getItemsMonstersFromTable(x.monsters, "monsters")
            end
            if(x.items) then
                missionstr = missionstr .. ((missionstr ~= "" and "\n") or "") .. getItemsMonstersFromTable(x.items, "items")
            end
             selfSay(x.message.."\n".. missionstr ..".", cid)
         elseif x then
             local imtable = x.items or x.monsters
             local amount = 0
      
            local failed = false
            local failstr = ""
            -- Check Monsters
            for i, monster in ipairs(x.monsters) do
                local mstorage = player:getStorageValue(monster.storage)
                if(mstorage < 0) then
                   mstorage = 0
                end
        
                if(#x.monsters > 1 and i == #x.monsters) then
                    failstr = failstr .." and "
                elseif(i ~= 1) then
                    failstr = failstr ..", "
                else
                    failstr = "Sorry, you are still missing some things...\nYou have killed: "
                end
                failstr = failstr .. mstorage .."/".. monster.count .." ".. monster.name
        
               if(mstorage < monster.count) then
                    failed = true
                end
            end
      
            -- Check Items
            for i, item in ipairs(x.items) do
                local icount = player:getItemCount(item.id)        
        
                if(#x.items > 1 and i == #x.items) then
                    failstr = failstr .." and "
                elseif(i ~= 1) then
                    failstr = failstr ..", "
                elseif(failstr == "") then
                    failstr = "Sorry, you are still missing some things...\nYou have collected: "
                else
                    failstr = failstr .."\nYou have collected: "
                end
        
                local itemInfo = ItemType(item.id)
                failstr = failstr .. ((icount > item.count and item.count) or icount) .."/".. (item.count > 1 and item.count or itemInfo:getArticle()).." "..(item.count > 1 and itemInfo:getPluralName() or itemInfo:getName())
        
                if(icount < item.count) then
                    failed = true
               end
            end
      
            if(failed) then
               selfSay(failstr, cid)
            else
               if x.items then
                     for it = 1, #x.items do
                         player:removeItem(x.items[it].id, x.items[it].count)
                     end
                 end
                 if x.rewarditems then
                     for r = 1, #x.rewarditems do
                         player:addItem(x.rewarditems[r].id, x.rewarditems[r].count)
                     end
                     player:sendTextMessage(MESSAGE_EVENT_DEFAULT, "You received "..getItemsMonstersFromTable(x.rewarditems)..".")
                 end
                 if x.rewardexp then
                     player:addExperience(x.rewardexp)
                     player:sendTextMessage(MESSAGE_EVENT_DEFAULT, "You received "..x.rewardexp.." experience.")
                 end
                 player:setStorageValue(storage, player:getStorageValue(storage) + 1)
                 local x = missions[player:getStorageValue(storage)]
                 if x then              
                    local missionstr = ""
                      if(x.monsters) then
                        missionstr = getItemsMonstersFromTable(x.monsters, "monsters")
                    end
                    if(x.items) then
                        missionstr = missionstr .. ((missionstr ~= "" and "\n") or "") .. getItemsMonstersFromTable(x.items, "items")
                    end
                     selfSay(x.message.."\n".. missionstr ..".", cid)
                 else
                     selfSay("Well done! You did a great job on all your missions.", cid)
                 end
            end
         end
         npcHandler.topic[cid] = 0
     elseif msgcontains(msg, 'no') and npcHandler.topic[cid] == 1 then
         selfSay("Oh well, I guess not then.", cid)
         npcHandler.topic[cid] = 0
     end
     return true
end

npcHandler:setMessage(MESSAGE_FAREWELL, "Bye!")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Good bye, have a nice day!")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())

here is not counting the count of dead monsters.
 
any chance to display progress? like in this one:
NPC - [TFS 1.1] Monster Tasks

i think the line is this:
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Task message: '..(stor +1)..' of '..monster.amount..' '..target:getName()..'s killed.')

but i have no idea how to add implemt it since it might be just only part code in the function.
 
Hey Limos, AMAZING SHARE
thanks alot,
i liked how it tells what the player is missing for the quest.
great work on this npc, and scripts
thanks

Hey I'm back, anyone got to add more than 5 missions?
seems it rolls back to first mission after 5th.
it adds the rats again
i have to figure out how its adding missions to remove the limit?
hopefully i'll get it to work eventually
 
Last edited by a moderator:
Tested with TFS 1.0 and TFS 1.1.

Requested by giddy92.
Based on the collecting items missions NPC Mitrox.


mJ0JHC5G0.png



Soraya.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Soraya" script="missions.lua" walkinterval="2000" floorchange="0">
     <health now="100" max="100"/>
     <look type="471" head="59" body="132" legs="0" feet="57" addons="0"/>
     <parameters>
         <parameter key="message_greet" value="Hello |PLAYERNAME|."/>
     </parameters>
</npc>


missions.lua
Code:
-- Collecting items and monster missions by Limos
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

local missions = {
   [1] = {
     items = {
       {id = 5890, count = 12},
       {id = 5878, count = 20},
       {id = 5894, count = 8}
     },
     message = "Great, for your first mission you need to collect some items, I need",
     level = 15, -- minimum level voor this mission
     rewarditems = {
       {id = 2160, count = 1},
       {id = 2152, count = 1}
     },
     rewardexp = 15000
   },
   [2] = {
     monsters = {
       {name = "Rats", count = 20, storage = 21900},
       {name = "Rotworms", count = 26, storage = 21901}
     },
     message = "Thanks, for your next mission kill",
     level = 30,
     rewarditems = {
       {id = 2160, count = 5}
     },
     rewardexp = 40000
   },
   [3] = {
     items = {
       {id = 5920, count = 45},
       {id = 5877, count = 22}
     },
     message = "Awesome, now get",
     level = 50,
     rewarditems = {
       {id = 2160, count = 15}
     },
     rewardexp = 100000
   },
   [4] = {
     monsters = {
       {name = "Dragon Lords", count = 25, storage = 21902}
     },
     message = "Good job, now kill",
     level = 70,
     rewarditems = {
       {id = 2160, count = 25}
     },
     rewardexp = 200000
   },
   [5] = {
     items = {
       {id = 5906, count = 35},
       {id = 5882, count = 42},
       {id = 4850, count = 1}
     },
     message = "Good, now your final mission, there are a few more items you need to get,",
     level = 100,
     rewarditems = {
       {id = 2160, count = 50}
     },
     rewardexp = 450000
   }
}

local storage = 45551

local function getItemsMonstersFromTable(imtable)
     local text = ""
     for v = 1, #imtable do
         local ret = ", "
         if v == 1 then
             ret = ""
         elseif v == #imtable then
             ret = " and "
         end
         text = text .. ret
         count = imtable[v].count
         if imtable[v].id then
             info = ItemType(imtable[v].id)
             text = text .. (count > 1 and count or info:getArticle()).." "..(count > 1 and info:getPluralName() or info:getName())
         else
             text = text .. count .." "..imtable[v].name
         end
     end
     return text
end

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

     local player = Player(cid)
     local x = missions[player:getStorageValue(storage)]

     if msgcontains(msg, 'mission') or msgcontains(msg, 'quest') then
         if player:getStorageValue(storage) == -1 then
             selfSay("I have several missions for you, do you accept the challenge?", cid)
             npcHandler.topic[cid] = 1
         elseif x then
             if player:getLevel() >= x.level then
                 selfSay("Did you "..(x.items and "get "..getItemsMonstersFromTable(x.items) or "kill "..getItemsMonstersFromTable(x.monsters)).."?", cid)
                 npcHandler.topic[cid] = 1
             else
                 selfSay("The mission I gave you is for level "..x.level..", come back later.", cid)
             end
         else
             selfSay("You already did all the missions, great job though.", cid)
             npcHandler:releaseFocus(cid)
         end
     elseif msgcontains(msg, 'yes') and npcHandler.topic[cid] == 1 then
         if player:getStorageValue(storage) == -1 then
             player:setStorageValue(storage, 1)
             local x = missions[player:getStorageValue(storage)]
             selfSay(x.message.." "..getItemsMonstersFromTable(x.items or x.monsters)..".", cid)
         elseif x then
             local imtable = x.items or x.monsters
             local amount = 0
             for it = 1, #imtable do
                 local check = x.items and player:getItemCount(imtable[it].id) or player:getStorageValue(imtable[it].storage)
                 if check >= imtable[it].count then
                     amount = amount + 1
                 end
             end
             if amount == #imtable then
                 if x.items then
                     for it = 1, #x.items do
                         player:removeItem(x.items[it].id, x.items[it].count)
                     end
                 end
                 if x.rewarditems then
                     for r = 1, #x.rewarditems do
                         player:addItem(x.rewarditems[r].id, x.rewarditems[r].count)
                     end
                     player:sendTextMessage(MESSAGE_EVENT_DEFAULT, "You received "..getItemsMonstersFromTable(x.rewarditems)..".")
                 end
                 if x.rewardexp then
                     player:addExperience(x.rewardexp)
                     player:sendTextMessage(MESSAGE_EVENT_DEFAULT, "You received "..x.rewardexp.." experience.")
                 end
                 player:setStorageValue(storage, player:getStorageValue(storage) + 1)
                 local x = missions[player:getStorageValue(storage)]
                 if x then
                     selfSay(x.message.." "..getItemsMonstersFromTable(x.items or x.monsters)..".", cid)
                 else
                     selfSay("Well done! You did a great job on all your missions.", cid)
                 end
             else
                 local n = 0
                 for i = 1, #imtable do
                     local check = x.items and player:getItemCount(imtable[i].id) or player:getStorageValue(imtable[i].storage)
                     if check < imtable[i].count then
                         n = n + 1
                     end
                 end
                 local text = ""
                 local c = 0
                 for v = 1, #imtable do
                     local check = x.items and player:getItemCount(imtable[v].id) or player:getStorageValue(imtable[v].storage)
                     if check < imtable[v].count then
                         c = c + 1
                         local ret = ", "
                         if c == 1 then
                             ret = ""
                         elseif c == n then
                             ret = " and "
                         end
                         text = text .. ret
                         if x.items then
                             local count, info = imtable[v].count - player:getItemCount(imtable[v].id), ItemType(imtable[v].id)
                             text = text .. (count > 1 and count or info:getArticle()).." "..(count > 1 and info:getPluralName() or info:getName())
                         else
                             local count = imtable[v].count - (player:getStorageValue(imtable[v].storage) + 1)
                             text = text .. count.." "..imtable[v].name
                         end
                     end
                 end
                 selfSay(x.items and "You don't have all items, you still need to get "..text.."." or "You didn't kill all monsters, you still need to kill "..text..".", cid)
             end
         end
         npcHandler.topic[cid] = 0
     elseif msgcontains(msg, 'no') and npcHandler.topic[cid] == 1 then
         selfSay("Oh well, I guess not then.", cid)
         npcHandler.topic[cid] = 0
     end
     return true
end

npcHandler:setMessage(MESSAGE_FAREWELL, "Bye!")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Good bye, have a nice day!")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())

For older versions: monsteritemsmissions - Pastebin.com (http://pastebin.com/frSUfSrp)

[10/03/2021 19:57:14] [Error - Npc interface]
[10/03/2021 19:57:14] data/npc/scripts/Soraya.lua:eek:nCreatureSay
[10/03/2021 19:57:14] Description:
[10/03/2021 19:57:14] data/npc/scripts/Soraya.lua:104: attempt to call global 'Player' (a nil value)
[10/03/2021 19:57:14] stack traceback:
[10/03/2021 19:57:14] data/npc/scripts/Soraya.lua:104: in function 'callback'
[10/03/2021 19:57:14] data/npc/lib/npcsystem/npchandler.lua:394: in function 'onCreatureSay'
[10/03/2021 19:57:14] data/npc/scripts/Soraya.lua:8: in function <data/npc/scripts/Soraya.lua:8>
 
Lua Script Error: [Npc interface]
data/npc/scripts/missions.lua:eek:nCreatureSay
data/npc/scripts/missions.lua:92: attempt to call global 'getItemInfo' (a nil value)
stack traceback:
[C]: in function 'getItemInfo'
data/npc/scripts/missions.lua:92: in function 'getItemsMonstersFromTable'
data/npc/scripts/missions.lua:117: in function 'callback'
data/npc/lib/npcsystem/npchandler.lua:379: in function 'onCreatureSay'
data/npc/scripts/missions.lua:10: in function <data/npc/scripts/missions.lua:10>
in tibia 8.7 :(
 
Back
Top