refactor(logic): replace arbitrary action hooks with typed events

This commit is contained in:
2026-07-30 03:31:31 +00:00
parent 96b41ef4b4
commit 7d3cb50a5b
168 changed files with 1554 additions and 631 deletions
+132
View File
@@ -0,0 +1,132 @@
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,
loadDomesticTraitModules,
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';
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
): Promise<ActionModuleBundle<TriggerState>> => {
const [domestic, war, personality, nation, itemModules] = await Promise.all([
loadDomesticTraitModules([...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, war, personality, nation });
const officer = createOfficerLevelActionModules<TriggerState>();
const items = createItemActionModules(createItemModuleRegistry(itemModules));
const inherit = createInheritBuffModules();
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>,
// scenarioEffect는 현재 core runtime module이 없어 명시적으로 빈 slot입니다.
scenario: null,
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>,
// ref의 scenarioEffect 위치를 보존하되 미이식 module은 별도 gap으로 남깁니다.
scenario: null,
items: items.war,
}),
itemModules,
nationTraitModules: nation,
};
};
@@ -0,0 +1,88 @@
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { RandomGenerator } from '@sammo-ts/common';
const generalActionEventBrand: unique symbol = Symbol('GeneralActionEvent');
export interface GeneralActionEventPayloadMap {
'item.purchased': {
itemKey: string;
slot: 'horse' | 'weapon' | 'book' | 'item';
};
'item.sold': {
itemKey: string;
slot: 'horse' | 'weapon' | 'book' | 'item';
};
'strategy.succeeded': {
consumedItems: readonly string[];
};
'city.conquered': {
attacker: General;
};
}
export type GeneralActionEventType = keyof GeneralActionEventPayloadMap;
export type GeneralActionEventContext<
K extends GeneralActionEventType,
TriggerState extends GeneralTriggerState = GeneralTriggerState,
> = K extends 'item.sold' | 'city.conquered'
? GeneralActionContext<TriggerState> & { rng: RandomGenerator } & (K extends 'item.sold'
? { time: NonNullable<GeneralActionContext<TriggerState>['time']> }
: object)
: GeneralActionContext<TriggerState>;
/**
* 레거시 문자열/phase/aux 삼중항을 닫힌 이벤트 계약으로 투영합니다.
*
* unique-symbol 필드는 런타임 분기용이 아니라 서로 다른 이벤트 payload가
* 구조적으로 우연히 호환되는 것을 막는 nominal shadow type입니다. 이벤트는
* 반드시 createGeneralActionEvent()로 만들며, handler는 같은 K만 반환합니다.
*/
export type GeneralActionEvent<
K extends GeneralActionEventType,
_TriggerState extends GeneralTriggerState = GeneralTriggerState,
> = Readonly<{
type: K;
payload: Readonly<GeneralActionEventPayloadMap[K]>;
[generalActionEventBrand]: K;
}>;
export type GeneralActionEventHandler<TriggerState extends GeneralTriggerState, K extends GeneralActionEventType> = {
bivarianceHack(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> | void;
}['bivarianceHack'];
export type GeneralActionEventHandlers<TriggerState extends GeneralTriggerState = GeneralTriggerState> = Partial<{
[K in GeneralActionEventType]: GeneralActionEventHandler<TriggerState, K>;
}>;
export const createGeneralActionEvent = <
TriggerState extends GeneralTriggerState = GeneralTriggerState,
K extends GeneralActionEventType = GeneralActionEventType,
>(
type: K,
payload: GeneralActionEventPayloadMap[K]
): GeneralActionEvent<K, TriggerState> => ({
type,
payload,
[generalActionEventBrand]: type,
});
export const dispatchGeneralActionEventHandlers = <
TriggerState extends GeneralTriggerState,
K extends GeneralActionEventType,
>(
handlers: GeneralActionEventHandlers<TriggerState> | null | undefined,
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> => {
// Mapped-type lookup preserves K, but TypeScript cannot currently retain
// that correlation through a generic indexed access. This single local
// assertion is the proof boundary; module authors and call sites remain
// fully checked without unknown/any casts.
const handler = handlers?.[event.type] as GeneralActionEventHandler<TriggerState, K> | undefined;
return handler?.(context, event) ?? event;
};
@@ -1,23 +1,27 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import { type GeneralActionContext, GeneralTriggerCaller } from './general.js';
import { type GeneralActionContext, GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js';
import type {
GeneralStatName,
TriggerActionPhase,
TriggerActionType,
TriggerDomesticActionType,
TriggerDomesticVarType,
TriggerNationalIncomeType,
TriggerStrategicActionType,
TriggerStrategicVarType,
} from './types.js';
import {
dispatchGeneralActionEventHandlers,
type GeneralActionEvent,
type GeneralActionEventContext,
type GeneralActionEventHandlers,
type GeneralActionEventType,
} from './events.js';
export interface GeneralActionModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
interface GeneralActionModuleBase<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
getName?: (() => string) | undefined;
getInfo?: (() => string) | undefined;
getPreTurnExecuteTriggerList?:
| ((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null)
| undefined;
((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null) | undefined;
onCalcDomestic?:
| ((
@@ -59,22 +63,46 @@ export interface GeneralActionModule<TriggerState extends GeneralTriggerState =
onCalcNationalIncome?:
| ((context: GeneralActionContext<TriggerState>, type: TriggerNationalIncomeType, amount: number) => number)
| undefined;
onArbitraryAction?:
| ((
context: GeneralActionContext<TriggerState>,
actionType: TriggerActionType,
phase?: TriggerActionPhase | null,
aux?: Record<string, unknown> | null
) => Record<string, unknown> | null)
| undefined;
}
export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
private readonly modules: GeneralActionModule<TriggerState>[];
interface GeneralActionLeafModule<TriggerState extends GeneralTriggerState> {
eventHandlers?: GeneralActionEventHandlers<TriggerState> | undefined;
handleEvent?: never;
}
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
this.modules = modules.filter(Boolean) as GeneralActionModule<TriggerState>[];
interface GeneralActionCompositeModule<TriggerState extends GeneralTriggerState> {
eventHandlers?: never;
handleEvent<K extends GeneralActionEventType>(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState>;
}
/**
* leaf handler와 router는 . module이
* .
*/
export type GeneralActionModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> =
GeneralActionModuleBase<TriggerState> &
(GeneralActionLeafModule<TriggerState> | GeneralActionCompositeModule<TriggerState>);
export const dispatchGeneralActionModuleEvent = <
TriggerState extends GeneralTriggerState,
K extends GeneralActionEventType,
>(
module: GeneralActionModule<TriggerState>,
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> =>
module.handleEvent
? module.handleEvent(context, event)
: dispatchGeneralActionEventHandlers(module.eventHandlers, context, event);
export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
private readonly modules: ReadonlyArray<GeneralActionModule<TriggerState>>;
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
this.modules = modules.filter(Boolean) as ReadonlyArray<GeneralActionModule<TriggerState>>;
}
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>): GeneralTriggerCaller<TriggerState> {
@@ -170,21 +198,13 @@ export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = Ge
return current;
}
onArbitraryAction(
context: GeneralActionContext<TriggerState>,
actionType: TriggerActionType,
phase?: TriggerActionPhase | null,
aux?: Record<string, unknown> | null
): Record<string, unknown> | null {
let current = aux ?? null;
dispatch<K extends GeneralActionEventType>(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> {
let current = event;
for (const module of this.modules) {
if (!module.onArbitraryAction) {
continue;
}
const result = module.onArbitraryAction(context, actionType, phase, current);
if (result !== undefined) {
current = result;
}
current = dispatchGeneralActionModuleEvent(module, context, current);
}
return current;
}
@@ -0,0 +1,6 @@
export * from './events.js';
export * from './general.js';
export * from './types.js';
export * from './officerLevel.js';
export * from './bundle.js';
export * from './traits/index.js';
@@ -1,6 +1,6 @@
import { asRecord } from '@sammo-ts/common';
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionModule } from './general-action.js';
import type { GeneralActionModule } from './general.js';
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
const resolveOfficerLevel = (context: {
@@ -65,9 +65,7 @@ const officerWarModule: WarActionModule = {
},
};
export const createOfficerLevelActionModules = <
TriggerState extends GeneralTriggerState = GeneralTriggerState,
>(): {
export const createOfficerLevelActionModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(): {
general: GeneralActionModule<TriggerState>;
war: WarActionModule<TriggerState>;
} => ({
@@ -1,21 +1,24 @@
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 { dispatchGeneralActionModuleEvent, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import {
type GeneralActionEvent,
type GeneralActionEventContext,
type GeneralActionEventType,
} from '@sammo-ts/logic/actionModules/events.js';
import type {
GeneralStatName,
TriggerActionPhase,
TriggerActionType,
TriggerDomesticActionType,
TriggerDomesticVarType,
TriggerNationalIncomeType,
TriggerStrategicActionType,
TriggerStrategicVarType,
WarStatName,
} from '@sammo-ts/logic/triggers/types.js';
} from '@sammo-ts/logic/actionModules/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';
import type { TraitCatalog, TraitKind, TraitModule } from './types.js';
const resolveTraitKey = (
context: {
@@ -43,7 +46,7 @@ const resolveTraitKey = (
};
const resolveModule = <TriggerState extends GeneralTriggerState>(
registry: TraitModuleRegistry<TriggerState>,
catalog: TraitCatalog<TriggerState>,
kind: TraitKind,
key: string | null
): TraitModule<TriggerState> | null => {
@@ -52,29 +55,27 @@ const resolveModule = <TriggerState extends GeneralTriggerState>(
}
let bucket: Map<string, TraitModule<TriggerState>>;
if (kind === 'domestic') {
bucket = registry.domestic;
bucket = catalog.domestic;
} else if (kind === 'war') {
bucket = registry.war;
bucket = catalog.war;
} else if (kind === 'nation') {
bucket = registry.nation;
bucket = catalog.nation;
} else {
bucket = registry.personality;
bucket = catalog.personality;
}
return bucket.get(key) ?? null;
};
// General 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터.
export class TraitGeneralActionRouter<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
> implements GeneralActionModule<TriggerState> {
export class TraitGeneralActionRouter<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry<TriggerState>
private readonly catalog: TraitCatalog<TriggerState>
) {}
private getModule(context: GeneralActionContext<TriggerState>): TraitModule<TriggerState> | null {
const key = resolveTraitKey(context, this.kind);
return resolveModule(this.registry, this.kind, key);
return resolveModule(this.catalog, this.kind, key);
}
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>) {
@@ -132,15 +133,15 @@ export class TraitGeneralActionRouter<
return module?.onCalcNationalIncome?.(context, type, amount) ?? amount;
}
onArbitraryAction(
context: GeneralActionContext<TriggerState>,
actionType: TriggerActionType,
phase?: TriggerActionPhase | null,
aux?: Record<string, unknown> | null
): Record<string, unknown> | null {
handleEvent<K extends GeneralActionEventType>(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> {
const module = this.getModule(context);
const result = module?.onArbitraryAction?.(context, actionType, phase, aux);
return result === undefined ? (aux ?? null) : result;
if (!module) {
return event;
}
return dispatchGeneralActionModuleEvent(module, context, event);
}
}
@@ -150,12 +151,12 @@ export class TraitWarActionRouter<
> implements WarActionModule<TriggerState> {
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry<TriggerState>
private readonly catalog: TraitCatalog<TriggerState>
) {}
private getModule(context: WarActionContext<TriggerState>): TraitModule<TriggerState> | null {
const key = resolveTraitKey(context, this.kind);
return resolveModule(this.registry, this.kind, key);
return resolveModule(this.catalog, this.kind, key);
}
getBattleInitTriggerList(context: WarActionContext<TriggerState>): WarTriggerCaller | null {
@@ -199,32 +200,46 @@ export class TraitWarActionRouter<
}
export interface TraitModuleSet<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
general: GeneralActionModule<TriggerState>[];
general: ReadonlyArray<GeneralActionModule<TriggerState>>;
war: WarActionModule<TriggerState>[];
}
export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(options: {
export const createTraitCatalog = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(options: {
domestic?: TraitModule<TriggerState>[];
war?: TraitModule<TriggerState>[];
personality?: TraitModule<TriggerState>[];
nation?: TraitModule<TriggerState>[];
}): TraitModuleRegistry<TriggerState> => {
}): TraitCatalog<TriggerState> => {
const domestic = new Map<string, TraitModule<TriggerState>>();
const war = new Map<string, TraitModule<TriggerState>>();
const personality = new Map<string, TraitModule<TriggerState>>();
const nation = new Map<string, TraitModule<TriggerState>>();
const insert = (
bucket: Map<string, TraitModule<TriggerState>>,
kind: TraitKind,
module: TraitModule<TriggerState>
): void => {
if (module.kind !== kind) {
throw new Error(`Trait ${module.key} declared kind ${module.kind}, expected ${kind}`);
}
if (bucket.has(module.key)) {
throw new Error(`Duplicate ${kind} trait key: ${module.key}`);
}
bucket.set(module.key, module);
};
for (const module of options.domestic ?? []) {
domestic.set(module.key, module);
insert(domestic, 'domestic', module);
}
for (const module of options.war ?? []) {
war.set(module.key, module);
insert(war, 'war', module);
}
for (const module of options.personality ?? []) {
personality.set(module.key, module);
insert(personality, 'personality', module);
}
for (const module of options.nation ?? []) {
nation.set(module.key, module);
insert(nation, 'nation', module);
}
return { domestic, war, personality, nation };
@@ -232,18 +247,18 @@ export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerSta
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
export const createTraitModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
registry: TraitModuleRegistry<TriggerState>
catalog: TraitCatalog<TriggerState>
): TraitModuleSet<TriggerState> => ({
general: [
new TraitGeneralActionRouter<TriggerState>('domestic', registry),
new TraitGeneralActionRouter<TriggerState>('war', registry),
new TraitGeneralActionRouter<TriggerState>('personality', registry),
new TraitGeneralActionRouter<TriggerState>('nation', registry),
new TraitGeneralActionRouter<TriggerState>('domestic', catalog),
new TraitGeneralActionRouter<TriggerState>('war', catalog),
new TraitGeneralActionRouter<TriggerState>('personality', catalog),
new TraitGeneralActionRouter<TriggerState>('nation', catalog),
],
war: [
new TraitWarActionRouter<TriggerState>('domestic', registry),
new TraitWarActionRouter<TriggerState>('war', registry),
new TraitWarActionRouter<TriggerState>('personality', registry),
new TraitWarActionRouter<TriggerState>('nation', registry),
new TraitWarActionRouter<TriggerState>('domestic', catalog),
new TraitWarActionRouter<TriggerState>('war', catalog),
new TraitWarActionRouter<TriggerState>('personality', catalog),
new TraitWarActionRouter<TriggerState>('nation', catalog),
],
});
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 경작
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 귀모
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 발명
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 상재
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 수비
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 인덕
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 축성
export const traitModule: TraitModule = {
@@ -1,5 +1,5 @@
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 내정 특기: 통찰
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
export const DOMESTIC_TRAIT_KEYS = [
'che_인덕',
@@ -1,7 +1,7 @@
export * from './types.js';
export * from './requirements.js';
export * from './selector.js';
export * from './registry.js';
export * from './catalog.js';
export * from './domestic/index.js';
export * from './war/index.js';
export * from './personality/index.js';
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 덕가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 도가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 도적
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 명가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 묵가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 법가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 병가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 불가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 오두미도
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 유가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 음양가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 종횡가
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 중립
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
// 국가 성향: 태평도
export const traitModule: TraitModule = {
@@ -1,4 +1,4 @@
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
export const NATION_TRAIT_KEYS = [
'che_중립',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_대의',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_안전',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_왕좌',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_유지',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_은둔',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_의협',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_재간',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_정복',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_출세',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_패권',
@@ -1,7 +1,7 @@
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
export const traitModule: TraitModule = {
key: 'che_할거',
@@ -1,4 +1,4 @@
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
export const PERSONALITY_TRAIT_KEYS = [
'che_안전',
@@ -1,5 +1,5 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import type { TraitSelection } from './requirements.js';
@@ -21,7 +21,7 @@ export interface TraitModuleExport<TriggerState extends GeneralTriggerState = Ge
traitModule: TraitModule<TriggerState>;
}
export interface TraitModuleRegistry<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
export interface TraitCatalog<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
domestic: Map<string, TraitModule<TriggerState>>;
war: Map<string, TraitModule<TriggerState>>;
personality: Map<string, TraitModule<TriggerState>>;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_격노발동, che_격노시도 } from '@sammo-ts/logic/war/triggers/che_격노.js';
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_부상무효 } from '@sammo-ts/logic/war/triggers/che_견고.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { WarUnitCity } from '@sammo-ts/logic/war/units.js';
import { getAuxArmType, parseWarDexAux } from './aux.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { getAuxArmType, parseWarDexAux } from './aux.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { getAuxArmType, parseWarDexAux } from './aux.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { getAuxArmType, parseWarDexAux } from './aux.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_돌격지속 } from '@sammo-ts/logic/war/triggers/che_돌격.js';
@@ -1,8 +1,8 @@
import type { TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
@@ -53,11 +53,7 @@ export const traitModule: TraitModule = {
// Note: unit.getGeneral() is only available for WarUnitGeneral.
// In a real scenario, we should check if unit is WarUnitGeneral.
if (hasGeneral(unit)) {
const killnum = getMetaNumber(
unit.getGeneral().meta as Record<string, TriggerValue>,
'rank_killnum',
0
);
const killnum = getMetaNumber(unit.getGeneral().meta as Record<string, TriggerValue>, 'rank_killnum', 0);
const logVal = Math.log2(Math.max(1, killnum / 5));
attackMultiplier += logVal / 20;
defenceMultiplier -= logVal / 50;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_반계발동, che_반계시도 } from '@sammo-ts/logic/war/triggers/che_반계.js';
@@ -1,8 +1,8 @@
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { getAuxArmType, parseWarDexAux } from './aux.js';
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_위압발동, che_위압시도 } from '@sammo-ts/logic/war/triggers/che_위압.js';
@@ -2,7 +2,7 @@ import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js';
import { triggerModule as cheUisulTriggerModule } from '@sammo-ts/logic/war/triggers/che_의술.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
// 전투 특기: 의술
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_저격발동, che_저격시도 } from '@sammo-ts/logic/war/triggers/che_저격.js';
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
const RECRUIT_TRAIN = 70;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_필살강화_회피불가 } from '@sammo-ts/logic/war/triggers/che_필살.js';
@@ -1,7 +1,7 @@
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
import { TraitRequirement, TraitWeightType } from '../requirements.js';
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
@@ -1,4 +1,4 @@
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
export const WAR_TRAIT_KEYS = [
'che_귀병',
@@ -1,7 +1,3 @@
export type TriggerActionType = '장비매매' | 'GeneralCommand';
export type TriggerActionPhase = '판매' | '구매';
export type TriggerDomesticActionType =
| '상업'
| '농업'
@@ -22,6 +22,11 @@ export type ActionContextBase = {
worldView?: GeneralWorldView;
rng: ActionRandomSource;
uniqueLottery?: UniqueLotteryRunner;
time?: {
year: number;
month: number;
startYear: number;
};
};
export type ActionResolveContext = ActionContextBase & Record<string, unknown>;
@@ -1,7 +1,8 @@
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import type { NationTraitModule } from '@sammo-ts/logic/triggers/special/nation/index.js';
import type { NationTraitModule } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
import type { RefOrderedActionStack } from '@sammo-ts/logic/actionModules/bundle.js';
export interface TurnCommandItemCatalogEntry {
slot: 'horse' | 'weapon' | 'book' | 'item';
@@ -56,7 +57,7 @@ export interface TurnCommandEnv {
npcSeizureMessageProb?: number;
maxResourceActionAmount: number;
itemCatalog?: Record<string, TurnCommandItemCatalogEntry>;
generalActionModules?: Array<GeneralActionModule>;
warActionModules?: Array<WarActionModule>;
generalActionModules?: RefOrderedActionStack<GeneralActionModule>;
warActionModules?: RefOrderedActionStack<WarActionModule>;
nationTraitModules?: Array<NationTraitModule>;
}
@@ -8,7 +8,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { DOMESTIC_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/domestic/index.js';
import { DOMESTIC_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/domestic/index.js';
export interface ResetSpecialDomesticArgs {}
@@ -6,7 +6,7 @@ import {
} from './che_징병.js';
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
import type { GeneralTurnCommandSpec } from './index.js';
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
export class ActionDefinition<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
@@ -14,7 +14,7 @@ export class ActionDefinition<
public override readonly key = 'che_모병';
public override readonly name = '모병';
constructor(modules: GeneralActionModule<TriggerState>[]) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState>>) {
super(modules, {
actionName: '모병',
costOffset: 2,
@@ -1,7 +1,7 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import { notBeNeutral, notWanderingNation, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionOutcome,
@@ -31,7 +31,7 @@ export class ActionResolver<
readonly key = ACTION_KEY;
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
this.pipeline = new GeneralActionPipeline(modules);
}
@@ -186,7 +186,7 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
this.resolver = new ActionResolver(modules);
}
@@ -16,7 +16,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { clamp } from 'es-toolkit';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
export interface BoostMoraleArgs {}
@@ -11,8 +11,8 @@ import {
reqGeneralRice,
suppliedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type { TriggerDomesticActionType } from '@sammo-ts/logic/triggers/types.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { TriggerDomesticActionType } from '@sammo-ts/logic/actionModules/types.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionOutcome,
@@ -168,7 +168,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly config: InvestmentConfig;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: InvestmentEnvironment,
config: InvestmentConfig = DEFAULT_CONFIG
) {
@@ -324,7 +324,7 @@ export class ActionResolver<
private readonly config: InvestmentConfig;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: InvestmentEnvironment,
config: InvestmentConfig = DEFAULT_CONFIG
) {
@@ -398,7 +398,7 @@ export class ActionDefinition<
private readonly config: InvestmentConfig;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: InvestmentEnvironment,
config: InvestmentConfig = DEFAULT_CONFIG
) {
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
import type { GeneralTurnCommandSpec } from './index.js';
import { JosaUtil } from '@sammo-ts/common';
import { parseArgsWithSchema } from '../parseArgs.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
import {
buildStrategyActionContext,
@@ -6,7 +6,7 @@ import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-t
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
export interface DisbandArgs {}
@@ -9,7 +9,7 @@ import type {
} 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';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionOutcome,
@@ -175,12 +175,11 @@ const legacyChoiceIndex = (rng: RandomGenerator, length: number): number => {
throw new Error('Empty items');
}
const inclusive = rng as InclusiveRandomGenerator;
return inclusive.nextIntInclusive
? inclusive.nextIntInclusive(length - 1)
: rng.nextInt(0, length);
return inclusive.nextIntInclusive ? inclusive.nextIntInclusive(length - 1) : rng.nextInt(0, length);
};
const legacyChoice = <T>(rng: RandomGenerator, values: readonly T[]): T => values[legacyChoiceIndex(rng, values.length)]!;
const legacyChoice = <T>(rng: RandomGenerator, values: readonly T[]): T =>
values[legacyChoiceIndex(rng, values.length)]!;
const resolveCandidate = (
context: TalentScoutResolveContext,
@@ -239,7 +238,10 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
private readonly env: TalentScoutEnvironment;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: TalentScoutEnvironment
) {
this.pipeline = new GeneralActionPipeline(modules);
this.env = env;
}
@@ -269,7 +271,10 @@ export class ActionResolver<
private readonly env: TalentScoutEnvironment;
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: TalentScoutEnvironment
) {
this.env = env;
this.command = new CommandResolver(modules, env);
}
@@ -353,20 +358,19 @@ export class ActionResolver<
let dex: [number, number, number, number, number];
if (pickType === '무') {
const distributions = [
[dexTotal * 5 / 8, dexTotal / 8, dexTotal / 8, dexTotal / 8],
[dexTotal / 8, dexTotal * 5 / 8, dexTotal / 8, dexTotal / 8],
[dexTotal / 8, dexTotal / 8, dexTotal * 5 / 8, dexTotal / 8],
[(dexTotal * 5) / 8, dexTotal / 8, dexTotal / 8, dexTotal / 8],
[dexTotal / 8, (dexTotal * 5) / 8, dexTotal / 8, dexTotal / 8],
[dexTotal / 8, dexTotal / 8, (dexTotal * 5) / 8, dexTotal / 8],
] as const;
const picked = legacyChoice(context.rng, distributions);
dex = [picked[0], picked[1], picked[2], picked[3], averageDex[4]];
} else if (pickType === '지') {
dex = [dexTotal / 8, dexTotal / 8, dexTotal / 8, dexTotal * 5 / 8, averageDex[4]];
dex = [dexTotal / 8, dexTotal / 8, dexTotal / 8, (dexTotal * 5) / 8, averageDex[4]];
} else {
dex = [dexTotal / 4, dexTotal / 4, dexTotal / 4, dexTotal / 4, averageDex[4]];
}
const personality =
resolvedCandidate.personality ??
legacyChoice(context.rng, this.env.availablePersonalities ?? ['che_안전']);
resolvedCandidate.personality ?? legacyChoice(context.rng, this.env.availablePersonalities ?? ['che_안전']);
const name = this.env.decorateName
? this.env.decorateName(resolvedCandidate.name, NPC_TYPE)
: `${resolvedCandidate.name}`;
@@ -374,10 +378,7 @@ export class ActionResolver<
const turnSecond = randomRangeInt(context.rng, 0, context.turnTermMinutes * 60 - 1);
const turnFraction = randomRangeInt(context.rng, 0, 999_999);
const killturn =
(deathYear - context.currentYear) * 12 +
randomRangeInt(context.rng, 0, 11) +
context.currentMonth -
1;
(deathYear - context.currentYear) * 12 + randomRangeInt(context.rng, 0, 11) + context.currentMonth - 1;
const meta: GeneralMeta = {
killturn,
npcType: NPC_TYPE,
@@ -461,7 +462,10 @@ export class ActionDefinition<
private readonly command: CommandResolver<TriggerState>;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: TalentScoutEnvironment
) {
this.command = new CommandResolver(modules, env);
this.resolver = new ActionResolver(modules, env);
}
@@ -517,6 +521,5 @@ export const commandSpec: GeneralTurnCommandSpec = {
category: '인사',
reqArg: false,
createDefinition: (env: TurnCommandEnv) =>
new ActionDefinition(env.generalActionModules ?? [], env),
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], env),
};
@@ -8,8 +8,12 @@ import {
reqGeneralRice,
} from '@sammo-ts/logic/constraints/presets.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
import { createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
import type {
GeneralActionEffect,
GeneralActionOutcome,
GeneralActionResolveContext,
} from '@sammo-ts/logic/actions/engine.js';
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
import { JosaUtil } from '@sammo-ts/common';
import { z } from 'zod';
@@ -19,6 +23,8 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
import type { GeneralTurnCommandSpec } from './index.js';
import { parseArgsWithSchema } from '../parseArgs.js';
import { equipNewItem, removeEquippedItem } from '@sammo-ts/logic/items/inventory.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
import { createGeneralActionEvent } from '@sammo-ts/logic/actionModules/events.js';
const ACTION_NAME = '장비매매';
const ACTION_KEY = 'che_장비매매';
@@ -54,8 +60,11 @@ export class ActionDefinition<
> implements GeneralActionDefinition<TriggerState, TradeItemArgs> {
public readonly key = ACTION_KEY;
public readonly name = ACTION_NAME;
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(private readonly env: TurnCommandEnv) {}
constructor(private readonly env: TurnCommandEnv) {
this.pipeline = new GeneralActionPipeline(env.generalActionModules ?? []);
}
parseArgs(raw: unknown): TradeItemArgs | null {
const args = parseArgsWithSchema(ARGS_SCHEMA, raw);
@@ -144,6 +153,7 @@ export class ActionDefinition<
): GeneralActionOutcome<TriggerState> {
const general = context.general;
const nation = context.nation;
const nationResourcesBeforeEvent = nation ? { gold: nation.gold, rice: nation.rice } : null;
const itemType = args.itemType;
const requestedItemCode = args.itemCode;
@@ -162,14 +172,6 @@ export class ActionDefinition<
const josaUl = JosaUtil.pick(itemRawName, '을');
const nextGold = buying ? Math.max(0, general.gold - itemCost) : general.gold + Math.floor(itemCost / 2);
if (buying) {
equipNewItem(general, itemType, finalItemCode, {
...(item?.initialCharges === undefined ? {} : { charges: item.initialCharges }),
});
} else {
removeEquippedItem(general, itemType);
}
if (buying) {
context.addLog(`<C>${itemName}</>${josaUl} 구입했습니다.`, {
scope: LogScope.GENERAL,
@@ -184,6 +186,43 @@ export class ActionDefinition<
});
}
general.gold = nextGold;
if (buying) {
equipNewItem(general, itemType, finalItemCode, {
...(item?.initialCharges === undefined ? {} : { charges: item.initialCharges }),
});
}
const eventLog = {
push: (message: string) =>
context.addLog(message, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
}),
};
if (buying) {
this.pipeline.dispatch(
{ ...context, log: eventLog },
createGeneralActionEvent<TriggerState, 'item.purchased'>('item.purchased', {
itemKey: finalItemCode,
slot: itemType,
})
);
} else {
if (!context.time) {
throw new Error('장비 판매 이벤트에는 현재 연도와 시나리오 시작 연도가 필요합니다.');
}
this.pipeline.dispatch(
{ ...context, time: context.time, log: eventLog },
createGeneralActionEvent<TriggerState, 'item.sold'>('item.sold', {
itemKey: finalItemCode,
slot: itemType,
})
);
removeEquippedItem(general, itemType);
}
if (!buying && item && !item.buyable && nation) {
const josaYi = JosaUtil.pick(general.name, '이');
context.addLog(`<Y>${general.name}</>${josaYi} <C>${itemName}</>${josaUl} 판매했습니다!`, {
@@ -201,13 +240,31 @@ export class ActionDefinition<
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
const effects: Array<GeneralActionEffect<TriggerState>> = [
createGeneralPatchEffect<TriggerState>({
gold: general.gold,
rice: general.rice,
experience: general.experience + 10,
}),
];
if (
nation &&
nationResourcesBeforeEvent &&
(nation.gold !== nationResourcesBeforeEvent.gold || nation.rice !== nationResourcesBeforeEvent.rice)
) {
effects.push(
createNationPatchEffect(
{
gold: nation.gold,
rice: nation.rice,
},
nation.id
)
);
}
return {
effects: [
createGeneralPatchEffect<TriggerState>({
gold: nextGold,
experience: general.experience + 10,
}),
],
effects,
};
}
}
@@ -8,7 +8,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
import { WAR_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/war/index.js';
import { WAR_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/war/index.js';
export interface ResetSpecialWarArgs {}
@@ -9,7 +9,7 @@ import {
reqGeneralGold,
reqGeneralRice,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionOutcome,
@@ -217,7 +217,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
private readonly env: RecruitEnvironment;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
this.pipeline = new GeneralActionPipeline(modules);
this.env = env;
}
@@ -331,7 +331,7 @@ export class ActionResolver<
private readonly env: RecruitEnvironment;
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
this.env = env;
this.command = new CommandResolver(modules, env);
}
@@ -444,7 +444,7 @@ export class ActionDefinition<
private readonly resolver: ActionResolver<TriggerState>;
private readonly env: RecruitEnvironment;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
this.command = new CommandResolver(modules, env);
this.resolver = new ActionResolver(modules, env);
this.env = env;
@@ -31,7 +31,8 @@ import type { WarAftermathConfig, WarEngineConfig, WarTimeContext } from '@sammo
import { resolveWarAftermath } from '@sammo-ts/logic/war/aftermath.js';
import { resolveWarBattle } from '@sammo-ts/logic/war/engine.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import type { NationTraitModule } from '@sammo-ts/logic/triggers/special/nation/index.js';
import type { NationTraitModule } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import { increaseMetaNumber, simpleSerialize } from '@sammo-ts/logic/war/utils.js';
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
@@ -163,9 +164,7 @@ const pickCandidateCity = (
const legacyCompatibleRng = rng as typeof rng & {
nextIntInclusive?: (maxInclusive: number) => number;
};
const index =
legacyCompatibleRng.nextIntInclusive?.(items.length - 1) ??
rng.nextInt(0, items.length);
const index = legacyCompatibleRng.nextIntInclusive?.(items.length - 1) ?? rng.nextInt(0, items.length);
return items[index]!;
};
const distances = Array.from(distanceList.keys()).sort((a, b) => a - b);
@@ -255,15 +254,18 @@ export class ActionDefinition<
getInheritanceActiveActionAmount(): number {
return 1;
}
private readonly warModules: Array<WarActionModule<TriggerState>>;
private readonly warModules: ReadonlyArray<WarActionModule<TriggerState>>;
private readonly nationTraitModules: Map<string, NationTraitModule>;
private readonly generalModules: ReadonlyArray<GeneralActionModule<TriggerState>>;
constructor(
modules: Array<WarActionModule<TriggerState> | null | undefined> = [],
nationTraitModules: NationTraitModule[] = []
modules: ReadonlyArray<WarActionModule<TriggerState> | null | undefined> = [],
nationTraitModules: NationTraitModule[] = [],
generalModules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined> = []
) {
this.warModules = modules.filter(Boolean) as Array<WarActionModule<TriggerState>>;
this.warModules = modules.filter(Boolean) as ReadonlyArray<WarActionModule<TriggerState>>;
this.nationTraitModules = new Map(nationTraitModules.map((module) => [module.key, module]));
this.generalModules = generalModules.filter(Boolean) as ReadonlyArray<GeneralActionModule<TriggerState>>;
}
parseArgs(raw: unknown): DispatchArgs | null {
@@ -474,15 +476,12 @@ export class ActionDefinition<
config: context.aftermathConfig,
time,
hiddenSeed: context.seedBase,
generalActionModules: this.generalModules,
calcNationTechGain: ({ nation, baseGain }) => {
const module = this.nationTraitModules.get(nation.typeCode);
return (
module?.onCalcDomestic?.(
{ general: context.general, nation },
'기술',
'score',
baseGain
) ?? baseGain
module?.onCalcDomestic?.({ general: context.general, nation }, '기술', 'score', baseGain) ??
baseGain
);
},
});
@@ -601,5 +600,5 @@ export const commandSpec: GeneralTurnCommandSpec = {
availabilityArgs: { destCityId: 0 },
argsSchema: ARGS_SCHEMA,
createDefinition: (env: TurnCommandEnv) =>
new ActionDefinition(env.warActionModules ?? [], env.nationTraitModules ?? []),
new ActionDefinition(env.warActionModules ?? [], env.nationTraitModules ?? [], env.generalActionModules ?? []),
};
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
import type { GeneralTurnCommandSpec } from './index.js';
import { JosaUtil } from '@sammo-ts/common';
import { parseArgsWithSchema } from '../parseArgs.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
import {
buildStrategyActionContext,
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
import type { GeneralTurnCommandSpec } from './index.js';
import { JosaUtil } from '@sammo-ts/common';
import { parseArgsWithSchema } from '../parseArgs.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
import {
buildStrategyActionContext,
@@ -12,7 +12,7 @@ import {
suppliedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -125,7 +125,10 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly env: FireAttackEnvironment;
private readonly statKey: 'leadership' | 'strength' | 'intelligence';
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: FireAttackEnvironment
) {
this.pipeline = new GeneralActionPipeline(modules);
this.env = env;
this.statKey = env.statKey ?? 'intelligence';
@@ -287,7 +290,10 @@ export class ActionResolver<
private readonly command: CommandResolver<TriggerState>;
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: FireAttackEnvironment
) {
this.command = new CommandResolver(modules, env);
this.pipeline = new GeneralActionPipeline(modules);
}
@@ -376,8 +382,7 @@ export class ActionResolver<
);
const itemCode = general.role.items.item;
const actionResult = consumeSuccessfulStrategyItem(this.pipeline, context);
const consumedItems = Array.isArray(actionResult?.['consumedItems']) ? actionResult['consumedItems'] : [];
const consumedItems = consumeSuccessfulStrategyItem(this.pipeline, context);
if (typeof itemCode === 'string' && consumedItems.includes(itemCode)) {
context.addLog(`<C>${itemCode}</>${JosaUtil.pick(itemCode, '을')} 사용!`, {
format: LogFormat.PLAIN,
@@ -405,7 +410,10 @@ export class ActionDefinition<
private readonly command: CommandResolver<TriggerState>;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: FireAttackEnvironment
) {
this.command = new CommandResolver(modules, env);
this.resolver = new ActionResolver(modules, env);
}
@@ -15,7 +15,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
const ACTION_NAME = '맹훈련';
const ACTION_KEY = 'cr_맹훈련';
@@ -1,4 +1,4 @@
import { NATION_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/nation/index.js';
import { NATION_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
import { getLegacyStringWidth } from '@sammo-ts/logic/troop/management.js';
import { z } from 'zod';
@@ -1,12 +1,15 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
import type { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
import type { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
import { createGeneralActionEvent } from '@sammo-ts/logic/actionModules/events.js';
export const consumeSuccessfulStrategyItem = <TriggerState extends GeneralTriggerState>(
pipeline: GeneralActionPipeline<TriggerState>,
context: GeneralActionResolveContext<TriggerState>
): Record<string, unknown> | null =>
pipeline.onArbitraryAction(context, 'GeneralCommand', null, {
command: '계략',
success: true,
});
): readonly string[] =>
pipeline.dispatch(
context,
createGeneralActionEvent<TriggerState, 'strategy.succeeded'>('strategy.succeeded', {
consumedItems: [],
})
).payload.consumedItems;
@@ -7,7 +7,7 @@ import {
existsDestNation,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -51,7 +51,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -75,7 +75,10 @@ export class ActionResolver<
readonly key = 'che_급습';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -177,7 +180,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -6,7 +6,7 @@ import {
occupiedCity,
occupiedDestCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -46,7 +46,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -70,7 +70,10 @@ export class ActionResolver<
readonly key = 'che_백성동원';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -154,7 +157,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -8,7 +8,7 @@ import {
notOccupiedDestCity,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -56,7 +56,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -86,7 +86,10 @@ export class ActionResolver<
readonly key = 'che_수몰';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -194,7 +197,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -14,7 +14,7 @@ import {
notOpeningPart,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -238,7 +238,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly env: VolunteerRecruitEnvironment;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: VolunteerRecruitEnvironment
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -272,7 +272,7 @@ export class ActionResolver<
private readonly command: CommandResolver<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: VolunteerRecruitEnvironment
) {
this.env = env;
@@ -461,7 +461,7 @@ export class ActionDefinition<
private readonly env: VolunteerRecruitEnvironment;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
env: VolunteerRecruitEnvironment
) {
this.env = env;
@@ -7,7 +7,7 @@ import {
existsDestNation,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -52,7 +52,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -76,7 +76,10 @@ export class ActionResolver<
readonly key = 'che_이호경식';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -184,7 +187,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -8,7 +8,7 @@ import {
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { allow, unknownOrDeny } from '@sammo-ts/logic/constraints/helpers.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -123,7 +123,7 @@ export class ActionResolver<
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined> = [],
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined> = [],
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -263,7 +263,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined> = [], initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined> = [],
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -6,7 +6,7 @@ import {
beChief,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -41,7 +41,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -65,7 +65,10 @@ export class ActionResolver<
readonly key = 'che_필사즉생';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -155,7 +158,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
@@ -8,7 +8,7 @@ import {
notOccupiedDestCity,
occupiedCity,
} from '@sammo-ts/logic/constraints/presets.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
GeneralActionEffect,
@@ -72,7 +72,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
private readonly pipeline: GeneralActionPipeline<TriggerState>;
constructor(
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
private readonly initialNationGenLimit = 10
) {
this.pipeline = new GeneralActionPipeline(modules);
@@ -96,7 +96,10 @@ export class ActionResolver<
readonly key = 'che_허보';
private readonly command: CommandResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.command = new CommandResolver(modules, initialNationGenLimit);
}
@@ -195,7 +198,10 @@ export class ActionDefinition<
public readonly name = ACTION_NAME;
private readonly resolver: ActionResolver<TriggerState>;
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
constructor(
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
initialNationGenLimit = 10
) {
this.resolver = new ActionResolver(modules, initialNationGenLimit);
}
+17 -8
View File
@@ -1,7 +1,12 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import { dispatchGeneralActionModuleEvent, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import {
type GeneralActionEvent,
type GeneralActionEventContext,
type GeneralActionEventType,
} from '@sammo-ts/logic/actionModules/events.js';
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
import { WarTriggerCaller, type WarTriggerRegistry } from '@sammo-ts/logic/war/triggers.js';
import type { CrewTypeDefinition, CrewTypeRequirement, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
@@ -109,6 +114,16 @@ const createGeneralActionRouter = <TriggerState extends GeneralTriggerState>(
(byId.get(context.general.crewTypeId)?.actions ?? [])
.map((action) => action.general as GeneralActionModule<TriggerState> | undefined)
.filter((action): action is GeneralActionModule<TriggerState> => action !== undefined);
const handleEvent = <K extends GeneralActionEventType>(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> => {
let current = event;
for (const module of modules(context)) {
current = dispatchGeneralActionModuleEvent(module, context, current);
}
return current;
};
return {
getPreTurnExecuteTriggerList: (context) => {
@@ -153,13 +168,7 @@ const createGeneralActionRouter = <TriggerState extends GeneralTriggerState>(
}
return current;
},
onArbitraryAction: (context, actionType, phase, aux) => {
let current = aux ?? null;
for (const module of modules(context)) {
current = module.onArbitraryAction?.(context, actionType, phase, current) ?? current;
}
return current;
},
handleEvent,
} satisfies GeneralActionModule<TriggerState>;
};
+1 -1
View File
@@ -1,4 +1,4 @@
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import type { CrewTypeDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
+1 -1
View File
@@ -1,6 +1,6 @@
import type { General, Nation } from '../domain/entities.js';
import type { GeneralActionContext } from '../triggers/general.js';
import type { TriggerNationalIncomeType } from '../triggers/types.js';
import type { TriggerNationalIncomeType } from '../actionModules/types.js';
export type NationIncomeModifier = (type: TriggerNationalIncomeType, amount: number) => number;

Some files were not shown because too many files have changed in this diff Show More