feat: improve combat feedback and progression

This commit is contained in:
2026-07-19 00:34:11 +09:00
parent f29956b90e
commit 87e3ddb047
16 changed files with 1284 additions and 80 deletions

View File

@@ -5,6 +5,7 @@ import {
battleUiIconFrames,
battleUiIconMicroTextureKey,
battleUiIconTextureKey,
loadBattleUiIcons,
type BattleUiIconKey
} from '../data/battleUiIcons';
import { portraitAssetEntriesForKey, portraitKeyForSpeaker, type PortraitAssetEntry } from '../data/portraitAssets';
@@ -26,7 +27,7 @@ import {
import { prologuePages, type PortraitKey, type StoryPage } from '../data/scenario';
import { campaignVictoryRewardPresentation, getFirstBattleReport } from '../state/campaignState';
import { palette } from '../ui/palette';
import { startGameScene } from './lazyScenes';
import { ensureLazyScene, startGameScene } from './lazyScenes';
type AlphaObject = Phaser.GameObjects.Container | Phaser.GameObjects.Image | Phaser.GameObjects.Rectangle | Phaser.GameObjects.Text;
@@ -120,6 +121,11 @@ const firstBattleVictoryPageIds = new Set([
'first-victory-next'
]);
const firstBattleId = 'first-battle-zhuo-commandery';
const firstBattleWarmupUnitTextureKeys = [
'unit-rebel',
'unit-rebel-archer',
'unit-rebel-cavalry'
] as const;
export class StoryScene extends Phaser.Scene {
private pageIndex = 0;
@@ -250,6 +256,7 @@ export class StoryScene extends Phaser.Scene {
}
this.pageLoadingText = undefined;
});
this.warmFirstBattleSceneModule();
this.ensureStoryPageAssets(0, () => {
if (generation !== this.storyAssetLoadGeneration) {
@@ -348,20 +355,31 @@ export class StoryScene extends Phaser.Scene {
this.processStoryPageAssetQueue();
};
const finishUnitBases = () => {
if (generation !== this.storyAssetLoadGeneration) {
return;
}
if (this.isFirstBattleWarmupPage(request.pageIndex)) {
loadBattleUiIcons(this, finishRequest);
return;
}
finishRequest();
};
const loadUnitBases = () => {
if (generation !== this.storyAssetLoadGeneration || plan.unitTextureKeys.length === 0) {
finishRequest();
finishUnitBases();
return;
}
try {
loadUnitBaseSheets(this, plan.unitTextureKeys, finishRequest);
loadUnitBaseSheets(this, plan.unitTextureKeys, finishUnitBases);
} catch (error) {
console.warn(`Failed to prepare story unit bases for page ${request.pageIndex}`, error);
plan.unitTextureKeys
.filter((key) => !this.textures.exists(key))
.forEach((key) => this.storyAssetFailures.add(key));
finishRequest();
finishUnitBases();
}
};
@@ -416,13 +434,39 @@ export class StoryScene extends Phaser.Scene {
.filter((entry): entry is PortraitAssetEntry => entry !== undefined)
.filter((entry, index, entries) => entries.findIndex((candidate) => candidate.textureKey === entry.textureKey) === index);
const warmupUnitTextureKeys = this.isFirstBattleWarmupPage(pageIndex)
? firstBattleWarmupUnitTextureKeys
: [];
return {
backgrounds: backgroundKey && backgroundUrl ? [{ key: backgroundKey, url: backgroundUrl }] : [],
portraits,
unitTextureKeys: Array.from(new Set(storyCutsceneActorTextureKeys(page.cutscene)))
unitTextureKeys: Array.from(new Set([
...storyCutsceneActorTextureKeys(page.cutscene),
...warmupUnitTextureKeys
]))
};
}
private isFirstBattlePrelude() {
const requestedBattleId = typeof this.nextSceneData?.battleId === 'string'
? this.nextSceneData.battleId
: firstBattleId;
return this.nextScene === 'BattleScene' && requestedBattleId === firstBattleId;
}
private isFirstBattleWarmupPage(pageIndex: number) {
return this.isFirstBattlePrelude() && pageIndex === Math.min(1, this.pages.length - 1);
}
private warmFirstBattleSceneModule() {
if (!this.isFirstBattlePrelude()) {
return;
}
void ensureLazyScene(this.game, 'BattleScene').catch((error) => {
console.warn('Failed to warm the first battle scene module.', error);
});
}
private prefetchNextStoryPage(pageIndex: number) {
const nextPageIndex = pageIndex + 1;
if (nextPageIndex < this.pages.length) {