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
+1 -1
View File
@@ -1,5 +1,5 @@
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 { ItemModule, ItemSlot } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -13,7 +13,7 @@ export const itemModule: ItemModule = {
consumable: true,
reqSecu: 1000,
unique: false,
consumeOn: [{ actionType: 'GeneralCommand', command: '계략', successOnly: true }],
consumeOnStrategySuccess: true,
onCalcDomestic: (_context, turnType, varType, value) => {
if (turnType === '계략' && varType === 'success') {
return value + 0.2;
@@ -13,7 +13,7 @@ export const itemModule: ItemModule = {
consumable: true,
reqSecu: 2000,
unique: false,
consumeOn: [{ actionType: 'GeneralCommand', command: '계략', successOnly: true }],
consumeOnStrategySuccess: true,
onCalcDomestic: (_context, turnType, varType, value) => {
if (turnType === '계략' && varType === 'success') {
return value + 0.5;
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,4 +1,4 @@
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import { clamp } from '@sammo-ts/logic/war/utils.js';
@@ -1,4 +1,4 @@
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import { clamp } from '@sammo-ts/logic/war/utils.js';
@@ -1,4 +1,4 @@
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import { clamp } from '@sammo-ts/logic/war/utils.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -33,10 +33,7 @@ export const itemModule: ItemModule = {
}
if (statName === 'warAvoidRatio' && typeof newValue === 'number') {
const leadership =
typeof aux === 'object' &&
aux !== null &&
'leadership' in aux &&
typeof aux.leadership === 'number'
typeof aux === 'object' && aux !== null && 'leadership' in aux && typeof aux.leadership === 'number'
? aux.leadership
: context.general.stats.leadership + STAT_VALUE;
const crewL = context.general.crew / 100;
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
+24 -39
View File
@@ -1,4 +1,3 @@
import { JosaUtil } from '@sammo-ts/common';
import type { ItemModule } from './types.js';
const ITEM_KEY = 'che_보물_도기';
@@ -17,46 +16,32 @@ export const itemModule: ItemModule = {
consumable: false,
reqSecu: 0,
unique: true,
onArbitraryAction: (context, actionType, phase, aux) => {
if (!aux || actionType !== '장비매매' || phase !== '판매') {
return aux ?? null;
}
if (aux['itemKey'] !== ITEM_KEY && aux['itemCode'] !== ITEM_KEY) {
return aux;
}
const year = resolveNumber(aux['year']);
const startYear = resolveNumber(aux['startYear']);
const relYear = Math.max(0, year - startYear);
const score = Math.round(10000 + 5000 * Math.floor(relYear / 2));
const rng = context.rng;
const pick = rng?.nextBool(0.5) ?? true;
const resName = pick ? '금' : '쌀';
const resKey = pick ? 'gold' : 'rice';
const nation = aux['nation'];
if (nation && typeof nation === 'object') {
const cast = nation as { gold?: number; rice?: number };
const half = Math.floor(score / 2);
if (resKey === 'gold') {
cast.gold = (cast.gold ?? 0) + half;
} else {
cast.rice = (cast.rice ?? 0) + half;
eventHandlers: {
'item.sold': (context, event) => {
if (event.payload.itemKey !== ITEM_KEY) {
return event;
}
}
const selfGain = score - Math.floor(score / 2);
if (resKey === 'gold') {
context.general.gold += selfGain;
} else {
context.general.rice += selfGain;
}
const year = resolveNumber(context.time.year);
const startYear = resolveNumber(context.time.startYear);
const relYear = Math.max(0, year - startYear);
const score = Math.round(10000 + 5000 * Math.floor(relYear / 2));
const josa = JosaUtil.pick('도기', '을');
context.log?.push(
`<C>${itemModule.name}</>${josa} 판매하여 ${resName} <C>${score.toLocaleString('en-US')}</>을 보충합니다.`
);
return aux;
// ref RandUtil::choice([gold, rice])는 index 0을 금으로 고릅니다.
const pickGold = context.rng.nextInt(0, 2) === 0;
const resName = pickGold ? '금' : '쌀';
const resKey = pickGold ? 'gold' : 'rice';
const nation = context.nation;
if (nation && nation.id !== 0) {
const half = Math.floor(score / 2);
nation[resKey] += half;
}
const selfGain = score - Math.floor(score / 2);
context.general[resKey] += selfGain;
context.log?.push(`재산과 국고에 총 ${resName} <C>${score.toLocaleString('en-US')}</>을 보충합니다.`);
return event;
},
},
};
@@ -1,5 +1,5 @@
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 { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import { che_부적 } from '@sammo-ts/logic/war/triggers/che_부적.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,7 +1,7 @@
import { createStatItemModule } from './base.js';
import type { ItemModule } from './types.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';
const STAT_VALUE = 3;
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,7 +1,7 @@
import { createStatItemModule } from './base.js';
import type { ItemModule } from './types.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';
const STAT_VALUE = 8;
@@ -1,5 +1,5 @@
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 { createStatItemModule } from './base.js';
import type { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
@@ -1,5 +1,5 @@
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 { ItemModule } from './types.js';
+3 -3
View File
@@ -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';
import type { ItemModule } from './types.js';
export const createEventBattleTraitItemModule = (
@@ -38,8 +38,8 @@ export const createEventBattleTraitItemModule = (
if (traitModule.onCalcNationalIncome) {
itemModule.onCalcNationalIncome = traitModule.onCalcNationalIncome;
}
if (traitModule.onArbitraryAction) {
itemModule.onArbitraryAction = traitModule.onArbitraryAction;
if (traitModule.eventHandlers) {
itemModule.eventHandlers = traitModule.eventHandlers;
}
if (traitModule.getBattleInitTriggerList) {
itemModule.getBattleInitTriggerList = traitModule.getBattleInitTriggerList;
+43 -57
View File
@@ -1,17 +1,22 @@
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 {
createGeneralActionEvent,
dispatchGeneralActionEventHandlers,
type GeneralActionEvent,
type GeneralActionEventContext,
type GeneralActionEventType,
} from '@sammo-ts/logic/actionModules/events.js';
import { GeneralTriggerCaller, type GeneralActionContext } from '@sammo-ts/logic/triggers/general.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 { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import type { WarUnit } from '@sammo-ts/logic/war/units.js';
@@ -275,7 +280,7 @@ const defaultImporters: Record<ItemKey, ItemImporter> = {
che_약탈_옥벽: async () => import('./che_약탈_옥벽.js'),
che_위압_조목삭: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_위압.js'),
import('../actionModules/traits/war/che_위압.js'),
import('./eventBattleTrait.js'),
]);
return {
@@ -312,140 +317,140 @@ const defaultImporters: Record<ItemKey, ItemImporter> = {
che_훈련_청주: async () => import('./che_훈련_청주.js'),
event_전투특기_격노: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_격노.js'),
import('../actionModules/traits/war/che_격노.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_격노', traitModule) };
},
event_전투특기_견고: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_견고.js'),
import('../actionModules/traits/war/che_견고.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_견고', traitModule) };
},
event_전투특기_공성: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_공성.js'),
import('../actionModules/traits/war/che_공성.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_공성', traitModule) };
},
event_전투특기_궁병: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_궁병.js'),
import('../actionModules/traits/war/che_궁병.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_궁병', traitModule) };
},
event_전투특기_귀병: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_귀병.js'),
import('../actionModules/traits/war/che_귀병.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_귀병', traitModule) };
},
event_전투특기_기병: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_기병.js'),
import('../actionModules/traits/war/che_기병.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_기병', traitModule) };
},
event_전투특기_돌격: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_돌격.js'),
import('../actionModules/traits/war/che_돌격.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_돌격', traitModule) };
},
event_전투특기_무쌍: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_무쌍.js'),
import('../actionModules/traits/war/che_무쌍.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_무쌍', traitModule) };
},
event_전투특기_반계: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_반계.js'),
import('../actionModules/traits/war/che_반계.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_반계', traitModule) };
},
event_전투특기_보병: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_보병.js'),
import('../actionModules/traits/war/che_보병.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_보병', traitModule) };
},
event_전투특기_신산: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_신산.js'),
import('../actionModules/traits/war/che_신산.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_신산', traitModule) };
},
event_전투특기_신중: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_신중.js'),
import('../actionModules/traits/war/che_신중.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_신중', traitModule) };
},
event_전투특기_위압: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_위압.js'),
import('../actionModules/traits/war/che_위압.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_위압', traitModule) };
},
event_전투특기_의술: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_의술.js'),
import('../actionModules/traits/war/che_의술.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_의술', traitModule) };
},
event_전투특기_저격: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_저격.js'),
import('../actionModules/traits/war/che_저격.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_저격', traitModule) };
},
event_전투특기_집중: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_집중.js'),
import('../actionModules/traits/war/che_집중.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_집중', traitModule) };
},
event_전투특기_징병: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_징병.js'),
import('../actionModules/traits/war/che_징병.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_징병', traitModule) };
},
event_전투특기_척사: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_척사.js'),
import('../actionModules/traits/war/che_척사.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_척사', traitModule) };
},
event_전투특기_필살: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_필살.js'),
import('../actionModules/traits/war/che_필살.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_필살', traitModule) };
},
event_전투특기_환술: async () => {
const [{ traitModule }, { createEventBattleTraitItemModule }] = await Promise.all([
import('../triggers/special/war/che_환술.js'),
import('../actionModules/traits/war/che_환술.js'),
import('./eventBattleTrait.js'),
]);
return { itemModule: createEventBattleTraitItemModule('event_전투특기_환술', traitModule) };
@@ -521,9 +526,7 @@ export const createItemModuleRegistry = <TriggerState extends GeneralTriggerStat
return registry;
};
class ItemGeneralActionRouter<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
> implements GeneralActionModule<TriggerState> {
class ItemGeneralActionRouter<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
constructor(private readonly registry: ItemModuleRegistry<TriggerState>) {}
private resolveModules(context: GeneralActionContext<TriggerState>): Array<ItemModule<TriggerState>> {
@@ -631,38 +634,21 @@ class ItemGeneralActionRouter<
return current;
}
onArbitraryAction(
context: GeneralActionContext<TriggerState>,
actionType: TriggerActionType,
phase?: TriggerActionPhase | null,
aux?: Record<string, unknown> | null
): Record<string, unknown> | null {
let current = aux ?? null;
handleEvent<K extends GeneralActionEventType>(
context: GeneralActionEventContext<K, TriggerState>,
event: GeneralActionEvent<K, TriggerState>
): GeneralActionEvent<K, TriggerState> {
let current = event;
for (const module of this.resolveModules(context)) {
if (!module.onArbitraryAction) {
// Declarative consumption rules are evaluated below even when
// the item has no custom arbitrary-action hook.
} else {
const result = module.onArbitraryAction(context, actionType, phase, current);
if (result !== undefined) {
current = result;
}
}
current = dispatchGeneralActionEventHandlers(module.eventHandlers, context, current);
const shouldConsume = module.consumeOn?.some(
(rule) =>
rule.actionType === actionType &&
(rule.phase === undefined || rule.phase === phase) &&
(rule.command === undefined || current?.['command'] === rule.command) &&
(!rule.successOnly || current?.['success'] === true)
);
if (shouldConsume) {
if (current.type === 'strategy.succeeded' && module.consumeOnStrategySuccess) {
const removed = removeEquippedItem(context.general, module.slot);
if (removed?.itemKey === module.key) {
const consumedItems = Array.isArray(current?.['consumedItems'])
? (current['consumedItems'] as unknown[])
: [];
current = { ...(current ?? {}), consumedItems: [...consumedItems, module.key] };
const strategyEvent = current as GeneralActionEvent<'strategy.succeeded', TriggerState>;
current = createGeneralActionEvent<TriggerState, 'strategy.succeeded'>('strategy.succeeded', {
consumedItems: [...strategyEvent.payload.consumedItems, module.key],
}) as GeneralActionEvent<K, TriggerState>;
}
}
}
@@ -762,7 +748,7 @@ class ItemWarActionRouter<
export const createItemActionModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
registry: ItemModuleRegistry<TriggerState>
): { general: GeneralActionModule<TriggerState>[]; war: WarActionModule<TriggerState>[] } => ({
): { general: ReadonlyArray<GeneralActionModule<TriggerState>>; war: WarActionModule<TriggerState>[] } => ({
general: [new ItemGeneralActionRouter(registry)],
war: [new ItemWarActionRouter(registry)],
});
+4 -17
View File
@@ -2,28 +2,20 @@ import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionContext, GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.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 { GeneralActionEventHandlers } from '@sammo-ts/logic/actionModules/events.js';
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
import type { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
import type { WarUnit } from '@sammo-ts/logic/war/units.js';
export type ItemSlot = 'horse' | 'weapon' | 'book' | 'item';
export interface ItemActionConsumptionRule {
actionType: TriggerActionType;
phase?: TriggerActionPhase | null;
command?: string;
successOnly?: boolean;
}
export interface ItemModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
key: string;
name: string;
@@ -34,7 +26,7 @@ export interface ItemModule<TriggerState extends GeneralTriggerState = GeneralTr
buyable: boolean;
consumable: boolean;
initialCharges?: number;
consumeOn?: ItemActionConsumptionRule[];
consumeOnStrategySuccess?: boolean;
reqSecu: number;
unique: boolean;
@@ -83,12 +75,7 @@ export interface ItemModule<TriggerState extends GeneralTriggerState = GeneralTr
amount: number
): number;
onArbitraryAction?(
context: GeneralActionContext<TriggerState>,
actionType: TriggerActionType,
phase?: TriggerActionPhase | null,
aux?: Record<string, unknown> | null
): Record<string, unknown> | null;
eventHandlers?: GeneralActionEventHandlers<TriggerState>;
getBattleInitTriggerList?(context: WarActionContext<TriggerState>): WarTriggerCaller | null;