feat(game): match Ref nation basic card

This commit is contained in:
2026-08-13 17:55:19 +00:00
parent 6972db1faa
commit 4a930f3bec
7 changed files with 581 additions and 80 deletions
@@ -0,0 +1,75 @@
import { asRecord } from '@sammo-ts/common';
const STRATEGIC_COMMAND_NAMES = [
'필사즉생',
'백성동원',
'수몰',
'허보',
'의병모집',
'이호경식',
'급습',
'피장파장',
] as const;
const readFiniteNumber = (value: unknown, fallback = 0): number => {
if (typeof value === 'number' && Number.isFinite(value)) return value;
if (typeof value === 'string') {
const parsed = Number(value);
if (Number.isFinite(parsed)) return parsed;
}
return fallback;
};
const clamp = (value: number, min: number, max: number): number => Math.min(max, Math.max(min, value));
export const splitNationTraitInfo = (info: string): { pros: string; cons: string } => {
const tokens = info.trim().split(/\s+/u).filter(Boolean);
return {
pros: tokens.filter((token) => token.endsWith('↑')).join(' '),
cons: tokens.filter((token) => token.endsWith('↓')).join(' '),
};
};
export const resolveMainNationTech = (options: {
tech: number;
currentYear: number;
worldConfig: unknown;
worldMeta: unknown;
}): { level: number; limited: boolean } => {
const config = asRecord(options.worldConfig);
const constValues = asRecord(config.const ?? config.consts);
const scenarioMeta = asRecord(asRecord(options.worldMeta).scenarioMeta);
const maxLevel = Math.max(1, Math.floor(readFiniteNumber(constValues.maxTechLevel, 12)));
const initialLevel = Math.max(1, Math.floor(readFiniteNumber(constValues.initialAllowedTechLevel, 1)));
const increaseYears = Math.max(1, Math.floor(readFiniteNumber(constValues.techLevelIncYear, 5)));
const startYear = readFiniteNumber(scenarioMeta.startYear, options.currentYear);
const relativeMaximum = clamp(
Math.floor((options.currentYear - startYear) / increaseYears) + initialLevel,
1,
maxLevel
);
const level = clamp(Math.floor(options.tech / 1000), 0, maxLevel);
return { level, limited: level >= relativeMaximum };
};
export const resolveImpossibleStrategicCommands = (
nationMeta: unknown,
currentYear: number,
currentMonth: number
): Array<{ name: string; remainingTurns: number; availableYear: number; availableMonth: number }> => {
const meta = asRecord(nationMeta);
const currentYearMonth = Math.floor(currentYear) * 12 + Math.floor(currentMonth) - 1;
const result: Array<{ name: string; remainingTurns: number; availableYear: number; availableMonth: number }> = [];
for (const name of STRATEGIC_COMMAND_NAMES) {
const nextAvailable = Math.floor(readFiniteNumber(meta[`next_execute_${name}`], 0));
if (nextAvailable <= currentYearMonth) continue;
result.push({
name,
remainingTurns: nextAvailable - currentYearMonth,
availableYear: Math.floor(nextAvailable / 12),
availableMonth: (nextAvailable % 12) + 1,
});
}
return result;
};