How to write dialog
From Post-Apocalyptic RPG wiki
This article describes how dialog works in PARPG. Furthermore it also explains how to add your own dialog into the game.
|Please help FIXME: This article only explores the technical side of dialog writing. We'll need another article that covers creative guidelines for dialog writing.|
What is Dialog?
A Dialog is the meaningful conversation that take place between the player character (PC) and a non-player character (NPC). At least for now dialogs in PARPG are text-based, meaning that the content of dialogs is displayed as text on the screen.
How does it work?
The dialog system in PARPG is generally similar to the text-based dialogs in other RPGs. The player can initiate a dialog with an NPC through a drop-down menu after right-clicking on the NPC, which opens up a window to display the text of the dialog and provide the means by which the player interacts with the NPC through dialog. The game is essentially paused while in a dialog, and only resumes once the player either aborts the dialog or replies with a response that ends the dialog. There are no time limits or other constraints placed upon the pace of a dialog - how fast or how slow the dialog progresses is entirely up to the player.
Unlike some RPGs which give the player little or no power to shape the flow of conversation, in PARPG players are responsible for directing the course of a dialog by making choices about how to respond to what NPCs say. It is entirely possible and desireable for dialogs to go down permanent one-way paths, so decisions about how to respond in a dialog have lasting consequences both within a particular dialog and throughout the rest of the game as relationships between the player and NPCs are defined primarily through dialog.
No really, how does it work? Give me details!
In PARPG a dialog is broken up into self-contained sections called DialogSections, where each DialogSection defines the text that the NPC displays (the "say" text) and a list of possible player responses called DialogResponses. Which DialogResponse the player chooses will determine the DialogSection that is presented next and may even have consequences outside of the dialog, e.g. starting or ending a quest, giving or receiving items, etc. These external events are called DialogActions, and may be triggered by selecting a particular DialogResponse or even automatically upon reaching a certain DialogSection. DialogResponses can also be hidden or made available to the player contingent upon the current state of the game, so for example if the player has completed a particular quest different DialogResponses will be presented.
This simple yet powerful dialog model allows for extremely complex dialogs with dozens or even hundreds of possible paths for the player to choose from, and yet it is intuitive and relatively easy to write such complex dialogs.
Dialog File Syntax
You don't need to know how to write code to create and modify dialogs. Currently dialogs are created for a particular NPC by writing a YAML file (YAML is a structured data markup language, similar to XML and JSON but easier to read and write by hand), so you do need to understand the general format of YAML to be able to write dialog but the syntax isn't hard to learn (see the following sections for examples). We're planning to build a GUI tool for creating and editing dialog without messing with YAML in the near future.
Lets look at the following example dialog file:
--- NPC_NAME: Mr. NPC AVATAR_PATH: gui/icons/npc.png START_SECTION: main_dialog SECTIONS: - ID: main_dialog SAY: "Hi there! This is how I greet you!" ACTIONS: - meet: mr_npc RESPONSES: - REPLY: "Uhh... right then. So what do you do around here?" CONDITION: "not pc.met('mr_npc')" GOTO: first_impression - REPLY: "Yeah, that's really starting to get annoying." CONDITION: "pc.met('mr_npc') and not quest.hasFinishedQuest('quest_for_variety')" GOTO: annoying - REPLY: "Back off loon, I've got better things to do that shoot the breeze with you!" GOTO: end - ID: first_impression SAY: "Not much, actually. I mostly stand around and greet people. Damn lazy dialog writers!" RESPONSES: - REPLY: "I see. Well, nice meeting you... kind of..." GOTO: end - REPLY: "Uhuh. Anything I can do to help?" GOTO: quest_for_variety - ID: annoying SAY: "Hey, its not my fault! I just do what I've been programmed to do." RESPONSES: - REPLY: "Okay... anything I can do to help?" GOTO: quest_for_variety - REPLY: "Yeah, well that doesn't mean I have to like you. So scram!" GOTO: end - ID: quest_for_variety SAY: "Yeah, actually you can. Just complete this quest!" ACTIONS: - start_quest: quest_for_variety RESPONSES: - REPLY: "Quest? What quest? What the hell are you talking about!" ACTIONS: - complete_quest: quest_for_variety GOTO: success - ID: success SAY: "You did it! Thank you so much. Here's a moldy lump of bread for your effort." ACTIONS: - take_items: - moldy_bread RESPONSES: - REPLY: "..." GOTO: end ...
There are some things to notice here:
- The "---" at the top of the file defines the start of the dialog file. It isn't mandatory, but is probably good practice;
- NPC_NAME specifies the name of the NPC that should be displayed in the dialog gui. This is not the same as the NPC's id, which is used to link to dialog to a particular NPC. That is done later in a different file, see Step 2 in #Creating a dialog below;
- AVATAR_PATH specifies the image that should be displayed in the dialog gui for the NPC, and should be a path relative to the root PARPG installation;
- START_SECTION specifies the ID of the first DialogSection in the conversation to be displayed;
- SECTIONS defines a list all of the different DialogSections for this NPC.
- The final "..." at the bottom of the file defines the end of the dialog file. Like the "---" symbol "..." isn't mandatory, but is generally good practice;
Each entry under the SECTIONS tag defines a DialogSection with the following mandatory attributes:
- ID is the human-readable name used to identify a particular DialogSection within a Dialog. There are no restrictions placed upon the format of the DialogSectin's ID, but for the sake of consistency the ID should use only lowercase ASCII letters and the underscore character "_";
- SAY defines the text to display for the NPC within the dialog GUI when the DialogSection is reached;
- RESPONSES defines the lists of possible DialogResponses that the player can choose from for the DialogSection;
In addition, the following optional tags are allowed within a DialogSection:
- ACTIONS defines a list of DialogActions that are executed when the DialogSection is reached;
Each entry under the RESPONSES tag defines a DialogResponse with the following mandatory attributes:
- REPLY specifies what text is displayed to the player as the content of the response;
- GOTO specifies the ID of the DialogSection should be jumped to if the user selects the DialogResponse. The special GOTO anchors "end" and "back" can also be used (called flow commands), which direct the DialogEngine to either end the dialog or jump to the previous DialogSection, respectively.
The following optional tags are also allowed within a DialogResponse:
- ACTIONS defines a list of DialogActions that are executed when/if the DialogResponse is selected by the player;
- CONDITION specifies a Python boolean expression which is evaluated each time the DialogSection containing the DialogResponse is reached. If the outcome of the expression is "True", then the DialogResponse will be displayed as a valid response for the player to select, otherwise the DialogResponse is hidden. If no CONDITION is specified then it is assumed that the DialogResponse should always be displayed as a valid response.
In general, DialogActions are specified using a keyword and a list of arguments. For instance, in the example file above the "take_items" actions is specified using the following syntax:
ACTIONS: - take_items: - moldy_bread
In this example "take_items" is the keyword and "moldy_bread" is the argument, which instructs the DialogEngine to move the "moldy_bread" item from Mr. NPC's inventory to the player's inventory. For DialogActions that take multiple arguments, like take_items, each argument may be specified as a list element using the dash "-" notation where each dash represents a new element in the list. For convenience, DialogActions that take a single argument may be specified without the dash notation e.g.:
ACTIONS: - start_quest: quest_for_variety
Currently the following DialogAction keywords are defined:
- meet records that the NPC has been met by the player;
- start_quest starts a quest;
- complete_quest marks a quest as successfully completed;
- fail_quest marks a quest as failed;
- restart_quest fails the quest if it is currently active and then starts it over again from the begining;
- increase_quest_variable increases a quest variable by a set amount;
- decrease_quest_variable decreases a quest variable by a set amount;
- set_quest_variable sets a quest variable to the specified value;
- give_items moves items from the player's inventory to the NPC's inventory;
- take_items moves items from the NPC's inventory to the player's inventory;
Creating a dialog
Step 1: Create a dialog file
Create a new text file with the '.yaml' extension in the dialog directory of your PARPG installation and write up a simple dialog following the YAML syntax rules defined above.
Step 2: Linking the dialog to an NPC
To link an NPC to this dialog file, there has to be an NPC with the exact same name in one of the agent files (e.g. "maps/all_agents.yaml")
For the example above ("Mr. NPC") there should be something like this in the file:
--- Mr. NPC: #This is the important part ViewName: "Mr. NPC" # This is how the npc name is shown in the map RealName: "Bob" # This is the real name of the npc. Can be used for characters that want to hide their real identify. ObjectType: "NonPlayerCharacter" # For npcs this needs to be "NonPlayerCharacter". ObjectModel: "long_coat_male" # The graphical representation of the character Text: "An abnormally cheerful fellow." # What is shown when examining the character Map: "Mall" # On what map the character is. This is only needed in the "All Agents" file. Position: [-5.0, -4.0] # The characters starting position on the map Rotation: 0 # The characters starting rotation
If such an entry is already present then there is no need to add it. The game will determine the correct dialog file automatically from the name. For this the dialog files has to be in the "dialog" directory.
Step 3: Try it out
Run the game and try to interact with the NPC. When you offer to talk to them you should see your dialog.
Some hints on how to do this
First, you have to decide what "game effects" (if any) the NPC is going to have. Does he/she have something to give you? An item? Information? A quest? If there are no "puzzles" to solve then you can just have this as a dialog option. After the "specifics" for the NPC you probably need to write some "generalities" - what can you ask this person about other quests (you obviously don't have to have the same questions for every NPC, but you can.. they can have "canned" answers (default info) or maybe this one knows a little more.
There is a mall_template.yaml file that has some generic question-and-answer for the the techdemo quests (fedex and beer).
If you want to have a "puzzle" dialog, like zenbitz did for skwisgaar, the Crazy Swede, you should first make a flow chart.
Then just add the dialog with conditionals to switch on and off parts.