1
0
Fork 0

DRY questLog

This commit is contained in:
Pabloader 2026-04-28 19:58:43 +00:00
parent b75dc078f9
commit 9a44605469
1 changed files with 37 additions and 31 deletions

View File

@ -19,19 +19,47 @@ export class QuestLog extends Component {
readonly #quests = new Map<string, QuestEntry>(); readonly #quests = new Map<string, QuestEntry>();
addQuest(quest: Quest): void { addQuest(quest: Quest): void {
if (!this.#quests.has(quest.id)) { if (this.#quests.has(quest.id)) {
console.warn(`[QuestLog] quest '${quest.id}' is already registered, ignoring duplicate`);
return;
}
this.#quests.set(quest.id, { quest, state: { status: 'inactive', stageIndex: 0 } }); this.#quests.set(quest.id, { quest, state: { status: 'inactive', stageIndex: 0 } });
} }
#transition(op: string, questId: string, from: QuestStatus, to: QuestStatus, event: string): boolean {
const entry = this.#quests.get(questId);
if (!entry) {
console.warn(`[QuestLog] ${op}: quest '${questId}' is not registered`);
return false;
}
if (entry.state.status !== from) {
console.warn(`[QuestLog] ${op}: quest '${questId}' cannot transition from status '${entry.state.status}'`);
return false;
}
entry.state.status = to;
if (to === 'active' || to === 'inactive') entry.state.stageIndex = 0;
this.emit(event, { questId });
return true;
} }
@action @action
start(questId: string): boolean { start(questId: string): boolean {
const entry = this.#quests.get(questId); return this.#transition('start', questId, 'inactive', 'active', 'started');
if (!entry || entry.state.status !== 'inactive') return false; }
entry.state.status = 'active';
entry.state.stageIndex = 0; @action
this.emit('started', { questId }); complete(questId: string): boolean {
return true; return this.#transition('complete', questId, 'active', 'completed', 'completed');
}
@action
fail(questId: string): boolean {
return this.#transition('fail', questId, 'active', 'failed', 'failed');
}
@action
abandon(questId: string): boolean {
return this.#transition('abandon', questId, 'active', 'inactive', 'abandoned');
} }
getState(questId: string): QuestRuntimeState | undefined { getState(questId: string): QuestRuntimeState | undefined {
@ -46,25 +74,6 @@ export class QuestLog extends Component {
return quest.conditions.every(c => evaluateCondition(parseCondition(c), ctx)); return quest.conditions.every(c => evaluateCondition(parseCondition(c), ctx));
} }
@action
fail(questId: string): boolean {
const entry = this.#quests.get(questId);
if (!entry || entry.state.status !== 'active') return false;
entry.state.status = 'failed';
this.emit('failed', { questId });
return true;
}
@action
abandon(questId: string): boolean {
const entry = this.#quests.get(questId);
if (!entry || entry.state.status !== 'active') return false;
entry.state.status = 'inactive';
entry.state.stageIndex = 0;
this.emit('abandoned', { questId });
return true;
}
getStage(questId: string): QuestStage | undefined { getStage(questId: string): QuestStage | undefined {
const entry = this.#quests.get(questId); const entry = this.#quests.get(questId);
if (!entry || entry.state.status !== 'active') return undefined; if (!entry || entry.state.status !== 'active') return undefined;
@ -91,10 +100,7 @@ export class QuestLog extends Component {
/** @internal called by QuestSystem when a fail condition is met */ /** @internal called by QuestSystem when a fail condition is met */
_fail(questId: string): void { _fail(questId: string): void {
const entry = this.#quests.get(questId); this.#transition('_fail', questId, 'active', 'failed', 'failed');
if (!entry) return;
entry.state.status = 'failed';
this.emit('failed', { questId });
} }
/** @internal called by QuestSystem after stage actions complete */ /** @internal called by QuestSystem after stage actions complete */