Descant logo

Descant

Enhanced Unity Dialogue System

by Owen Hellum

Please view the README for information regarding installation and usage!

Unity Asset Store

GitHub

Descant is a Unity dialogue system plugin. The Unity Asset Store is chock full of many such types of plugins, ranging from feature-rich, to ultra-minimalist, to downright bad. Descant aims to hit the sweet spot between quality UI, powerful features, and easy-to-lean functionality, while also addressing many of the game-specific consequences of the standard dialogue manager setup. Besides acting as a standard tool for creating, saving, and actualizing non-linear game dialogue, it also pushes the envelope by adding optional dialogue-enhancing node components that introduce features to break away from the overused and underwhelming trends seen in many interactive fiction games. These enhancements act similar to Unity's standard GameObject Component system, and can be applied at-will to nodes. This modular approach is so-far not explored in the world of Unity dialogue systems. The project will be free (and collaborative open-source) forever. Feel free to send me a message or submit a pull request if you want to make any changes.

Component documentation

A number of Descant Components come bundled with the system by default. They cover a wide range of applications, and can be edited at-will. Please see the next section, Component creation, for a guide on how to write your own Components in C#.

ChangedChoice

Changes the text of one of a ChoiceNode's choices if some condition is met.

Max Quantity: None

Node Type(s): Choice

Variables:

Actor: A reference to the actor who's variable is being checked

ChoiceNumber: The index of the choice being changed (base 1)

VariableType: The type of the variable being checked (e.g. Statistic, Topic, etc.)

VariableName: The name of the variable being checked

ComparisonType: The type of the comparison being performed against the variable

Comparison: The value to compare the variable against

ChangeTo: The text to change the choice to if the comparison succeeds

ChangedResponse

Changes the text of a ResponseNode's response if some condition is met.

Max Quantity: None

Node Type(s): Response

Variables:

Actor: A reference to the actor who's variable is being checked

VariableType: The type of the variable being checked (e.g. Statistic, Topic, etc.)

VariableName: The name of the variable being checked

ComparisonType: The type of the comparison being performed against the variable

Comparison: The value to compare the variable against

ChangeTo: The text to change the choice to if the comparison succeeds

Event

Calls a method from a script.

Max Quantity: None

Node Type(s): Any

Variables:

ObjectTag: The tag of the GameObject on which the script is located (optional)

ScriptName: The name of the script on the GameObject

MethodName: The name of the method being called

Parameter: The parameter to pass to the method (optional)

Disclaimers:

If ObjectTag is empty, the first found script in the scene with the given name is called instead.

If the ScriptName or MethodName are empty, no method is called.

While Parameter is technically of type string, Integers and Floats can also be written, and will be parsed accordingly.

Currently, methods with more than one parameter cannot be called.

Interruptable

Allows for the dialogue to be abruptly stopped with a key or button press. Once this happens, a method from a script can be called.

Max Quantity: None

Node Type(s): Response

Variables:

KeyCode: The lowercase name of the key press to check for (e.g. "e", "space", etc.) (optional)

ButtonName: The name of the button press to check for (e.g. "Fire1", etc.) (optional)

ObjectTag: The tag of the GameObject on which the script is located (optional)

ScriptName: The name of the script on the GameObject (optional)

MethodName: The name of the method being called (optional)

Parameter: The parameter to pass to the method (optional)

Disclaimers:

If ObjectTag is empty, the first found script in the scene with the given name is called instead.

If the ScriptName or MethodName are empty, no method is called.

While Parameter is technically of type string, Integers and Floats can also be written, and will be parsed accordingly.

Currently, methods with more than one parameter cannot be called.

LockedChoice

Removes one of a ChoiceNode's choices if some condition is met.

Max Quantity: None

Node Type(s): Choice

Variables:

Actor: A reference to the actor who's variable is being checked

ChoiceNumber: The index of the choice being removed (base 1)

VariableType: The type of the variable being checked (e.g. Statistic, Topic, etc.)

VariableName: The name of the variable being checked

ComparisonType: The type of the comparison being performed against the variable

Comparison: The value to compare the variable against

Log

Prints a Debug.Log to the console.

Max Quantity: None

Node Type(s): Any

Variables:

Message: The message to log

PortraitChange

Changes and actor's portrait.

Max Quantity: None

Node Type(s): Any

Variables:

Actor: A reference to the actor who's portrait is being changed

ChangeType: The change being made to the portrait (set, enabled, or disabled)

PortraitIndex: The index of the portrait to be set (from within the actor's Portraits

Disclaimers:

For a portrait to be set, a Sprite with the corresponding index must be in the DescantActor's Portraits property.

RandomizedChoice

Randomizes/shuffles a ChoiceNode's choices.

Max Quantity: 1

Node Type(s): Choice

Disclaimers:

This Component will automatically always be set to be the last variable, to avoid unintended errors.

RelationshipChange

Changes one of an actor's relationships.

Max Quantity: None

Node Type(s): Any

Variables:

FirstActor: A reference to the actor who's relationship is being checked

SecondActor: A reference to the actor that the relationship corresponds to

OperationType: The change being made to the relationship (increase, decrease, or set)

OperationValue: The value to change the relationship by

Disclaimers:

Changing the first actor's relationship to the second will not change the second's relationship to the first.

StatisticChange

Changes an one of actor's statistics.

Max Quantity: None

Node Type(s): Any

Variables:

Actor: A reference to the actor who's statistic is being changed

StatisticName: The name of the statistic being changed

OperationType: The change being made to the statistic (increase, decrease, or set)

OperationValue: The value to change the statistic by

StatisticReveal

Calls a method from a script, passing it an actor's statistic (e.g. to display how an NPC's mood might increase/decrease during a dialogue).

Max Quantity: None

Node Type(s): Any

Variables:

Actor: A reference to the actor who's statistic is being revealed

StatisticName: The name of the statistic being revealed

ObjectTag: The tag of the GameObject on which the script is located (optional)

ScriptName: The name of the script on the GameObject

MethodName: The name of the method being called

Disclaimers:

If ObjectTag is empty, the first found script in the scene with the given name is called instead.

If the ScriptName or MethodName are empty, no method is called.

Currently, methods with more than one parameter cannot be called.

TimedChoice

Imposes a time restriction for choosing a TimedChoice's choice. Each FixedUpdate frame that the time is counting down, a method from a script can be called, passing the timer completion percentage (e.g. to update a timer UI). When the time reaches 0, a choice is automatically made, and another method can be called (e.g. to initiate a point penalty).

Max Quantity: 1

Node Type(s): Choice

Variables:

Time: The amount of time the player has to choose (in seconds)

ChoiceToPick: The index of the choice to pick if the timer runs out (base 1)

ObjectTag: The tag of the GameObject on which the script is located (optional)

ScriptName: The name of the script on the GameObject

TimerMethodName: The name of the method called while the timer is counting down (optional)

FinishedMethodName: The name of the method called when the timer reaches 0 (optional)

Disclaimers:

If ObjectTag is empty, the first found script in the scene with the given name is called instead.

If the ScriptName is empty, no method is called. If TimerMethodName is empty, that method isn't called. If FinishedMethodName is empty, that method isn't called.

Currently, methods with more than one parameter cannot be called.

TopicChange

Changes one of an actor's topics.

Max Quantity: None

Node Type(s): Response

Variables:

Actor: A reference to the actor who's topic is being changed

TopicName: The name of the topic being changed

ChangeType: The change being made to the topic (add or remove)

Component creation

  1. Create a new C# class in Descant/Components/Custom.
  2. Make sure that the Component is in the Descant.Components namespace.
  3. Make sure that the Component inherits from the DescantComponent abstract class.
  4. Add a [Serializable] attribute to the Component.
  5. Add a [MaxQuantity(...)] attribute to the Component (replace the '...' with the maximum number of Components of this type that can be added to a single node) ('...' can be float.PositiveInfinity).
  6. Add a [NodeType(...)] attribute to the Component (replace the '...' with the DescantNodeType indicating which types of nodes it can be added to).
  7. Optional: Add a [DontShowInEditor] attribute to the Component to bar it from being added in the Descant Graph Editor.
  8. Add any number of public variables/properties to the Component (these properties will show up in the Descant Graph Editor when you add the Component to a node) (you may also create private/protected properties, but they won't appear in the editor). Properties may only be of type string, float, int, bool, Vector2, Vector3, Color, UnityEngine.Object (including but not limited to DescantActor), or Enum.
  9. For each public variable, add either an [Inline] attribute (indicating that it will be visually nestled beside the Component name in the editor) or a [ParameterGroup(...)] attribute (indicating that it will be visually arranged in a new group beneath the Component name in the editor) (replace the '...' with the string name of the group to order it into).
  10. Optional: By default, all Component fields filter any out most special characters on input. You can override this by giving any public variable a [NoFiltering] attribute, disabling filtering for that variable's corresponding field in the Descant Graph Editor. This is useful for long-form fields that may have sentence grammar and punctuation.
  11. If this Component performs some action when it is reached during dialogue, give it the following method: public override DescantNodeInvokeResult Invoke(DescantNodeInvokeResult result). The DescantNodeInvokeResult object being passed contains all the choice/response text for the current node, the current actors, and info regarding the actor portraits) (see the DescantNodeInvokeResult class for more info). The Invoke method must return a DescantNodeInvokeResult object (almost always just result itself, with its properties modified).
  12. Optional: Many default Descant Components only do their effect if some comparison is made. Should your Component also wish to do so, the CompareVariable method in DescantComponentUtilities may be of use.
  13. Optional: If you need the Component to do something continuously while it is active during dialogue, give it one of the following methods: public override bool FixedUpdate() or public override bool Update(). They function in exactly the same manner as the classic MonoBehaviour methods of the same names, save for the fact that if they ever return false, the dialogue ends immediately (should the Component want to end the dialogue for some reason).
  14. That's it! Your new Component will now show up as an option to add to a node in the Descant Graph Editor.