Merge branch 'main' into feature/nation-personnel-finance-parity

# Conflicts:
#	docs/frontend-legacy-parity.md
This commit is contained in:
2026-07-26 04:35:16 +00:00
32 changed files with 2629 additions and 1485 deletions
@@ -198,6 +198,7 @@ const zAdjustGeneralResources = z.object({
generalId: zFiniteNumber,
goldDelta: zFiniteNumber.optional(),
riceDelta: zFiniteNumber.optional(),
minGoldAfter: zFiniteNumber.optional(),
})
.refine((value) => value.goldDelta !== undefined || value.riceDelta !== undefined)
)
@@ -857,7 +857,8 @@ export const createReservedTurnHandler = async (options: {
fallbackDefinition: GeneralActionDefinition,
command: ReservedTurnEntry,
applyNextTurnAt: boolean,
alternativeDepth = 0
alternativeDepth = 0,
sharedActionRng?: RandUtil
): { nextTurnAt?: Date; actionKey: string; usedFallback: boolean; blockedReason?: string } => {
const resolvedDefinition = resolveDefinition(command.action, definitionMap, fallbackDefinition);
const rawArgs = extractArgsRecord(command.args);
@@ -954,11 +955,12 @@ export const createReservedTurnHandler = async (options: {
uniqueConfig,
getAdditionalOccupiedUniqueItemKeys: options.getAdditionalOccupiedUniqueItemKeys,
});
let actionRng = sharedActionRng ?? buildRng(actionKey);
let baseContext: ActionContextBase = {
general: currentGeneral,
city: currentCity,
nation: currentNation,
rng: buildRng(actionKey),
rng: actionRng,
uniqueLottery,
};
let specificContext = buildActionContext(
@@ -985,11 +987,12 @@ export const createReservedTurnHandler = async (options: {
usedFallback = true;
blockedReason = '예약된 명령을 실행하지 못했습니다.';
logs.push(createActionLog('예약된 명령을 실행하지 못했습니다.'));
actionRng = sharedActionRng ?? buildRng(actionKey);
baseContext = {
general: currentGeneral,
city: currentCity,
nation: currentNation,
rng: buildRng(actionKey),
rng: actionRng,
};
specificContext = baseContext;
}
@@ -1287,7 +1290,8 @@ export const createReservedTurnHandler = async (options: {
args: extractArgsRecord(resolution.alternative.args),
},
applyNextTurnAt,
alternativeDepth + 1
alternativeDepth + 1,
actionRng
);
}
@@ -194,7 +194,8 @@ async function handleAdjustGeneralResources(
}
const nextGold = general.gold + (adjustment.goldDelta ?? 0);
const nextRice = general.rice + (adjustment.riceDelta ?? 0);
if (nextGold < 0 || nextRice < 0) {
const minGoldAfter = adjustment.minGoldAfter ?? 0;
if (nextGold < minGoldAfter || nextRice < 0) {
return { type: 'adjustGeneralResources', ok: false, reason: '자원이 부족합니다.' };
}
}
@@ -307,7 +308,7 @@ async function handleTournamentMatchResult(
};
}
const rankKey = (suffix: string): string => `rank_${prefix}${suffix}`;
const rankKey = (suffix: string): string => `${prefix}${suffix}`;
const getRankNumber = (general: TurnGeneral | null, key: string): number =>
general && typeof general.meta[key] === 'number' ? Number(general.meta[key]) : 0;
@@ -1394,8 +1395,8 @@ async function handleTournamentBettingPayout(
continue;
}
const nextMeta = { ...general.meta } as TurnGeneral['meta'];
const betwinKey = 'rank_betwin';
const betwingoldKey = 'rank_betwingold';
const betwinKey = 'betwin';
const betwingoldKey = 'betwingold';
const currentBetwin = typeof nextMeta[betwinKey] === 'number' ? Number(nextMeta[betwinKey]) : 0;
const currentBetwingold = typeof nextMeta[betwingoldKey] === 'number' ? Number(nextMeta[betwingoldKey]) : 0;
nextMeta[betwinKey] = currentBetwin + delta.betwin;