import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js'; import type { GeneralStatName, TriggerActionPhase, TriggerActionType, TriggerDomesticActionType, TriggerDomesticVarType, TriggerNationalIncomeType, TriggerStrategicActionType, TriggerStrategicVarType, WarStatName, } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; import type { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { TraitKind, TraitModule, TraitModuleRegistry } from './types.js'; const resolveTraitKey = ( context: { general: { role: { personality: string | null; specialDomestic: string | null; specialWar: string | null; }; }; nation?: { typeCode: string } | null; }, kind: TraitKind ): string | null => { if (kind === 'domestic') { return context.general.role.specialDomestic; } if (kind === 'war') { return context.general.role.specialWar; } if (kind === 'nation') { return context.nation?.typeCode ?? null; } return context.general.role.personality; }; const resolveModule = ( registry: TraitModuleRegistry, kind: TraitKind, key: string | null ): TraitModule | null => { if (!key) { return null; } let bucket: Map>; if (kind === 'domestic') { bucket = registry.domestic; } else if (kind === 'war') { bucket = registry.war; } else if (kind === 'nation') { bucket = registry.nation; } else { bucket = registry.personality; } return bucket.get(key) ?? null; }; // General 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터. export class TraitGeneralActionRouter< TriggerState extends GeneralTriggerState = GeneralTriggerState, > implements GeneralActionModule { constructor( private readonly kind: TraitKind, private readonly registry: TraitModuleRegistry ) {} private getModule(context: GeneralActionContext): TraitModule | null { const key = resolveTraitKey(context, this.kind); return resolveModule(this.registry, this.kind, key); } getPreTurnExecuteTriggerList(context: GeneralActionContext) { const module = this.getModule(context); return module?.getPreTurnExecuteTriggerList?.(context) ?? null; } onCalcDomestic( context: GeneralActionContext, turnType: TriggerDomesticActionType, varType: TriggerDomesticVarType, value: number, aux?: unknown ): number { const module = this.getModule(context); return module?.onCalcDomestic?.(context, turnType, varType, value, aux) ?? value; } onCalcStat( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ): number { const module = this.getModule(context); return module?.onCalcStat?.(context, statName, value, aux) ?? value; } onCalcOpposeStat( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ): number { const module = this.getModule(context); return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value; } onCalcStrategic( context: GeneralActionContext, turnType: TriggerStrategicActionType, varType: TriggerStrategicVarType, value: number ): number { const module = this.getModule(context); return module?.onCalcStrategic?.(context, turnType, varType, value) ?? value; } onCalcNationalIncome( context: GeneralActionContext, type: TriggerNationalIncomeType, amount: number ): number { const module = this.getModule(context); return module?.onCalcNationalIncome?.(context, type, amount) ?? amount; } onArbitraryAction( context: GeneralActionContext, actionType: TriggerActionType, phase?: TriggerActionPhase | null, aux?: Record | null ): Record | null { const module = this.getModule(context); const result = module?.onArbitraryAction?.(context, actionType, phase, aux); return result === undefined ? (aux ?? null) : result; } } // 전투 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터. export class TraitWarActionRouter< TriggerState extends GeneralTriggerState = GeneralTriggerState, > implements WarActionModule { constructor( private readonly kind: TraitKind, private readonly registry: TraitModuleRegistry ) {} private getModule(context: WarActionContext): TraitModule | null { const key = resolveTraitKey(context, this.kind); return resolveModule(this.registry, this.kind, key); } getBattleInitTriggerList(context: WarActionContext): WarTriggerCaller | null { const module = this.getModule(context); return module?.getBattleInitTriggerList?.(context) ?? null; } getBattlePhaseTriggerList(context: WarActionContext): WarTriggerCaller | null { const module = this.getModule(context); return module?.getBattlePhaseTriggerList?.(context) ?? null; } onCalcStat( context: WarActionContext, statName: WarStatName, value: number | [number, number], aux?: unknown ): number | [number, number] { const module = this.getModule(context); return module?.onCalcStat?.(context, statName, value, aux) ?? value; } onCalcOpposeStat( context: WarActionContext, statName: WarStatName, value: number | [number, number], aux?: unknown ): number | [number, number] { const module = this.getModule(context); return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value; } getWarPowerMultiplier( context: WarActionContext, unit: WarUnit, oppose: WarUnit ): [number, number] { const module = this.getModule(context); return module?.getWarPowerMultiplier?.(context, unit, oppose) ?? [1, 1]; } } export interface TraitModuleSet { general: GeneralActionModule[]; war: WarActionModule[]; } export const createTraitModuleRegistry = (options: { domestic?: TraitModule[]; war?: TraitModule[]; personality?: TraitModule[]; nation?: TraitModule[]; }): TraitModuleRegistry => { const domestic = new Map>(); const war = new Map>(); const personality = new Map>(); const nation = new Map>(); for (const module of options.domestic ?? []) { domestic.set(module.key, module); } for (const module of options.war ?? []) { war.set(module.key, module); } for (const module of options.personality ?? []) { personality.set(module.key, module); } for (const module of options.nation ?? []) { nation.set(module.key, module); } return { domestic, war, personality, nation }; }; // 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다. export const createTraitModules = ( registry: TraitModuleRegistry ): TraitModuleSet => ({ general: [ new TraitGeneralActionRouter('domestic', registry), new TraitGeneralActionRouter('war', registry), new TraitGeneralActionRouter('personality', registry), new TraitGeneralActionRouter('nation', registry), ], war: [ new TraitWarActionRouter('domestic', registry), new TraitWarActionRouter('war', registry), new TraitWarActionRouter('personality', registry), new TraitWarActionRouter('nation', registry), ], });