Quest System Documentation

From Nexus Mods Wiki
Revision as of 11:31, 18 February 2020 by Ali3kaa (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Quest System

Quest Systems is one of the major systems for scripting the content logic and storing the game state. All data for this system are stored in various DB tables. Flow Graph is the tool for scripting the content of the Quest System.


Quest structure

  • Quest
    • Assets
    • Objectives
    • Transitions between objectives

Quests consist of objectives - nodes connected with edges (transitions).

Quest System Documentation Image1.png


How it works

Quests and objectives have their names through which they a referenced. Quest works as a sort of namespaces for their Objectives. Therefore each objective is referred to via the parent quest name and the objective name (Example. LUA script QuestSystem.StartObjective(“q_quest1”,”objective1”) attempts to start the objective1 of quest q_quest1). Objective name must be unique within the scope of its namespace.

Flow Graph quest can have a Quest Smart Object (QSO) assigned to it. This QSO must carry the same name as the FG quest and will automatically receive messaged about quest and objective states changes.

Quest states

A quest can go through these states:

  • Inactive/Unchanged
    • An untouched or reset quest. Quest and objectives are in state Unchanged.
  • Activated – If quest is activated, you can change states of its objectives. Your QSO also receives the first message about quest state update.
    • Started – Is also Activated. A started quest is shown and updated in the Started section of the quest journal.
    • Completed – Is also Activated. A completed quest is shown in the Completed section of the quest journal. A completed quest cannot have any visible objectives in Started state. All started visible objective are automatically cancelled on quest completion.
    • Canceled (yes, one l) – is also Activated. A canceled quest is shown in the failed section of the quest journal. A failed quest cannot have any visible objectives in Started state. All started visible objective are automatically cancelled on quest cancellation.

Additional state:

  • Available – true if quest is Activated and quest giver is alive. Legacy state which is nigh impossible to reach due to VIP NPC revive system which was introduced later in development.

Valid quest state transitions and related LUA functions and Expression Evaluator functions are described in the following image:

Quest System Documentation Image2.png

Quest must have at least one visible objective to appear in quest log.

Objective states

Objectives can go through these states:

  • Unchanged/AfterReset
  • Started
    • StartedTrackingDone – compound state. True if the Objective is started and its tracker condition is currently met
  • Completed
  • Canceled

Valid state transitions for objectives are described in the following image:

Quest System Documentation Image3.png

Objectives are frequently used as persistent 5-state global variables in script.

 

Automatic Objective completion

Objective is completed automatically if all of the following conditions are met:

  • The objective Started
  • Condition (see Expression Evaluator) is TRUE (1 is always true)
  • Tracker condition is either undefined or met
  • Autocomplete timer is either undefined or expired

Otherwise Objective can be set manually (via lua, dedicated MBT tree node, or objective action in Skald) to any state.

Condition on a started Objective is evaluated each time any objective changes its state.

Automatic transitions of Objectives

An Objective may be connected via edge to another Objective. If this connection is simple (obj1 -> obj2) the next objective is automatically started. If there are more preceding objectives the following objective is started when ALL preceding objectives are completed. If the preceding objectives are set to IsExclusive, the following objective is started when at least one preceding objective is complete. All the other exclusive objectives are automatically cancelled.

Hidden/Visible objectives

Objectives can be set to IsHidden TRUE or FALSE. Hidden objective nodes have grey color and are hidden in the game’s UI/HUD.

Visible objectives are blue and can be shown in game’s UI/HUD and carry compass/map markers. They must be linked to an objective element in Skald, which carries all the UI data (name, update messages, logs). Otherwise they are functionally the same.

Note: It is strongly advised against using a visible objective as carrier of visual information/guidance for the player and as a controlling variable in game script at the same time. More often than not you want to control the script with a hidden objective carrying the game-state information and properly update a separate visible objective as the design requires it. Splitting a fully functional but insufficient control-visible objective into a hidden controlling one and a visible one is often a time-consuming and bugs-introducing procedure.

Tracking

Objectives can track some state of various game assets or some game events. One or more Asset nodes must be properly set up and plugged to Objective port Tacked via interface node AssetTracked (commonly referred to as “tracker”). If more objectives need to track the same asset, additional tracker node is required for each objective. Tracking is active when the objective is started.

You can track these states and events:

  • soul has died
    • By any hand
    • By specified soul
  • Items in inventory
  • soul entered/left an area
  • game statistic value (see more info in node description below)

Markers

Tracked assets can also have quest markers assigned to them. This is the only way to create quest markers in the game.

Quest System Documentation Image4.jpg

(Blue markers are of type side-quest marker, blue A is additionally an area marker. Red-yellow A marker is of type main-quest marker and is also an area marker)

Tracking system also allows a light-weight version where the asset has a marker but its state is not tracked. This saves some performance demands. To do that, simply plug the Asset node (it must have a specified entity, not a whole class of them!!) into MapAsset port of the tracker.

Notes:

  • Use markers on items with caution. A marker on AssetItem disappears when the item is in any inventory (stash, NPC inventory)
  • Markers cannot appear if the asset entity is not present in level at the time of tracker initialization. A tracker is re-initialized on save load so it may reappear that way.
  • There is a 1:1 parity between an objective and a marker. An objective cannot have more that one marker and cannot be dynamically changed.
  • Since markers are provided via the tracking system a marker is automatically turned on when the objective is started, and turned off when it’s cancelled or completed.

Objective timers

Timer and Autocomplete properties of the node Objective are the only persistent timers in game (beside the imprecise Timekeeper utility MBT tree). Timer defines when the started objective auto-fails. Autocomplete defines when the started objective can first attempt auto-completion (see Automatic Objective completion). The Quest Smart Object, if defined, receives objective state update message. This is frequently used for accurate and save/load persistent reactions to timed events.

The timers accept timer definition in the following format:

<IntegerNumber> <TimeUnit>#<TimeType>

Where:
TimeUnit = ms, s, m, h, d... for miliseconds, seconds, hours, days respectively
TimeType = WT, GT... for WorldTime and GameTime respectively

Examples:

30m#GT = 30 minutes of real-world time. Pausing the game pauses this time as well.

30m#WT = 30 minutes game-world time. Since 1 hour takes ca 4 minutes, this means the timer runs out in 2 minutes real-world time. Several systems may pause this time (open inventory, dialogs etc.) or it may be paused for a whole mission or its part in script (e.g. the whole Skalitz intro is paused).

5s#GT = The timer runs out within 5 seconds.

5s#WT = The timer runs out almost instantaneously. Basically in the next AI tick.

7d#GT = You probably wanted to use WT. You would have to play the game for 7 full days, that is 168 hours or real-world time. Most people play the game for 80-120 hours. They will never see the end of your timer. Yes, we had this typo in one quest.

Game saving

Autosaves are also handled by objectives. Autosave points are defined in Skald objective elements. If a Skald objective element (with autosave setting) is linked with a Quest System Objective, a save request is created when the objective is completed. Save request may be rarely discarded for various reasons (see Save/Load documentation).

Various valid setups – transitions

Quest System Documentation Image5.png

Quest named q_quest is a side quest and sends state update messages to QSO q_quest. When the quest is started objectives startObj1 and startObj2 are started. Objective startObj2 automatically completes itself immediately (condition=1). Both objectives are hidden and will not update the game UI/HUD.

Quest System Documentation Image6.png

Objective obj2 is automatically started when the obj1 is completed. Objectives are visible and capable of updating the game UI/HUD.

Quest System Documentation Image7.png

Objectives excl1 and excl2 are mutually exclusive. If one of them is completed, the other is auto-cancelled, and the objective reaction1 is started.

Quest System Documentation Image8.png

Objective didABC is started only when all the other objectives doA, doB, doC are completed. Objective doABC also auto-completes itself immediately after being started. This will also complete the quest.

Various valid setups – tracking and markers

Quest System Documentation Image9.png

Objective obj1 tracks the death of aus_bailiff. NPC aus_innkeeper must land the killing blow. Marker is on NPC aus_bailiff. Once that happens obj1 completes itself.

Quest System Documentation Image10.png

Objective obj1 tracks if the player entered area entity named area1 (The user, if undefined, is implicitly the player). Marker is on area1 and takes the form of an area marker. The objective completes itself if the player is inside AND the objective canEnterArea in quest1 is in completed state.

Quest System Documentation Image12.png

Objective findCamp tracks nothing. It only shows an area marker on the area entity named areaMarker1. The objective never completes itself (empty Condition = FALSE). It must be completed manually in MBT tree, through objective action in Skald, or via any LUA script.

 

Quest System Documentation Image13.png

Objective obj1 is tracking if player has at least 5 apples with quality over 50%. No marker. The objective completes itself when this condition is met AND if 1 hour of World Time (=4 real minutes) has elapsed since obj1 was started.

Quest System Documentation Image14.png

Objective named fired5Arrows tracks if the player fired at least 5 arrows. The objective is hidden. It completes itself when this condition is met.

Quest System Documentation Image15.png

An example of different objectives tracking the same asset (NPC mon_cellarius) for different reasons. Objective talkToNPC doesn’t track anything. It has a marker on the NPC and is visible. Hidden objective isNpcDead tracks if the NPC has died. If it’s dead the objective auto-completes. Hidden objective isNpcInArea never auto-completes. It tracks if the NPC entered the area entity named area1.

 

Quest Flow Graph Nodes

Begin

Mandatory. One instance only. Created automatically.

Behavior: Sends signal along the Out edges when the quest is Started.

Ports:

Name [string]

Defines name of the quest

SmartObject [string]

Defines QSO which receives all quest-state and objective-state update messages

Type [enum]

Defines which graphical set of icons will be used in journal and on map for quest markers. Use “side” or “main”.

Counter [int]

How many times can you repeat this quest? -1 means repeatable infinite times.

IsActivated [bool]

DON’T USE. A known bug prevents the initial state to be sent to the QSO. Leave set at 0. Defines if the quest is Activated from the start. This is better controlled from centralized brains (q_master_main) or from dialog exit script.

EdgesEnabled [bool]

DON’T USE

 

End

Mandatory. One instance only. Created automatically.

Behavior: If any flowgraph signal reaches this node the quest is set to Completed (if Started). This is the only way to complete quests.

Ports:

In [signal]

Accepts the signal for quest completion

 


Objective

Objectives serve as persistent 5-state global variables, as the means to update the game UI/HUD, as on of the means of giving the player quest rewards, and as the only means to control auto-saves.

Ports:

In [signal]

Receives signals from Out ports of Begin and Objective nodes. Upon receiving the signal the Objective is set to Started if it was Unchanged or Canceled (see valid state transitions)

Reward [Reward node]

All Reward nodes are plugged here. Can take any number of rewards at a time.

Tracked [AssetTracked node]

Input for all asset tracking logic. Accepts only AssetTracked node. No more than one AssetTracked per one Objective is allowed. Has a say in auto-completion of the objective.

Name [string]

Name of the objective. Used in all references to this objective (in combination with quest name)

Exp [int]

DON’T USE. Obsolete function.

IsHidden [bool]

0 = objective will be listed in journal. 1 = objective is hidden but may still show state-update UI messages (set in Skald)

IsExclusive [bool]

Allows you to auto-cancel this objective if another sibling exclusive objective is completed.

Timer [string, specific format]

Objective cancels itself after the timer runs out. Accepts timer definition in specific format.

Condition [string, specific format]

Accepts conditions in Expression Evaluator format (same as dialog entry conditions in Skald). Objective CANNOT be auto-completed until the conditions is evaluated as TRUE (1 is always true).

Autocomplete [string, specific format]

The objective may attempt auto-completion after the set timer runs out. Accepts timer definition in specific format.

Tracking nodes

AssetTracked

Serves as the interface for asset tracking and defining tracking conditions. Plug an edge from Out out-port into “Tracked” in-port of an Objective node. Unplugged AssetTracked node is taken as an orphaned one.

Behavior: Is only active when the objective is started. Updates its state in continually.

Ports:

Asset [Asset node]

Accepts any Asset node. Defines the Asset that is being tracked.

MapAsset [Asset node]

Defines an asset which is only meant to have a quest marker assigned and is not meant to be tracked.

TrackCnt [int]

Track Count. Defines how many times the tracked action on the tracked Asset must be performed for the tracking to be considered “completed”.

OnMap [bool]

If set to 1, the Asset or MapAsset is assigned a quest marker.

User [Asset node]

Defines a soul which plays a role in the tracking. Player is the implicit default, i.e. you don’t have to plug player (soul dude) in.

 

AssetItem

Duplicates results in error.

Behavior: Serves as input for AssetTracked node.

There are 4 ways to define the item you want to track. These options are mutually exclusive. You cannot track any specific instance of an item object (e.g. specific apple). If you wish to track such item it must be the only instance of its kind. So, for an apple you’d have to create a duplicate definition of an apple in the DB and place one in the level or some inventory. Quest item typically have only one instance of themselves in the game.

Ports:

Item id

Defines the kind of object to be tracked (as defined in DB item tables). Any instance of it - e.g. any apple, or any “Piercer” sword.

Category

Defines a whole category of items to be tracked. E.g. any body armor.

Type

Defines a whole type of items to be tracked. E.g. any chainmail body armor.

Subtype

Defines a whole subtype of items to be tracked. E.g. any cuman helmets. You can define your own subtype for any non-food item.

MinHelath [float]

Range [0-1]. Defines the minimal quality of the item for it to be counted. Any items in worse condition will not be counted towards the required TrackCnt value.

 

AssetNPC

Duplicates results in error.

Behavior: Serves as input for AssetTracked node.

Holds reference to an NPC or a group of NPCs.

If plugged into Asset in-port of AssetTracked, the tracker will track NPC’s death.

If plugged into Asset in-port of AssetTracked, this NPC will be marked by a quest marker.

If plugged into User in-port of AssetTracked, this NPC must carry out the action (e.g. enter an area, kill an Asset NPC, pick up the Asset Item)

There are 3 mutually exclusive ways to define an NPC to be tracked.

Ports:

IsVIP [bool]

If set to TRUE the NPC defined by Soul id will be revived when the quest starts. This VIP property is different from VIP status in DB table soul.

Soul id

Defines a specific soul

SoulClass

Defines a whole soul class to be tracked

SoulFaction

Defines a whole faction to be tracked

 

AssetPlace

Duplicates result in error.

Behavior: Serves as input for AssetTracked node.

Holds reference to various level entities – typically areas and tagpoints.

If it’s an area and if plugged into Asset in-port of AssetTracked, the state of the User entering the area is being tracked.

Ports:

EntityName [string]

Reference to the entity by entity name, as it is set in the level.

UIMap [string]

DON’T USE. Obsolte function

ShowAsArea

If the entity is an area, and if OnMap in AssetTracked is TRUE, the marker will be on the area and will take the form of area marker.

Note: Don’t change the name of the entity after it’s used in the FG. You may break your tracker.

AssetStatistic

Determines the statistic to be tracked. Statistics are defined in DB table “statistic”. Examples: number of arrows shot, number of times you got drunk etc.

Behavior: Serves as input for AssetTracked node.

Reward nodes

All reward nodes have one property in common: Immediately [bool]
If set to true, the reward is granted at the moment the objective is completed.
If set to false, the reward is granted when the quest is completed, but only if the objective is completed state.

Many reward nodes contain value definition in form of a predefined enum. This is done to facilitate balancing. You will find the actual values behind those enums in various DB tables.

RewardAchievement

Rewards the player with an achievement. Achievement are predefined in code and are platform independent (Steam, PS, XBox).

RewardExp

Rewards the player with XP in selected skill or stat.

Exp [enum]

Predefined XP amount

RPG

Stat to receive the XP

Exact values behind the Exp enums are defined in DB table exp_change

RewardItem

Rewards the player with an item.

Item

The item to be received

Count [int]

 

IsExclusive [bool]

If more rewards, with this value set to TRUE, are plugged into one objective the player will be prompted to choose one of these rewards.

Use only if you don’t mind the item is created out of thin air. To move existing items between inventories, use MBT tree script or LUA exit script in dialogs.

RewardMoney

Rewards the player with money.

Count [enum]

Predefined amount of money

IsExclusive [bool]

See RewardItem

 

RewardPerk

Rewards selected soul with a perk

SoulId

Soul to receive the perk

PerkId

The perk to be received

UnlockOnly [bool]

If set to TRUE the perk is only made available for selection in character sheet. Additional perks points are not granted.
If set to FALSE the perk is received regardless of the number of achievement points available.

 

RewardReputation

Receive reputation reward or reputation hit towards specified faction or a soul. Soul and faction settings are mutually exclusive.

Reputation [enum]

Predefined change of reputation value. See additional info below this table.

SoulId

Defines the soul towards wish your reputation should change. Don’t use Faction if you use this.

Faction [enum]

Defines the whole faction towards which your reputation should change

Actual values of Reputation change enums are defined in DB table “reputation_change”

If you reward faction reputation change, use only enums named “quest_rewardFaction*” or “quest_decreaseFaction*”.

If you reward individual reputation change, use only enums named “quest_reward*” or “quest_decrease*”. These enums are also used in Skald reputation changes. Skald is incapable of affecting faction reputation.

RewardScript

Runs a custom LUA script as a reward.


Debugging

Debugging in Flow Graph is described in its documentation

Console Cvar
wh_quest_debugquest <questName>
allows you to see the state of the entire quest in simplified manner.

Grey = unchanged/reset objective
Yellow = started objective
Blue = objective in StartedTrackingDone
Green = completed objective

Quest state is described at the top

RTENOTITLE