Author Topic: Questjournal - Understanding and Debugging Quests  (Read 8809 times)

0 Members and 1 Guest are viewing this topic.

Offline erwin

  • Sr. Member
  • ****
  • Posts: 314
    • View Profile
Questjournal - Understanding and Debugging Quests
« on: January 05, 2017, 08:29:52 pm »
Hi all,

This post is meant to illustrate how to debug quest scripts with the questjournal. Writing triggers for the questjournal itself (and debugging them)will be in another post.

PS (sorry Roland, Thotter in advance) - feel free to add on to this post, clarify it if I skip some points.

questflags now look like this: questcardx_questname, for example, there's:

Code: [Select]
questcard7_viking
questcard19_riddle

To find all quest related triggers pertaining to that questcard, you can simply do
Code: [Select]
tsearch all questcardxx, example:
Code: [Select]
*find triggers related to questcard 19
tsearch all questcard19

All flags related to this quest will be in this flag. Sometimes, there may be subflags, eg
Code: [Select]
questcard19a
questcard19b
...

Most flags follow the below style. Here, we have a fake flag (questcard200_myquest), and show how it might look like, when you search for this flag on a player.

Code: [Select]
questcard200_myquest: noprog 0 notdone inprog 2 notdone inprog 3 done noprog 0 done
How do you read this? You can think of this in "groups of 3", so in this zone, there are four quests.

For the first quest, the player is not on the quest, is at step 0, and hasn't completed it.
For the second quest, the player is on the quest, is at step 2, and hasn't completed it.
For the third quest, the player is on the quest, is at step 3, and has completed the quest at least once.
For the fourth quest, the player has completed the quest, and hasn't restarted it again.

Think of noprog / inprog as noprogress and inprogress, notdone and done as whether the player has completed the quest at least once.

So we have two benefits already: First, flags are consolidated into one flag (less spam when you vstat a player's flags). Secondly, you can tsearch questflags easily by tsearch questcardxx.

However, because there are "multiple flags" on one flag (multiple variables in one array), things are a bit trickier.

Previously, you could do something like:
Code: [Select]
if !%actor.varexists(hanna)%
  * Player doesn't have this flag
  %send% %actor% You are not on this quest!
  %send% %actor% I will put you on this quest!
  set hanna 1
  remote hanna %actor.id%
else
  * Player has this flag
  set hanna %actor.hanna%
  if %hanna% == 1
    %send% %actor% You are on step 1. Let me progress you to step 2
    set hanna 2
    remote hanna %actor.id%
  elseif %hanna% == 2
    %send% %actor% You are on step 2. Let me progress you to step 3
    set hanna 2
    remote hanna %actor.id%
  endif
endif

How can you do this now? Let's imagine Hanna is the third quest for this zone, so we need to look at the third group, i.e. the group in bold here.

questcard200_myquest: noprog 0 notdone inprog 2 notdone inprog 3 done noprog 0 done

Let's look at a WRONG way to do this first.

Code: [Select]
* A wrong way
if !%actor.varexists(questcard200_myquest)%
  %send% %actor% You are not on this quest!
  %send% %actor% I will put you on this quest!
  set questcard200_myquest noprog 0 notdone noprog 0 notdone inprog 1 notdone noprog 0 notdone
  remote questcard200_myquest %actor.id%
endif

You might think the above code makes sense, since you're setting just the variables for the third quest. But, what if the player was on the other quests? You'd be resetting his or her progress.

Thus, every questcard now has up to three FUNCTIONS. A room function, a obj function, and a mob function. You can tsearch to find these functions, which look like this, and each have identical code (only the type - room, obj, mob differs).

Code: [Select]
* Example of an object function
Name: 'Questcard200 obj function',  VNum: [12345], RNum: [----]
Trigger Intended Assignment: Objects
Trigger Type: FUNCTION , Numeric Arg: 100, Arg list: None
Commands:
* Create this questflag if it doesn't exist
if !%actor.varexists(questcard200_quest)%
  set questcard200_quest noprog 0 notdone noprog 0 notdone noprog 0 notdone noprog 0 notdone
  remote questcard200_quest %actor.id%

  * To reassure people that their old flags aren't deleted
  * suppose they completed quest 1 before
  if %actor.varexists(oldflag1)%
    replace_word done 3 questcard200_quest
    rdelete oldflag1 %actor.id% 
  endif
 
  remote questcard200_quest %actor.id%
endif

Now, this is what you can do:
Code: [Select]
* Need to check if is PC before calling any functions.
if %actor.is_pc%
  *For any trigger which deals with questflags 
  *Call the appropriate function (room, mob or obj?)
  *Pretend it's an object so call the function above

  * This function sets the questflag ONCE, if it doesn't exist.
  function 12345
  * The below line can't bug, because we've created the flag if it didn't exist.
  set questcard200_quest %actor.questcard200_quest%

  * Now, proceed as normal, eg:

  if %questcard200_quest.wordat(7)% == noprog
    %send% %actor% You are not on this quest.
    %send% %actor% I will put you on this quest
    %send% %actor% I will replace the 7th word in your flag to show you are now in progress
    replace_word inprog 7 questcard200_quest
    %send% %actor% I will replace the 8th word by 1 to show you are now on step 1 for this quest
    replace_word 1 8 questcard200_quest
    remote questcard200_quest %actor.id%
  else
    if %questcard200_quest.wordat(8)% == 1
      %send% %actor% You are on step 1
      replace_word 2 8 questcard200_quest
      remote questcard200_quest %actor.id%
      %send% %actor% Now you are on step 2
    elseif %questcard200_quest.wordat(8)% == 2
      %send% %actor perfect, let's give you a reward
      if %questcard200_quest.wordat(9)% == notdone
        %send% %actor% You haven't done this quest before, so I'll give you a big reward!
        replace_word done 9 questcard200_quest
      else
        %send% %actor% You've done this quest before, so a smaller reward!
      endif
      * Reset all other questflags for this quest so
      replace_word 7 noprog questcard200_quest
      replace_word 8 0 questcard200_quest
      remote questcard200_quest %actor.id%
    endif
  endif
endif

So this is how the code would look like. Finally - how can we debug?

Here's some common errors.

Firstly, the trigger is not enclosed within:
Code: [Select]
if %actor.is_pc%
  ...
endif

Previously, you didn't need to have this check. Now you always need to have it.

Secondly, the WRONG type of function is called. We called function 12345, which was an Object function. If the trigger was a Mobile trigger, then you must call an Mobile function. If the trigger was a Room trigger, then you must call a Room function. Again, these three functions would have identical code, just different types.

Thirdly, logic wise. In this case, this is usually a problem with the old quest. As you can see, quests have the same logic. However, we have just used replace_word and wordat to work with arrays.



Finally, you may have a question. Hold on: How do I know if this player's quest is the THIRD quest or the FOURTH quest? Good question! Imms have a command (note me if you can't get this to work): questcheck card<num> debug <playername>, which actually goes into way more detail what each variable represents.




« Last Edit: January 05, 2017, 08:32:28 pm by erwin »