Skip to main content

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.

Overview

Conditional entries allow your dialogue to branch dynamically based on game state, player choices, or any other logic. Unlike text entries, conditional entries execute a callable that returns a boolean, then jump to different branches based on the result.

Creating Conditional Entries

Conditional entries are created using add_conditional_entry() with a callable that returns bool:
extends DialogueEngine

var have_we_talked_before = false

func check_if_talked() -> bool:
    return have_we_talked_before

func _setup() -> void:
    add_text_entry("Hello!")
    
    # Add a conditional entry
    var condition_entry = add_conditional_entry(check_if_talked)
    
    # Set where to go based on the condition result
    var if_true = add_text_entry("Hey! We meet again!")
    var if_false = add_text_entry("It's nice to meet you!")
    condition_entry.set_condition_goto_ids(if_true.get_id(), if_false.get_id())

How Conditions Work

When advance() encounters a conditional entry:
  1. The callable is executed immediately
  2. The boolean return value determines the path:
    • true: Jumps to the “true” goto ID
    • false: Jumps to the “false” goto ID
  3. The branch ID needle updates automatically to match the target entry’s branch
  4. The conditional entry emits entry_visited but not dialogue_continued
# This happens automatically inside advance()
var result = condition.call()
var target_goto_id = get_entry_condition_goto_ids(entry_id)[result]
Conditional entries don’t pause dialogue flow - they’re processed instantly and dialogue continues to the target entry.

Setting Condition Gotos

You must specify both the true and false paths for a conditional entry:
var condition_entry = add_conditional_entry(some_callable)

# Set both paths
var true_entry = add_text_entry("Condition was true")
var false_entry = add_text_entry("Condition was false")
condition_entry.set_condition_goto_ids(true_entry.get_id(), false_entry.get_id())

# You can also get the current goto IDs
var goto_ids = condition_entry.get_condition_goto_ids()
print(goto_ids[true])  # Entry ID for true path
print(goto_ids[false]) # Entry ID for false path
Failing to set valid condition goto IDs will cause the dialogue to be canceled with a warning when the condition is reached.

Using Callables

Conditions can use any callable that returns a boolean:

Method Reference

func is_player_friendly() -> bool:
    return player_reputation >= 50

var condition = add_conditional_entry(is_player_friendly)

Lambda Function

var gold = 100

var condition = add_conditional_entry(func() -> bool:
    return gold >= 50
)

Bound Callable

func has_item(item_name: String) -> bool:
    return inventory.has(item_name)

var condition = add_conditional_entry(has_item.bind("key"))

Conditional Entry with Branches

Conditional entries work seamlessly with branch IDs:
extends DialogueEngine

var have_we_talked_before = 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 = add_conditional_entry(__have_we_talked_before)
    
    # Each path goes to a different branch
    var if_true = add_text_entry("Hey! We meet again!", branch.STRANGERS)
    var if_false = 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>")
    
    # Update state when dialogue finishes
    dialogue_finished.connect(func() -> void:
        have_we_talked_before = true
    )

Managing Conditions

You can modify conditional entries after creation:
var entry = add_conditional_entry(some_condition)

# Check if entry has a condition
if entry.has_condition():
    var condition = entry.get_condition()
    
# Change the condition
entry.set_condition(different_condition)

# Remove the condition (converts to text entry)
entry.remove_condition()

Text vs Conditional Entries

An entry can be either text-based or conditional, not both. Setting a condition on a text entry will cause the text to be ignored.
var entry = add_text_entry("Hello!")
entry.set_condition(some_callable) # The text "Hello!" will be ignored!
If you need dialogue text after a condition, create separate entries:
# Good: Separate entries
var condition = add_conditional_entry(check_something)
var true_text = add_text_entry("Condition was true!")
var false_text = add_text_entry("Condition was false!")
condition.set_condition_goto_ids(true_text.get_id(), false_text.get_id())

Multiple Conditions in Sequence

You can chain conditional entries for complex logic:
func _setup() -> void:
    add_text_entry("Evaluating your character...")
    
    # First condition: Check reputation
    var rep_check = add_conditional_entry(func() -> bool:
        return reputation >= 50
    )
    
    # If high reputation, check gold
    var gold_check = add_conditional_entry(func() -> bool:
        return gold >= 100
    )
    
    # Different outcomes
    var rich_and_famous = add_text_entry("Welcome, honored guest!")
    var famous_only = add_text_entry("Welcome, friend!")
    var low_rep = add_text_entry("What do you want?")
    
    # Wire up the conditions
    rep_check.set_condition_goto_ids(gold_check.get_id(), low_rep.get_id())
    gold_check.set_condition_goto_ids(rich_and_famous.get_id(), famous_only.get_id())

Condition Signals

Conditional entries emit the entry_visited signal but not dialogue_continued:
# This fires for ALL entries (text and conditional)
dialogue_engine.entry_visited.connect(func(entry: DialogueEntry) -> void:
    if entry.has_condition():
        print("Condition evaluated!")
)

# This ONLY fires for text entries
dialogue_engine.dialogue_continued.connect(func(entry: DialogueEntry) -> void:
    print(entry.get_text())
)

Common Patterns

State Machine

Use conditions to implement quest states:
enum QuestState { NOT_STARTED, IN_PROGRESS, COMPLETED }
var quest_state = QuestState.NOT_STARTED

func check_quest_started() -> bool:
    return quest_state != QuestState.NOT_STARTED

func check_quest_completed() -> bool:
    return quest_state == QuestState.COMPLETED

func _setup() -> void:
    var state_check = add_conditional_entry(check_quest_started)
    
    var not_started = add_text_entry("I need your help with something...")
    var started_check = add_conditional_entry(check_quest_completed)
    
    var in_progress = add_text_entry("How's the quest going?")
    var completed = add_text_entry("Thank you for your help!")
    
    state_check.set_condition_goto_ids(started_check.get_id(), not_started.get_id())
    started_check.set_condition_goto_ids(completed.get_id(), in_progress.get_id())

Item Checks

Gate dialogue behind inventory items:
var inventory = ["sword", "shield"]

func has_key() -> bool:
    return "key" in inventory

func _setup() -> void:
    add_text_entry("The door is locked.")
    
    var key_check = add_conditional_entry(has_key)
    var with_key = add_text_entry("You unlock the door with your key.")
    var no_key = add_text_entry("You need a key to open this door.")
    
    key_check.set_condition_goto_ids(with_key.get_id(), no_key.get_id())

Time-Based Dialogue

func is_daytime() -> bool:
    var hour = Time.get_time_dict_from_system()["hour"]
    return hour >= 6 and hour < 18

func _setup() -> void:
    var time_check = add_conditional_entry(is_daytime)
    var day = add_text_entry("Good morning!")
    var night = add_text_entry("Good evening!")
    
    time_check.set_condition_goto_ids(day.get_id(), night.get_id())

Debugging Conditions

The dialogue debugger shows conditional entries as special nodes in the graph, making it easy to visualize branching logic.
Conditions can be complex, so consider adding debug logging:
func check_complex_condition() -> bool:
    var result = (gold >= 100 and reputation >= 50) or has_special_item
    if OS.is_debug_build():
        print("Condition result: ", result)
    return result

Best Practices

  1. Keep conditions simple: Complex logic should be in your game code, not in dialogue callables
  2. Always set both paths: Never leave condition gotos unset
  3. Use descriptive names: Name your condition functions clearly (e.g., has_completed_quest not check1)
  4. Test both branches: Make sure to test both true and false paths
  5. Consider using enums for branches: Makes it clear which branch each condition leads to
If a condition throws an error or returns a non-boolean value, it may cause unexpected behavior. Always ensure your callables return a valid boolean.

Next Steps

Options

Let players make choices with options

Branching

Learn more about branch IDs and gotos

Build docs developers (and LLMs) love