feat: carry sortie doctrine through campaign battles

This commit is contained in:
2026-07-10 14:14:54 +09:00
parent 3caf03fe2f
commit 4a5a73a220
8 changed files with 792 additions and 125 deletions

View File

@@ -8456,7 +8456,7 @@ export const fiftySeventhBattleScenario: BattleScenarioDefinition = {
},
sortie: {
sortieLimit: 7,
requiredUnits: ['zhuge-liang'],
requiredUnits: ['zhuge-liang', 'wang-ping'],
recommendedUnits: [
{ unitId: 'zhuge-liang', role: 'support', reason: '가정 배치 위기의 총지휘관입니다. 고지와 물길 판단을 끝까지 조율해야 합니다.' },
{ unitId: 'wang-ping', role: 'front', reason: '가정의 물길과 고지 배치를 읽는 핵심 장수입니다. 왕평 생존 목표도 직접 걸려 있습니다.' },

View File

@@ -3,11 +3,12 @@ import type { SortieFormationRole } from './sortieDeployment';
export const coreSortieSynergyRoles = ['front', 'flank', 'support'] as const;
export const firstPursuitSynergyBattleId = 'second-battle-yellow-turban-pursuit';
export const firstPursuitBrotherUnitIds = ['liu-bei', 'guan-yu', 'zhang-fei'] as const;
export const firstPursuitRolePreviewSummaries: Partial<Record<SortieFormationRole, string>> = {
export const sortieRoleEffectSummaries: Partial<Record<SortieFormationRole, string>> = {
front: '일반 공격 피해 -8%(최소 1) · 반격 +20%',
flank: '초반 2턴 이동 +1 · 공격 피해 +10%',
support: '공격 책략 +10% · 회복 +2'
};
export const firstPursuitRolePreviewSummaries = sortieRoleEffectSummaries;
export type SortieSynergyMember = {
id: string;

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,7 @@ import {
compareSortieSynergy,
coreSortieSynergyRoles,
evaluateSortieSynergy,
firstPursuitRolePreviewSummaries,
sortieRoleEffectSummaries,
type SortieSynergyComparison,
type SortieSynergySnapshot
} from '../data/sortieSynergy';
@@ -1938,7 +1938,7 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
},
'fifty-seventh-battle-jieting-crisis': {
maxUnits: 7,
requiredUnitIds: ['zhuge-liang'],
requiredUnitIds: ['zhuge-liang', 'wang-ping'],
excludedUnitIds: ['liu-bei'],
recommended: [
{ unitId: 'zhuge-liang', reason: '가정 배치 위기의 총지휘관입니다. 고지와 물길 판단을 끝까지 조율해야 합니다.' },
@@ -12651,7 +12651,7 @@ export class CampScene extends Phaser.Scene {
this.trackSortie(this.add.text(slotX + 38, slotY + 10, definition.label, this.textStyle(13, filled ? '#a8ffd0' : '#ffdf7b', true))).setDepth(depth + 2);
this.trackSortie(this.add.text(slotX + 12, slotY + 40, unitNames.join(', ') || '담당 없음', this.textStyle(13, filled ? '#f2e3bf' : '#ff9d7d', true))).setDepth(depth + 2);
this.trackSortie(
this.add.text(slotX + 12, slotY + 59, firstPursuitRolePreviewSummaries[definition.role] ?? definition.description, {
this.add.text(slotX + 12, slotY + 59, sortieRoleEffectSummaries[definition.role] ?? definition.description, {
...this.textStyle(8, '#9fb0bf'),
wordWrap: { width: slotWidth - 24, useAdvancedWrap: true },
lineSpacing: 0
@@ -14069,7 +14069,12 @@ export class CampScene extends Phaser.Scene {
this.selectedSortieUnitIds,
this.sortieFormationAssignments,
(unit) => this.sortieRecommendation(unit.id, scenario)?.role ?? this.defaultSortieFormationRole(unit),
this.nextSortieRule(scenario).deploymentSlots
this.nextSortieRule(scenario).deploymentSlots?.map((slot) => ({
x: slot.x,
y: slot.y,
role: slot.role,
label: slot.label
}))
);
}