feat: add selectable core resonance pairs
This commit is contained in:
@@ -3,6 +3,7 @@ import { unitClasses } from '../data/battleRules';
|
||||
import { battleScenarios, type BattleScenarioId } from '../data/battles';
|
||||
import { campaignRecruitUnits, type BattleBond, type UnitData } from '../data/scenario';
|
||||
import { normalizeSortieFormationAssignments, type SortieFormationAssignments } from '../data/sortieDeployment';
|
||||
import { coreSortieResonanceMinLevel } from '../data/sortieSynergy';
|
||||
import {
|
||||
isSortieOrderId,
|
||||
sortieOrderCheckIdsByOrder,
|
||||
@@ -395,6 +396,11 @@ export type CampaignSortieOrderSelection = {
|
||||
orderId: CampaignSortiePresetId;
|
||||
};
|
||||
|
||||
export type CampaignSortieResonanceSelection = {
|
||||
battleId: BattleScenarioId;
|
||||
bondId: string;
|
||||
};
|
||||
|
||||
export type CampaignSortieOrderHistory = Partial<
|
||||
Record<BattleScenarioId, Partial<Record<CampaignSortiePresetId, CampaignSortieOrderResultSnapshot>>>
|
||||
>;
|
||||
@@ -413,6 +419,7 @@ export type CampaignState = {
|
||||
sortieItemAssignments: CampaignSortieItemAssignments;
|
||||
sortieFormationPresets: CampaignSortieFormationPresets;
|
||||
sortieOrderSelection?: CampaignSortieOrderSelection;
|
||||
sortieResonanceSelection?: CampaignSortieResonanceSelection;
|
||||
sortieOrderHistory: CampaignSortieOrderHistory;
|
||||
claimedSortieOrderRewardIds: string[];
|
||||
reserveTrainingFocus: CampaignReserveTrainingFocusId;
|
||||
@@ -722,6 +729,32 @@ export function setCampaignSortieOrderSelection(battleId: BattleScenarioId, orde
|
||||
return cloneCampaignState(state);
|
||||
}
|
||||
|
||||
export function setCampaignSortieResonanceSelection(battleId: BattleScenarioId, bondId?: string) {
|
||||
const state = ensureCampaignState();
|
||||
if (!hasCampaignBattleScenario(battleId)) {
|
||||
return cloneCampaignState(state);
|
||||
}
|
||||
|
||||
if (bondId) {
|
||||
const normalizedBondId = normalizeKeyString(bondId);
|
||||
const bond = resolveCampaignSortieResonanceBond(battleId, normalizedBondId, state.bonds);
|
||||
const selectedUnitIds = new Set(state.selectedSortieUnitIds);
|
||||
if (
|
||||
!bond ||
|
||||
bond.level < coreSortieResonanceMinLevel ||
|
||||
!bond.unitIds.every((unitId) => selectedUnitIds.has(unitId))
|
||||
) {
|
||||
return cloneCampaignState(state);
|
||||
}
|
||||
state.sortieResonanceSelection = { battleId, bondId: bond.id };
|
||||
} else if (!state.sortieResonanceSelection || state.sortieResonanceSelection.battleId === battleId) {
|
||||
delete state.sortieResonanceSelection;
|
||||
}
|
||||
state.updatedAt = new Date().toISOString();
|
||||
persistCampaignState(state);
|
||||
return cloneCampaignState(state);
|
||||
}
|
||||
|
||||
export function setCampaignReserveTrainingFocus(focusId: CampaignReserveTrainingFocusId) {
|
||||
const state = ensureCampaignState();
|
||||
const normalizedFocusId = normalizeReserveTrainingFocusId(focusId);
|
||||
@@ -890,6 +923,9 @@ export function setFirstBattleReport(report: FirstBattleReport) {
|
||||
if (state.sortieOrderSelection?.battleId === battleId) {
|
||||
delete state.sortieOrderSelection;
|
||||
}
|
||||
if (state.sortieResonanceSelection?.battleId === battleId) {
|
||||
delete state.sortieResonanceSelection;
|
||||
}
|
||||
state.latestBattleId = battleId;
|
||||
state.updatedAt = new Date().toISOString();
|
||||
|
||||
@@ -1089,6 +1125,14 @@ function normalizeCampaignState(state: Partial<CampaignState>): CampaignState {
|
||||
if (!normalized.sortieOrderSelection) {
|
||||
delete normalized.sortieOrderSelection;
|
||||
}
|
||||
normalized.sortieResonanceSelection = normalizeCampaignSortieResonanceSelection(
|
||||
normalized.sortieResonanceSelection,
|
||||
normalized.bonds,
|
||||
normalized.selectedSortieUnitIds
|
||||
);
|
||||
if (!normalized.sortieResonanceSelection) {
|
||||
delete normalized.sortieResonanceSelection;
|
||||
}
|
||||
normalized.sortieOrderHistory = normalizeCampaignSortieOrderHistory(normalized.sortieOrderHistory);
|
||||
normalized.claimedSortieOrderRewardIds = normalizeCampaignSortieOrderRewardClaims(
|
||||
normalized.claimedSortieOrderRewardIds,
|
||||
@@ -1266,6 +1310,53 @@ function normalizeCampaignSortieOrderSelection(value: unknown): CampaignSortieOr
|
||||
return { battleId: battleId as BattleScenarioId, orderId: value.orderId };
|
||||
}
|
||||
|
||||
function normalizeCampaignSortieResonanceSelection(
|
||||
value: unknown,
|
||||
bonds: readonly CampBondSnapshot[],
|
||||
selectedSortieUnitIds: readonly string[]
|
||||
): CampaignSortieResonanceSelection | undefined {
|
||||
if (!isPlainObject(value)) {
|
||||
return undefined;
|
||||
}
|
||||
const battleId = typeof value.battleId === 'string' ? value.battleId : '';
|
||||
const bondId = normalizeKeyString(value.bondId);
|
||||
if (!hasCampaignBattleScenario(battleId) || !bondId) {
|
||||
return undefined;
|
||||
}
|
||||
const bond = resolveCampaignSortieResonanceBond(battleId, bondId, bonds);
|
||||
const selectedUnitIds = new Set(selectedSortieUnitIds);
|
||||
if (
|
||||
!bond ||
|
||||
bond.level < coreSortieResonanceMinLevel ||
|
||||
!bond.unitIds.every((unitId) => selectedUnitIds.has(unitId))
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return { battleId: battleId as BattleScenarioId, bondId };
|
||||
}
|
||||
|
||||
function resolveCampaignSortieResonanceBond(
|
||||
battleId: string,
|
||||
bondId: string,
|
||||
campaignBonds: readonly CampBondSnapshot[]
|
||||
): BattleBond | undefined {
|
||||
if (!hasCampaignBattleScenario(battleId)) {
|
||||
return undefined;
|
||||
}
|
||||
const scenarioBond = battleScenarios[battleId].bonds.find((bond) => bond.id === bondId);
|
||||
if (!scenarioBond) {
|
||||
return undefined;
|
||||
}
|
||||
const campaignBond = campaignBonds.find((bond) => bond.id === bondId);
|
||||
return campaignBond
|
||||
? { ...scenarioBond, level: campaignBond.level, exp: campaignBond.exp }
|
||||
: scenarioBond;
|
||||
}
|
||||
|
||||
function hasCampaignBattleScenario(battleId: string): battleId is BattleScenarioId {
|
||||
return Object.prototype.hasOwnProperty.call(battleScenarios, battleId);
|
||||
}
|
||||
|
||||
export function normalizeCampaignSortieOrderResultSnapshot(
|
||||
value: unknown,
|
||||
outcome?: FirstBattleReport['outcome'],
|
||||
|
||||
Reference in New Issue
Block a user