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

# Conflicts:
#	app/game-frontend/e2e/playwright.config.mjs
#	app/game-frontend/package.json
#	docs/frontend-legacy-parity.md
This commit is contained in:
2026-07-26 04:31:54 +00:00
42 changed files with 4790 additions and 1949 deletions
@@ -24,6 +24,7 @@ import {
evaluateConstraints,
resolveGeneralAction,
ITEM_KEYS,
addOccupiedUniqueItemKeys,
buildGenericUniqueSeed,
countOccupiedUniqueItems,
createItemModuleRegistry,
@@ -382,6 +383,7 @@ const buildUniqueLotteryRunner = (options: {
seedBase: string;
itemRegistry: Map<string, ItemModule>;
uniqueConfig: ReturnType<typeof resolveUniqueConfig>;
getAdditionalOccupiedUniqueItemKeys?: () => Iterable<string | null | undefined>;
}): UniqueLotteryRunner => {
if (!options.worldView) {
return () => null;
@@ -408,6 +410,11 @@ const buildUniqueLotteryRunner = (options: {
entry.id === general.id ? general.role.items : entry.role.items
);
const occupiedUniqueCounts = countOccupiedUniqueItems(generalItemsList, options.itemRegistry);
addOccupiedUniqueItemKeys(
occupiedUniqueCounts,
options.getAdditionalOccupiedUniqueItemKeys?.() ?? [],
options.itemRegistry
);
const rngSeed = buildGenericUniqueSeed(
options.seedBase,
world.currentYear,
@@ -723,6 +730,7 @@ export const createReservedTurnHandler = async (options: {
commandProfile?: TurnCommandProfile;
commandEnv?: TurnCommandEnv;
commandRngFactory?: (input: { kind: 'nation' | 'general'; actionKey: string; seed: string }) => RandUtil;
getAdditionalOccupiedUniqueItemKeys?: () => Iterable<string | null | undefined>;
onActionResolved?: (payload: {
kind: 'nation' | 'general';
generalId: number;
@@ -944,6 +952,7 @@ export const createReservedTurnHandler = async (options: {
seedBase,
itemRegistry,
uniqueConfig,
getAdditionalOccupiedUniqueItemKeys: options.getAdditionalOccupiedUniqueItemKeys,
});
let baseContext: ActionContextBase = {
general: currentGeneral,
+15
View File
@@ -473,6 +473,8 @@ const createTurnDaemonRuntimeWithLease = async (
neutralAuctionRegistrar.handler,
frontStateHandler
);
let occupiedAuctionUniqueItemKeys: string[] = [];
let refreshOccupiedAuctionUniqueItemKeys = async (): Promise<void> => {};
const worldOptions: InMemoryTurnWorldOptions = {
schedule,
generalTurnHandler:
@@ -486,6 +488,7 @@ const createTurnDaemonRuntimeWithLease = async (
getWorld: () => worldRef,
commandProfile,
commandEnv: monthlyCommandEnv,
getAdditionalOccupiedUniqueItemKeys: () => occupiedAuctionUniqueItemKeys,
})),
calendarHandler: calendarHandler ?? undefined,
autoAdvanceDiplomacyMonth: false,
@@ -501,6 +504,7 @@ const createTurnDaemonRuntimeWithLease = async (
? async (general) => {
const promises: Promise<unknown>[] = [];
promises.push(reservedTurnStoreHandle.store.refreshGeneralTurns(general.id));
promises.push(refreshOccupiedAuctionUniqueItemKeys());
if (general.nationId > 0 && general.officerLevel >= 5) {
promises.push(
reservedTurnStoreHandle.store.refreshNationTurns(general.nationId, general.officerLevel)
@@ -648,6 +652,17 @@ const createTurnDaemonRuntimeWithLease = async (
if (commandConnector && databaseCommandQueue) {
await commandConnector.connect();
await databaseCommandQueue.initialize();
refreshOccupiedAuctionUniqueItemKeys = async () => {
const rows = await commandConnector.prisma.auction.findMany({
where: {
type: 'UNIQUE_ITEM',
status: { in: ['OPEN', 'FINALIZING'] },
targetCode: { not: null },
},
select: { targetCode: true },
});
occupiedAuctionUniqueItemKeys = rows.flatMap((row) => (row.targetCode ? [row.targetCode] : []));
};
}
const baseClose = close;
@@ -11,6 +11,7 @@ import {
LogFormat,
LogScope,
ITEM_KEYS,
addOccupiedUniqueItemKeys,
buildVoteUniqueSeed,
countOccupiedUniqueItems,
createItemModuleRegistry,
@@ -1481,6 +1482,21 @@ async function handleVoteReward(
generals.map((entry) => entry.role.items),
itemRegistry
);
if (ctx.commandDb) {
const reservedUniqueRows = await ctx.commandDb.auction.findMany({
where: {
type: 'UNIQUE_ITEM',
status: { in: ['OPEN', 'FINALIZING'] },
targetCode: { not: null },
},
select: { targetCode: true },
});
addOccupiedUniqueItemKeys(
occupiedUniqueCounts,
reservedUniqueRows.map((row) => row.targetCode),
itemRegistry
);
}
const userCount = generals.filter((entry) => entry.npcState < 2).length;
const rngSeed = buildVoteUniqueSeed(
typeof hiddenSeed === 'string' || typeof hiddenSeed === 'number' ? hiddenSeed : String(hiddenSeed),