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

[Configuration] How to make a working Quest Log

Shadowsong

Game Developer & Graphic Designer
Joined
Feb 23, 2010
Messages
3,446
Solutions
21
Reaction score
2,999
Location
Bosnia & Herzegovina
YouTube
ShivaShadowsong
How to make a working Quest Log - Tutorial by Shadowsong
─────────────────────────────────────────────────────────────────


Hello! You might remember me and my older tutorials which, unfortunately, are now useless. (Since the pictures posted on them are no longer visible). Nevertheless , I decided to start over with making tutorials, and today I'm gonna show you how to properly set up a quest log. I hope you'll find it useful.

So let's get started. :rolleyes:

─────────────────────────────────────────────────────────────────
What's a quest log and what can you use it for?

Quest log is a built-in Tibia Client function which opens a new window that can contain information which appears only if player meets a certain requirement (in this case, a storage value). I haven't seen people using it in OTs almost at all. (few exceptions only). I think it's a very helpful and useful RPG-ish function.

Examples of how players can use a working quest log:

~ As a reminder of what's they currently have to do on a quest.
~ To navigate through dungeons or long traveling routes.
~ To keep track of which quests they've already done and which they haven't.
and more..

─────────────────────────────────────────────────────────────────
Structure of Quest Log.


So, if you open the quest log by clicking the button Quests at the right side of the client window, you will see a blank window titled Quest Log. In order to make something appear in it, you must learn what the quest log is actually made of, and that's:
~ Quest Lines (Quests)
~ Missions

Quest lines don't give any information about the quest, but they serve as a button (introduction) to the actual content of the quest / it's missions. Missions are what's found inside the quest line (what it's built of).
You can see a quest line and it's mission on the following picture:

7118d15bf4ba9959698eab7f38f06bfa.gif


So, supposedly , there are two ways that you can make your quest.

1.) Quest line can be the name of a particular quest , whereas it's missions would be every mission of that quest for itself.
2.) Quest line can be the name of a whole quest line, whereas each of it's missions would be a quest for itself.

We will use it the second method in the tutorial, but once you are familiar with how quest logs work, you will be able to do whatever you want.
─────────────────────────────────────────────────────────────────
Planning and Making


Before you make an actual quest and it's log, the best thing would be to plan everything out.
I am going to summarize the plan we're going to use in this tutorial:


Code:
An NPC is trapped, you need to pull a lever to unlock the door and then you can get a reward from the NPC.

So, now that we have the general idea, let's open the file: data/XML/quests.xml
Inside, put this:

Code:
<quest name="NAME" startstorageid="STORAGE" startstoragevalue="VALUE">
</quest>

NAME - Enter the name of quest here.
STORAGE - Enter the storage value that this quest will use.
VALUE - Enter a value of the STORAGE.

Now, when the player's storage reaches the entered value, the quest will appear in the Quest Log.
But if you open the quest, you will find nothing inside. That's why we'll now add a mission inside of that quest.
In order to do that, we need to edit between the lines we put in quests.xml, inserting a mission code so it will look like this:

Code:
    <quest name="NAME" startstorageid="STORAGE" startstoragevalue="VALUE">
        <mission name="NAME2" storageid="STOR1" startvalue="VAL1" endvalue="VAL2">
            <missionstate id="0" description="Enter a description here."/>
        </mission>
    </quest>

As you can see, we inserted a mission into the quest whose name you can enter instead of NAME2.
STOR1 is the storage value this mission will use.
VAL1 is the value of that storage which once player obtains, shows the mission.
VAL2 is the storage value that player needs to have in order to have the mission completed.

Missionstates are descriptions of the mission for each storage value used during the quest. VAL1 - VAL2 is the same range of values as defined for missionstates.(NOTE: You should, though not necessarily, start counting missionstates from 0.)
This way, for example, if we are using 3 mission states (0,1,2) -> start value will be 0 , and endvalue will be 2.

Now we will take a look at our summarized quest, and as we can notice, it can be broken into few states:


1.) The NPC asks for help
2.) You pull the lever
3.) You get a reward and finish the mission.


3 states were extracted from our analysis, and that's exactly how many states our mission will use.
I am also going to give a name and a random storage to our mission, which after editing, will look like this:


Code:
<quest name="OTLand Tutorial Quest" startstorageid="80012" startstoragevalue="1">
        <mission name="Prisoner" storageid="25578" startvalue="0" endvalue="2">
            <missionstate id="0" description="Nelly asked you to find a lever somewhere in the prison, and pull it in order to unlock her."/>
            <missionstate id="1" description="You pulled the lever. You should probably go and talk to Nelly now."/>
            <missionstate id="2" description="Nelly rewarded you for your noble act."/>
        </mission>
    </quest>

It's good to know that by default, all unused storages of a player come with value "-1".
But our first mission state requires storage value to be "0" in order to show the description. That's why you need to align your quests, actions, movements and other scripts to cooperate with quest log - by having in mind that everytime a state is changing, you need to set the proper storage value to player. I will create an NPC that we will use in our example quest:


data/NPC/nelly.xml

Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Nelly" script="nelly.lua" walkinterval="0" floorchange="0">
    <health now="90" max="150"/>
    <look type="148" head="40" body="45" legs="99" feet="79"/>
    <parameters>
        <parameter key="message_greet" value="Hello. I am trapped in here, please, {help} me!"/>
    </parameters>
</npc>

data/NPC/scripts/nelly.lua
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

-- QUEST --
function Task1(cid, message, keywords, parameters, node)

local stor1 = 25578 -- this is the same STOR1 from quests.xml

    if(not npcHandler:isFocused(cid)) then
        return false
    end

    if getPlayerStorageValue(cid,stor1) < 0 then
                npcHandler:say('I will be waiting here, I guess. Please hurry up!',cid)
            doPlayerSetStorageValue(cid, stor1, 0)
    elseif getPlayerStorageValue(cid, stor1) == 0 then
                npcHandler:say('I am still waiting for you to unlock this room.',cid)
    elseif getPlayerStorageValue(cid, stor1) == 1 then
                npcHandler:say('Thank you, the room is unlocked!! I must reward you somehow.. Here, take my money.',cid)
            doPlayerAddItem(cid, 2152, 25)
            doPlayerSetStorageValue(cid, stor1, 2)
                 doSendMagicEffect(getCreaturePosition(cid), 13)
    elseif getPlayerStorageValue(cid, stor1) == 2 then
                npcHandler:say('You already unlocked the room, thank you!',cid)
    end
end

local node1 = keywordHandler:addKeyword({'help'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = 'Some bastards forced me into entering here then locked the room by pulling a lever around here somewhere. Would you please find it and unlock me?'})
      node1:addChildKeyword({'yes'}, Task1, {})
    node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = 'Seems like you are no better than them.', reset = true})

npcHandler:addModule(FocusModule:new())

If you take a look at the NPC's script , you will notice that when interacting with player, it will change his storage value (the same one we're using for mission), and therefore, will enable our mission to work properly in quest log. This is how it looks ingame:

262pjly.gif


As I said, if you wish the player to advance in missionstate, his storage value must equal that value, so we will change the player's storage again once he pulls the lever:

Code:
function onUse(cid, item, fromPosition, itemEx, toPosition)

    if getPlayerStorageValue(cid, 25578) == 0 then
            doPlayerSetStorageValue(cid, 25578, 1)
                 doSendMagicEffect(getCreaturePosition(cid), 13)
            doCreatureSay(cid, "*creeek*", TALKTYPE_ORANGE_1)
              doPlayerSendCancel(cid, "You unlocked the prison cell.")
    else
            doCreatureSay(cid, "*crrrk* It's stuck.", TALKTYPE_ORANGE_1)
    end

end

The lever will also prevent player to pull it more times, since if he advances further in missions (to 2+) , and is still allowed to pull the lever, the mission will be set back to state 1. You mustn't forget to make these kinds of preventives, or it might ruin the flow of the quest. And our result is here:

20iysys.gif


Obviously, our lever is functioning and quest is working flawlessly. Let's finish the last mission which had already been defined in the NPC's lua script.

4i1uo5.gif

─────────────────────────────────────────────────────────────────
And there you go. This is how you make a quest that functions along with quest log. Don't forget that quest log unravels endless posibilities. Now that you know how it works, get creative.
Please comment and let me know what you think, also feel free to ask if something's unclear or if you have any other questions, I'll be glad to help.
More interesting tutorials coming soon.

Enjoy!

:rolleyes:
 
Last edited:
I just tried a simple quest, and it seems that an "endvalue" (in a mission line) of "true" also works!
 
Ok did everything just as you said, but how do I configure the switch to work.
Also It doen't show on the Quest log.


I am useing: 8.62 - The Forgotten Server - Version 0.2.08 (Mystic Spirit) -win32gui
 
nice tutorial! i've already know this..
@offtopic ~
tibia.api to manabar? :D
 
Worked like a charm, had to configure it differently for my custom quest but this definitely helped me lay it out.
 
Well if you know how storages work, you should be able to figure it out yourself from the idea of the post, cause you may have different storages or stuff, but the questlog system generally works like that.
 
Bad Tutorial..
Dunno where i have to put:
function onUse(cid, item, fromPosition, itemEx, toPosition)

if getPlayerStorageValue(cid, 25578) == 0 then
doPlayerSetStorageValue(cid, 25578, 1)
doSendMagicEffect(getCreaturePosition(cid), 13)
doCreatureSay(cid, "*creeek*", TALKTYPE_ORANGE_1)
doPlayerSendCancel(cid, "You unlocked the prison cell.")
else
doCreatureSay(cid, "*crrrk* It's stuck.", TALKTYPE_ORANGE_1)
end

end

Also i dunno what i have to do with the on the map placed lever. And how to let the gate open?
 
If you seriously don't know what to do with that script, even though it's an "onUse" script about pulling a lever - you shouldn't be reading this tutorial at all. Go learn some basics first then come back and everything will be clearer, my purpose here was not to teach you "2+2".
 
So i have to put:
function onUse(cid, item, fromPosition, itemEx, toPosition)

if getPlayerStorageValue(cid, 25578) == 0 then
doPlayerSetStorageValue(cid, 25578, 1)
doSendMagicEffect(getCreaturePosition(cid), 13)
doCreatureSay(cid, "*creeek*", TALKTYPE_ORANGE_1)
doPlayerSendCancel(cid, "You unlocked the prison cell.")
else
doCreatureSay(cid, "*crrrk* It's stuck.", TALKTYPE_ORANGE_1)
end

end

into the npc script, put the action id into the lever?
i know what it is..iam able to read, but it's strange that u explained all very well..but not this script. o_O
 
Alright man, look, onUse scripts are action scripts, they go as in script.lua into the actions/scripts/ folder and their actionID is defined in actions.xml, then you take that actionID - put it onto a lever, and when you use the lever, it will do what the script says.

The tutorial explains all other things accurately so I don't know what's the big deal. Also, this tutorial is not for opening or closing a gate, but to show you how to use a quest log.
 
Ah...Ok. Totally my fault sorry..Good tutorial then. Thought you want to explain it for "noobs" like me..:p
But i understand it now. Thx.^^
 
Back
Top