feat: make Xuzhou choices shape battle eight
This commit is contained in:
@@ -21,6 +21,10 @@ import {
|
||||
normalizeCityEquipmentContributionSnapshot,
|
||||
type CityEquipmentContributionSnapshot
|
||||
} from '../data/cityEquipmentPreparation';
|
||||
import {
|
||||
normalizeXuzhouStayBattlePayoffRuntime,
|
||||
type XuzhouStayBattlePayoffRuntime
|
||||
} from '../data/xuzhouStayBattlePayoff';
|
||||
|
||||
export type BattleSaveFaction = 'ally' | 'enemy';
|
||||
export type BattleSaveRosterTab = 'ally' | 'enemy';
|
||||
@@ -118,6 +122,8 @@ export type BattleSaveThirdCampPreparationState = {
|
||||
|
||||
export type BattleSaveCityEquipmentContributionState =
|
||||
CityEquipmentContributionSnapshot;
|
||||
export type BattleSaveXuzhouStayBattlePayoffState =
|
||||
XuzhouStayBattlePayoffRuntime;
|
||||
|
||||
export type BattleSaveEventPriority = 'critical' | 'high' | 'normal' | 'low';
|
||||
|
||||
@@ -141,6 +147,7 @@ export type BattleSaveState = {
|
||||
cooperationStatsByBond?: Record<string, BattleSaveCooperationStats>;
|
||||
thirdCampPreparation?: BattleSaveThirdCampPreparationState;
|
||||
cityEquipmentContribution?: BattleSaveCityEquipmentContributionState;
|
||||
xuzhouStayBattlePayoff?: BattleSaveXuzhouStayBattlePayoffState;
|
||||
savedAt: string;
|
||||
turnNumber: number;
|
||||
activeFaction: BattleSaveFaction;
|
||||
@@ -239,6 +246,7 @@ export function normalizeBattleSaveState(
|
||||
normalizeCooperationSaveFields(cloned, options);
|
||||
normalizeThirdCampPreparationSaveField(cloned);
|
||||
normalizeCityEquipmentContributionSaveField(cloned, options);
|
||||
normalizeXuzhouStayBattlePayoffSaveField(cloned, options);
|
||||
const recommendation = normalizeCampaignSortieRecommendationSnapshot(cloned.sortieRecommendation, {
|
||||
expectedBattleId: typeof cloned.battleId === 'string' ? cloned.battleId : options.expectedBattleId,
|
||||
allowedUnitIds: options.validAllyUnitIds
|
||||
@@ -296,6 +304,10 @@ export function isValidBattleSaveState(state: unknown, options: BattleSaveValida
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isOptionalXuzhouStayBattlePayoffState(state.xuzhouStayBattlePayoff, state, options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const attackIntents = state.attackIntents;
|
||||
const units = state.units;
|
||||
|
||||
@@ -803,6 +815,100 @@ function canonicalCityEquipmentContributionSaveState(
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeXuzhouStayBattlePayoffSaveField(
|
||||
state: Record<string, unknown>,
|
||||
options: BattleSaveValidationOptions
|
||||
) {
|
||||
const normalized = canonicalXuzhouStayBattlePayoffSaveState(
|
||||
state.xuzhouStayBattlePayoff,
|
||||
state,
|
||||
options
|
||||
);
|
||||
if (normalized) {
|
||||
state.xuzhouStayBattlePayoff = normalized;
|
||||
} else {
|
||||
delete state.xuzhouStayBattlePayoff;
|
||||
}
|
||||
}
|
||||
|
||||
function isOptionalXuzhouStayBattlePayoffState(
|
||||
value: unknown,
|
||||
state: Record<string, unknown>,
|
||||
options: BattleSaveValidationOptions
|
||||
) {
|
||||
if (value === undefined) {
|
||||
return true;
|
||||
}
|
||||
const normalized = canonicalXuzhouStayBattlePayoffSaveState(
|
||||
value,
|
||||
state,
|
||||
options
|
||||
);
|
||||
if (!normalized || !isRecord(value)) {
|
||||
return false;
|
||||
}
|
||||
const fields: Array<
|
||||
keyof BattleSaveXuzhouStayBattlePayoffState
|
||||
> = [
|
||||
'version',
|
||||
'recordId',
|
||||
'cityStayId',
|
||||
'sourceBattleId',
|
||||
'targetBattleId',
|
||||
'informationVisitId',
|
||||
'dialogueId',
|
||||
'informationCompleted',
|
||||
'informationCounterplays',
|
||||
'miZhuDeployed',
|
||||
'supportAttempts',
|
||||
'supportUses',
|
||||
'bonusHealing',
|
||||
'bonusBuffTurns'
|
||||
];
|
||||
if (normalized.choiceId) {
|
||||
fields.push('choiceId');
|
||||
}
|
||||
return (
|
||||
Object.keys(value).length === fields.length &&
|
||||
fields.every((field) => value[field] === normalized[field])
|
||||
);
|
||||
}
|
||||
|
||||
function canonicalXuzhouStayBattlePayoffSaveState(
|
||||
value: unknown,
|
||||
state: Record<string, unknown>,
|
||||
options: BattleSaveValidationOptions
|
||||
): BattleSaveXuzhouStayBattlePayoffState | undefined {
|
||||
const battleId =
|
||||
typeof state.battleId === 'string' ? state.battleId : undefined;
|
||||
if (!battleId || !Array.isArray(state.units)) {
|
||||
return undefined;
|
||||
}
|
||||
const deployedUnitIds = state.units
|
||||
.filter(isRecord)
|
||||
.map((unit) => unit.id)
|
||||
.filter(
|
||||
(unitId): unitId is string =>
|
||||
typeof unitId === 'string' &&
|
||||
(!options.validAllyUnitIds ||
|
||||
options.validAllyUnitIds.has(unitId))
|
||||
);
|
||||
const normalized = normalizeXuzhouStayBattlePayoffRuntime(
|
||||
value,
|
||||
{
|
||||
expectedBattleId: battleId,
|
||||
expectedRosterUnitIds: deployedUnitIds
|
||||
}
|
||||
);
|
||||
if (
|
||||
!normalized ||
|
||||
(!normalized.informationCompleted && !normalized.choiceId)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function isOptionalCoreResonanceState(
|
||||
state: Record<string, unknown>,
|
||||
options: BattleSaveValidationOptions
|
||||
|
||||
Reference in New Issue
Block a user