merge: scenario 2400 battle replay parity
This commit is contained in:
@@ -134,11 +134,14 @@ const mapCityPayload = (payload: BattleSimJobPayload['attackerCity']): City => (
|
||||
},
|
||||
});
|
||||
|
||||
const mapGeneralPayload = (payload: BattleSimJobPayload['attackerGeneral']): General => ({
|
||||
const mapGeneralPayload = (
|
||||
payload: BattleSimJobPayload['attackerGeneral'],
|
||||
currentCityId: number
|
||||
): General => ({
|
||||
id: payload.no,
|
||||
name: payload.name,
|
||||
nationId: payload.nation,
|
||||
cityId: payload.officer_city,
|
||||
cityId: payload.city ?? currentCityId,
|
||||
troopId: 0,
|
||||
stats: {
|
||||
leadership: payload.leadership,
|
||||
@@ -184,10 +187,12 @@ const mapGeneralPayload = (payload: BattleSimJobPayload['attackerGeneral']): Gen
|
||||
dex3: payload.dex3,
|
||||
dex4: payload.dex4,
|
||||
dex5: payload.dex5,
|
||||
intelExp: payload.intel_exp,
|
||||
strengthExp: payload.strength_exp,
|
||||
leadershipExp: payload.leadership_exp,
|
||||
defenceTrain: payload.defence_train,
|
||||
intel_exp: payload.intel_exp,
|
||||
strength_exp: payload.strength_exp,
|
||||
leadership_exp: payload.leadership_exp,
|
||||
defence_train: payload.defence_train,
|
||||
officerCity: payload.officer_city,
|
||||
officer_city: payload.officer_city,
|
||||
rank_warnum: payload.warnum,
|
||||
rank_killnum: payload.killnum,
|
||||
rank_killcrew: payload.killcrew,
|
||||
@@ -304,8 +309,8 @@ const resolveDefenderOrderPayload = (payload: BattleSimJobPayload): number[] =>
|
||||
const defenderNation = mapNationPayload(payload.defenderNation);
|
||||
const attackerCity = mapCityPayload(payload.attackerCity);
|
||||
const defenderCity = mapCityPayload(payload.defenderCity);
|
||||
const attacker = mapGeneralPayload(payload.attackerGeneral);
|
||||
const defenders = payload.defenderGenerals.map(mapGeneralPayload);
|
||||
const attacker = mapGeneralPayload(payload.attackerGeneral, attackerCity.id);
|
||||
const defenders = payload.defenderGenerals.map((general) => mapGeneralPayload(general, defenderCity.id));
|
||||
const warActionModules = buildWarActionModules(payload.unitSet, payload.scenarioEffect);
|
||||
|
||||
return resolveDefenderOrder({
|
||||
@@ -376,8 +381,10 @@ export const processBattleSimJob = (
|
||||
const defenderNation = mapNationPayload(payload.defenderNation);
|
||||
const attackerCity = mapCityPayload(payload.attackerCity);
|
||||
const defenderCity = mapCityPayload(payload.defenderCity);
|
||||
const attackerGeneral = mapGeneralPayload(payload.attackerGeneral);
|
||||
const defenderGenerals = payload.defenderGenerals.map(mapGeneralPayload);
|
||||
const attackerGeneral = mapGeneralPayload(payload.attackerGeneral, attackerCity.id);
|
||||
const defenderGenerals = payload.defenderGenerals.map((general) =>
|
||||
mapGeneralPayload(general, defenderCity.id)
|
||||
);
|
||||
|
||||
const initialRice = new Map<number, number>();
|
||||
initialRice.set(attackerGeneral.id, attackerGeneral.rice);
|
||||
|
||||
@@ -6,6 +6,7 @@ export const zBattleSimGeneral = z.object({
|
||||
no: z.number().int().positive(),
|
||||
name: z.string().min(1),
|
||||
nation: z.number().int().positive(),
|
||||
city: z.number().int().min(0).optional(),
|
||||
turntime: z.string().min(1),
|
||||
personal: z.string().nullable(),
|
||||
special: z.string().nullable().optional(),
|
||||
|
||||
@@ -8,6 +8,8 @@ export interface BattleSimGeneralPayload {
|
||||
no: number;
|
||||
name: string;
|
||||
nation: number;
|
||||
/** Current city. Older clients omit this; the surrounding city payload is authoritative then. */
|
||||
city?: number;
|
||||
turntime: string;
|
||||
personal: string | null;
|
||||
special?: string | null;
|
||||
|
||||
@@ -237,9 +237,9 @@ describe('battle sim processor', () => {
|
||||
datetime: '2026-01-01 00:00:00',
|
||||
avgWar: 1,
|
||||
phase: 2,
|
||||
killed: 625,
|
||||
maxKilled: 625,
|
||||
minKilled: 625,
|
||||
killed: 626,
|
||||
maxKilled: 626,
|
||||
minKilled: 626,
|
||||
dead: 1000,
|
||||
maxDead: 1000,
|
||||
minDead: 1000,
|
||||
@@ -267,6 +267,30 @@ describe('battle sim processor', () => {
|
||||
expect(result.order).toEqual([2]);
|
||||
});
|
||||
|
||||
it('uses the legacy defence training threshold when ordering defenders', () => {
|
||||
const payload = buildPayload('reorder');
|
||||
payload.defenderGenerals[0]!.defence_train = 101;
|
||||
|
||||
const result = processBattleSimJob(payload);
|
||||
|
||||
expect(result.result).toBe(true);
|
||||
expect(result.order).toEqual([]);
|
||||
});
|
||||
|
||||
it('keeps current city separate from the officer assignment city', () => {
|
||||
const localOfficer = buildPayload('battle');
|
||||
localOfficer.attackerGeneral.city = localOfficer.attackerCity.city;
|
||||
const remoteOfficer = buildPayload('battle');
|
||||
remoteOfficer.attackerGeneral.city = remoteOfficer.attackerCity.city;
|
||||
remoteOfficer.attackerGeneral.officer_city = 99;
|
||||
|
||||
const local = processBattleSimJob(localOfficer);
|
||||
const remote = processBattleSimJob(remoteOfficer);
|
||||
|
||||
expect(local.killed).toBeGreaterThan(remote.killed ?? 0);
|
||||
expect(local).not.toEqual(remote);
|
||||
});
|
||||
|
||||
it('executes crew trigger handlers in simulator battles', () => {
|
||||
const payload = buildPayload('battle');
|
||||
payload.unitSet.crewTypes![0]!.phaseSkillTrigger = ['che_선제사격시도', 'che_선제사격발동'];
|
||||
|
||||
Reference in New Issue
Block a user