Files
core2026/packages/logic/src/actionModules/bundle.ts
T

143 lines
5.8 KiB
TypeScript

import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import { compileCrewTypeCatalog } from '@sammo-ts/logic/crewType/catalog.js';
import { createCrewTypeWarTriggerRegistry } from '@sammo-ts/logic/war/crewTypeTriggers.js';
import { createInheritBuffModules } from '@sammo-ts/logic/inheritance/inheritBuff.js';
import {
createItemActionModules,
createItemModuleRegistry,
ITEM_KEYS,
loadItemModules,
type ItemModule,
} from '@sammo-ts/logic/items/index.js';
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import type { GeneralActionModule } from './general.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import { createOfficerLevelActionModules } from './officerLevel.js';
import {
createTraitCatalog,
DOMESTIC_TRAIT_KEYS,
EVENT_DOMESTIC_TRAIT_KEYS,
loadDomesticTraitModules,
loadEventDomesticTraitModules,
loadNationTraitModules,
loadPersonalityTraitModules,
loadWarTraitModules,
NATION_TRAIT_KEYS,
PERSONALITY_TRAIT_KEYS,
TraitGeneralActionRouter,
TraitWarActionRouter,
WAR_TRAIT_KEYS,
} from './traits/index.js';
import type { NationTraitModule } from './traits/nation/index.js';
import { createScenarioEffectActionModules } from './scenarioEffect.js';
import type { ScenarioEffectKey } from '@sammo-ts/logic/scenario/scenarioEffect.js';
export interface ActionModuleBundle<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
general: RefOrderedActionStack<GeneralActionModule<TriggerState>>;
war: RefOrderedActionStack<WarActionModule<TriggerState>>;
itemModules: ItemModule<TriggerState>[];
nationTraitModules: NationTraitModule[];
}
const refActionOrderBrand: unique symbol = Symbol('RefOrderedActionStack');
export type RefOrderedActionStack<Module> = ReadonlyArray<Module> & {
readonly [refActionOrderBrand]: true;
};
interface RefActionSlots<Module> {
nation: Module;
officer: Module;
domestic: Module;
war: Module;
personality: Module;
crewType: Module | null;
inheritance: Module;
scenario: Module | null;
items: readonly Module[];
}
const markRefOrderedActionStack: <Module>(
stack: Module[]
) => asserts stack is Module[] & { readonly [refActionOrderBrand]: true } = (stack) => {
Object.defineProperty(stack, refActionOrderBrand, {
value: true,
enumerable: false,
writable: false,
});
};
// ref General::getActionList()의 소유권 순서를 한 곳에서만 조립합니다.
export const createRefOrderedActionStack = <Module>(slots: RefActionSlots<Module>): RefOrderedActionStack<Module> => {
const stack = [
slots.nation,
slots.officer,
slots.domestic,
slots.war,
slots.personality,
...(slots.crewType ? [slots.crewType] : []),
slots.inheritance,
...(slots.scenario ? [slots.scenario] : []),
...slots.items,
];
markRefOrderedActionStack(stack);
return stack;
};
// General::getActionList와 같은 소유권 순서로 실제 턴과 시뮬레이터의 모듈을 조립한다.
export const loadActionModuleBundle = async <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
unitSet?: UnitSetDefinition,
scenarioEffect?: ScenarioEffectKey | null
): Promise<ActionModuleBundle<TriggerState>> => {
const [domestic, eventDomestic, war, personality, nation, itemModules] = await Promise.all([
loadDomesticTraitModules([...DOMESTIC_TRAIT_KEYS]),
loadEventDomesticTraitModules([...EVENT_DOMESTIC_TRAIT_KEYS]),
loadWarTraitModules([...WAR_TRAIT_KEYS]),
loadPersonalityTraitModules([...PERSONALITY_TRAIT_KEYS]),
loadNationTraitModules([...NATION_TRAIT_KEYS]),
loadItemModules([...ITEM_KEYS]) as Promise<ItemModule<TriggerState>[]>,
]);
const traitCatalog = createTraitCatalog<TriggerState>({
domestic: [...domestic, ...eventDomestic],
war,
personality,
nation,
});
const officer = createOfficerLevelActionModules<TriggerState>();
const items = createItemActionModules(createItemModuleRegistry(itemModules));
const inherit = createInheritBuffModules();
const scenario = createScenarioEffectActionModules<TriggerState>(scenarioEffect);
const crewTypeCatalog = unitSet?.crewTypes?.length
? compileCrewTypeCatalog(unitSet, createCrewTypeWarTriggerRegistry())
: null;
return {
general: createRefOrderedActionStack<GeneralActionModule<TriggerState>>({
nation: new TraitGeneralActionRouter('nation', traitCatalog),
officer: officer.general,
domestic: new TraitGeneralActionRouter('domestic', traitCatalog),
war: new TraitGeneralActionRouter('war', traitCatalog),
personality: new TraitGeneralActionRouter('personality', traitCatalog),
crewType: crewTypeCatalog
? (crewTypeCatalog.generalActionModule as GeneralActionModule<TriggerState>)
: null,
inheritance: inherit.general as GeneralActionModule<TriggerState>,
scenario: scenario.general,
items: items.general,
}),
war: createRefOrderedActionStack<WarActionModule<TriggerState>>({
nation: new TraitWarActionRouter('nation', traitCatalog),
officer: officer.war,
domestic: new TraitWarActionRouter('domestic', traitCatalog),
war: new TraitWarActionRouter('war', traitCatalog),
personality: new TraitWarActionRouter('personality', traitCatalog),
crewType: crewTypeCatalog ? (crewTypeCatalog.warActionModule as WarActionModule<TriggerState>) : null,
inheritance: inherit.war as WarActionModule<TriggerState>,
scenario: scenario.war,
items: items.war,
}),
itemModules,
nationTraitModules: nation,
};
};