feat: add spoiler-safe campaign objective journal

This commit is contained in:
2026-07-28 11:05:57 +09:00
parent a67cfbfbe3
commit 91607cfd4c
16 changed files with 5116 additions and 220 deletions

View File

@@ -50,6 +50,7 @@ import { ExplorationInputController } from '../input/ExplorationInputController'
import { releaseTextureSource } from '../render/loaderLifecycle';
import { isVisualMotionReduced } from '../settings/visualMotion';
import { getCampaignState } from '../state/campaignState';
import { resolveCampaignObjectiveJournal } from '../state/campaignObjectiveJournal';
import { completeFirstPursuitScoutVisit } from '../state/firstPursuitScoutActions';
import {
completeSecondBattleReliefExploration,
@@ -62,6 +63,7 @@ import {
recordThirdCampExplorationActivity,
thirdCampExplorationProgress
} from '../state/thirdCampExplorationActions';
import { CampaignObjectiveJournalOverlay } from '../ui/CampaignObjectiveJournalOverlay';
import { fitDialogueFacePortrait } from '../ui/dialoguePortrait';
import { startGameScene } from './lazyScenes';
@@ -351,6 +353,7 @@ export class CampVisitExplorationScene extends Phaser.Scene {
private lastNotice = '';
private ownedPresentationTextureKeys = new Set<string>();
private visualMotionReduced = false;
private campaignObjectiveJournal?: CampaignObjectiveJournalOverlay;
constructor() {
super('CampVisitExplorationScene');
@@ -400,6 +403,8 @@ export class CampVisitExplorationScene extends Phaser.Scene {
this.explorationInput?.destroy();
this.explorationInput = undefined;
this.dialogueState = undefined;
this.campaignObjectiveJournal?.destroy();
this.campaignObjectiveJournal = undefined;
this.closeChoicePanel();
releaseExplorationCharacterTextureKeys(
this,
@@ -445,6 +450,7 @@ export class CampVisitExplorationScene extends Phaser.Scene {
this.createDialoguePanel();
this.ready = true;
this.inputReadyAt = this.time.now + inputCarryoverGuardMs;
this.createCampaignObjectiveJournal();
this.refreshObjectiveHud();
this.refreshActorMarkers();
this.refreshInteractionPrompt();
@@ -493,6 +499,11 @@ export class CampVisitExplorationScene extends Phaser.Scene {
this.explorationInput?.discardInteractionRequest();
return;
}
if (this.campaignObjectiveJournal?.isOpen()) {
this.stopPlayerMovement();
this.explorationInput?.discardInteractionRequest();
return;
}
if (this.choicePanel) {
this.stopPlayerMovement();
this.explorationInput?.discardInteractionRequest();
@@ -560,6 +571,10 @@ export class CampVisitExplorationScene extends Phaser.Scene {
ready: this.ready,
viewport: { width: this.scale.width, height: this.scale.height },
campaignStep: campaign.step,
campaignObjectiveJournal: {
snapshot: resolveCampaignObjectiveJournal(campaign),
view: this.campaignObjectiveJournal?.getDebugState() ?? null
},
background: {
key: this.backgroundImage?.texture.key ?? this.currentBackgroundKey(),
ready: this.backgroundImage?.active === true,
@@ -1119,6 +1134,7 @@ export class CampVisitExplorationScene extends Phaser.Scene {
this.actorViews.clear();
this.blockers = [];
this.dialogueState = undefined;
this.campaignObjectiveJournal = undefined;
this.choicePanel = undefined;
this.choicePanelBounds = undefined;
this.choiceViews = [];
@@ -2291,7 +2307,16 @@ export class CampVisitExplorationScene extends Phaser.Scene {
.bindKey(
Phaser.Input.Keyboard.KeyCodes.TWO,
() => this.chooseChoiceByIndex(1)
)
.bindKey(
Phaser.Input.Keyboard.KeyCodes.J,
() => this.campaignObjectiveJournal?.toggle()
);
this.input.keyboard?.on('keydown-ESC', () => {
if (this.campaignObjectiveJournal?.isOpen()) {
this.campaignObjectiveJournal.close();
}
});
this.input.on(
Phaser.Input.Events.POINTER_DOWN,
@@ -2299,6 +2324,7 @@ export class CampVisitExplorationScene extends Phaser.Scene {
if (
!this.ready ||
this.navigationPending ||
this.campaignObjectiveJournal?.isOpen() ||
this.time.now < this.inputReadyAt
) {
return;
@@ -2334,6 +2360,10 @@ export class CampVisitExplorationScene extends Phaser.Scene {
) {
return;
}
if (this.campaignObjectiveJournal?.isOpen()) {
this.campaignObjectiveJournal.close();
return;
}
if (this.choicePanel) {
this.closeChoicePanel();
return;
@@ -2351,6 +2381,16 @@ export class CampVisitExplorationScene extends Phaser.Scene {
);
}
private createCampaignObjectiveJournal() {
this.campaignObjectiveJournal = new CampaignObjectiveJournalOverlay(this, {
snapshotProvider: () =>
resolveCampaignObjectiveJournal(getCampaignState()),
canOpen: () => this.ready && !this.navigationPending,
buttonX: 1215,
buttonY: 21
});
}
private updateMovement(time: number, delta: number) {
if (!this.player) {
return;
@@ -3466,6 +3506,7 @@ export class CampVisitExplorationScene extends Phaser.Scene {
if (
!this.choicePanel ||
this.navigationPending ||
this.campaignObjectiveJournal?.isOpen() ||
this.time.now < this.choiceReadyAt
) {
return;
@@ -3477,6 +3518,13 @@ export class CampVisitExplorationScene extends Phaser.Scene {
}
private chooseVisitChoice(choice: ChoiceOption) {
if (
!this.choicePanel ||
this.navigationPending ||
this.campaignObjectiveJournal?.isOpen()
) {
return;
}
if (this.isThirdCampVisit()) {
if ('rewardExp' in choice) {
this.chooseThirdCampCompanion(choice);