147 lines
5.5 KiB
TypeScript
147 lines
5.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { RedisConnector } from '@sammo-ts/infra';
|
|
import type { Nation } from '@sammo-ts/logic';
|
|
|
|
import { InMemoryTurnWorld } from '../src/turn/inMemoryWorld.js';
|
|
import { createTournamentAutoStartHandler } from '../src/turn/tournamentAutoStart.js';
|
|
import type { TurnWorldSnapshot, TurnWorldState } from '../src/turn/types.js';
|
|
|
|
const buildNation = (id: number): Nation => ({
|
|
id,
|
|
name: `국가${id}`,
|
|
color: '#777777',
|
|
capitalCityId: null,
|
|
chiefGeneralId: null,
|
|
gold: 0,
|
|
rice: 0,
|
|
power: 0,
|
|
level: 1,
|
|
typeCode: 'che_중립',
|
|
meta: {},
|
|
});
|
|
|
|
describe('monthly tournament auto start', () => {
|
|
it('uses the legacy monthly RNG after nation power rolls and persists the remaining pattern', async () => {
|
|
const state: TurnWorldState = {
|
|
id: 1,
|
|
currentYear: 193,
|
|
currentMonth: 1,
|
|
tickSeconds: 600,
|
|
lastTurnTime: new Date('0193-01-01T00:00:00.000Z'),
|
|
meta: {
|
|
hiddenSeed: 'monthly-post-tail-2',
|
|
tournamentPattern: [0, 1, 2, 3],
|
|
},
|
|
};
|
|
const snapshot: TurnWorldSnapshot = {
|
|
scenarioConfig: {
|
|
stat: { total: 300, min: 10, max: 100, npcTotal: 150, npcMax: 50, npcMin: 10, chiefMin: 70 },
|
|
iconPath: '',
|
|
map: {},
|
|
const: {},
|
|
environment: { mapName: 'test', unitSet: 'default' },
|
|
},
|
|
map: { id: 'test', name: 'test', cities: [] },
|
|
diplomacy: [],
|
|
events: [],
|
|
initialEvents: [],
|
|
generals: [],
|
|
cities: [],
|
|
nations: [buildNation(1), buildNation(2)],
|
|
troops: [],
|
|
};
|
|
const values = new Map<string, string>();
|
|
const redis = {
|
|
get: async (key: string) => values.get(key) ?? null,
|
|
set: async (key: string, value: string) => {
|
|
values.set(key, value);
|
|
return 'OK';
|
|
},
|
|
} as unknown as RedisConnector['client'];
|
|
let world: InMemoryTurnWorld | null = null;
|
|
const consumed: boolean[] = [];
|
|
world = new InMemoryTurnWorld(state, snapshot, {
|
|
schedule: { entries: [{ startMinute: 0, tickMinutes: 10 }] },
|
|
calendarHandler: createTournamentAutoStartHandler({
|
|
profileName: 'test',
|
|
getWorld: () => world,
|
|
getRedisClient: () => redis,
|
|
getWorldConfig: () => ({ tournamentTrig: true }),
|
|
getNationPowerRollCount: () => 2,
|
|
onTournamentRollConsumed: (value) => consumed.push(value),
|
|
now: () => new Date('2026-07-25T00:00:00.000Z'),
|
|
}),
|
|
});
|
|
|
|
await world.advanceMonth(new Date('0193-02-01T00:00:00.000Z'));
|
|
|
|
expect(consumed).toEqual([false, true]);
|
|
expect(JSON.parse(values.get('sammo:test:tournament:state') ?? '{}')).toMatchObject({
|
|
stage: 1,
|
|
phase: 0,
|
|
type: 3,
|
|
auto: true,
|
|
openYear: 193,
|
|
openMonth: 2,
|
|
termSeconds: 600,
|
|
nextAt: '2026-07-25T00:10:00.000Z',
|
|
});
|
|
expect(world.getState().meta.tournamentPattern).toEqual([0, 1, 2]);
|
|
expect(world.peekDirtyState().logs).toEqual([
|
|
expect.objectContaining({
|
|
text: "<B><b>【대회】</b></><C>설전</> 대회가 개최됩니다! 천하의 <span class='ev_highlight'>책사</span>들을 모집하고 있습니다!",
|
|
}),
|
|
]);
|
|
});
|
|
|
|
it('does not consume a tournament roll while a tournament is active', async () => {
|
|
const state: TurnWorldState = {
|
|
id: 1,
|
|
currentYear: 193,
|
|
currentMonth: 1,
|
|
tickSeconds: 600,
|
|
lastTurnTime: new Date('0193-01-01T00:00:00.000Z'),
|
|
meta: { hiddenSeed: 'active-tournament' },
|
|
};
|
|
const snapshot: TurnWorldSnapshot = {
|
|
scenarioConfig: {
|
|
stat: { total: 300, min: 10, max: 100, npcTotal: 150, npcMax: 50, npcMin: 10, chiefMin: 70 },
|
|
iconPath: '',
|
|
map: {},
|
|
const: {},
|
|
environment: { mapName: 'test', unitSet: 'default' },
|
|
},
|
|
map: { id: 'test', name: 'test', cities: [] },
|
|
diplomacy: [],
|
|
events: [],
|
|
initialEvents: [],
|
|
generals: [],
|
|
cities: [],
|
|
nations: [buildNation(1)],
|
|
troops: [],
|
|
};
|
|
const redis = {
|
|
get: async () => JSON.stringify({ stage: 1 }),
|
|
set: async () => 'OK',
|
|
} as unknown as RedisConnector['client'];
|
|
let world: InMemoryTurnWorld | null = null;
|
|
const consumed: boolean[] = [];
|
|
world = new InMemoryTurnWorld(state, snapshot, {
|
|
schedule: { entries: [{ startMinute: 0, tickMinutes: 10 }] },
|
|
calendarHandler: createTournamentAutoStartHandler({
|
|
profileName: 'test',
|
|
getWorld: () => world,
|
|
getRedisClient: () => redis,
|
|
getWorldConfig: () => ({ tournamentTrig: true }),
|
|
getNationPowerRollCount: () => 1,
|
|
onTournamentRollConsumed: (value) => consumed.push(value),
|
|
}),
|
|
});
|
|
|
|
await world.advanceMonth(new Date('0193-02-01T00:00:00.000Z'));
|
|
|
|
expect(consumed).toEqual([false]);
|
|
expect(world.peekDirtyState().logs).toEqual([]);
|
|
});
|
|
});
|