Browse/Narrative & Choice/Flag / Semaphore
Narrative & Choice

Flag / Semaphore

Structured approach to flag / semaphore that balances depth with accessibility, creating satisfying player experiences.

Medium complexity
2 examples
1 patterns

Overview

As a core game system, flag / semaphore provides meaningful choices and consequences for player actions. When well-implemented, this mechanic creates a satisfying feedback loop that keeps players engaged and motivated to continue playing. The ongoing evolution of this mechanic reflects the broader maturation of game design as a discipline.

Game Examples

Dungeon Crawlers

Dungeon Crawlers use this mechanic where players interact with NPCs to tell their own story. The mechanic creates natural tension and release cycles, resulting in risk-reward tension.

Martial Arts Games

Martial Arts Games use this mechanic where players balance risk and reward to progress through the content. The mechanic integrates seamlessly with other systems, resulting in exploration incentives.

Pros & Cons

Advantages

  • Balances mechanical against mechanical effectively
  • Balances spatial against temporal effectively
  • Creates satisfying cumulative loops
  • Rewards both team coordination and team coordination

Disadvantages

  • Risk of exploitation in multiplayer contexts
  • May conflict with narrative systems in the game
  • May overwhelm returning players with too many options
  • Increases storage requirements significantly

Implementation Patterns

Quest Tracker

Core implementation pattern for handling flag / semaphore logic with clean state management.

class FlagSemaphoreController {
  currentNode: string = "start";
  flags: Set<string> = new Set();

  getDialogue() {
    const node = DIALOGUE_TREE[this.currentNode];
    return {
      text: node.text,
      choices: node.choices.filter(c =>
        !c.requires || c.requires.every(f => this.flags.has(f))
      )
    };
  }

  choose(choiceIndex: number) {
    const node = DIALOGUE_TREE[this.currentNode];
    const choice = node.choices[choiceIndex];
    if (choice.setsFlag) this.flags.add(choice.setsFlag);
    this.currentNode = choice.next;
    return this.getDialogue();
  }
}