How PHPDTS Implements Its Dialogue System: The noskip_dialogue Flag Explained

PHPDTS uses a lightweight flag-based dialogue system where actions trigger conversations by setting $clbpara['dialogue'] and $clbpara['noskip_dialogue'] flags, with the latter forcing players to make choices before proceeding.

PHPDTS implements a flexible, lightweight dialogue system that integrates narrative moments directly into the game loop through simple array parameters. The system distinguishes between skippable story text and mandatory choice branches using the noskip_dialogue flag. According to the amarillonmc/phpdts source code, this design allows any in-game action—from item usage to combat events—to trigger interactive conversations without complex state management.

Core Architecture of the PHPDTS Dialogue System

The implementation spans three primary components working in concert across the codebase:

  • Data Layer: gamedata/cache/dialogue_1.php stores static content including text blocks, icons, branching choices, and endings.
  • Game Loop: game.php (lines 250-267) evaluates dialogue flags during each request to determine when to render conversation interfaces.
  • Command Processor: command.php (lines 108-119 and 523-570) parses player interactions like dialogue_choice and end_dialogue commands.

Declaring Dialogues with $clbpara Flags

Actions trigger dialogues by manipulating the global $clbpara array. This parameter-based approach decouples dialogue initiation from core engine logic.

Standard Skippable Dialogues

For narrative text that players can dismiss by clicking the overlay:

$clbpara['dialogue'] = 'welcome_message';
// Optional: explicitly allow skipping
$clbpara['noskip_dialogue'] = 0;

Forced Choice Dialogues Using noskip_dialogue

When a dialogue requires player input through choice branches, set the noskip_dialogue flag:

$clbpara['dialogue'] = 'choose_faction';
$clbpara['noskip_dialogue'] = 1;  // Forces UI to disable overlay-click closing

As documented in gamedata/cache/dialogue_1.php (lines 5-9), this flag ensures players cannot bypass critical decision points. Example usage appears in include/game/item.test.php (lines 44-48), demonstrating both skippable and forced dialogue patterns.

Static Data Structure in dialogue_1.php

The file gamedata/cache/dialogue_1.php contains five associative arrays that define conversation content:

  • $dialogues: Main text content indexed by dialogue ID.
  • $dialogue_icon: Optional icon URLs for speaker portraits.
  • $dialogue_branch: Available choices mapped to each dialogue ID.
  • $dialogue_ending: Text displayed after branch resolution.
  • $dialogue_log: Runtime cache storing rendered HTML for completed conversations.

Game Loop Detection in game.php

During each request cycle, the engine checks for active dialogue flags before processing combat or movement. The detection logic in game.php (lines 250-267) evaluates:

elseif(!$just_made_choice && (!empty($clbpara['dialogue']) || !empty($clbpara['noskip_dialogue']))) {
    $opendialog = $clbpara['noskip_dialogue'];   // 1 = forced, 0 = skippable
    if(!empty($clbpara['dialogue'])) $dialogue_id = $clbpara['dialogue'];
}

The $opendialog variable directly receives the noskip_dialogue value. When set to 1, the front-end disables click-away closing and renders mandatory choice buttons. When 0 or empty, players may dismiss the modal by clicking outside the dialogue window.

Processing Player Commands in command.php

When players interact with dialogue interfaces, the system generates special commands processed by command.php.

Handling Choice Selection

The dialogue_choice command follows the format dialogue_choice:<dialogue_id>:<choice_index>. The parser in command.php (lines 108-119) extracts these parameters:

} elseif(strpos($command,'dialogue_choice') === 0) {
    $choice_parts = explode(':', $command);
    $dialogue_id  = $choice_parts[1];
    $choice_index = $choice_parts[2];
    
    $clbpara['dialogue_choice'] = [
        'dialogue_id'   => $dialogue_id,
        'choice_text'   => $dialogue_branch[$dialogue_id][$choice_index]
    ];
    $log .= "你选择了:<span class=\"yellow\">{$dialogue_branch[$dialogue_id][$choice_index]}</span><br>";
}

After processing, the system clears both flags to prevent dialogue recurrence:

unset($clbpara['dialogue']);
unset($clbpara['noskip_dialogue']);

Explicit Dialogue Termination

For closing forced dialogues without choices, the end_dialogue command (processed in command.php lines 523-570) appends any cached ending text and clears the flags:

} elseif(strpos($command,'end_dialogue') === 0) {
    if(!empty($dialogue_log[$clbpara['dialogue']])) 
        $log .= $dialogue_log[$clbpara['dialogue']];
    unset($clbpara['dialogue']);
    unset($clbpara['noskip_dialogue']);
}

API Integration for External Clients

The dialogue state is exposed through api.php (lines 788-793), enabling third-party front-ends and mobile clients to respect skip restrictions:

"dialog"      => $clbpara['dialogue'],
"noSkipDialog"=> $clbpara['noskip_dialogue'],

Summary

  • PHPDTS uses $clbpara array flags to trigger dialogues from any game action without tight coupling to the core engine.
  • The noskip_dialogue flag (set to 1) forces players to interact with choice branches, disabling overlay-click dismissal.
  • Static content resides in gamedata/cache/dialogue_1.php, separating narrative text from runtime logic.
  • The game loop in game.php checks these flags before other processing, setting $opendialog to control UI behavior.
  • Player choices are processed via dialogue_choice commands in command.php, which automatically clean up flags after resolution.
  • API exposure allows external clients to detect active dialogues and respect skip permissions.

Frequently Asked Questions

What is the difference between dialogue and noskip_dialogue in PHPDTS?

The $clbpara['dialogue'] flag specifies which conversation ID to display from dialogue_1.php, while $clbpara['noskip_dialogue'] controls player interaction permissions. When noskip_dialogue equals 1, the UI disables clicking outside the modal to close it, effectively forcing the player to select a choice branch or use the explicit close button.

How does PHPDTS handle dialogue choices programmatically?

When a player clicks a choice button, the client sends a dialogue_choice:<id>:<index> command to command.php. The parser extracts the dialogue ID and choice index, logs the selection to the game log, displays any associated ending text from $dialogue_ending, and unsets both $clbpara['dialogue'] and $clbpara['noskip_dialogue'] to prevent the dialogue from reappearing.

Can external applications access the dialogue state?

Yes. The api.php endpoint exposes both "dialog" (the current dialogue ID) and "noSkipDialog" (the skip restriction flag) in its JSON response. This allows mobile clients or alternative front-ends to synchronize dialogue rendering and enforce the same interaction constraints as the main web interface.

Where are dialogue texts and branches defined?

All static dialogue content is stored in gamedata/cache/dialogue_1.php. This file contains the $dialogues array for text content, $dialogue_branch for available choices, $dialogue_ending for post-choice messages, and $dialogue_icon for speaker portraits. Runtime conversation history is cached separately in $dialogue_log.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →