import type { RandUtil } from '@sammo-ts/common'; import type { City, General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js'; import type { ActionLogger } from '@sammo-ts/logic/logging/actionLogger.js'; import type { WarStatName } from '@sammo-ts/logic/actionModules/types.js'; import type { WarUnit } from './units.js'; import { WarTriggerCaller } from './triggers.js'; export interface WarActionContext { general: General; nation?: Nation | null; city?: City; log?: ActionLogger; rng?: RandUtil; unit?: WarUnit; } export interface WarActionModule { getName?: (() => string) | undefined; getInfo?: (() => string) | undefined; getBattleInitTriggerList?: ((context: WarActionContext) => WarTriggerCaller | null) | undefined; getBattlePhaseTriggerList?: ((context: WarActionContext) => WarTriggerCaller | null) | undefined; onCalcStat?: | (( context: WarActionContext, statName: WarStatName, value: number | [number, number], aux?: unknown ) => number | [number, number]) | undefined; onCalcOpposeStat?: | (( context: WarActionContext, statName: WarStatName, value: number | [number, number], aux?: unknown ) => number | [number, number]) | undefined; getWarPowerMultiplier?: | (( context: WarActionContext, unit: WarUnit, oppose: WarUnit ) => [number, number]) | undefined; } export class WarActionPipeline { // 전투용 iAction 파이프라인: 스탯/트리거/전투력 보정 흐름을 순서대로 적용한다. private readonly modules: WarActionModule[]; constructor(modules: ReadonlyArray | null | undefined>) { this.modules = modules.filter(Boolean) as WarActionModule[]; } getBattleInitTriggerList(context: WarActionContext): WarTriggerCaller { const caller = new WarTriggerCaller(); for (const module of this.modules) { const triggers = module.getBattleInitTriggerList?.(context); if (triggers) { caller.merge(triggers); } } return caller; } getBattlePhaseTriggerList(context: WarActionContext): WarTriggerCaller { const caller = new WarTriggerCaller(); for (const module of this.modules) { const triggers = module.getBattlePhaseTriggerList?.(context); if (triggers) { caller.merge(triggers); } } return caller; } onCalcStat( context: WarActionContext, statName: WarStatName, value: T, aux?: unknown ): T { let current: number | [number, number] = value; for (const module of this.modules) { if (!module.onCalcStat) { continue; } current = module.onCalcStat(context, statName, current, aux); } return current as T; } onCalcOpposeStat( context: WarActionContext, statName: WarStatName, value: T, aux?: unknown ): T { let current: number | [number, number] = value; for (const module of this.modules) { if (!module.onCalcOpposeStat) { continue; } current = module.onCalcOpposeStat(context, statName, current, aux); } return current as T; } getWarPowerMultiplier( context: WarActionContext, unit: WarUnit, oppose: WarUnit ): [number, number] { let attack = 1; let defence = 1; for (const module of this.modules) { if (!module.getWarPowerMultiplier) { continue; } const [attMul, defMul] = module.getWarPowerMultiplier(context, unit, oppose); attack *= attMul; defence *= defMul; } return [attack, defence]; } }