fix: 시나리오별 장비 매매 품목 범위를 보존

현재 시나리오 allItems를 API 선택지와 턴 실행 검증에 함께 적용한다. 빈 설정은 Ref 기본 장비 24종으로 복원하고 명시된 비급 시나리오는 기존 품목을 유지한다.
This commit is contained in:
2026-08-21 02:11:40 +00:00
parent 4ce2477103
commit 3b933a75b8
12 changed files with 301 additions and 28 deletions
+7 -23
View File
@@ -13,6 +13,7 @@ import {
} from '../../turns/commandTable.js';
import { loadMapDefinitionByName } from '../../maps/mapDefinition.js';
import {
buildEquipmentTradeItemOptions,
parseReservedTurnArgs,
TURN_COMMAND_NATION_COLORS,
type TurnCommandInputOptions,
@@ -283,29 +284,12 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
cityNames: new Map(cities.map((entry) => [entry.id, entry.name])),
troopNames: new Map(troops.map((entry) => [entry.troopLeaderId, entry.name])),
});
const items: TurnCommandInputOptions['items'] = {
horse: [{ value: 'None', label: '판매/해제' }],
weapon: [{ value: 'None', label: '판매/해제' }],
book: [{ value: 'None', label: '판매/해제' }],
item: [{ value: 'None', label: '판매/해제' }],
};
for (const item of moduleBundle.itemModules) {
if (item.buyable) {
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 items = buildEquipmentTradeItemOptions({
configConst: asRecord(asRecord(worldState.config).const),
itemModules: moduleBundle.itemModules,
currentSecurity: city?.security ?? 0,
generalGold: general.gold,
});
const inputOptions: TurnCommandInputOptions = {
cities: cities.map((entry) => ({
value: entry.id,
+45
View File
@@ -5,6 +5,8 @@ import {
type NationTurnCommandSpec,
} from '@sammo-ts/logic';
import { asRecord, isRecord } from '@sammo-ts/common';
import type { ItemModule } from '@sammo-ts/logic/items/types.js';
import { resolveLegacyPurchasableItemKeys } from '@sammo-ts/logic/rewards/legacyUniqueItemPool.js';
import { z } from 'zod';
import { loadTurnCommandProfile } from '@sammo-ts/game-engine/turn/turnCommandProfile.js';
@@ -103,6 +105,49 @@ export interface TurnCommandInputOptions {
};
}
type EquipmentTradeItemModule = Pick<ItemModule, 'key' | 'slot' | 'name' | 'info' | 'cost' | 'reqSecu' | 'buyable'>;
const plainLegacyInfo = (value: string): string =>
value
.replace(/<br\s*\/?>/giu, ' · ')
.replace(/<[^>]+>/gu, '')
.replace(/\s+/gu, ' ')
.trim();
export const buildEquipmentTradeItemOptions = (options: {
configConst: Record<string, unknown>;
itemModules: readonly EquipmentTradeItemModule[];
currentSecurity: number;
generalGold: number;
}): TurnCommandInputOptions['items'] => {
const purchasableItemKeys = resolveLegacyPurchasableItemKeys(options.configConst);
const items: TurnCommandInputOptions['items'] = {
horse: [{ value: 'None', label: '판매/해제' }],
weapon: [{ value: 'None', label: '판매/해제' }],
book: [{ value: 'None', label: '판매/해제' }],
item: [{ value: 'None', label: '판매/해제' }],
};
for (const item of options.itemModules) {
if (!item.buyable || !purchasableItemKeys.has(item.key)) {
continue;
}
const cost = item.cost ?? 0;
const availability =
options.currentSecurity < item.reqSecu
? `현재 구입 불가: 치안 ${item.reqSecu.toLocaleString()} 필요`
: options.generalGold < cost
? `현재 구입 불가: 자금 ${cost.toLocaleString()} 필요`
: '현재 구입 가능';
items[item.slot].push({
value: item.key,
label: item.name,
description: `${availability} · 가격 ${cost.toLocaleString()} · ${plainLegacyInfo(item.info)}`,
});
}
return items;
};
// 레거시 및 명령 실행 모듈의 인덱스 순서와 동일해야 한다.
export const TURN_COMMAND_NATION_COLORS = [
'#FF0000',