Spaces:
Running on Zero
Running on Zero
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;
}
}
|