Quest system - mganzarcik/fabulae GitHub Wiki

Tasks the player needs to complete in order to advance in the game are known as quests. A quest is basically a state machine with a defined set of states and transitions between these states. Each transition has an associated set of conditions and actions. Each state has a name, description (visible to the player) and a possible experience award which is awarded to the party once this state is reached. States can also have actions defined that are fired when the state is entered. There are two special states, a start state and an end state (which should have no transitions defined). A quest is considered completed when it is in the end state.

Transitions between quest states can be triggered by any script, since quests are globally accessible. In general, a quest transition (or a quest start) can be triggered by talking to a character, entering / exiting a location, acquiring an item, using an item, casting a spell or effect and killing a character.

Firing an event on a quest only ever does anything if the quest is active (i.e. assigned to the player), started and in a state that has a transition that listens for this event. In case that is not the case, nothing happens.

All active and completed quests are automatically tracked in a journal where the current state is displayed. The state descriptions form the journal entries, while the state names are the journal headings.

Example simple quest:

	<quest name="Kill the rats in Svetlana's cellar">
		<startState>
			<action>
				<fireQuestEvent event="startQuest" />
			</action>
			<transition event="startQuest" toState="allRatsKilled">
				<condition>
					<and>
						<visitedLocation location="SvetlanasCellar" targetObject="__player" />
						<script>
							location = GameState.getLocation("SvetlanasCellar");
							location != null &amp;&amp; location.getGameObjectsOfType("svetlanasCellarRat", false).size &lt; 1;
						</script>
					</and>
				</condition>
			</transition>
			<transition event="startQuest" toState="haveTheKeyAlready">
				<condition>
					<hasItem item="svetlanasKey" targetObject="__player" />
				</condition>
			</transition>
			<transition event="startQuest" toState="enterTheBarn" />
		</startState>
		<state id="enterTheBarn">
			<name>Get the cellar key</name>
			<description>Svetlana asked us to kill some rats in her cellar that have been bothering her. Unfortunately, she also lost the cellar key. She suspects one of the rats might have carried it off. She suggested looking in the barn.</description>
			<transition event ="enteredTheBarn" toState="findTheKey">
				<condition>
					<not><hasItem item="svetlanasKey"  targetObject="__player"/></not>
				</condition>
			</transition>
			<transition event="enteredTheCellar" toState="killTheRats" />
		</state>
		<state id="findTheKey">
			<name>Find the key in the barn</name>
			<description>We entered Svetlana’s barn. We now need to find the key and then enter the cellar to kill the rats.</description>
			<transition event ="foundTheKey" toState="enterTheCellar" />
			<transition event="enteredTheCellar" toState="killTheRats" />
		</state>
		<state id="haveTheKeyAlready">
			<name>Enter the cellar</name>
			<description>We already found the cellar key, so all we need to do is enter the cellar and murder all the poor rats</description>
			<transition event="enteredTheCellar" toState="killTheRats" />
		</state>
		<state id="enterTheCellar">
			<name>Enter the cellar</name>
			<description>We found the cellar key! Now we just need to enter the cellar and murder all the poor rats</description>
			<transition event="enteredTheCellar" toState="killTheRats" />
		</state>
		<state id="killTheRats">
			<name>Kill the rats</name>
			<description>We entered the cellar. Now let’s kill some rats.</description>
			<transition event ="killedARat" toState="allRatsKilled">
				<condition>
					<script>
						GameState.getCurrentMap().getGameObjectsOfType("svetlanasCellarRat", false).size &lt; 1;
					</script>
				</condition>
			</transition>
		</state>
		<state id="allRatsKilled">
			<name>Collect the reward from Svetlana</name>
			<description>We killed all the rats. All that remains is to talk to Svetlana about our reward.</description>
			<experience>50</experience>
			<transition event="questCompleted" toState="endState" />
		</state>
		<endState>
			<name>Rats dead</name>
			<description>All the rats in Svetlana’s cellar have been killed. Svetlana gave us some gold for the effort and seemed very thankful. Another good deed done.</description>
		</endState>
	</quest>

Triggers for the example quest would be fired for example from the cellar location:

	...
	<triggers>
		<onEntry>
			<action>
				<fireQuestEvent quest="svetlanasCellarRats" event="enteredTheCellar" />
			</action>
		</onEntry>
	</triggers>
	...

The quest represented in a diagram form:

This quest only works correctly with the assumption that the cellar can only ever be accessed with the key in inventory and that the key is initially in the barn. If you can unlock the cellar first and then later return without a key, the quest would need an additional state to accommodate that.

⚠️ **GitHub.com Fallback** ⚠️