fix: 불가침 제의 기한을 20년으로 제한

This commit is contained in:
2026-08-30 07:24:33 +00:00
parent d68209879b
commit 24e57ee94c
13 changed files with 174 additions and 14 deletions
+1
View File
@@ -80,6 +80,7 @@ export interface TurnCommandInputField {
min?: number;
max?: number;
step?: number;
defaultValue?: TurnCommandOptionValue | boolean;
constValue?: TurnCommandOptionValue;
options?: TurnCommandOption[];
optionSource?: TurnCommandOptionSource;
+22 -4
View File
@@ -18,7 +18,7 @@ import type {
TriggerValue,
UnitSetDefinition,
} from '@sammo-ts/logic';
import { evaluateConstraints, LEGACY_DEFAULT_MAX_LEVEL } from '@sammo-ts/logic';
import { evaluateConstraints, LEGACY_DEFAULT_MAX_LEVEL, resolveNonAggressionMaxEndYear } from '@sammo-ts/logic';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import { CommandResolver as RecruitmentCommandResolver } from '@sammo-ts/logic/actions/turn/general/che_징병.js';
import { projectItemSlots, readItemInventoryFromMeta } from '@sammo-ts/logic/items/index.js';
@@ -656,18 +656,33 @@ const FOUNDING_COMMAND_KEYS = new Set(['che_건국', 'cr_건국', 'che_무작위
const buildEntries = (
env: CommandEnv,
specs: TurnCommandSpec[],
options: { foundingAvailable?: boolean } = {}
options: { foundingAvailable?: boolean; currentYear?: number; currentMonth?: number } = {}
): CommandEntry[] => {
const entries: CommandEntry[] = [];
for (const spec of specs) {
const definition = spec.createDefinition(env);
const inputFields = buildTurnCommandInputFields(spec).map((field) => {
if (spec.key !== 'che_불가침제의') return field;
if (field.key === 'year' && options.currentYear !== undefined) {
return {
...field,
min: options.currentYear + 1,
max: resolveNonAggressionMaxEndYear(options.currentYear),
defaultValue: options.currentYear + 1,
};
}
if (field.key === 'month' && options.currentMonth !== undefined) {
return { ...field, defaultValue: options.currentMonth };
}
return field;
});
const entry: CommandEntry = {
category: spec.category,
definition,
reqArg: spec.reqArg,
availabilityArgs: spec.reqArg ? spec.availabilityArgs : {},
inputFields: buildTurnCommandInputFields(spec),
inputFields,
};
if (spec.key === 'che_포상') {
@@ -817,7 +832,10 @@ export const buildTurnCommandTable = async (options: {
? undefined
: options.realNationCount < resolveMaxNation(options.worldState),
});
const nationEntries = buildEntries(env, nationSpecs);
const nationEntries = buildEntries(env, nationSpecs, {
currentYear: options.worldState.currentYear,
currentMonth: options.worldState.currentMonth,
});
return {
general: buildGroups(
+21
View File
@@ -337,6 +337,27 @@ describe('buildTurnCommandTable', () => {
}
});
it('projects the Ref twenty-year non-aggression end-year window', async () => {
const table = await buildTurnCommandTable({
worldState: buildWorldState(),
general: buildGeneral(),
city: buildCity(),
nation: buildNation(),
nationGenerals: null,
});
const proposal = table.nation
.flatMap((group) => group.values)
.find((command) => command.key === 'che_불가침제의');
expect(proposal?.inputFields.find((field) => field.key === 'year')).toMatchObject({
kind: 'number',
min: 4,
max: 23,
defaultValue: 4,
});
expect(proposal?.inputFields.find((field) => field.key === 'month')).toMatchObject({ defaultValue: 1 });
});
it('projects the Ref availability boundaries for force move, retirement, and resignation', async () => {
const buildTable = (general: GeneralRow, nation: NationRow | null = buildNation()) =>
buildTurnCommandTable({
+22
View File
@@ -1462,6 +1462,28 @@ describe('appRouter', () => {
})
).resolves.toMatchObject({ ok: true });
expect(validTermWrites).toHaveLength(1);
const excessiveTermWrites: unknown[] = [];
const excessiveTermCaller = appRouter.createCaller(
buildContext({
state: buildWorldState(),
general,
nationTurnWrites: excessiveTermWrites,
})
);
await expect(
excessiveTermCaller.turns.reserved.setNation({
generalId: general.id,
turnIndex: 0,
action: 'che_불가침제의',
args: { destNationId: 2, year: 211, month: 1 },
expectedRevision: 0,
})
).rejects.toMatchObject({
code: 'PRECONDITION_FAILED',
message: expect.stringContaining('기한은 210년 이하'),
});
expect(excessiveTermWrites).toHaveLength(0);
});
it('validates every bulk reservation permission before writing any turn', async () => {