fix general status transition parity

This commit is contained in:
2026-07-26 17:12:54 +00:00
parent a0df7f5b3c
commit 80a2c9502f
10 changed files with 238 additions and 17 deletions
@@ -847,6 +847,7 @@ export const createReservedTurnHandler = async (options: {
}> = [];
const createdGenerals: TurnGeneral[] = [];
const createdNations: Nation[] = [];
const commandDeletedTroopIds = new Set<number>();
let currentGeneral = context.general;
let currentCity = context.city;
@@ -1092,6 +1093,9 @@ export const createReservedTurnHandler = async (options: {
},
actionArgs
);
for (const troopId of resolution.deletedTroopIds ?? []) {
commandDeletedTroopIds.add(troopId);
}
currentGeneral = resolution.general as TurnGeneral;
currentCity = resolution.city ?? currentCity;
@@ -1599,7 +1603,7 @@ export const createReservedTurnHandler = async (options: {
let lifecycleOutcome: 'active' | 'detached' | 'deleted' | 'retired' = 'active';
let deleteGeneral = false;
const deletedTroopIds: number[] = [];
const deletedTroopIds = Array.from(commandDeletedTroopIds);
const lifecycleSnapshot = cloneTurnGeneral(currentGeneral);
if (currentGeneral.meta.killturn <= 0 && typeof currentGeneral.deadYear === 'number') {
if (
@@ -1752,10 +1756,10 @@ export const createReservedTurnHandler = async (options: {
...(createdNations.length > 0 ? { nations: createdNations } : {}),
}
: undefined,
...(deleteGeneral
...(deleteGeneral || deletedTroopIds.length > 0
? {
deleted: {
general: true,
general: deleteGeneral,
...(deletedTroopIds.length > 0 ? { troopIds: deletedTroopIds } : {}),
},
}
@@ -68,7 +68,10 @@ const makeGeneral = (patch: Partial<TurnGeneral> = {}): TurnGeneral => ({
...patch,
});
const makeSnapshot = (general: TurnGeneral): TurnWorldSnapshot => ({
const makeSnapshot = (
general: TurnGeneral,
extras: { generals?: TurnGeneral[]; troops?: TurnWorldSnapshot['troops'] } = {}
): TurnWorldSnapshot => ({
scenarioConfig: {
stat: { total: 300, min: 10, max: 100, npcTotal: 150, npcMax: 50, npcMin: 10, chiefMin: 70 },
iconPath: '',
@@ -132,8 +135,8 @@ const makeSnapshot = (general: TurnGeneral): TurnWorldSnapshot => ({
meta: { trust: 50, trade: 100, region: 1 },
},
],
generals: [general],
troops: [],
generals: [general, ...(extras.generals ?? [])],
troops: extras.troops ?? [],
diplomacy: [],
events: [],
initialEvents: [],
@@ -248,4 +251,33 @@ describe('legacy general-turn execution contract', () => {
expect(harness.reservedTurnStore.getGeneralTurn(1, 0).action).toBe('휴식');
expect(harness.getCollectedLogs().some((log) => log.text.includes('악성유저'))).toBe(true);
});
it('deletes the troop row and releases members when a troop leader resigns', async () => {
const leader = makeGeneral({ troopId: 1 });
const member = makeGeneral({
id: 2,
name: '부대원',
troopId: 1,
turnTime: new Date(start.getTime() + 10 * 60_000),
});
const snapshot = makeSnapshot(leader, {
generals: [member],
troops: [{ id: 1, nationId: 1, name: '테스트군' }],
});
snapshot.nations[0]!.meta.gennum = 2;
const harness = await createTurnTestHarness({
snapshot,
state: makeState(),
schedule,
map,
});
harness.reservedTurnStore.getGeneralTurns(1)[0] = { action: 'che_하야', args: {} };
await harness.runOneTick({ maxGenerals: 1 });
expect(harness.world.getGeneralById(1)?.troopId).toBe(0);
expect(harness.world.getGeneralById(2)?.troopId).toBe(0);
expect(harness.world.getTroopById(1)).toBeNull();
expect(harness.world.consumeDirtyState().deletedTroops).toEqual([1]);
});
});