feat: enrich command option dialogs with Ref context

This commit is contained in:
2026-08-13 16:11:30 +00:00
parent 94b5b7813c
commit 8b1ca2a3f5
15 changed files with 868 additions and 135 deletions
+49 -5
View File
@@ -89,6 +89,24 @@ const getReservationWorldState = async (ctx: GameApiContext): Promise<WorldState
return worldState;
};
const plainLegacyInfo = (value: string): string =>
value
.replace(/<br\s*\/?>/giu, ' · ')
.replace(/<[^>]+>/gu, '')
.replace(/\s+/gu, ' ')
.trim();
const readGeneralMetaNumber = (meta: unknown, key: string): number | null => {
if (!meta || typeof meta !== 'object' || Array.isArray(meta)) return null;
const value = (meta as Record<string, unknown>)[key];
if (typeof value === 'number' && Number.isFinite(value)) return value;
if (typeof value === 'string') {
const parsed = Number(value);
if (Number.isFinite(parsed)) return parsed;
}
return null;
};
const assertReservedTurnPermission = async (
worldState: WorldStateRow,
general: GeneralRow,
@@ -168,7 +186,19 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
};
for (const item of itemModules) {
if (item.buyable) {
items[item.slot].push({ value: item.key, label: item.name });
const cost = item.cost ?? 0;
const currentSecurity = city?.security ?? 0;
const availability =
currentSecurity < item.reqSecu
? `현재 구입 불가: 치안 ${item.reqSecu.toLocaleString()} 필요`
: general.gold < cost
? `현재 구입 불가: 자금 ${cost.toLocaleString()} 필요`
: '현재 구입 가능';
items[item.slot].push({
value: item.key,
label: item.name,
description: `${availability} · 가격 ${cost.toLocaleString()} · ${plainLegacyInfo(item.info)}`,
});
}
}
const inputOptions: TurnCommandInputOptions = {
@@ -190,17 +220,31 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
crewTypes: (environment.unitSet.crewTypes ?? [])
.filter((entry) => !entry.requirements.some((requirement) => requirement.type === 'Impossible'))
.map((entry) => ({ value: entry.id, label: entry.name })),
armTypes: Object.entries(environment.unitSet.armTypes ?? {}).map(([value, label]) => ({
value: Number(value),
label,
armTypes: Object.entries(environment.unitSet.armTypes ?? {}).map(([value, label]) => {
const dexterity = readGeneralMetaNumber(general.meta, `dex${value}`);
return {
value: Number(value),
label,
...(dexterity === null ? {} : { description: `현재 숙련 ${dexterity.toLocaleString()}` }),
};
}),
nationTypes: traits.nationTypes.map((entry) => ({
value: entry.key,
label: entry.name,
description: plainLegacyInfo(entry.info),
})),
nationTypes: traits.nationTypes.map((entry) => ({ value: entry.key, label: entry.name })),
colors: TURN_COMMAND_NATION_COLORS.map((color, index) => ({
value: index,
label: `색상 ${index + 1}`,
color,
})),
items,
context: {
actorGold: general.gold,
actorRice: general.rice,
...(city ? { citySecurity: city.security } : {}),
...(nation ? { nationGold: nation.gold, nationRice: nation.rice, nationLevel: nation.level } : {}),
},
};
return buildTurnCommandTable({
+42 -12
View File
@@ -15,17 +15,11 @@ export interface TurnCommandOption {
value: TurnCommandOptionValue;
label: string;
color?: string;
description?: string;
}
export type TurnCommandOptionSource =
| 'cities'
| 'nations'
| 'generals'
| 'crewTypes'
| 'armTypes'
| 'nationTypes'
| 'colors'
| 'items';
'cities' | 'nations' | 'generals' | 'crewTypes' | 'armTypes' | 'nationTypes' | 'colors' | 'items';
export interface TurnCommandInputField {
key: string;
@@ -50,14 +44,50 @@ export interface TurnCommandInputOptions {
nationTypes: TurnCommandOption[];
colors: TurnCommandOption[];
items: Record<string, TurnCommandOption[]>;
context?: {
actorGold: number;
actorRice: number;
citySecurity?: number;
nationGold?: number;
nationRice?: number;
nationLevel?: number;
};
}
// 레거시 및 명령 실행 모듈의 인덱스 순서와 동일해야 한다.
export const TURN_COMMAND_NATION_COLORS = [
'#FF0000', '#800000', '#A0522D', '#FF6347', '#FFA500', '#FFDAB9', '#FFD700', '#FFFF00',
'#7CFC00', '#00FF00', '#808000', '#008000', '#2E8B57', '#008080', '#20B2AA', '#6495ED',
'#7FFFD4', '#AFEEEE', '#87CEEB', '#00FFFF', '#00BFFF', '#0000FF', '#000080', '#483D8B',
'#7B68EE', '#BA55D3', '#800080', '#FF00FF', '#FFC0CB', '#F5F5DC', '#E0FFFF', '#FFFFFF',
'#FF0000',
'#800000',
'#A0522D',
'#FF6347',
'#FFA500',
'#FFDAB9',
'#FFD700',
'#FFFF00',
'#7CFC00',
'#00FF00',
'#808000',
'#008000',
'#2E8B57',
'#008080',
'#20B2AA',
'#6495ED',
'#7FFFD4',
'#AFEEEE',
'#87CEEB',
'#00FFFF',
'#00BFFF',
'#0000FF',
'#000080',
'#483D8B',
'#7B68EE',
'#BA55D3',
'#800080',
'#FF00FF',
'#FFC0CB',
'#F5F5DC',
'#E0FFFF',
'#FFFFFF',
'#A9A9A9',
] as const;