fix: 커맨드 차등 생명주기와 로그 그래프를 보강
장수 55종과 수뇌 35종의 상태, 로그, 메시지, 예약 턴 비교를 닫습니다. 실제 시나리오 프로필과 대표 PostgreSQL 수명주기, 즉시 외교와 출병 회귀를 추가하고 발견된 Ref 로그 및 생성 장수 저장 차이를 교정합니다.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { ActionResolver } from '../../../src/actions/turn/general/che_등용.js';
|
||||
import { ActionResolver, actionContextBuilder } from '../../../src/actions/turn/general/che_등용.js';
|
||||
|
||||
describe('che_등용 recruitment message', () => {
|
||||
it('queues the Ref scout prompt with sender and receiver snapshots', () => {
|
||||
@@ -30,6 +30,23 @@ describe('che_등용 recruitment message', () => {
|
||||
const sourceNation = { id: 1, name: '위', color: '#ffffff' };
|
||||
const destinationNation = { id: 2, name: '촉', color: '#000000' };
|
||||
const messageTime = new Date('0200-01-01T00:10:00.000Z');
|
||||
const actorTurnTime = new Date('0200-01-01T00:00:00.000Z');
|
||||
|
||||
const builtContext = actionContextBuilder(
|
||||
{
|
||||
general: { ...general, turnTime: actorTurnTime },
|
||||
nation: sourceNation,
|
||||
rng: {},
|
||||
} as never,
|
||||
{
|
||||
gameNow: messageTime,
|
||||
messageSharedIconBaseUrl: 'https://ref.example/image/icons',
|
||||
actionArgs: { destGeneralId: destination.id },
|
||||
worldRef: { getGeneralById: () => destination },
|
||||
scenarioConfig: { const: {} },
|
||||
} as never
|
||||
);
|
||||
expect(builtContext).toMatchObject({ messageTime });
|
||||
|
||||
const result = new ActionResolver().resolve(
|
||||
{
|
||||
@@ -54,7 +71,7 @@ describe('che_등용 recruitment message', () => {
|
||||
nationId: sourceNation.id,
|
||||
nationName: sourceNation.name,
|
||||
color: sourceNation.color,
|
||||
icon: '',
|
||||
icon: 'https://sam-image.hided.net/icons/default.jpg',
|
||||
},
|
||||
dest: {
|
||||
generalId: destination.id,
|
||||
@@ -62,13 +79,16 @@ describe('che_등용 recruitment message', () => {
|
||||
nationId: destinationNation.id,
|
||||
nationName: destinationNation.name,
|
||||
color: destinationNation.color,
|
||||
icon: '',
|
||||
icon: 'https://sam-image.hided.net/icons/default.jpg',
|
||||
},
|
||||
text: '위로 망명 권유 서신',
|
||||
time: messageTime,
|
||||
validUntil: new Date('9999-12-31T12:59:59.000Z'),
|
||||
option: { action: 'scout' },
|
||||
sendDestOnly: true,
|
||||
},
|
||||
});
|
||||
expect(result.effects.filter((effect) => effect.type === 'log')).toEqual([]);
|
||||
expect(logs).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,9 @@ import { InMemoryWorld, TestGameRunner } from '../../testEnv.js';
|
||||
import { evaluateActionConstraints } from '../../../src/constraints/evaluate.js';
|
||||
import type { TurnCommandEnv } from '../../../src/actions/turn/commandEnv.js';
|
||||
import type { ConstraintContext, RequirementKey, StateView } from '../../../src/constraints/types.js';
|
||||
import { resolveGeneralAction } from '../../../src/actions/engine.js';
|
||||
import { orderLegacyActionLoggerFlush } from '../../../src/logging/actionLogger.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '../../../src/logging/types.js';
|
||||
|
||||
const MOCK_SCENARIO_BASE = {
|
||||
title: 'Test',
|
||||
@@ -224,6 +227,57 @@ describe('che_등용수락', () => {
|
||||
|
||||
const { commandSpec } = await import('../../../src/actions/turn/general/che_등용수락.js');
|
||||
|
||||
const orderingResolution = resolveGeneralAction(
|
||||
commandSpec.createDefinition(systemEnv),
|
||||
{
|
||||
general: structuredClone(neutralGen),
|
||||
city: structuredClone(world.getCity(neutralGen.cityId)),
|
||||
nation: null,
|
||||
destNation: structuredClone(nation2),
|
||||
destGeneral: structuredClone(recruiterGen),
|
||||
rng: {} as any,
|
||||
addLog: () => {},
|
||||
} as any,
|
||||
{
|
||||
now: new Date('2026-08-23T00:00:00.000Z'),
|
||||
schedule: { entries: [{ startMinute: 0, tickMinutes: 60 }] },
|
||||
},
|
||||
{ destNationId: 2, destGeneralId: 2 }
|
||||
);
|
||||
const recruiterLogs = orderLegacyActionLoggerFlush(orderingResolution.logs).filter(
|
||||
(log) => log.generalId === recruiterGen.id
|
||||
);
|
||||
expect(recruiterLogs.map((log) => [log.category, log.legacyFlushGroup])).toEqual([
|
||||
[LogCategory.HISTORY, 1],
|
||||
[LogCategory.ACTION, 1],
|
||||
[LogCategory.ACTION, 1],
|
||||
[LogCategory.ACTION, 1],
|
||||
]);
|
||||
expect(recruiterLogs.map((log) => log.text)).toEqual([
|
||||
expect.stringContaining('등용에 성공'),
|
||||
expect.stringContaining('레벨업'),
|
||||
expect.stringContaining('승급'),
|
||||
expect.stringContaining('등용에 성공했습니다.'),
|
||||
]);
|
||||
expect(recruiterLogs.map((log) => log.format)).toEqual([
|
||||
LogFormat.YEAR_MONTH,
|
||||
LogFormat.PLAIN,
|
||||
LogFormat.PLAIN,
|
||||
LogFormat.MONTH,
|
||||
]);
|
||||
expect(
|
||||
orderingResolution.logs.find(
|
||||
(log) =>
|
||||
log.scope === LogScope.GENERAL &&
|
||||
log.category === LogCategory.ACTION &&
|
||||
log.text.includes('망명하여 수도로')
|
||||
)?.format
|
||||
).toBe(LogFormat.MONTH);
|
||||
expect(
|
||||
orderingResolution.logs.find((log) => log.scope === LogScope.SYSTEM && log.category === LogCategory.SUMMARY)
|
||||
?.format
|
||||
).toBe(LogFormat.MONTH);
|
||||
|
||||
await runner.runTurn([
|
||||
{
|
||||
generalId: neutralGen.id,
|
||||
|
||||
@@ -3,6 +3,8 @@ import type { General, Nation } from '../../../src/domain/entities.js';
|
||||
import { buildScenarioBootstrap } from '../../../src/world/bootstrap.js';
|
||||
import { InMemoryWorld, TestGameRunner } from '../../testEnv.js';
|
||||
import type { MapDefinition } from '../../../src/world/types.js';
|
||||
import { resolveGeneralAction } from '../../../src/actions/engine.js';
|
||||
import { orderLegacyActionLoggerFlush } from '../../../src/logging/actionLogger.js';
|
||||
|
||||
const MOCK_SCENARIO_BASE = {
|
||||
title: 'Test',
|
||||
@@ -56,6 +58,49 @@ const LINEAR_MAP: MapDefinition = {
|
||||
defaults: { trust: 50, trade: 100, supplyState: 1, frontState: 0 },
|
||||
};
|
||||
|
||||
const buildGeneral = (id: number, name: string): General => ({
|
||||
id,
|
||||
name,
|
||||
nationId: 1,
|
||||
cityId: 101,
|
||||
troopId: 0,
|
||||
stats: { leadership: 50, strength: 50, intelligence: 50 },
|
||||
experience: 0,
|
||||
dedication: 0,
|
||||
officerLevel: 1,
|
||||
role: {
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
items: { horse: null, weapon: null, book: null, item: null },
|
||||
},
|
||||
injury: 0,
|
||||
gold: 1000,
|
||||
rice: 1000,
|
||||
crew: 0,
|
||||
crewTypeId: 0,
|
||||
train: 0,
|
||||
atmos: 10,
|
||||
age: 20,
|
||||
npcState: 0,
|
||||
triggerState: { flags: {}, counters: {}, modifiers: {}, meta: {} },
|
||||
meta: { killturn: 24 },
|
||||
});
|
||||
|
||||
const buildNation = (level = 1): Nation => ({
|
||||
id: 1,
|
||||
name: 'MyNation',
|
||||
color: '#000',
|
||||
capitalCityId: 101,
|
||||
chiefGeneralId: 1,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
power: 0,
|
||||
level,
|
||||
typeCode: 'che_def',
|
||||
meta: {},
|
||||
});
|
||||
|
||||
describe('che_이동', () => {
|
||||
it('applies movement side effects (gold/atmos/exp/leadership_exp)', async () => {
|
||||
const bootstrapResult = buildScenarioBootstrap({
|
||||
@@ -66,47 +111,8 @@ describe('che_이동', () => {
|
||||
const world = new InMemoryWorld(bootstrapResult.snapshot);
|
||||
const runner = new TestGameRunner(world, 200, 1);
|
||||
|
||||
const general: General = {
|
||||
id: 1,
|
||||
name: 'Mover',
|
||||
nationId: 1,
|
||||
cityId: 101,
|
||||
troopId: 0,
|
||||
stats: { leadership: 50, strength: 50, intelligence: 50 },
|
||||
experience: 0,
|
||||
dedication: 0,
|
||||
officerLevel: 1,
|
||||
role: {
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
items: { horse: null, weapon: null, book: null, item: null },
|
||||
},
|
||||
injury: 0,
|
||||
gold: 1000,
|
||||
rice: 1000,
|
||||
crew: 0,
|
||||
crewTypeId: 0,
|
||||
train: 0,
|
||||
atmos: 10,
|
||||
age: 20,
|
||||
npcState: 0,
|
||||
triggerState: { flags: {}, counters: {}, modifiers: {}, meta: {} },
|
||||
meta: { killturn: 24 },
|
||||
};
|
||||
const nation: Nation = {
|
||||
id: 1,
|
||||
name: 'MyNation',
|
||||
color: '#000',
|
||||
capitalCityId: 101,
|
||||
chiefGeneralId: 1,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
power: 0,
|
||||
level: 1,
|
||||
typeCode: 'che_def',
|
||||
meta: {},
|
||||
};
|
||||
const general = buildGeneral(1, 'Mover');
|
||||
const nation = buildNation();
|
||||
world.snapshot.generals.push(general);
|
||||
world.snapshot.nations.push(nation);
|
||||
|
||||
@@ -134,4 +140,46 @@ describe('che_이동', () => {
|
||||
expect(updated?.experience).toBe(50);
|
||||
expect(updated?.meta.leadership_exp).toBe(1);
|
||||
});
|
||||
|
||||
it('logs roaming followers before the actor logger flush', async () => {
|
||||
const leader = { ...buildGeneral(1, 'Leader'), officerLevel: 12 };
|
||||
const follower = buildGeneral(2, 'Follower');
|
||||
const nation = buildNation(0);
|
||||
const moveDef = (await import('../../../src/actions/turn/general/che_이동.js')).commandSpec.createDefinition(
|
||||
{} as any
|
||||
);
|
||||
|
||||
const resolution = resolveGeneralAction(
|
||||
moveDef,
|
||||
{
|
||||
general: leader,
|
||||
nation,
|
||||
moveGenerals: [leader, follower],
|
||||
map: LINEAR_MAP,
|
||||
develCost: 100,
|
||||
rng: {} as any,
|
||||
addLog: () => {},
|
||||
} as any,
|
||||
{
|
||||
now: new Date('2026-08-23T00:00:00.000Z'),
|
||||
schedule: { entries: [{ startMinute: 0, tickMinutes: 60 }] },
|
||||
},
|
||||
{ destCityId: 102 }
|
||||
);
|
||||
|
||||
expect(resolution.patches?.generals).toContainEqual({
|
||||
id: follower.id,
|
||||
patch: expect.objectContaining({ cityId: 102 }),
|
||||
});
|
||||
const orderedLogs = orderLegacyActionLoggerFlush(resolution.logs);
|
||||
expect(orderedLogs.map((log) => log.generalId)).toEqual([follower.id, leader.id]);
|
||||
expect(orderedLogs[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
text: '방랑군 세력이 <G><b>City2</b></>로 이동했습니다.',
|
||||
generalId: follower.id,
|
||||
legacyFlushGroup: -1,
|
||||
})
|
||||
);
|
||||
expect(orderedLogs[1]?.legacyFlushGroup).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { ActionResolver } from '../../../src/actions/turn/general/che_하야.js';
|
||||
|
||||
describe('che_하야 Ref ordering', () => {
|
||||
it('resets belong before refreshing max_belong', () => {
|
||||
const general = {
|
||||
id: 1,
|
||||
name: '하야자',
|
||||
nationId: 1,
|
||||
cityId: 1,
|
||||
troopId: 0,
|
||||
npcState: 0,
|
||||
experience: 100,
|
||||
dedication: 100,
|
||||
officerLevel: 5,
|
||||
gold: 100,
|
||||
rice: 100,
|
||||
crew: 0,
|
||||
crewTypeId: 0,
|
||||
train: 0,
|
||||
atmos: 0,
|
||||
injury: 0,
|
||||
age: 30,
|
||||
stats: { leadership: 70, strength: 60, intelligence: 50 },
|
||||
role: { items: {} },
|
||||
triggerState: { flags: {}, counters: {}, modifiers: {}, meta: {} },
|
||||
meta: { belong: 10 },
|
||||
};
|
||||
const nation = {
|
||||
id: 1,
|
||||
name: '소속국',
|
||||
gold: 1_000,
|
||||
rice: 1_000,
|
||||
meta: { gennum: 1 },
|
||||
};
|
||||
|
||||
const result = new ActionResolver({ defaultNpcGold: 1_000, defaultNpcRice: 1_000 } as never).resolve(
|
||||
{
|
||||
general,
|
||||
nation,
|
||||
troopMembers: [],
|
||||
addLog: () => {},
|
||||
} as never,
|
||||
{}
|
||||
);
|
||||
const generalPatch = result.effects.find(
|
||||
(effect) => effect.type === 'general:patch' && effect.targetId === general.id
|
||||
);
|
||||
|
||||
expect(generalPatch).toMatchObject({
|
||||
type: 'general:patch',
|
||||
patch: { meta: { belong: 0, max_belong: 0 } },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,12 +6,16 @@ import { MINIMAL_MAP } from '../../fixtures/minimalMap.js';
|
||||
import type { TurnCommandEnv, TurnCommandItemCatalogEntry } from '../../../src/actions/turn/commandEnv.js';
|
||||
import { commandSpec as rebellionSpec } from '../../../src/actions/turn/general/che_모반시도.js';
|
||||
import { commandSpec as abdicationSpec } from '../../../src/actions/turn/general/che_선양.js';
|
||||
import { commandSpec as uprisingSpec } from '../../../src/actions/turn/general/che_거병.js';
|
||||
import { commandSpec as giftSpec } from '../../../src/actions/turn/general/che_증여.js';
|
||||
import { commandSpec as disbandSpec } from '../../../src/actions/turn/general/che_해산.js';
|
||||
import { commandSpec as foundNationSpec } from '../../../src/actions/turn/general/cr_건국.js';
|
||||
import { commandSpec as tradeItemSpec } from '../../../src/actions/turn/general/che_장비매매.js';
|
||||
import type { ConstraintContext, RequirementKey, StateView } from '../../../src/constraints/types.js';
|
||||
import { evaluateActionConstraints } from '../../../src/constraints/evaluate.js';
|
||||
import { resolveGeneralAction } from '../../../src/actions/engine.js';
|
||||
import { orderLegacyActionLoggerFlush } from '../../../src/logging/actionLogger.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '../../../src/logging/types.js';
|
||||
|
||||
const SYSTEM_ENV: TurnCommandEnv = {
|
||||
develCost: 100,
|
||||
@@ -168,6 +172,31 @@ const makeSnapshot = (params: {
|
||||
initialEvents: [],
|
||||
});
|
||||
|
||||
const resolveForLogOrdering = (
|
||||
resolver: any,
|
||||
general: General,
|
||||
city: City,
|
||||
nation: Nation | null,
|
||||
args: unknown,
|
||||
context: Record<string, unknown>
|
||||
) =>
|
||||
resolveGeneralAction(
|
||||
resolver,
|
||||
{
|
||||
general,
|
||||
city,
|
||||
nation,
|
||||
rng: {} as any,
|
||||
addLog: () => {},
|
||||
...context,
|
||||
} as any,
|
||||
{
|
||||
now: new Date('2026-08-23T00:00:00.000Z'),
|
||||
schedule: { entries: [{ startMinute: 0, tickMinutes: 60 }] },
|
||||
},
|
||||
args
|
||||
);
|
||||
|
||||
describe('migrated general commands', () => {
|
||||
it('che_모반시도: 군주를 찬탈한다', async () => {
|
||||
const lord = makeGeneral({ id: 1, nationId: 1, cityId: 1, name: '군주', officerLevel: 12, experience: 1000 });
|
||||
@@ -319,6 +348,208 @@ describe('migrated general commands', () => {
|
||||
expect(world.getNation(1)!.meta.collapsed).toBe(true);
|
||||
});
|
||||
|
||||
it('별도 General logger를 actor applyDB 전후 순서로 flush한다', () => {
|
||||
const city = makeCity({ id: 1, nationId: 1 });
|
||||
const nation = makeNation({ id: 1, name: '위', chiefGeneralId: 1, capitalCityId: 1 });
|
||||
|
||||
const rebel = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '중신', officerLevel: 2 });
|
||||
const displacedLord = makeGeneral({
|
||||
id: 1,
|
||||
nationId: 1,
|
||||
cityId: 1,
|
||||
name: '군주',
|
||||
officerLevel: 12,
|
||||
experience: 1000,
|
||||
});
|
||||
const rebellionLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
rebellionSpec.createDefinition(SYSTEM_ENV),
|
||||
rebel,
|
||||
city,
|
||||
nation,
|
||||
{},
|
||||
{
|
||||
nationGenerals: [displacedLord, rebel],
|
||||
}
|
||||
).logs
|
||||
);
|
||||
expect(
|
||||
rebellionLogs
|
||||
.filter((log) => log.generalId === displacedLord.id)
|
||||
.map((log) => [log.category, log.legacyFlushGroup])
|
||||
).toEqual([
|
||||
[LogCategory.HISTORY, 1],
|
||||
[LogCategory.ACTION, 1],
|
||||
]);
|
||||
|
||||
const abdicator = makeGeneral({ id: 1, nationId: 1, cityId: 1, name: '군주', officerLevel: 12 });
|
||||
const recipient = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '후계자' });
|
||||
const abdicationLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
abdicationSpec.createDefinition(SYSTEM_ENV),
|
||||
abdicator,
|
||||
city,
|
||||
nation,
|
||||
{ destGeneralID: recipient.id },
|
||||
{ destGeneral: recipient }
|
||||
).logs
|
||||
);
|
||||
expect(
|
||||
abdicationLogs
|
||||
.filter((log) => log.generalId === recipient.id)
|
||||
.map((log) => [log.category, log.legacyFlushGroup])
|
||||
).toEqual([
|
||||
[LogCategory.HISTORY, 1],
|
||||
[LogCategory.ACTION, 1],
|
||||
]);
|
||||
|
||||
const giver = makeGeneral({ id: 1, nationId: 1, cityId: 1, name: '증여자', gold: 1300 });
|
||||
const receiver = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '수령자', gold: 200 });
|
||||
const giftLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
giftSpec.createDefinition(SYSTEM_ENV),
|
||||
giver,
|
||||
city,
|
||||
nation,
|
||||
{ isGold: true, amount: 500, destGeneralID: receiver.id },
|
||||
{ destGeneral: receiver }
|
||||
).logs
|
||||
);
|
||||
expect(giftLogs.map((log) => [log.generalId, log.legacyFlushGroup ?? 0])).toEqual([
|
||||
[giver.id, 0],
|
||||
[receiver.id, 1],
|
||||
]);
|
||||
|
||||
const disbandActor = makeGeneral({ id: 10, nationId: 1, cityId: 1, name: '방랑군주', officerLevel: 12 });
|
||||
const member2 = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '부하2' });
|
||||
const member3 = makeGeneral({ id: 3, nationId: 1, cityId: 1, name: '부하3' });
|
||||
const wanderingNation = makeNation({
|
||||
id: 1,
|
||||
name: '방랑군',
|
||||
chiefGeneralId: disbandActor.id,
|
||||
capitalCityId: 1,
|
||||
level: 0,
|
||||
typeCode: 'None',
|
||||
});
|
||||
const disbandLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
disbandSpec.createDefinition(SYSTEM_ENV),
|
||||
disbandActor,
|
||||
city,
|
||||
wanderingNation,
|
||||
{},
|
||||
{
|
||||
nationGenerals: [disbandActor, member3, member2],
|
||||
nationCities: [city],
|
||||
currentYearMonth: 201 * 12 + 2 - 1,
|
||||
initYearMonth: 201 * 12 + 1 - 1,
|
||||
}
|
||||
).logs
|
||||
);
|
||||
const nonActorDestructionLogs = disbandLogs.filter(
|
||||
(log) =>
|
||||
log.scope === LogScope.GENERAL && log.generalId !== disbandActor.id && log.text.includes('<R>멸망</>')
|
||||
);
|
||||
expect(nonActorDestructionLogs.map((log) => [log.generalId, log.category, log.legacyFlushGroup])).toEqual([
|
||||
[member2.id, LogCategory.HISTORY, -2],
|
||||
[member2.id, LogCategory.ACTION, -2],
|
||||
[member3.id, LogCategory.HISTORY, -1],
|
||||
[member3.id, LogCategory.ACTION, -1],
|
||||
]);
|
||||
const actorLogs = disbandLogs.filter(
|
||||
(log) => log.scope === LogScope.GENERAL && log.generalId === disbandActor.id
|
||||
);
|
||||
expect(actorLogs).toHaveLength(4);
|
||||
expect(actorLogs.every((log) => (log.legacyFlushGroup ?? 0) === 0)).toBe(true);
|
||||
});
|
||||
|
||||
it('선양·모반시도의 Ref logger format과 거병 중립 nation flush 계약을 보존한다', () => {
|
||||
const city = makeCity({ id: 1, nationId: 1 });
|
||||
const nation = makeNation({ id: 1, name: '위', chiefGeneralId: 1, capitalCityId: 1 });
|
||||
const projectRoute = (logs: ReturnType<typeof orderLegacyActionLoggerFlush>) =>
|
||||
logs.map((log) => [
|
||||
log.scope,
|
||||
log.category,
|
||||
log.generalId ?? null,
|
||||
log.nationId ?? null,
|
||||
log.format,
|
||||
log.legacyFlushGroup ?? 0,
|
||||
]);
|
||||
|
||||
const rebel = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '중신', officerLevel: 2 });
|
||||
const displacedLord = makeGeneral({
|
||||
id: 1,
|
||||
nationId: 1,
|
||||
cityId: 1,
|
||||
name: '군주',
|
||||
officerLevel: 12,
|
||||
experience: 1_000,
|
||||
});
|
||||
const rebellionLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
rebellionSpec.createDefinition(SYSTEM_ENV),
|
||||
rebel,
|
||||
city,
|
||||
nation,
|
||||
{},
|
||||
{ nationGenerals: [displacedLord, rebel] }
|
||||
).logs
|
||||
);
|
||||
expect(projectRoute(rebellionLogs)).toEqual([
|
||||
[LogScope.GENERAL, LogCategory.HISTORY, rebel.id, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.GENERAL, LogCategory.ACTION, rebel.id, null, LogFormat.MONTH, 0],
|
||||
[LogScope.NATION, LogCategory.HISTORY, null, nation.id, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.SYSTEM, LogCategory.HISTORY, null, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.GENERAL, LogCategory.HISTORY, displacedLord.id, null, LogFormat.YEAR_MONTH, 1],
|
||||
[LogScope.GENERAL, LogCategory.ACTION, displacedLord.id, null, LogFormat.MONTH, 1],
|
||||
]);
|
||||
|
||||
const abdicator = makeGeneral({ id: 1, nationId: 1, cityId: 1, name: '군주', officerLevel: 12 });
|
||||
const recipient = makeGeneral({ id: 2, nationId: 1, cityId: 1, name: '후계자' });
|
||||
const abdicationLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
abdicationSpec.createDefinition(SYSTEM_ENV),
|
||||
abdicator,
|
||||
city,
|
||||
nation,
|
||||
{ destGeneralID: recipient.id },
|
||||
{ destGeneral: recipient }
|
||||
).logs
|
||||
);
|
||||
expect(projectRoute(abdicationLogs)).toEqual([
|
||||
[LogScope.GENERAL, LogCategory.HISTORY, abdicator.id, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.GENERAL, LogCategory.ACTION, abdicator.id, null, LogFormat.MONTH, 0],
|
||||
[LogScope.NATION, LogCategory.HISTORY, null, nation.id, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.SYSTEM, LogCategory.HISTORY, null, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.GENERAL, LogCategory.HISTORY, recipient.id, null, LogFormat.YEAR_MONTH, 1],
|
||||
[LogScope.GENERAL, LogCategory.ACTION, recipient.id, null, LogFormat.MONTH, 1],
|
||||
]);
|
||||
|
||||
const founder = makeGeneral({ id: 7, nationId: 0, cityId: 1, name: '운영자' });
|
||||
const uprisingLogs = orderLegacyActionLoggerFlush(
|
||||
resolveForLogOrdering(
|
||||
uprisingSpec.createDefinition(SYSTEM_ENV),
|
||||
founder,
|
||||
city,
|
||||
null,
|
||||
{},
|
||||
{
|
||||
createNationId: () => 2,
|
||||
listNations: () => [],
|
||||
scenarioId: 1,
|
||||
baseRice: 1_000,
|
||||
}
|
||||
).logs
|
||||
);
|
||||
expect(projectRoute(uprisingLogs)).toEqual([
|
||||
[LogScope.GENERAL, LogCategory.HISTORY, founder.id, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.GENERAL, LogCategory.ACTION, founder.id, null, LogFormat.MONTH, 0],
|
||||
[LogScope.SYSTEM, LogCategory.HISTORY, null, null, LogFormat.YEAR_MONTH, 0],
|
||||
[LogScope.SYSTEM, LogCategory.SUMMARY, null, null, LogFormat.MONTH, 0],
|
||||
]);
|
||||
expect(uprisingLogs.some((log) => log.scope === LogScope.NATION)).toBe(false);
|
||||
});
|
||||
|
||||
it('cr_건국: 국가 정보를 건국 상태로 갱신한다', async () => {
|
||||
const lord = makeGeneral({
|
||||
id: 1,
|
||||
|
||||
Reference in New Issue
Block a user