import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js'; import { type GeneralActionContext, GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, TriggerDomesticActionType, TriggerDomesticVarType, TriggerNationalIncomeType, TriggerStrategicActionType, TriggerStrategicVarType, } from './types.js'; import { dispatchGeneralActionEventHandlers, type GeneralActionEvent, type GeneralActionEventContext, type GeneralActionEventHandlers, type GeneralActionEventType, } from './events.js'; interface GeneralActionModuleBase { getName?: (() => string) | undefined; getInfo?: (() => string) | undefined; getPreTurnExecuteTriggerList?: ((context: GeneralActionContext) => GeneralTriggerCaller | null) | undefined; onCalcDomestic?: | (( context: GeneralActionContext, turnType: TriggerDomesticActionType, varType: TriggerDomesticVarType, value: number, aux?: unknown ) => number) | undefined; onCalcStat?: | (( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ) => number) | undefined; onCalcOpposeStat?: | (( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ) => number) | undefined; onCalcStrategic?: | (( context: GeneralActionContext, turnType: TriggerStrategicActionType, varType: TriggerStrategicVarType, value: number ) => number) | undefined; onCalcNationalIncome?: | ((context: GeneralActionContext, type: TriggerNationalIncomeType, amount: number) => number) | undefined; } interface GeneralActionLeafModule { eventHandlers?: GeneralActionEventHandlers | undefined; handleEvent?: never; } interface GeneralActionCompositeModule { eventHandlers?: never; handleEvent( context: GeneralActionEventContext, event: GeneralActionEvent ): GeneralActionEvent; } /** * leaf handler와 합성 router는 상호 배타적입니다. 한 module이 같은 이벤트를 * 두 경로로 중복 처리할 수 없습니다. */ export type GeneralActionModule = GeneralActionModuleBase & (GeneralActionLeafModule | GeneralActionCompositeModule); export const dispatchGeneralActionModuleEvent = < TriggerState extends GeneralTriggerState, K extends GeneralActionEventType, >( module: GeneralActionModule, context: GeneralActionEventContext, event: GeneralActionEvent ): GeneralActionEvent => module.handleEvent ? module.handleEvent(context, event) : dispatchGeneralActionEventHandlers(module.eventHandlers, context, event); export class GeneralActionPipeline { private readonly modules: ReadonlyArray>; constructor(modules: ReadonlyArray | null | undefined>) { this.modules = modules.filter(Boolean) as ReadonlyArray>; } getPreTurnExecuteTriggerList(context: GeneralActionContext): GeneralTriggerCaller { const triggerCaller = new GeneralTriggerCaller(); for (const module of this.modules) { const triggers = module.getPreTurnExecuteTriggerList?.(context); if (triggers) { triggerCaller.merge(triggers); } } return triggerCaller; } onCalcDomestic( context: GeneralActionContext, turnType: TriggerDomesticActionType, varType: TriggerDomesticVarType, value: number, aux?: unknown ): number { let current = value; for (const module of this.modules) { if (!module.onCalcDomestic) { continue; } current = module.onCalcDomestic(context, turnType, varType, current, aux); } return current; } onCalcStat( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ): number { let current = value; for (const module of this.modules) { if (!module.onCalcStat) { continue; } current = module.onCalcStat(context, statName, current, aux); } return current; } onCalcOpposeStat( context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown ): number { let current = value; for (const module of this.modules) { if (!module.onCalcOpposeStat) { continue; } current = module.onCalcOpposeStat(context, statName, current, aux); } return current; } onCalcStrategic( context: GeneralActionContext, turnType: TriggerStrategicActionType, varType: TriggerStrategicVarType, value: number ): number { let current = value; for (const module of this.modules) { if (!module.onCalcStrategic) { continue; } current = module.onCalcStrategic(context, turnType, varType, current); } return current; } onCalcNationalIncome( context: GeneralActionContext, type: TriggerNationalIncomeType, amount: number ): number { let current = amount; for (const module of this.modules) { if (!module.onCalcNationalIncome) { continue; } current = module.onCalcNationalIncome(context, type, current); } return current; } dispatch( context: GeneralActionEventContext, event: GeneralActionEvent ): GeneralActionEvent { let current = event; for (const module of this.modules) { current = dispatchGeneralActionModuleEvent(module, context, current); } return current; } }