Merge general command differential coverage
This commit is contained in:
@@ -118,10 +118,15 @@ const applyLegacyGeneralProgression = (
|
|||||||
);
|
);
|
||||||
const dedicationLevel = Math.max(0, Math.min(maxDedicationLevel, Math.ceil(Math.sqrt(general.dedication) / 10)));
|
const dedicationLevel = Math.max(0, Math.min(maxDedicationLevel, Math.ceil(Math.sqrt(general.dedication) / 10)));
|
||||||
const meta = { ...general.meta };
|
const meta = { ...general.meta };
|
||||||
if (general.experience !== previousGeneral.experience) {
|
// 하야는 ref에서 addExperience(0)/addDedication(0)을 호출해 현재 값으로
|
||||||
|
// 등급을 강제 재계산한다. 반대로 은퇴의 rebirth()와 선양의
|
||||||
|
// multiplyVar('experience')는 수치를 줄이면서도 기존 등급을 그대로 둔다.
|
||||||
|
const forceRefreshLevel = actionKey === 'che_하야';
|
||||||
|
const preserveLevel = actionKey === 'che_은퇴' || actionKey === 'che_선양';
|
||||||
|
if (!preserveLevel && (forceRefreshLevel || general.experience !== previousGeneral.experience)) {
|
||||||
meta.explevel = expLevel;
|
meta.explevel = expLevel;
|
||||||
}
|
}
|
||||||
if (general.dedication !== previousGeneral.dedication) {
|
if (!preserveLevel && (forceRefreshLevel || general.dedication !== previousGeneral.dedication)) {
|
||||||
meta.dedlevel = dedicationLevel;
|
meta.dedlevel = dedicationLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,7 +1229,10 @@ export const createReservedTurnHandler = async (options: {
|
|||||||
const hasNationChange = (resolution.patches?.cities ?? []).some((patch) =>
|
const hasNationChange = (resolution.patches?.cities ?? []).some((patch) =>
|
||||||
Object.prototype.hasOwnProperty.call(patch.patch ?? {}, 'nationId')
|
Object.prototype.hasOwnProperty.call(patch.patch ?? {}, 'nationId')
|
||||||
);
|
);
|
||||||
if (hasNationChange) {
|
// 레거시 건국 계열은 도시의 nation만 바꾸고 supply/front를
|
||||||
|
// 즉시 재계산하지 않는다. 다음 월 처리 전까지 그 상태를 보존한다.
|
||||||
|
const preservesFoundingFrontState = ['che_건국', 'cr_건국', 'che_무작위건국'].includes(actionKey);
|
||||||
|
if (hasNationChange && !preservesFoundingFrontState) {
|
||||||
const worldView = worldOverlay?.view ?? worldRef;
|
const worldView = worldOverlay?.view ?? worldRef;
|
||||||
if (worldView && options.map) {
|
if (worldView && options.map) {
|
||||||
const frontPatches = buildFrontStatePatches({
|
const frontPatches = buildFrontStatePatches({
|
||||||
|
|||||||
@@ -56,10 +56,12 @@ normalized to the core `*Id` spelling before command identity comparison.
|
|||||||
canonical projection.
|
canonical projection.
|
||||||
- `trace.ts`: before/execute/after capture boundary.
|
- `trace.ts`: before/execute/after capture boundary.
|
||||||
- `compare.ts`: exact snapshot and delta comparison.
|
- `compare.ts`: exact snapshot and delta comparison.
|
||||||
- `turnCommandGeneralMatrix.integration.test.ts`: 37 successful general
|
- `turnCommandGeneralMatrix.integration.test.ts`: 54 successful general
|
||||||
command paths, including the four-call `전투태세` completion path and
|
command paths. Together with the live sortie fixture, this exercises a
|
||||||
movement/return/gift/spy/sabotage, recruitment, proficiency transfer,
|
completed success path for every one of the 55 general command keys.
|
||||||
trait reset and equipment-trade commands.
|
The matrix includes the four-call `전투태세` path, lifecycle and
|
||||||
|
appointment commands, troop assembly, rebellion and all three founding
|
||||||
|
variants.
|
||||||
- `turnCommandNationMatrix.integration.test.ts`: 8 successful nation
|
- `turnCommandNationMatrix.integration.test.ts`: 8 successful nation
|
||||||
command paths.
|
command paths.
|
||||||
- `turnCommandCoreReference.integration.test.ts`: declaration and live
|
- `turnCommandCoreReference.integration.test.ts`: declaration and live
|
||||||
@@ -77,9 +79,11 @@ Two committed cases exercise the guarded runner end to end:
|
|||||||
defeated-general neutralization and last-city nation collapse.
|
defeated-general neutralization and last-city nation collapse.
|
||||||
|
|
||||||
Each case may include a structured `setup` object for `world`, `nations`,
|
Each case may include a structured `setup` object for `world`, `nations`,
|
||||||
`cities`, `generals` and `diplomacy`. The runner accepts only explicitly mapped
|
`cities`, `generals`, `troops` and `diplomacy`. The runner accepts only
|
||||||
fields; it does not accept SQL. Setup and command mutation happen only inside
|
explicitly mapped fields; it does not accept SQL. Founding fixtures may pin
|
||||||
the cloned `sammo_td_*` databases.
|
`initYear`/`initMonth` and an ordered random-founding city candidate set so
|
||||||
|
both maps expose the same RNG domain. Setup and command mutation happen only
|
||||||
|
inside the cloned `sammo_td_*` databases.
|
||||||
|
|
||||||
## Case request
|
## Case request
|
||||||
|
|
||||||
@@ -164,13 +168,17 @@ Compatibility is established per case only when:
|
|||||||
4. live sortie also passes the battle trace comparison;
|
4. live sortie also passes the battle trace comparison;
|
||||||
5. any ignored path is documented in the case evidence.
|
5. any ignored path is documented in the case evidence.
|
||||||
|
|
||||||
As of 2026-07-25, 37 general cases, 8 nation cases, declaration and live sortie
|
As of 2026-07-25, 54 general matrix cases, 8 nation matrix cases, declaration
|
||||||
pass this boundary. Live sortie covers battle entry, conquest, defeated-general
|
and live sortie pass this boundary. Live sortie is the remaining general
|
||||||
neutralization and last-city nation collapse. This is 47 executable comparison
|
command key and covers battle entry, conquest, defeated-general neutralization
|
||||||
cases, not a claim that all 55 general and 38 nation command classes have been
|
and last-city nation collapse. Thus all 55 general command keys have a
|
||||||
dynamically compared.
|
completed success-path comparison. This is 64 executable comparison cases;
|
||||||
|
it is not yet a claim that failure/boundary paths or all 38 nation commands
|
||||||
|
have been dynamically compared.
|
||||||
|
|
||||||
The fixture runner also reports whether the requested legacy command reached
|
The fixture runner also reports whether the requested legacy command reached
|
||||||
its completed execution path. For multi-turn commands this is derived from the
|
its completed execution path. For multi-turn commands this is derived from the
|
||||||
pre-execution `LastTurn`, because commands such as `전투태세` reset their result
|
pre-execution `LastTurn`, because commands such as `전투태세` reset their result
|
||||||
term to `1` on the completion call.
|
term to `1` on the completion call. `등용수락` and the founding commands have
|
||||||
|
explicit state-based completion checks because their successful legacy result
|
||||||
|
turn is not a reliable completion marker.
|
||||||
|
|||||||
@@ -82,11 +82,31 @@ export class ActionResolver<
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 2. Recruiter Rewards
|
// 2. Recruiter Rewards
|
||||||
|
const recruiterExperience = destGeneral.experience + 100;
|
||||||
|
const recruiterDedication = destGeneral.dedication + 100;
|
||||||
|
const recruiterExpLevel = Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(
|
||||||
|
this.env.maxStatLevel ?? 255,
|
||||||
|
recruiterExperience < 1_000
|
||||||
|
? Math.trunc(recruiterExperience / 100)
|
||||||
|
: Math.trunc(Math.sqrt(recruiterExperience / 10))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const recruiterDedicationLevel = Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(this.env.maxDedicationLevel ?? 30, Math.ceil(Math.sqrt(recruiterDedication) / 10))
|
||||||
|
);
|
||||||
effects.push(
|
effects.push(
|
||||||
createGeneralPatchEffect(
|
createGeneralPatchEffect(
|
||||||
{
|
{
|
||||||
experience: destGeneral.experience + 100,
|
experience: recruiterExperience,
|
||||||
dedication: destGeneral.dedication + 100,
|
dedication: recruiterDedication,
|
||||||
|
meta: {
|
||||||
|
...destGeneral.meta,
|
||||||
|
explevel: recruiterExpLevel,
|
||||||
|
dedlevel: recruiterDedicationLevel,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
destGeneral.id
|
destGeneral.id
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export class ActionResolver<
|
|||||||
level: 0,
|
level: 0,
|
||||||
typeCode: 'None',
|
typeCode: 'None',
|
||||||
meta: { ...nation.meta, tech: 0 },
|
meta: { ...nation.meta, tech: 0 },
|
||||||
capitalCityId: null,
|
capitalCityId: 0,
|
||||||
},
|
},
|
||||||
nation.id
|
nation.id
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ export class ActionDefinition<
|
|||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||||
|
|
||||||
const baseGold = this.env.baseGold > 0 ? this.env.baseGold : 1000;
|
const defaultGold = this.env.defaultNpcGold > 0 ? this.env.defaultNpcGold : 1000;
|
||||||
const baseRice = this.env.baseRice > 0 ? this.env.baseRice : 1000;
|
const defaultRice = this.env.defaultNpcRice > 0 ? this.env.defaultNpcRice : 1000;
|
||||||
|
|
||||||
const nationGenerals = context.nationGenerals ?? [];
|
const nationGenerals = context.nationGenerals ?? [];
|
||||||
for (const targetGeneral of nationGenerals) {
|
for (const targetGeneral of nationGenerals) {
|
||||||
@@ -81,8 +81,11 @@ export class ActionDefinition<
|
|||||||
nationId: 0,
|
nationId: 0,
|
||||||
officerLevel: 0,
|
officerLevel: 0,
|
||||||
troopId: 0,
|
troopId: 0,
|
||||||
gold: Math.min(targetGeneral.gold, baseGold),
|
gold: Math.min(targetGeneral.gold, defaultGold),
|
||||||
rice: Math.min(targetGeneral.rice, baseRice),
|
// 레거시는 전체 장수의 gold를 먼저 제한한 뒤 rice UPDATE의
|
||||||
|
// WHERE에도 gold를 사용한다. 따라서 다른 장수의 rice는
|
||||||
|
// 그대로 남고, 실행 장수만 아래 명시적 제한을 받는다.
|
||||||
|
rice: isActor ? Math.min(targetGeneral.rice, defaultRice) : targetGeneral.rice,
|
||||||
meta: {
|
meta: {
|
||||||
...targetGeneral.meta,
|
...targetGeneral.meta,
|
||||||
belong: 0,
|
belong: 0,
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export interface TurnCommandFixtureRequest {
|
|||||||
setup?: {
|
setup?: {
|
||||||
world?: {
|
world?: {
|
||||||
startYear?: number;
|
startYear?: number;
|
||||||
|
initYear?: number;
|
||||||
|
initMonth?: number;
|
||||||
year?: number;
|
year?: number;
|
||||||
month?: number;
|
month?: number;
|
||||||
hiddenSeed?: string;
|
hiddenSeed?: string;
|
||||||
@@ -42,7 +44,9 @@ export interface TurnCommandFixtureRequest {
|
|||||||
generals?: Array<Record<string, unknown>>;
|
generals?: Array<Record<string, unknown>>;
|
||||||
nations?: Array<Record<string, unknown>>;
|
nations?: Array<Record<string, unknown>>;
|
||||||
cities?: Array<Record<string, unknown>>;
|
cities?: Array<Record<string, unknown>>;
|
||||||
|
troops?: Array<Record<string, unknown>>;
|
||||||
diplomacy?: Array<Record<string, unknown>>;
|
diplomacy?: Array<Record<string, unknown>>;
|
||||||
|
randomFoundingCandidateCityIds?: number[];
|
||||||
};
|
};
|
||||||
observe?: {
|
observe?: {
|
||||||
generalIds?: number[];
|
generalIds?: number[];
|
||||||
@@ -245,7 +249,7 @@ const buildNation = (row: Record<string, unknown>, generals: TurnGeneral[]): Nat
|
|||||||
id,
|
id,
|
||||||
name: readString(row, 'name', `국가${id}`),
|
name: readString(row, 'name', `국가${id}`),
|
||||||
color: readString(row, 'color', '#777777'),
|
color: readString(row, 'color', '#777777'),
|
||||||
capitalCityId: readNumber(row, 'capitalCityId') || null,
|
capitalCityId: readNumber(row, 'capitalCityId'),
|
||||||
chiefGeneralId: generals.find((general) => general.nationId === id && general.officerLevel === 12)?.id ?? null,
|
chiefGeneralId: generals.find((general) => general.nationId === id && general.officerLevel === 12)?.id ?? null,
|
||||||
gold: readNumber(row, 'gold'),
|
gold: readNumber(row, 'gold'),
|
||||||
rice: readNumber(row, 'rice'),
|
rice: readNumber(row, 'rice'),
|
||||||
@@ -274,6 +278,9 @@ const buildWorldInput = (
|
|||||||
const generals = referenceBefore.generals.map((row) => buildGeneral(row, turnTime));
|
const generals = referenceBefore.generals.map((row) => buildGeneral(row, turnTime));
|
||||||
const nations = referenceBefore.nations.map((row) => buildNation(row, generals));
|
const nations = referenceBefore.nations.map((row) => buildNation(row, generals));
|
||||||
const observedCityRows = new Map(referenceBefore.cities.map((row) => [readNumber(row, 'id'), row] as const));
|
const observedCityRows = new Map(referenceBefore.cities.map((row) => [readNumber(row, 'id'), row] as const));
|
||||||
|
const randomFoundingCandidateCityIds = request.setup?.randomFoundingCandidateCityIds
|
||||||
|
? new Set(request.setup.randomFoundingCandidateCityIds)
|
||||||
|
: null;
|
||||||
const diplomacy: TurnDiplomacy[] = referenceBefore.diplomacy.map((row) => ({
|
const diplomacy: TurnDiplomacy[] = referenceBefore.diplomacy.map((row) => ({
|
||||||
fromNationId: readNumber(row, 'fromNationId'),
|
fromNationId: readNumber(row, 'fromNationId'),
|
||||||
toNationId: readNumber(row, 'toNationId'),
|
toNationId: readNumber(row, 'toNationId'),
|
||||||
@@ -323,7 +330,12 @@ const buildWorldInput = (
|
|||||||
id: definition.id,
|
id: definition.id,
|
||||||
name: readString(row, 'name', definition.name),
|
name: readString(row, 'name', definition.name),
|
||||||
nationId: readNumber(row, 'nationId'),
|
nationId: readNumber(row, 'nationId'),
|
||||||
level: readNumber(row, 'level', definition.level),
|
level:
|
||||||
|
randomFoundingCandidateCityIds === null
|
||||||
|
? readNumber(row, 'level', definition.level)
|
||||||
|
: randomFoundingCandidateCityIds.has(definition.id)
|
||||||
|
? 5
|
||||||
|
: 4,
|
||||||
state: readNumber(row, 'state'),
|
state: readNumber(row, 'state'),
|
||||||
population: readNumber(row, 'population', definition.initial.population),
|
population: readNumber(row, 'population', definition.initial.population),
|
||||||
populationMax: readNumber(row, 'populationMax', definition.max.population),
|
populationMax: readNumber(row, 'populationMax', definition.max.population),
|
||||||
@@ -347,7 +359,15 @@ const buildWorldInput = (
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
generals,
|
generals,
|
||||||
troops: [],
|
troops:
|
||||||
|
request.setup?.troops?.map((row) => {
|
||||||
|
const id = readNumber(row, 'id');
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
nationId: readNumber(row, 'nationId'),
|
||||||
|
name: readString(row, 'name', `부대${id}`),
|
||||||
|
};
|
||||||
|
}) ?? [],
|
||||||
diplomacy,
|
diplomacy,
|
||||||
events: [],
|
events: [],
|
||||||
initialEvents: [],
|
initialEvents: [],
|
||||||
@@ -364,8 +384,12 @@ const buildWorldInput = (
|
|||||||
killturn: 24,
|
killturn: 24,
|
||||||
isUnited: readNumber(referenceBefore.world, 'isUnited'),
|
isUnited: readNumber(referenceBefore.world, 'isUnited'),
|
||||||
scenarioId: readNumber(referenceBefore.world, 'scenarioId'),
|
scenarioId: readNumber(referenceBefore.world, 'scenarioId'),
|
||||||
initYear: readNumber(referenceBefore.world, 'initYear', request.setup?.world?.startYear ?? year),
|
initYear: readNumber(
|
||||||
initMonth: readNumber(referenceBefore.world, 'initMonth', 1),
|
referenceBefore.world,
|
||||||
|
'initYear',
|
||||||
|
request.setup?.world?.initYear ?? request.setup?.world?.startYear ?? year
|
||||||
|
),
|
||||||
|
initMonth: readNumber(referenceBefore.world, 'initMonth', request.setup?.world?.initMonth ?? 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
snapshot,
|
snapshot,
|
||||||
|
|||||||
@@ -64,10 +64,21 @@ const general = (id: number, nationId: number, cityId: number, officerLevel: num
|
|||||||
meta: {},
|
meta: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface FixturePatches {
|
||||||
|
world?: NonNullable<NonNullable<TurnCommandFixtureRequest['setup']>['world']>;
|
||||||
|
generals?: Record<number, Record<string, unknown>>;
|
||||||
|
nations?: Record<number, Record<string, unknown>>;
|
||||||
|
cities?: Record<number, Record<string, unknown>>;
|
||||||
|
troops?: Array<Record<string, unknown>>;
|
||||||
|
diplomacy?: Record<string, Record<string, unknown>>;
|
||||||
|
randomFoundingCandidateCityIds?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
const buildRequest = (
|
const buildRequest = (
|
||||||
action: string,
|
action: string,
|
||||||
args?: Record<string, unknown>,
|
args?: Record<string, unknown>,
|
||||||
actorPatch: Record<string, unknown> = {}
|
actorPatch: Record<string, unknown> = {},
|
||||||
|
fixturePatches: FixturePatches = {}
|
||||||
): TurnCommandFixtureRequest => ({
|
): TurnCommandFixtureRequest => ({
|
||||||
kind: 'general',
|
kind: 'general',
|
||||||
actorGeneralId: 1,
|
actorGeneralId: 1,
|
||||||
@@ -80,6 +91,7 @@ const buildRequest = (
|
|||||||
year: 190,
|
year: 190,
|
||||||
month: 1,
|
month: 1,
|
||||||
hiddenSeed: 'turn-command-general-matrix-v1',
|
hiddenSeed: 'turn-command-general-matrix-v1',
|
||||||
|
...fixturePatches.world,
|
||||||
},
|
},
|
||||||
nations: [
|
nations: [
|
||||||
{
|
{
|
||||||
@@ -94,6 +106,7 @@ const buildRequest = (
|
|||||||
war: 0,
|
war: 0,
|
||||||
generalCount: 2,
|
generalCount: 2,
|
||||||
meta: {},
|
meta: {},
|
||||||
|
...fixturePatches.nations?.[1],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
@@ -107,6 +120,7 @@ const buildRequest = (
|
|||||||
war: 0,
|
war: 0,
|
||||||
generalCount: 1,
|
generalCount: 1,
|
||||||
meta: {},
|
meta: {},
|
||||||
|
...fixturePatches.nations?.[2],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cities: [
|
cities: [
|
||||||
@@ -126,6 +140,7 @@ const buildRequest = (
|
|||||||
term: 0,
|
term: 0,
|
||||||
trust: 80,
|
trust: 80,
|
||||||
trade: 100,
|
trade: 100,
|
||||||
|
...fixturePatches.cities?.[3],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 70,
|
id: 70,
|
||||||
@@ -143,12 +158,35 @@ const buildRequest = (
|
|||||||
term: 0,
|
term: 0,
|
||||||
trust: 80,
|
trust: 80,
|
||||||
trade: 100,
|
trade: 100,
|
||||||
|
...fixturePatches.cities?.[70],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
generals: [{ ...general(1, 1, 3, 12), ...actorPatch }, general(2, 2, 70, 12), general(3, 1, 3, 1)],
|
generals: [
|
||||||
|
{ ...general(1, 1, 3, 12), ...actorPatch, ...fixturePatches.generals?.[1] },
|
||||||
|
{ ...general(2, 2, 70, 12), ...fixturePatches.generals?.[2] },
|
||||||
|
{ ...general(3, 1, 3, 1), ...fixturePatches.generals?.[3] },
|
||||||
|
],
|
||||||
|
...(fixturePatches.troops ? { troops: fixturePatches.troops } : {}),
|
||||||
|
...(fixturePatches.randomFoundingCandidateCityIds
|
||||||
|
? { randomFoundingCandidateCityIds: fixturePatches.randomFoundingCandidateCityIds }
|
||||||
|
: {}),
|
||||||
diplomacy: [
|
diplomacy: [
|
||||||
{ fromNationId: 1, toNationId: 2, state: 0, term: 12, dead: 0 },
|
{
|
||||||
{ fromNationId: 2, toNationId: 1, state: 0, term: 12, dead: 0 },
|
fromNationId: 1,
|
||||||
|
toNationId: 2,
|
||||||
|
state: 0,
|
||||||
|
term: 12,
|
||||||
|
dead: 0,
|
||||||
|
...fixturePatches.diplomacy?.['1:2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromNationId: 2,
|
||||||
|
toNationId: 1,
|
||||||
|
state: 0,
|
||||||
|
term: 12,
|
||||||
|
dead: 0,
|
||||||
|
...fixturePatches.diplomacy?.['2:1'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
observe: {
|
observe: {
|
||||||
@@ -160,7 +198,9 @@ const buildRequest = (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const cases: Array<[string, Record<string, unknown> | undefined, Record<string, unknown> | undefined]> = [
|
const cases: Array<
|
||||||
|
[string, Record<string, unknown> | undefined, Record<string, unknown> | undefined, FixturePatches?]
|
||||||
|
> = [
|
||||||
['휴식', undefined, undefined],
|
['휴식', undefined, undefined],
|
||||||
['che_훈련', undefined, undefined],
|
['che_훈련', undefined, undefined],
|
||||||
['cr_맹훈련', undefined, undefined],
|
['cr_맹훈련', undefined, undefined],
|
||||||
@@ -200,19 +240,94 @@ const cases: Array<[string, Record<string, unknown> | undefined, Record<string,
|
|||||||
undefined,
|
undefined,
|
||||||
{ specialDomestic: 'che_인덕', lastTurn: { command: '내정 특기 초기화', term: 1 } },
|
{ specialDomestic: 'che_인덕', lastTurn: { command: '내정 특기 초기화', term: 1 } },
|
||||||
],
|
],
|
||||||
[
|
['che_전투특기초기화', undefined, { specialWar: 'che_귀병', lastTurn: { command: '전투 특기 초기화', term: 1 } }],
|
||||||
'che_전투특기초기화',
|
|
||||||
undefined,
|
|
||||||
{ specialWar: 'che_귀병', lastTurn: { command: '전투 특기 초기화', term: 1 } },
|
|
||||||
],
|
|
||||||
['che_장비매매', { itemType: 'weapon', itemCode: 'che_무기_01_단도' }, undefined],
|
['che_장비매매', { itemType: 'weapon', itemCode: 'che_무기_01_단도' }, undefined],
|
||||||
|
['che_하야', undefined, { officerLevel: 1 }],
|
||||||
|
['che_은퇴', undefined, { age: 60, lastTurn: { command: '은퇴', term: 1 } }],
|
||||||
|
[
|
||||||
|
'che_임관',
|
||||||
|
{ destNationID: 1 },
|
||||||
|
{ nationId: 0, officerLevel: 0 },
|
||||||
|
{ generals: { 3: { officerLevel: 12, officerCityId: 3 } } },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'che_랜덤임관',
|
||||||
|
undefined,
|
||||||
|
{ nationId: 0, officerLevel: 0 },
|
||||||
|
{ generals: { 3: { officerLevel: 12, officerCityId: 3 } } },
|
||||||
|
],
|
||||||
|
['che_장수대상임관', { destGeneralID: 2 }, { nationId: 0, officerLevel: 0 }],
|
||||||
|
['che_등용', { destGeneralID: 2 }, undefined, { generals: { 2: { officerLevel: 1 } } }],
|
||||||
|
['che_등용수락', { destNationID: 2, destGeneralID: 2 }, { nationId: 0, officerLevel: 0 }],
|
||||||
|
['che_선양', { destGeneralID: 3 }, undefined],
|
||||||
|
['che_NPC능동', { optionText: '순간이동', destCityID: 70 }, { npcState: 2 }],
|
||||||
|
['che_방랑', undefined, undefined, { diplomacy: { '1:2': { state: 2 }, '2:1': { state: 2 } } }],
|
||||||
|
[
|
||||||
|
'che_해산',
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
nations: { 1: { name: '조조', level: 0, capitalCityId: 0, typeCode: 'None' } },
|
||||||
|
cities: { 3: { nationId: 0, supplyState: 0, frontState: 0 } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'che_집합',
|
||||||
|
undefined,
|
||||||
|
{ troopId: 1 },
|
||||||
|
{
|
||||||
|
generals: { 3: { cityId: 70, troopId: 1 } },
|
||||||
|
troops: [{ id: 1, nationId: 1, name: '조조군' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['che_거병', undefined, { nationId: 0, officerLevel: 0 }, { world: { startYear: 180, year: 181 } }],
|
||||||
|
[
|
||||||
|
'che_모반시도',
|
||||||
|
undefined,
|
||||||
|
{ officerLevel: 11 },
|
||||||
|
{ generals: { 3: { officerLevel: 12, officerCityId: 3, killTurn: 0 } } },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'che_건국',
|
||||||
|
{ nationName: '신국', nationType: 'che_도적', colorType: 1 },
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
world: { startYear: 180, initYear: 180, initMonth: 1, year: 181 },
|
||||||
|
nations: { 1: { name: '조조', level: 0, capitalCityId: 0, typeCode: 'None' } },
|
||||||
|
cities: { 3: { nationId: 0, level: 5 } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'cr_건국',
|
||||||
|
{ nationName: '신국', nationType: 'che_도적', colorType: 1 },
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
world: { startYear: 180, initYear: 180, initMonth: 1, year: 181 },
|
||||||
|
nations: { 1: { name: '조조', level: 0, capitalCityId: 0, typeCode: 'None' } },
|
||||||
|
cities: { 3: { nationId: 0, level: 5 } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'che_무작위건국',
|
||||||
|
{ nationName: '신국', nationType: 'che_도적', colorType: 1 },
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
world: { startYear: 180, initYear: 180, initMonth: 1, year: 181 },
|
||||||
|
nations: { 1: { name: '조조', level: 0, capitalCityId: 0, typeCode: 'None' } },
|
||||||
|
cities: {
|
||||||
|
3: { nationId: 0, level: 5 },
|
||||||
|
70: { nationId: 0, level: 5 },
|
||||||
|
},
|
||||||
|
randomFoundingCandidateCityIds: [3, 70],
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
integration('general command success matrix', () => {
|
integration('general command success matrix', () => {
|
||||||
it.each(cases)(
|
it.each(cases)(
|
||||||
'%s matches the legacy state delta and command RNG',
|
'%s matches the legacy state delta and command RNG',
|
||||||
async (action, args, actorPatch) => {
|
async (action, args, actorPatch, fixturePatches) => {
|
||||||
const request = buildRequest(action, args, actorPatch);
|
const request = buildRequest(action, args, actorPatch, fixturePatches);
|
||||||
const reference = runReferenceTurnCommandTraceRequest(
|
const reference = runReferenceTurnCommandTraceRequest(
|
||||||
workspaceRoot!,
|
workspaceRoot!,
|
||||||
request as unknown as Record<string, unknown>
|
request as unknown as Record<string, unknown>
|
||||||
|
|||||||
Reference in New Issue
Block a user