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

Colandus

Advanced OT User
Senator
Joined
Jun 6, 2007
Messages
2,434
Solutions
19
Reaction score
218
Location
Sweden
Class for "multi quests" :)

Note: The code is untested (cookie for whoever tests it for me!)

Code:
missionQuest = {}
missionQuest.__index = missionQuest

function missionQuest.new(doneStorage, confirmedStorage)
    if(type(doneStorage) ~= 'number') then
        return FALSE, error("missionQuest: Requiring number for 'doneStorage' (got " .. type(doneStorage) .. ")")
    end
   
    local mt = {
        doneStorage = doneStorage,
        confirmedStorage = confirmedStorage,
        missions = {}
    }
    setmetatable(mt, missionQuest)
   
    return mt
end

function missionQuest.add(name)
    table.insert(self.missions, name)
    _G["MISSION_" .. name:gsub(" ", "_"):upper()] = #self.missions
end

function missionQuest.check(cid, storageValue)
    local flags = getPlayerStorageValue(cid, storageValue)
   
    local found = 0
    local success = TRUE
    for k, name in ipairs(self.missions) do
        local flag = k ^ 2
        if(bit.band(flags, flag) == flag) then
            found = found + 1
        elseif(success == TRUE) then
            success = FALSE
        end
    end
   
    return success, found
end

function missionQuest.checkDone(cid)
    return self:check(cid, self.doneStorage)
end

function missionQuest.checkConfirmed(cid)
    return self:check(cid, self.confirmedStorage)
end

function missionQuest.has(cid, flag, storageValue)
    flag = flag ^ 2
    local flags = getPlayerStorageValue(cid, storageValue)
    return (bit.band(flags, flag) == flag) and TRUE or FALSE
end

function missionQuest.hasDone(cid, flag)
    return self:has(cid, flag, self.doneStorage)
end

function missionQuest.doneTakeItems(cid, flag, ...)
    if(self:hasDone(cid, flag) == FALSE) then
        return FALSE
    end
   
    for _, v in ipairs(arg) do
        local count, itemid = 1
        if(type(v) == 'table') then
            itemid, count = unpack(v)
        else
            itemid = v
        end
       
        if(getPlayerItemCount(cid, itemid) < count) then
            return FALSE, itemid, count
        end
    end
   
    for _, v in ipairs(arg) do
        local count, itemid = 1
        if(type(v) == 'table') then
            itemid, count = unpack(v)
        else
            itemid = v
        end
       
        if(isItemStackable(itemid) == TRUE) then
            doPlayerRemoveItem(cid, itemid, count)
        else
            for i = 1, count do
                doPlayerRemoveItem(cid, itemid, 1)
            end
        end
    end
   
    return TRUE
end

function missionQuest.hasConfirmed(cid, flag)
    return self:has(cid, flag, self.confirmedStorage)
end

function missionQuest.set(cid, flag, storageValue)
    local flags = getPlayerStorageValue(cid, storageValue)
   
    setPlayerStorageValue(cid, storageValue, bit.bor(flags, flag))
end

function missionQuest.setDone(cid, flag)
    self:set(cid, flag, self.doneStorage)
end

function missionQuest.setConfirmed(cid, flag)
    self:set(cid, flag, self.confirmedStorage)
end

-- Simplification function for adding missions using table.
function createMission(t, doneStorage, confirmedStorage)
    local missionQ = missionQuest.new(doneStorage, confirmedStorage)
   
    for _, name in ipairs(t) do
        missionQ:add(name)
    end
   
    return missionQ
end

Example [part of] NPC code
Code:
-- Would be best if this was placed in constant.lua
local missions = {
    "kill the rabbit", "slay the demon", "bring the key"
}

local missionQ = createMission(t, 4353)
-- End "best in constant.lua"

if(msgcontains(msg, "quest")) then
    if(missionQ:hasDone(cid, MISSION_KILL_THE_RABBIT) == FALSE) then
        selfSay('Please go kill the evil rabbit located at {Demon Shire}.', cid)
    elseif(missionQ:hasConfirmed(cid, MISSION_KILL_THE_RABBIT) == FALSE) then
        selfSay('Thank you so much! I never liked that rabbit.', cid)
        missionQ:setConfirmed(MISSION_KILL_THE_RABBIT)
    elseif(missionQ:hasDone(cid, MISSION_SLAY_THE_DEMON) == FALSE) then
        selfSay('Please go SLAY the Demon!', cid)
    elseif(missionQ:hasConfirmed(cid, MISSION_SLAY_THE_DEMON) == FALSE) then
        selfSay('Good Job!', cid)
        missionQ:setConfirmed(MISSION_SLAY_THE_DEMON)
    -- and so on
        end
elseif(msgcontains(msg, "rabbit"))
    if(missionQ:hasDone(cid, MISSION_KILL_THE_RABBIT) == FALSE) then
        selfSay('Please go kill the evil rabbit located at {Demon Shire}.', cid)
    elseif(missionQ:hasConfirmed(cid, MISSION_KILL_THE_RABBIT) == FALSE) then
        selfSay('Thank you so much! I never liked that rabbit.', cid)
        missionQ:setConfirmed(MISSION_KILL_THE_RABBIT)
    else
        selfSay('You already killed the Rabbit!', cid)
    end
end

Now you also need to make so when you kill that rabbit and demon it will add as he's been killed. Example script for rabbit:
Code:
-- Would be best if this was placed in constant.lua
local missions = {
    "kill the rabbit", "slay the demon", "bring the key"
}

local missionQ = createMission(missions, 4353)

function onDeath(cid, killer)
    if(isPlayer(killer) == TRUE) then
        if(missionQ:hasDone(killer, MISSION_KILL_THE_RABBIT) == FALSE) then
            doPlayerSendTextMessage(killer, MESSAGE_INFO_DESCR, "Congratulations! You killed the evil rabbit.")
            missionQ:setDone(killer, MISSION_KILL_THE_RABBIT)
        end
    end
    return TRUE
end


Functions:
Code:
missionQuest.checkDone(cid) -- checks whether player has done all the missions. returns TRUE/FALSE and as second return value how many he has done.
missionQuest.checkConfirmed(cid) -- same as above, but checks if he has confirmed all missions.

missionQuest.hasDone(cid, flag) -- checks whether player has done a certain mission. returns TRUE/FALSE
missionQuest.hasConfirmed(cid, flag) -- same as above, but checks if he has confirmed a certain mission.

missionQuest.doneTakeItems(cid, flags, items) -- returns TRUE if player has done quest + has all items needed.
-- but if he has done quest but does not have required items, it will return FALSE, itemid, count of the item he did not have (will only return one, even though there could be many...)
-- example: missionQ:doneTakeItems(cid, MISSION_HELP_GEORGE, 4433, {1004, 5}, 4324, 1923, 5403, {7433, 4})
-- This would require 1x of itemid 4433, 5x of itemid 1004 etc...

missionQuest.setDone(cid, flag) -- sets a certain flag to done, so it will be classed as it has been done.
missionQuest.setConfirmed(cid, flag) -- same as above, but sets flag to confirmed.


What's done and what's confirmed?
When you finish a mission it's usually done. But when you go speak to the NPC he will see it as done and skip it right? So then I have this confirmed thingy, that will be set after he has done it and then spoken to NPC or whatever.

Note that this must not be used only for NPC's. You can use as talkaction/action/movement or whatever you want!


BAD: Code is untested
GOOD: Code r0x meenz
 
Last edited:
Using missionQuest.add(name) it will automatically create a global variable.

So if you write like:
Code:
-- Create new mission with storages 1003 and 1004.
missionQ = missionQuest.new(1003, 1004)

-- This will be the main "mission" that will be done as fast as he accepts the mission.
missionQ:add("started troubleseeking")
-- Now a new global variable was created: MISSION_STARTED_TROUBLESEEKING

missionQ:add("help santa")
-- Now a new global variable was created: MISSION_HELP_SANTA

missionQ:add("deliver candy")
-- New global variable: MISSION_DELIVER_CANDY

Now with these words you added, you use them as missions. You can use them in any way you want. You can make for example a Santa NPC that will make the "help santa" mission done, and then you need to go to another NPC that will make it complete by just talking to him and confirming.

I'll give you example NPC's

Alfred
Code:
if(msgcontains(msg, 'hi')) then
	if(missionQ:checkConfirmed(cid) == TRUE) then
		selfSay('Hello |PLAYER|. What can I do for you?', cid)
	else
		selfSay('Hi |PLAYER|. Are you a {troubleseeker}?', cid)
	end
elseif(crap_code_to_check_if_player_is_talking_to_npc) then
	-- If he say "troubleseeker"
	if(msgcontains(msg, 'troubleseeker')) then
		-- "confirmed" is TRUE if player is fully completed with quest while "amount" is how many missions of the quest that he has confirmed.
		local confirmed, amount = missionQ:checkConfirmed(cid)
		
		if(confirmed == TRUE) then
			-- If player is fully completed with quest.
			selfSay('I much appreciate your help |PLAYER|!', cid)
		else
			-- If player is not fully completed with quest.
			if(amount == 0) then
				-- If player has not even started the mission.
				selfSay('Go help Santa. Hurry up!', cid)
				missionQ:setConfirmed(cid, MISSION_STARTED_TROUBLESEEKING)
			else
				if(missionQ:hasDone(cid, MISSION_HELP_SANTA) == FALSE) then
					selfSay('Come on! Go help Santa. Don\'t be so lazy!', cid)
				elseif(missionQ:hasConfirmed(cid, MISSION_HELP_SANTA) == FALSE) then
					selfSay('Good Job! Now go deliver the candy.', cid)
					missionQ:setConfirmed(cid, MISSION_HELP_SANTA)
				elseif(missionQ:hasDone(cid, MISSION_DELIVER_CANDY) == FALSE) then
					selfSay('Stupid n00b... Just go give that fat Santa his candy, what\'s so damn hard???', cid)
				elseif(missionQ:hasConfirmed(cid, MISSION_DELIVER_CANDY) == FALSE) then
					selfSay('Wow, congratulations LoL... Hard job ehh??', cid)
					missionQ:setConfirmed(cid, MISSION_DELIVER_CANDY)
				end
				-- No more missions left, he won't even go this far :D He'll stay in  "confirmed == TRUE".
			end
		end
	end
end

Santa
Code:
if(msgcontains(msg, 'hi')) then
	if(missionQ:checkConfirmed(cid) == TRUE) then
		selfSay('Hello there gentle |PLAYER|. What can I do for you?', cid)
	else
		selfSay('Hi |PLAYER|, do you think you could {help} me out?', cid)
	end
elseif(crap_code_to_check_if_player_is_talking_to_npc) then
	-- If he say "troubleseeker"
	if(msgcontains(msg, 'help')) then
		if(missionQ:hasDone(cid, MISSION_HELP_SANTA) == FALSE) then
			if(doPlayerRemoveItem(cid, ITEMID_TORCH) == TRUE) then
				selfSay('Thanks a lot for the torch! Now I can finally go get my bags in the cave.', cid)
				missionQ:setDone(cid, MISSION_HELP_SANTA)
			else
				selfSay('Could you please bring me a torch. This cave is very dark.', cid)
			end
		else
			selfSay('Thanks for helping me out. I don\'t know how to reward you enough.', cid)
		end
	end
end

Bah, the candy part you can figure yourselves :p

I'm thinking of going far enough to merge this with Jiddo's NPC system :)
 
Last edited:
Thank you slawkens. You mind testing it as well? :p I wish to know if it has any bugs and I can currently not test it.
 
Really sweet as always mate : ) I'll check it out tomorrow.
 
I know that this is very nooooob but in TFS CD I cant find "functions.lua" or "global.lua" please someone help me..
 
Shouldn't

PHP:
local missions = {
	"kill the rabbit", "slay the demon", "bring the key"
}

local missionQ = createMission(t, 4353)

be

PHP:
local missions = {
	"kill the rabbit", "slay the demon", "bring the key"
}

local missionQ = createMission(missions, 4353)

?
 
0j0j0j I will test this system soon, and I will fix all bugs if there are any (as it's currently untested).
 
Back
Top