feat: add killturn to general meta and update related tests

- Introduced a new meta property `killturn` to the GeneralMeta interface.
- Implemented a function `readMetaNumber` to handle the retrieval of numeric values from meta.
- Updated the `mapGeneralRow` function to ensure `killturn` is required and properly handled.
- Modified various tests to include the `killturn` property in the general's meta data.
- Adjusted related action files to utilize the new GeneralMeta type for better type safety.
- Ensured backward compatibility by updating existing test cases across multiple scenarios.
This commit is contained in:
2026-01-25 05:48:56 +00:00
parent 340cadb8ce
commit 5d5ed9ee2a
39 changed files with 164 additions and 99 deletions
@@ -1,5 +1,5 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { City, General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext, RequirementKey, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
notBeNeutral,
@@ -85,7 +85,7 @@ const pickByWeight = (rng: RandomGenerator, weights: Record<DomesticCriticalPick
return 'normal';
};
const addMetaNumber = (meta: Record<string, unknown>, key: string, delta: number): Record<string, unknown> => {
const addMetaNumber = (meta: GeneralMeta, key: string, delta: number): GeneralMeta => {
const current = getMetaNumber(meta, key) ?? 0;
return { ...meta, [key]: current + delta };
};
@@ -1,5 +1,12 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { City, General, GeneralTriggerState, StatBlock, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type {
City,
General,
GeneralMeta,
GeneralTriggerState,
StatBlock,
TriggerValue,
} from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import { reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
@@ -90,11 +97,7 @@ const addMetaValue = (
meta[key] = value;
};
const addMetaNumber = (
meta: Record<string, TriggerValue>,
key: StatExpKey,
delta: number
): Record<string, TriggerValue> => {
const addMetaNumber = (meta: GeneralMeta, key: StatExpKey, delta: number): GeneralMeta => {
const current = typeof meta[key] === 'number' ? (meta[key] as number) : 0;
return { ...meta, [key]: current + delta };
};
@@ -298,7 +301,8 @@ export class ActionResolver<
const name = this.env.decorateName
? this.env.decorateName(resolvedCandidate.name, NPC_TYPE)
: resolvedCandidate.name;
const meta: Record<string, TriggerValue> = {
const meta: GeneralMeta = {
killturn: context.general.meta.killturn,
npcType: NPC_TYPE,
crewTypeId: this.env.defaultCrewTypeId,
};
@@ -1,5 +1,5 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { City, General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext, RequirementKey } from '@sammo-ts/logic/constraints/types.js';
import {
notBeNeutral,
@@ -42,7 +42,7 @@ const getMetaNumber = (meta: Record<string, unknown>, key: string): number | nul
return typeof raw === 'number' ? raw : null;
};
const addMetaNumber = (meta: Record<string, unknown>, key: string, delta: number): Record<string, unknown> => {
const addMetaNumber = (meta: GeneralMeta, key: string, delta: number): GeneralMeta => {
const current = getMetaNumber(meta, key) ?? 0;
return { ...meta, [key]: current + delta };
};
@@ -1,4 +1,4 @@
import type { City, General, GeneralTriggerState, Nation, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext, RequirementKey, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
notBeNeutral,
@@ -105,11 +105,7 @@ const readCityTrust = (city: City, fallback: number): number => {
return typeof trust === 'number' ? trust : fallback;
};
const addMetaNumber = (
meta: Record<string, TriggerValue>,
key: string,
delta: number
): Record<string, TriggerValue> => {
const addMetaNumber = (meta: GeneralMeta, key: string, delta: number): GeneralMeta => {
const current = typeof meta[key] === 'number' ? (meta[key] as number) : 0;
return { ...meta, [key]: current + delta };
};
@@ -1,5 +1,12 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { City, General, GeneralTriggerState, Nation, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type {
City,
General,
GeneralMeta,
GeneralTriggerState,
Nation,
TriggerValue,
} from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import {
disallowDiplomacyBetweenStatus,
@@ -103,11 +110,7 @@ const getStatValue = (general: General, statKey: 'leadership' | 'strength' | 'in
return general.stats.intelligence;
};
const addMetaNumber = (
meta: Record<string, TriggerValue>,
key: string,
delta: number
): Record<string, TriggerValue> => {
const addMetaNumber = (meta: GeneralMeta, key: string, delta: number): GeneralMeta => {
const current = typeof meta[key] === 'number' ? (meta[key] as number) : 0;
return { ...meta, [key]: current + delta };
};
@@ -1,9 +1,9 @@
import type {
General,
GeneralMeta,
GeneralRole,
GeneralTriggerState,
StatBlock,
TriggerValue,
} from '@sammo-ts/logic/domain/entities.js';
export interface GeneralRecruitmentInput<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
@@ -26,7 +26,7 @@ export interface GeneralRecruitmentInput<TriggerState extends GeneralTriggerStat
specialDomestic: string | null;
specialWar: string | null;
};
meta?: Record<string, TriggerValue>;
meta: GeneralMeta;
triggerState?: TriggerState;
}
@@ -76,5 +76,5 @@ export const buildRecruitmentGeneral = <TriggerState extends GeneralTriggerState
age: input.age,
npcState: input.npcState,
triggerState: input.triggerState ?? (createEmptyTriggerState() as TriggerState),
meta: input.meta ?? {},
meta: input.meta,
});
@@ -1,4 +1,10 @@
import type { City, General, GeneralTriggerState, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type {
City,
General,
GeneralMeta,
GeneralTriggerState,
TriggerValue,
} from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import {
alwaysFail,
@@ -72,11 +78,7 @@ const resolveLastAssignment = (context: AssignmentResolveContext): number => {
return yearMonth;
};
const addMetaValue = (
meta: Record<string, TriggerValue>,
key: string,
value: TriggerValue
): Record<string, TriggerValue> => ({
const addMetaValue = (meta: GeneralMeta, key: string, value: TriggerValue): GeneralMeta => ({
...meta,
[key]: value,
});
@@ -1,5 +1,5 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { GeneralTriggerState, StatBlock, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralMeta, GeneralTriggerState, StatBlock, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import {
availableStrategicCommand,
@@ -268,7 +268,8 @@ export class ActionResolver<
const birthYear = context.currentYear - baseAge;
const deathYear = context.currentYear + deathYears;
const stats = resolveStats(context, context.rng, this.env, candidate);
const meta: Record<string, TriggerValue> = {
const meta: GeneralMeta = {
killturn: randomRangeInt(context.rng, killTurnMin, killTurnMax),
npcType: NPC_TYPE,
crewTypeId: this.env.defaultCrewTypeId,
};
@@ -278,7 +279,7 @@ export class ActionResolver<
addMetaValue(meta, 'deathYear', deathYear);
addMetaValue(meta, 'specAge', DEFAULT_SPEC_AGE);
addMetaValue(meta, 'specAge2', DEFAULT_SPEC_AGE);
addMetaValue(meta, 'killturn', randomRangeInt(context.rng, killTurnMin, killTurnMax));
addMetaValue(meta, 'killturn', meta.killturn);
addMetaValue(meta, 'text', candidate.text ?? null);
const newGeneral = buildRecruitmentGeneral<TriggerState>({
+5 -1
View File
@@ -44,6 +44,10 @@ export interface GeneralRole {
items: GeneralItemSlots;
}
export type GeneralMeta = Record<string, TriggerValue> & {
killturn: number;
};
export interface General<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
id: GeneralId;
name: string;
@@ -65,7 +69,7 @@ export interface General<TriggerState extends GeneralTriggerState = GeneralTrigg
age: number;
npcState: number;
triggerState: TriggerState;
meta: Record<string, TriggerValue>;
meta: GeneralMeta;
}
export interface City {
+1 -1
View File
@@ -82,7 +82,7 @@ export const createIncomeActionContext = (nation: Nation): GeneralActionContext
modifiers: {},
meta: {},
},
meta: {},
meta: { killturn: 0 },
};
return { general, nation };
};
+11 -2
View File
@@ -1,4 +1,11 @@
import type { City, General, GeneralTriggerState, Nation, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type {
City,
General,
GeneralMeta,
GeneralTriggerState,
Nation,
TriggerValue,
} from '@sammo-ts/logic/domain/entities.js';
import type { ScenarioDefinition, ScenarioGeneral } from '@sammo-ts/logic/scenario/types.js';
import type {
CitySeed,
@@ -56,6 +63,7 @@ const DEFAULT_NEUTRAL_NATION_COLOR = '#000000';
const DEFAULT_GENERAL_GOLD = 1000;
const DEFAULT_GENERAL_RICE = 1000;
const DEFAULT_CREWTYPE_ID = 1100;
const DEFAULT_GENERAL_KILLTURN = 24;
const DEFAULT_CITY_TRUST = 50;
const DEFAULT_CITY_TRADE = 100;
const DEFAULT_CITY_SUPPLY_STATE = 1;
@@ -290,7 +298,8 @@ const buildGeneralSeeds = (
};
seeds.push(seed);
const generalMeta: Record<string, TriggerValue> = {
const generalMeta: GeneralMeta = {
killturn: DEFAULT_GENERAL_KILLTURN,
npcType,
crewTypeId: defaultCrewTypeId,
};