Add officer roster reserve growth
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { equipmentExpToNext, equipmentSlots } from '../data/battleItems';
|
||||
import type { BattleBond, UnitData } from '../data/scenario';
|
||||
|
||||
export type BattleObjectiveSnapshot = {
|
||||
@@ -96,6 +97,15 @@ export type CampaignBondProgressSnapshot = {
|
||||
battleExp: number;
|
||||
};
|
||||
|
||||
export type CampaignReserveTrainingSnapshot = {
|
||||
unitId: string;
|
||||
name: string;
|
||||
expGained: number;
|
||||
equipmentExpGained: number;
|
||||
level: number;
|
||||
exp: number;
|
||||
};
|
||||
|
||||
export type CampaignBattleSettlement = {
|
||||
battleId: string;
|
||||
battleTitle: string;
|
||||
@@ -105,6 +115,7 @@ export type CampaignBattleSettlement = {
|
||||
objectives: BattleObjectiveSnapshot[];
|
||||
units: CampaignUnitProgressSnapshot[];
|
||||
bonds: CampaignBondProgressSnapshot[];
|
||||
reserveTraining?: CampaignReserveTrainingSnapshot[];
|
||||
completedAt: string;
|
||||
};
|
||||
|
||||
@@ -265,12 +276,15 @@ export function setFirstBattleReport(report: FirstBattleReport) {
|
||||
state.step = reportClone.outcome === 'victory' ? victoryStep : retryStep;
|
||||
state.gold = Math.max(0, state.gold - (previousSettlement?.rewardGold ?? 0) + reportClone.rewardGold);
|
||||
state.roster = mergeRosterProgress(state.roster, reportClone.units.filter((unit) => unit.faction === 'ally'));
|
||||
const reserveTraining = previousSettlement || reportClone.outcome !== 'victory'
|
||||
? previousSettlement?.reserveTraining ?? []
|
||||
: applyReserveTrainingProgress(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);
|
||||
state.battleHistory[battleId] = createBattleSettlement(reportClone, reserveTraining);
|
||||
state.latestBattleId = battleId;
|
||||
state.updatedAt = new Date().toISOString();
|
||||
|
||||
@@ -492,7 +506,7 @@ function advanceBond(bond: CampBondSnapshot, amount: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function createBattleSettlement(report: FirstBattleReport): CampaignBattleSettlement {
|
||||
function createBattleSettlement(report: FirstBattleReport, reserveTraining: CampaignReserveTrainingSnapshot[] = []): CampaignBattleSettlement {
|
||||
return {
|
||||
battleId: report.battleId,
|
||||
battleTitle: report.battleTitle,
|
||||
@@ -518,6 +532,7 @@ function createBattleSettlement(report: FirstBattleReport): CampaignBattleSettle
|
||||
exp: bond.exp,
|
||||
battleExp: bond.battleExp
|
||||
})),
|
||||
reserveTraining: reserveTraining.map((entry) => ({ ...entry })),
|
||||
completedAt: report.createdAt
|
||||
};
|
||||
}
|
||||
@@ -540,6 +555,50 @@ function mergeRosterProgress(currentRoster: UnitData[], deployedUnits: UnitData[
|
||||
return Array.from(merged.values());
|
||||
}
|
||||
|
||||
function applyReserveTrainingProgress(roster: UnitData[], deployedUnits: UnitData[]): CampaignReserveTrainingSnapshot[] {
|
||||
const deployedIds = new Set(deployedUnits.map((unit) => unit.id));
|
||||
return roster
|
||||
.filter((unit) => unit.faction === 'ally' && !deployedIds.has(unit.id))
|
||||
.map((unit) => {
|
||||
const expGained = 6;
|
||||
const equipmentExpGained = 2;
|
||||
advanceUnitExp(unit, expGained);
|
||||
advanceReserveEquipment(unit, equipmentExpGained);
|
||||
return {
|
||||
unitId: unit.id,
|
||||
name: unit.name,
|
||||
expGained,
|
||||
equipmentExpGained,
|
||||
level: unit.level,
|
||||
exp: unit.exp
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function advanceUnitExp(unit: UnitData, amount: number) {
|
||||
let exp = unit.exp + amount;
|
||||
while (unit.level < 99 && exp >= 100) {
|
||||
exp -= 100;
|
||||
unit.level += 1;
|
||||
unit.maxHp += 2;
|
||||
unit.hp = Math.min(unit.maxHp, unit.hp + 2);
|
||||
unit.attack += 1;
|
||||
}
|
||||
unit.exp = unit.level >= 99 ? Math.min(exp, 100) : exp;
|
||||
}
|
||||
|
||||
function advanceReserveEquipment(unit: UnitData, amount: number) {
|
||||
equipmentSlots.forEach((slot) => {
|
||||
const state = unit.equipment[slot];
|
||||
let exp = state.exp + amount;
|
||||
while (state.level < 9 && exp >= equipmentExpToNext(state.level)) {
|
||||
exp -= equipmentExpToNext(state.level);
|
||||
state.level += 1;
|
||||
}
|
||||
state.exp = state.level >= 9 ? Math.min(exp, equipmentExpToNext(state.level)) : exp;
|
||||
});
|
||||
}
|
||||
|
||||
function parseRewardLabel(reward: string) {
|
||||
const normalized = reward.replace(/\s+/g, ' ').trim();
|
||||
const match = normalized.match(/^(.*?)(?:\s*[+xX]?\s*(\d+))$/);
|
||||
|
||||
Reference in New Issue
Block a user