> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Rubonnek/dialogue-engine/llms.txt
> Use this file to discover all available pages before exploring further.

# Player Choices

> Add player options and conditional branching to your dialogue

Player choices allow your dialogue to respond to player decisions, creating interactive and branching conversations.

## Adding Options to Dialogue

Options are choices presented to the player. When an entry has options, the dialogue pauses until the player chooses one.

<Steps>
  <Step title="Create an entry with options">
    Add options to a dialogue entry and specify where each option leads:

    ```gdscript theme={null}
    extends DialogueEngine

    enum {
        DEFAULT_TOPIC = 0,
        GO_BACK_TO_SLEEP = 1,
        KEEP_WORKING = 2,
    }

    func _setup() -> void:
        var entry: DialogueEntry = add_text_entry(
            "The storm rages right outside the window. I should..."
        )
        
        # Add option 1
        var option_id_1: int = entry.add_option("Go back to sleep.")
        var option_id_1_entry: DialogueEntry = add_text_entry(
            "That's right, sleep is for the strong 💪.",
            GO_BACK_TO_SLEEP
        )
        entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id())
        
        # Add option 2
        var option_id_2: int = entry.add_option("Get back to work.")
        var option_id_2_entry: DialogueEntry = add_text_entry(
            "That's right, let's get back to work 🫡",
            KEEP_WORKING
        )
        entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id())
    ```
  </Step>

  <Step title="Display options in your UI">
    When a dialogue entry has options, create buttons for each one:

    ```gdscript theme={null}
    func __on_dialogue_continued(p_dialogue_entry: DialogueEntry) -> void:
        # Display the dialogue text
        display_text(p_dialogue_entry.get_text())
        
        # Check if this entry has options
        if p_dialogue_entry.has_options():
            for option_id in p_dialogue_entry.get_option_count():
                var option_text: String = p_dialogue_entry.get_option_text(option_id)
                create_option_button(option_text, option_id, p_dialogue_entry)
    ```
  </Step>

  <Step title="Handle player choice">
    When the player clicks an option, tell the DialogueEntry which option was chosen, then advance:

    ```gdscript theme={null}
    func _on_option_button_pressed(option_id: int, dialogue_entry: DialogueEntry) -> void:
        # Set the chosen option
        dialogue_entry.choose_option(option_id)
        
        # Clear option buttons from UI
        clear_option_buttons()
        
        # Advance to the chosen branch
        dialogue_engine.advance()
    ```
  </Step>
</Steps>

## Rejoining Branches

After branching, you often want the dialogue to converge back to a common path:

```gdscript theme={null}
func _setup() -> void:
    var entry: DialogueEntry = add_text_entry(
        "The storm rages right outside the window. I should..."
    )
    
    # Branch 1: Sleep
    var option_id_1: int = entry.add_option("Go back to sleep.")
    var option_id_1_entry: DialogueEntry = add_text_entry(
        "That's right, sleep is for the strong 💪.",
        GO_BACK_TO_SLEEP
    )
    entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id())
    
    # Branch 2: Work
    var option_id_2: int = entry.add_option("Get back to work.")
    var option_id_2_entry: DialogueEntry = add_text_entry(
        "That's right, let's get back to work 🫡",
        KEEP_WORKING
    )
    entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id())
    
    # Join both branches back to the default topic
    var default_topic: DialogueEntry = add_text_entry("Some time passes...")
    option_id_1_entry.set_goto_id(default_topic.get_id())
    option_id_2_entry.set_goto_id(default_topic.get_id())
    
    add_text_entry("<Press 'Space' or 'Enter' to quit>")
```

<Tip>
  Using gotos to rejoin branches lets you avoid duplicating dialogue that should appear regardless of the player's choice.
</Tip>

## Conditional Branching

Conditional entries let you branch based on game state without showing options to the player:

<Steps>
  <Step title="Create a condition function">
    Define a function that returns a boolean:

    ```gdscript theme={null}
    extends DialogueEngine

    var have_we_talked_before: bool = false

    func __have_we_talked_before() -> bool:
        return have_we_talked_before
    ```
  </Step>

  <Step title="Add a conditional entry">
    Use `add_conditional_entry()` instead of `add_text_entry()`:

    ```gdscript theme={null}
    enum branch {
        STRANGERS,
        ACQUAINTANCES,
    }

    func _setup() -> void:
        add_text_entry("Hello!")
        
        # Create the conditional entry
        var condition_entry: DialogueEntry = add_conditional_entry(__have_we_talked_before)
        
        # Define where to go based on the condition
        var if_true: DialogueEntry = add_text_entry(
            "Hey! We meet again!",
            branch.ACQUAINTANCES
        )
        var if_false: DialogueEntry = add_text_entry(
            "It's nice to meet you!",
            branch.STRANGERS
        )
        
        # Set the condition gotos
        condition_entry.set_condition_goto_ids(if_true.get_id(), if_false.get_id())
        
        add_text_entry("<Press 'Enter' or 'Space' to exit>")
        
        # Update the state after dialogue finishes
        dialogue_finished.connect(func() -> void:
            have_we_talked_before = true
        )
    ```
  </Step>
</Steps>

<Note>
  Conditional entries are evaluated automatically when reached. The player never sees the condition itself - the dialogue just branches silently based on the result.
</Note>

## Complete Example

<CodeGroup>
  ```gdscript branching_options_dialogue.gd theme={null}
  extends DialogueEngine

  enum {
      DEFAULT_TOPIC = 0,
      GO_BACK_TO_SLEEP = 1,
      KEEP_WORKING = 2,
  }

  func _setup() -> void:
      var entry: DialogueEntry = add_text_entry(
          "The storm rages right outside the window. I should..."
      )
      
      var option_id_1: int = entry.add_option("Go back to sleep.")
      var option_id_1_entry: DialogueEntry = add_text_entry(
          "That's right, sleep is for the strong 💪.",
          GO_BACK_TO_SLEEP
      )
      entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id())
      
      var option_id_2: int = entry.add_option("Get back to work.")
      var option_id_2_entry: DialogueEntry = add_text_entry(
          "That's right, let's get back to work 🫡",
          KEEP_WORKING
      )
      entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id())
      
      # Join branches into the default topic (i.e. branch id 0)
      var default_topic: DialogueEntry = add_text_entry("Some time passes...")
      option_id_1_entry.set_goto_id(default_topic.get_id())
      option_id_2_entry.set_goto_id(default_topic.get_id())
      
      # None of the following entries will be connected on the graph
      add_text_entry(
          "A sleep entry skipped due to missing goto against this entry.",
          GO_BACK_TO_SLEEP
      )
      add_text_entry(
          "A working entry due to missing goto against this entry.",
          KEEP_WORKING
      )
      
      add_text_entry("<Press 'Space' or 'Enter' to quit>")
  ```

  ```gdscript branching_condition_dialogue.gd theme={null}
  extends DialogueEngine

  var have_we_talked_before: bool = false

  enum branch {
      STRANGERS,
      ACQUAINTANCES,
  }

  func __have_we_talked_before() -> bool:
      return have_we_talked_before

  func _setup() -> void:
      add_text_entry("Hello!")
      
      var condition_entry: DialogueEntry = add_conditional_entry(__have_we_talked_before)
      var if_true: DialogueEntry = add_text_entry(
          "Hey! We meet again!",
          branch.STRANGERS
      )
      var if_false: DialogueEntry = add_text_entry(
          "It's nice to meet you!",
          branch.ACQUAINTANCES
      )
      condition_entry.set_condition_goto_ids(if_true.get_id(), if_false.get_id())
      
      add_text_entry("<Press 'Enter' or 'Space' to exit>")
      
      dialogue_finished.connect(func() -> void:
          have_we_talked_before = true
      )
  ```
</CodeGroup>

## Entry Methods for Options

| Method                                             | Description                                  |
| -------------------------------------------------- | -------------------------------------------- |
| `add_option(text: String) -> int`                  | Adds an option and returns its ID            |
| `set_option_goto_id(option_id: int, goto_id: int)` | Sets where an option leads                   |
| `get_option_text(option_id: int) -> String`        | Gets the text of an option                   |
| `get_option_count() -> int`                        | Returns the number of options                |
| `has_options() -> bool`                            | Returns true if the entry has options        |
| `choose_option(option_id: int)`                    | Sets the chosen option (call before advance) |

## Conditional Entry Methods

| Method                                                       | Description                          |
| ------------------------------------------------------------ | ------------------------------------ |
| `add_conditional_entry(callable: Callable) -> DialogueEntry` | Creates a conditional branch         |
| `set_condition_goto_ids(true_id: int, false_id: int)`        | Sets where to go for true/false      |
| `get_condition() -> Callable`                                | Returns the condition function       |
| `has_condition() -> bool`                                    | Returns true if entry is conditional |

## Best Practices

<AccordionGroup>
  <Accordion title="Always set goto IDs for all options">
    If you forget to set a goto ID for an option, the dialogue will cancel when that option is chosen.

    ```gdscript theme={null}
    var option_id: int = entry.add_option("My choice")
    var target: DialogueEntry = add_text_entry("Response")
    entry.set_option_goto_id(option_id, target.get_id())  # Don't forget this!
    ```
  </Accordion>

  <Accordion title="Use meaningful branch IDs for options">
    Instead of arbitrary numbers, use enums that describe what each branch represents:

    ```gdscript theme={null}
    enum Path {
        PEACEFUL = 0,
        AGGRESSIVE = 1,
    }
    ```
  </Accordion>

  <Accordion title="Clear options from UI before advancing">
    Always remove option buttons before calling `advance()` to prevent the player from clicking them again.
  </Accordion>

  <Accordion title="Conditions are evaluated at runtime">
    The condition callable is called when the entry is visited, so you can check any game state (inventory, flags, stats, etc.).
  </Accordion>
</AccordionGroup>

## Next Steps

* Use [dynamic text](/guides/dynamic-text) to personalize dialogue based on game state
* Learn about [save/load](/guides/save-load) to preserve player choices
* Check the [debugging guide](/guides/debugging) to visualize your branching dialogue
