Modding:Conversation

Conversations are loaded as templates from  - The base conversations can not be extended or modified through the XML, only overwritten. However there are events that will allow dynamically editing conversations as they happen, and mod authors can define their own conversation templates in their xml.

For extensive conversation design in mods that use a lot of conversations, some Qud modders have recommended using a tool such as Twine to map out your conversation logic.

Conversation Object Parts
In order to be conversable, an object should use the  part and attach a   which references a conversation template from Conversations.xml.

Snippet of ObjectBlueprints.xml that links Mehmet's Conversation to "JoppaMehmet"

ConversationScript configuration
Skipping over a small section of pre-conversation / checks / etc handled inside the "ConversationScript" part (for now, documentation TODO here). ConversationScript should definitely be used because it checks all sorts of parameters about whether or not the player is capable of speaking with the object. Telepathy and other special conversation choices are considered when ConversationScript is the way into the ConversationUI.HaveConversation

XRL.UI.ConversationUI.HaveConversation
This is the main loop that handles the conversation start / end and setup. First, it deep copies the Conversation object as an original template, allowing mods and parts responding to the following events to mutate the nodes as much as they want.

Starting Conversation: Pick Start Node
Then, it checks in order  looking for the first node which passes the   and sets it as

Modding and Event Hooks
Then 3 events will fire in a row - all 3 will cancel the conversation if "false" is returned.

Event:
Fired on: "Speaker" (not the player) Parameters: "Conversation" and "With" pointing to the player.

Event:
Fired on: "Player" Parameters: "Conversation" and "Speaker" pointing to the person to be talked to.

Event:
Is fired on the speaker when asked to check object talking in the HaveConversation parameters. This event would normally be checked before getting this far if you enter via ConversationScript, so before these other events, but can sometimes be fired after.

Core Conversation Loop
After the pre-conversation events above, the conversation has started, and enters at the selected "Start" node. This could have been mutated during the previous events as well, so is checked once as we begin the loop.

During each step of the loop, we call, to trigger any "on visit" effects in the node. We then sort the  using the   which uses the Choices's "Ordinal" property to sort, but also automatically handles any "End" nodes with. To sort an option after an End node, you can set it to END_SORT_ORDINAL + 1.

Event: ShowConversationChoices
Fired on "Speaker" Parameters:
 * - can set this parameter as well as read to "extend" the choices available in a node.
 * - the current conversation node.
 * - the start node for conversation. (lowercase f intentional)

This event is passed the sorted choices and gets one last chance to pass back additional choices / resort / or whatever it wants to do. We suggest setting the response to a  before mutating it as changes made to the original "Choices" here will persist throught the current conversation, but the choices used are not the Node.Choices, it is the response from this event's.

Peek at result nodes ConversationChoice.Goto(Speaker, peekOnly: true)
We use this information to mark if the choice is visited or not, but each choice will have "goto" called with peekOnly to ask to resolve the node it will visit.

Building the message
After this event fires, the current menu will render its text. The conversation itself has a  which will prepend the node's message if it is set, and after it is displayed, the value will be reset to   &mdash; showing the "intro" only once. We take the  and select from its random selections (  separated) and apply Variable Replacement to it, then prepend the intro, and affix a TradeNote if enabled on the node. This is the conversation's content and the choices are displayed.

Call: ConversationChoice.Visit(Speaker, Player)
When the choice is selected, we call ConversationChoice.Visit &mdash; it can return false to abort following through with the choice. The default implementation handles checks for things like "GiveBook".

Event: LeaveConversationNode
Fired on "Speaker" Parameters:
 * - the current conversation node.
 * - the goto id of the node WE ARE LEAVING (not the one we are going to!!!)

Call: ConversationChoice.Goto(Speaker, peekOnly: false)
is responsible for telling us the next node in the conversation. By default it resolves GotoID or other special GotoIDs.

Optional Event: GetConversationNode
In the default handling of ConversationChoice.Goto it will resolve any GotoID starting with  into a ConversationNode by broadcasting a   on the speaker.

Parameters: * GotoID - Input the "GotoID" including a * - I.E.  *  ConversationNode - This is "output" from the event - we read this to get the result node. Check the  part for an example of returning the water ritual.

Event: VisitConversationNode
Fired on "Speaker" Parameters:
 * - the new conversation node.
 * - the goto id of the node

Call: ConversationNode.Enter(ConversationNode previous, GameObject speaker)
This virtual method can return even yet another new node if it wants,

Event: AfterConversation
Fired on: Speaker No Parameters

Conversation Classes and XML properties
The xml file for conversation consists of a single node with multiple nodes underneath. It does not currently support extending the base game dialog via  or the other similar tricks used for many of the XMLs. Creating a Conversation.xml file for your mod would be done when you want to add a new specific conversation / template to be used in the game.

XRL.World.Conversation XML Node: &lt;conversation>
Conversation's have children  nodes:

XRL.World.ConversationChoice - XML Node: &lt;choice>
Snippet of Conversation.xml with Mehmet's script