feat: port scenario action effects

This commit is contained in:
2026-07-30 19:00:04 +00:00
parent 7f31459385
commit c68d992046
39 changed files with 1131 additions and 95 deletions
@@ -81,6 +81,7 @@ export const buildCommandEnv = (config: ScenarioConfig, unitSet?: UnitSetDefinit
return {
...(unitSet ? { unitSet } : {}),
scenarioEffect: config.environment.scenarioEffect ?? null,
develCost: resolveNumber(constValues, ['develCost', 'develcost', 'develrate'], 0),
minAvailableRecruitPop: resolveNumber(constValues, ['minAvailableRecruitPop'], 30000),
trainDelta: resolveNumber(constValues, ['trainDelta'], DEFAULT_TRAIN_DELTA),
@@ -169,7 +170,7 @@ export const buildReservedTurnDefinitions = async (options: {
general: Map<string, GeneralActionDefinition>;
nation: Map<string, GeneralActionDefinition>;
}> => {
const moduleBundle = await loadActionModuleBundle(options.env.unitSet);
const moduleBundle = await loadActionModuleBundle(options.env.unitSet, options.env.scenarioEffect);
const itemModules = moduleBundle.itemModules;
options.env.itemCatalog = Object.fromEntries(
itemModules.map((item) => [
+4 -1
View File
@@ -219,7 +219,10 @@ const createTurnDaemonRuntimeWithLease = async (
let redisConnector: ReturnType<typeof createRedisConnector> | null = null;
const nationTraits = await loadNationTraitModules([...NATION_TRAIT_KEYS], new NationTraitLoader());
const nationTraitMap = new Map(nationTraits.map((module) => [module.key, module]));
const monthlyActionModules = await loadActionModuleBundle(snapshot.unitSet);
const monthlyActionModules = await loadActionModuleBundle(
snapshot.unitSet,
snapshot.scenarioConfig.environment.scenarioEffect
);
const monthlyCommandEnv = buildCommandEnv(snapshot.scenarioConfig, snapshot.unitSet);
const unification = options.calendarHandler
? null
@@ -15,6 +15,7 @@ import {
buildVoteUniqueSeed,
countOccupiedUniqueItems,
createItemModuleRegistry,
isDefenceTrainPenaltyWaivedByScenarioEffect,
isValidTroopNameWidth,
loadItemModules,
normalizeTroopName,
@@ -948,10 +949,7 @@ async function handleSetMySetting(
nextMeta.defence_train = nextDefenceTrain;
if (nextDefenceTrain === 999) {
const scenarioEffect = world.getScenarioConfig().environment.scenarioEffect;
const ignoresPenalty =
scenarioEffect === 'event_UnlimitedDefenceThresholdChange' ||
scenarioEffect === 'event_StrongAttacker' ||
scenarioEffect === 'event_MoreEffect';
const ignoresPenalty = isDefenceTrainPenaltyWaivedByScenarioEffect(scenarioEffect);
const constValues = asRecord(world.getScenarioConfig().const);
const maxTrain = readMetaNumber(constValues, 'maxTrainByWar', 100);
const maxAtmos = readMetaNumber(constValues, 'maxAtmosByWar', 100);
+22 -2
View File
@@ -21,6 +21,7 @@ import type {
Troop,
TriggerValue,
} from '@sammo-ts/logic';
import { normalizeScenarioEffect } from '@sammo-ts/logic';
import { projectItemSlots, readItemInventoryFromMeta } from '@sammo-ts/logic/items/index.js';
import { z } from 'zod';
import { asRecord, isRecord } from '@sammo-ts/common';
@@ -90,7 +91,20 @@ const zScenarioStatBlock = z.object({
const zScenarioEnvironment = z.object({
mapName: z.string(),
unitSet: z.string(),
scenarioEffect: z.union([z.string(), z.null()]).optional(),
scenarioEffect: z
.union([z.string(), z.null()])
.optional()
.refine(
(value) => {
try {
normalizeScenarioEffect(value);
return true;
} catch {
return false;
}
},
{ message: 'Unknown scenario effect' }
),
});
const zScenarioConfig = z.object({
@@ -155,7 +169,13 @@ const mapScenarioConfig = (raw: JsonValue): ScenarioConfig => {
if (!parsed.success) {
throw new Error(`world_state.config is invalid: ${parsed.error.message}`);
}
return parsed.data;
return {
...parsed.data,
environment: {
...parsed.data.environment,
scenarioEffect: normalizeScenarioEffect(parsed.data.environment.scenarioEffect),
},
};
};
const mapGeneralRow = (