장비 구매 목록을 시나리오 JSON 순서로 표시
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
assertReservedTurnActionAvailable,
|
||||
assertReservedTurnArgsPassLegacyBasicValidation,
|
||||
buildEquipmentTradeItemOptions,
|
||||
loadEquipmentTradeItemOrder,
|
||||
parseReservedTurnArgs,
|
||||
TURN_COMMAND_NATION_COLORS,
|
||||
type TurnCommandInputOptions,
|
||||
@@ -272,6 +273,7 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
|
||||
traits,
|
||||
moduleBundle,
|
||||
map,
|
||||
itemOrder,
|
||||
] = await Promise.all([
|
||||
general.cityId > 0
|
||||
? ctx.db.city.findUnique({
|
||||
@@ -330,6 +332,7 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
|
||||
loadBattleSimTraitOptions(),
|
||||
moduleBundlePromise,
|
||||
loadMapDefinitionByName(resolveMapName(worldState, ctx.profile.id)),
|
||||
loadEquipmentTradeItemOrder(worldState.scenarioCode),
|
||||
]);
|
||||
|
||||
const nationById = new Map(nations.map((entry) => [entry.id, entry]));
|
||||
@@ -383,6 +386,7 @@ export const getTurnCommandTable = async (ctx: GameApiContext, generalId: number
|
||||
troopNames: new Map(troops.map((entry) => [entry.troopLeaderId, entry.name])),
|
||||
});
|
||||
const items = buildEquipmentTradeItemOptions({
|
||||
itemOrder,
|
||||
configConst: asRecord(asRecord(worldState.config).const),
|
||||
itemModules: moduleBundle.itemModules,
|
||||
currentSecurity: city?.security ?? 0,
|
||||
|
||||
@@ -11,6 +11,7 @@ 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 { loadScenarioDefinitionById } from '@sammo-ts/game-engine/scenario/scenarioLoader.js';
|
||||
|
||||
import { loadScenarioTurnCommandProfile } from '@sammo-ts/game-engine/turn/turnCommandProfile.js';
|
||||
|
||||
@@ -120,8 +121,29 @@ const plainLegacyInfo = (value: string): string =>
|
||||
.replace(/\s+/gu, ' ')
|
||||
.trim();
|
||||
|
||||
// JSONB는 객체 key 순서를 보존하지 않으므로 표시 순서는 배포된 원본 resource에서 읽는다.
|
||||
export const loadEquipmentTradeItemOrder = async (scenarioCode: string): Promise<readonly string[] | undefined> => {
|
||||
const normalized = scenarioCode.replace(/^scenario_/i, '').replace(/\.json$/i, '');
|
||||
if (!/^\d+$/.test(normalized) || !Number.isSafeInteger(Number(normalized))) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const scenario = await loadScenarioDefinitionById(Number(normalized));
|
||||
const configConst = scenario.config.const;
|
||||
const keys = Object.values(asRecord(configConst.allItems)).flatMap((entries) => Object.keys(asRecord(entries)));
|
||||
return keys.length > 0 ? keys : [...resolveLegacyPurchasableItemKeys(configConst)];
|
||||
} catch (error) {
|
||||
// 보존된 시즌의 resource가 없는 경우에도 현재 DB의 구매/판매 선택지는 유지한다.
|
||||
if (isRecord(error) && error.code === 'ENOENT') {
|
||||
return undefined;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const buildEquipmentTradeItemOptions = (options: {
|
||||
configConst: Record<string, unknown>;
|
||||
itemOrder?: readonly string[];
|
||||
itemModules: readonly EquipmentTradeItemModule[];
|
||||
currentSecurity: number;
|
||||
generalGold: number;
|
||||
@@ -148,8 +170,11 @@ export const buildEquipmentTradeItemOptions = (options: {
|
||||
];
|
||||
}
|
||||
|
||||
for (const item of options.itemModules) {
|
||||
if (!item.buyable || !purchasableItemKeys.has(item.key)) {
|
||||
// 원본 순서를 우선하되 구매 권한은 현재 DB 설정만 따른다. 추가된 품목은 뒤에 유지한다.
|
||||
const orderedKeys = new Set([...(options.itemOrder ?? []), ...purchasableItemKeys]);
|
||||
for (const key of orderedKeys) {
|
||||
const item = catalog.get(key);
|
||||
if (!item?.buyable || !purchasableItemKeys.has(key)) {
|
||||
continue;
|
||||
}
|
||||
const cost = item.cost ?? 0;
|
||||
|
||||
Reference in New Issue
Block a user