Add Liu Biao camp visit events

This commit is contained in:
2026-06-23 04:51:40 +09:00
parent 8f2479e5fc
commit c209107b43
5 changed files with 389 additions and 14 deletions

View File

@@ -33,6 +33,7 @@ export type FirstBattleReport = {
mvp?: CampMvpSnapshot;
itemRewards: string[];
completedCampDialogues: string[];
completedCampVisits: string[];
createdAt: string;
};
@@ -114,6 +115,7 @@ export type CampaignState = {
inventory: Record<string, number>;
selectedSortieUnitIds: string[];
completedCampDialogues: string[];
completedCampVisits: string[];
battleHistory: Record<string, CampaignBattleSettlement>;
latestBattleId?: string;
firstBattleReport?: FirstBattleReport;
@@ -164,6 +166,7 @@ export function createInitialCampaignState(): CampaignState {
inventory: {},
selectedSortieUnitIds: [],
completedCampDialogues: [],
completedCampVisits: [],
battleHistory: {}
};
}
@@ -244,8 +247,11 @@ export function setFirstBattleReport(report: FirstBattleReport) {
const previousSettlement = state.battleHistory[battleId];
const completedCampDialogues =
battleId === 'first-battle-zhuo-commandery' ? [...reportClone.completedCampDialogues] : [...state.completedCampDialogues];
const completedCampVisits =
battleId === 'first-battle-zhuo-commandery' ? [...(reportClone.completedCampVisits ?? [])] : [...state.completedCampVisits];
reportClone.completedCampDialogues = completedCampDialogues;
reportClone.completedCampVisits = completedCampVisits;
state.firstBattleReport = reportClone;
const stepRule = campaignBattleSteps[battleId] ?? campaignBattleSteps['first-battle-zhuo-commandery'];
const victoryStep: CampaignStep = stepRule.victory;
@@ -255,6 +261,7 @@ export function setFirstBattleReport(report: FirstBattleReport) {
state.roster = mergeRosterProgress(state.roster, reportClone.units.filter((unit) => unit.faction === 'ally'));
state.bonds = reportClone.bonds.map(cloneBondSnapshot);
state.completedCampDialogues = completedCampDialogues;
state.completedCampVisits = completedCampVisits;
state.inventory = applyRewardDelta(state.inventory, previousSettlement?.itemRewards ?? [], -1);
state.inventory = applyRewardDelta(state.inventory, reportClone.itemRewards, 1);
state.battleHistory[battleId] = createBattleSettlement(reportClone);
@@ -298,6 +305,50 @@ export function applyCampBondExp(dialogueId: string, bondId: string, amount: num
return cloneReport(state.firstBattleReport);
}
export function applyCampVisitReward(
visitId: string,
reward: { bondId?: string; bondExp?: number; gold?: number; itemRewards?: string[] }
) {
const state = ensureCampaignState();
if (!state.firstBattleReport) {
return undefined;
}
if (state.completedCampVisits.includes(visitId)) {
return cloneCampaignState(state);
}
state.completedCampVisits.push(visitId);
if (!state.firstBattleReport.completedCampVisits.includes(visitId)) {
state.firstBattleReport.completedCampVisits.push(visitId);
}
if (reward.bondId && reward.bondExp && reward.bondExp > 0) {
const campaignBond = state.bonds.find((candidate) => candidate.id === reward.bondId);
const reportBond = state.firstBattleReport.bonds.find((candidate) => candidate.id === reward.bondId);
if (campaignBond) {
advanceBond(campaignBond, reward.bondExp);
if (reportBond) {
reportBond.level = campaignBond.level;
reportBond.exp = campaignBond.exp;
reportBond.battleExp = campaignBond.battleExp;
}
}
}
if (reward.gold && reward.gold > 0) {
state.gold += reward.gold;
}
if (reward.itemRewards?.length) {
state.inventory = applyRewardDelta(state.inventory, reward.itemRewards, 1);
}
state.updatedAt = new Date().toISOString();
persistCampaignState(state);
return cloneCampaignState(state);
}
export function ensureCampaignRosterUnits(units: UnitData[], bonds: BattleBond[] = []) {
const state = ensureCampaignState();
let changed = false;
@@ -368,6 +419,7 @@ function normalizeCampaignState(state: CampaignState): CampaignState {
normalized.roster = (normalized.roster ?? []).map(cloneUnit);
normalized.bonds = (normalized.bonds ?? []).map(cloneBondSnapshot);
normalized.completedCampDialogues = [...new Set(normalized.completedCampDialogues ?? [])];
normalized.completedCampVisits = [...new Set(normalized.completedCampVisits ?? [])];
normalized.inventory = { ...(normalized.inventory ?? {}) };
normalized.selectedSortieUnitIds = [...new Set(normalized.selectedSortieUnitIds ?? [])];
normalized.battleHistory = normalized.battleHistory ?? {};
@@ -501,7 +553,9 @@ function cloneCampaignState(state: CampaignState): CampaignState {
}
function cloneReport(report: FirstBattleReport): FirstBattleReport {
return JSON.parse(JSON.stringify(report)) as FirstBattleReport;
const cloned = JSON.parse(JSON.stringify(report)) as FirstBattleReport;
cloned.completedCampVisits = [...new Set(cloned.completedCampVisits ?? [])];
return cloned;
}
function cloneUnit(unit: UnitData): UnitData {