File size: 3,053 Bytes
c670567
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
 * ============================================================================
 * CHOICE MANAGER - Branching choice logic with consequences
 * ============================================================================
 *
 * Manages player choices and their effects on game state.
 * Works with GameDataManager to apply effects and track history.
 * Works with DialogueManager to handle choice points in dialogue.
 *
 * EVENTS:
 *   - 'choicePresented': (choiceId, prompt, options[]) => void
 *   - 'choiceSelected': (choiceId, option, effects) => void
 *   - 'effectsApplied': (choiceId, effects) => void
 *
 * USAGE:
 *   const cm = new ChoiceManager(gameDataManager);
 *   cm.presentChoice('greeting', 'How do you respond?', [
 *     { text: 'Hello!', effects: { friendship: +1 } },
 *     { text: 'Go away.', effects: { friendship: -2, hostility: +1 } },
 *   ]);
 *   // When player selects:
 *   cm.selectOption('greeting', 0);  // applies effects to GameDataManager
 */

import Phaser from 'phaser';
import { type ChoiceOption } from '../scenes/BaseChapterScene';
import { type GameDataManager } from './GameDataManager';

export class ChoiceManager extends Phaser.Events.EventEmitter {
  private gameData: GameDataManager;
  private activeChoices: Map<string, ChoiceOption[]> = new Map();

  constructor(gameData: GameDataManager) {
    super();
    this.gameData = gameData;
  }

  /**
   * Present a choice to the player.
   * Filters options by their condition (if any).
   */
  presentChoice(
    choiceId: string,
    prompt: string,
    options: ChoiceOption[],
  ): ChoiceOption[] {
    // Filter by conditions, store active choice, emit event (includes prompt)
    const visible = options.filter((o) => !o.condition || o.condition());
    this.activeChoices.set(choiceId, visible);
    this.emit('choicePresented', choiceId, prompt, visible);
    return visible;
  }

  /**
   * Player selects an option.
   * Applies effects to GameDataManager and records in choice history.
   */
  selectOption(
    choiceId: string,
    optionIndex: number,
  ): ChoiceOption | undefined {
    const options = this.activeChoices.get(choiceId);
    if (!options || optionIndex < 0 || optionIndex >= options.length)
      return undefined;

    const selected = options[optionIndex];

    // Apply effects
    if (selected.effects) {
      for (const [key, value] of Object.entries(selected.effects)) {
        this.gameData.addTo(key, value);
      }
      this.emit('effectsApplied', choiceId, selected.effects);
    }

    // Record choice
    this.gameData.recordChoice(choiceId, selected.text);

    // Cleanup
    this.activeChoices.delete(choiceId);
    this.emit('choiceSelected', choiceId, selected, selected.effects);

    return selected;
  }

  /** Check if a choice is currently active (waiting for input). */
  isChoiceActive(choiceId: string): boolean {
    return this.activeChoices.has(choiceId);
  }

  /** Check if ANY choice is currently active. */
  hasActiveChoice(): boolean {
    return this.activeChoices.size > 0;
  }
}