diff --git a/packages/logic/src/items/base.ts b/packages/logic/src/items/base.ts
index 6837c67..2e97847 100644
--- a/packages/logic/src/items/base.ts
+++ b/packages/logic/src/items/base.ts
@@ -34,19 +34,31 @@ export const createStatItemModule = (options: StatItemOptions): ItemModule => {
const name = `${options.rawName}(+${options.statValue})`;
const baseInfo = `${statLabel} +${options.statValue}`;
const info = options.extraInfo ? `${baseInfo}
${options.extraInfo}` : baseInfo;
- const onCalcStat = (
+ function onCalcStat(
+ _context: GeneralActionContext,
+ statName: GeneralStatName,
+ value: number,
+ _aux?: unknown
+ ): number;
+ function onCalcStat(
+ _context: WarActionContext,
+ statName: WarStatName,
+ value: number | [number, number],
+ _aux?: unknown
+ ): number | [number, number];
+ function onCalcStat(
_context: GeneralActionContext | WarActionContext,
statName: GeneralStatName | WarStatName,
value: number | [number, number]
- ): number | [number, number] => {
+ ): number | [number, number] {
if (statName !== options.statName) {
return value;
}
- if (typeof value === 'number') {
- return value + options.statValue;
+ if (Array.isArray(value)) {
+ return value;
}
- return value;
- };
+ return value + options.statValue;
+ }
return {
key: options.key,
diff --git a/packages/logic/src/triggers/general-action.ts b/packages/logic/src/triggers/general-action.ts
index 6fed42e..a77bb00 100644
--- a/packages/logic/src/triggers/general-action.ts
+++ b/packages/logic/src/triggers/general-action.ts
@@ -1,9 +1,7 @@
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import { type GeneralActionContext, GeneralTriggerCaller } from './general.js';
import type {
- GeneralStatBundleMap,
GeneralStatName,
- WarStatBundleMap,
TriggerActionPhase,
TriggerActionType,
TriggerDomesticActionType,
@@ -18,58 +16,58 @@ export interface GeneralActionModule string) | undefined;
getPreTurnExecuteTriggerList?:
- | ((context: GeneralActionContext) => GeneralTriggerCaller | null)
- | undefined;
+ | ((context: GeneralActionContext) => GeneralTriggerCaller | null)
+ | undefined;
onCalcDomestic?:
- | ((
- context: GeneralActionContext,
- turnType: TriggerDomesticActionType,
- varType: TriggerDomesticVarType,
- value: number,
- aux?: unknown
- ) => number)
- | undefined;
+ | ((
+ context: GeneralActionContext,
+ turnType: TriggerDomesticActionType,
+ varType: TriggerDomesticVarType,
+ value: number,
+ aux?: unknown
+ ) => number)
+ | undefined;
onCalcStat?:
- | ((
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ) => GeneralStatBundleMap[T]['return'])
- | undefined;
+ | ((
+ context: GeneralActionContext,
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ) => number)
+ | undefined;
onCalcOpposeStat?:
- | ((
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ) => GeneralStatBundleMap[T]['return'])
- | undefined;
+ | ((
+ context: GeneralActionContext,
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ) => number)
+ | undefined;
onCalcStrategic?:
- | ((
- context: GeneralActionContext,
- turnType: TriggerStrategicActionType,
- varType: TriggerStrategicVarType,
- value: number
- ) => number)
- | undefined;
+ | ((
+ context: GeneralActionContext,
+ turnType: TriggerStrategicActionType,
+ varType: TriggerStrategicVarType,
+ value: number
+ ) => number)
+ | undefined;
onCalcNationalIncome?:
- | ((context: GeneralActionContext, type: TriggerNationalIncomeType, amount: number) => number)
- | undefined;
+ | ((context: GeneralActionContext, type: TriggerNationalIncomeType, amount: number) => number)
+ | undefined;
onArbitraryAction?:
- | ((
- context: GeneralActionContext,
- actionType: TriggerActionType,
- phase?: TriggerActionPhase | null,
- aux?: Record | null
- ) => Record | null)
- | undefined;
+ | ((
+ context: GeneralActionContext,
+ actionType: TriggerActionType,
+ phase?: TriggerActionPhase | null,
+ aux?: Record | null
+ ) => Record | null)
+ | undefined;
}
export class GeneralActionPipeline {
@@ -109,12 +107,12 @@ export class GeneralActionPipeline(
+ onCalcStat(
context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'] {
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ): number {
let current = value;
for (const module of this.modules) {
if (!module.onCalcStat) {
@@ -125,12 +123,12 @@ export class GeneralActionPipeline(
+ onCalcOpposeStat(
context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'] {
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ): number {
let current = value;
for (const module of this.modules) {
if (!module.onCalcOpposeStat) {
diff --git a/packages/logic/src/triggers/special/registry.ts b/packages/logic/src/triggers/special/registry.ts
index 1036242..44a84d4 100644
--- a/packages/logic/src/triggers/special/registry.ts
+++ b/packages/logic/src/triggers/special/registry.ts
@@ -2,7 +2,6 @@ import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
import type {
- GeneralStatBundleMap,
GeneralStatName,
TriggerActionPhase,
TriggerActionType,
@@ -11,7 +10,6 @@ import type {
TriggerNationalIncomeType,
TriggerStrategicActionType,
TriggerStrategicVarType,
- WarStatBundleMap,
WarStatName,
} from '@sammo-ts/logic/triggers/types.js';
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
@@ -66,7 +64,7 @@ export class TraitGeneralActionRouter<
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry
- ) { }
+ ) {}
private getModule(context: GeneralActionContext): TraitModule | null {
const key = resolveTraitKey(context, this.kind);
@@ -89,32 +87,24 @@ export class TraitGeneralActionRouter<
return module?.onCalcDomestic?.(context, turnType, varType, value, aux) ?? value;
}
- onCalcStat(
+ onCalcStat(
context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'] {
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ): number {
const module = this.getModule(context);
- const onCalcStat = module?.onCalcStat;
- if (onCalcStat) {
- return onCalcStat(context, statName, value as never, aux as never) as never;
- }
- return value;
+ return module?.onCalcStat?.(context, statName, value, aux) ?? value;
}
- onCalcOpposeStat(
+ onCalcOpposeStat(
context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'] {
+ statName: GeneralStatName,
+ value: number,
+ aux?: unknown
+ ): number {
const module = this.getModule(context);
- const onCalcOpposeStat = module?.onCalcOpposeStat;
- if (onCalcOpposeStat) {
- return onCalcOpposeStat(context, statName, value as never, aux as never) as never;
- }
- return value;
+ return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value;
}
onCalcStrategic(
@@ -155,7 +145,7 @@ export class TraitWarActionRouter<
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry
- ) { }
+ ) {}
private getModule(context: WarActionContext): TraitModule | null {
const key = resolveTraitKey(context, this.kind);
@@ -172,32 +162,24 @@ export class TraitWarActionRouter<
return module?.getBattlePhaseTriggerList?.(context) ?? null;
}
- onCalcStat(
+ onCalcStat(
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'] {
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ): number | [number, number] {
const module = this.getModule(context);
- const onCalcStat = module?.onCalcStat;
- if (onCalcStat) {
- return onCalcStat(context, statName, value as never, aux as never) as never;
- }
- return value;
+ return module?.onCalcStat?.(context, statName, value, aux) ?? value;
}
- onCalcOpposeStat(
+ onCalcOpposeStat(
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'] {
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ): number | [number, number] {
const module = this.getModule(context);
- const onCalcOpposeStat = module?.onCalcOpposeStat;
- if (onCalcOpposeStat) {
- return onCalcOpposeStat(context, statName, value as never, aux as never) as never;
- }
- return value;
+ return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value;
}
getWarPowerMultiplier(
diff --git a/packages/logic/src/triggers/special/types.ts b/packages/logic/src/triggers/special/types.ts
index f7f7a36..2cddcce 100644
--- a/packages/logic/src/triggers/special/types.ts
+++ b/packages/logic/src/triggers/special/types.ts
@@ -13,41 +13,24 @@ export interface TraitSpec {
kind: TraitKind;
}
-import type {
- GeneralStatName,
- GeneralStatBundleMap,
- WarStatName,
- WarStatBundleMap,
-} from '../types.js';
-
export interface TraitOnCalcStat {
- (
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'];
- (
+ (context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
+ (
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'];
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ): number | [number, number];
}
export interface TraitOnCalcOpposeStat {
- (
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'];
- (
+ (context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
+ (
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'];
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ): number | [number, number];
}
export type TraitModule = TraitSpec &
diff --git a/packages/logic/src/triggers/types.ts b/packages/logic/src/triggers/types.ts
index 088d365..c355eaf 100644
--- a/packages/logic/src/triggers/types.ts
+++ b/packages/logic/src/triggers/types.ts
@@ -1,6 +1,3 @@
-import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
-import type { GeneralActionContext } from './general.js';
-import type { WarActionContext } from '../war/actions.js';
export type TriggerActionType = '장비매매';
export type TriggerActionPhase = '판매' | '구매';
@@ -31,71 +28,17 @@ export type TriggerNationalIncomeType = 'gold' | 'rice';
export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication';
-export type GeneralStatBundle =
- | { statName: 'leadership'; value: number; aux: undefined; return: number }
- | { statName: 'strength'; value: number; aux: undefined; return: number }
- | { statName: 'intelligence'; value: number; aux: undefined; return: number }
- | { statName: 'experience'; value: number; aux: undefined; return: number }
- | { statName: 'dedication'; value: number; aux: undefined; return: number };
-
-export type GeneralStatBundleMap = {
- [T in GeneralStatBundle as T['statName']]: T;
-};
-
-export type WarStatBundle =
- | GeneralStatBundle
- | { statName: 'cityBattleOrder'; value: number; aux: undefined; return: number }
- | { statName: 'initWarPhase'; value: number; aux: { isAttacker: boolean }; return: number }
- | { statName: 'bonusTrain'; value: number; aux: { isAttacker: boolean }; return: number }
- | { statName: 'bonusAtmos'; value: number; aux: { isAttacker: boolean }; return: number }
- | { statName: 'warCriticalRatio'; value: number; aux: { isAttacker: boolean }; return: number }
- | { statName: 'warAvoidRatio'; value: number; aux: { isAttacker: boolean }; return: number }
- | { statName: 'killRice'; value: number; aux: undefined; return: number }
- | { statName: 'criticalDamageRange'; value: [number, number]; aux: undefined; return: [number, number] }
- | { statName: 'warMagicSuccessDamage'; value: number; aux: undefined; return: number }
- | { statName: 'warMagicTrialProb'; value: number; aux: undefined; return: number }
- | { statName: 'warMagicSuccessProb'; value: number; aux: undefined; return: number }
- | {
- statName: `dex${number}`;
- value: number;
- aux: { isAttacker: boolean; opposeType: { armType: number } | null };
- return: number;
- };
-
-export type WarStatBundleMap = {
- [T in WarStatBundle as T['statName']]: T;
-};
-
-export type WarStatName = WarStatBundle['statName'];
-
-export interface TraitOnCalcStat {
- (
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'];
- (
- context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'];
-}
-
-export interface TraitOnCalcOpposeStat {
- (
- context: GeneralActionContext,
- statName: T,
- value: GeneralStatBundleMap[T]['value'],
- aux?: GeneralStatBundleMap[T]['aux']
- ): GeneralStatBundleMap[T]['return'];
- (
- context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'];
-}
-
-export type TriggerActionType = '장비매매';
+export type WarStatName =
+ | GeneralStatName
+ | 'cityBattleOrder'
+ | 'initWarPhase'
+ | 'bonusTrain'
+ | 'bonusAtmos'
+ | 'warCriticalRatio'
+ | 'warAvoidRatio'
+ | 'killRice'
+ | 'criticalDamageRange'
+ | 'warMagicSuccessDamage'
+ | 'warMagicTrialProb'
+ | 'warMagicSuccessProb'
+ | `dex${number}`;
diff --git a/packages/logic/src/war/actions.ts b/packages/logic/src/war/actions.ts
index 33a0ffd..996537a 100644
--- a/packages/logic/src/war/actions.ts
+++ b/packages/logic/src/war/actions.ts
@@ -2,7 +2,7 @@ import type { RandUtil } from '@sammo-ts/common';
import type { City, General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { ActionLogger } from '@sammo-ts/logic/logging/actionLogger.js';
-import type { WarStatBundleMap, WarStatName } from '@sammo-ts/logic/triggers/types.js';
+import type { WarStatName } from '@sammo-ts/logic/triggers/types.js';
import type { WarUnit } from './units.js';
import { WarTriggerCaller } from './triggers.js';
@@ -24,30 +24,30 @@ export interface WarActionModule) => WarTriggerCaller | null) | undefined;
onCalcStat?:
- | ((
- context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ) => WarStatBundleMap[T]['return'])
- | undefined;
+ | ((
+ context: WarActionContext,
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ) => number | [number, number])
+ | undefined;
onCalcOpposeStat?:
- | ((
- context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ) => WarStatBundleMap[T]['return'])
- | undefined;
+ | ((
+ context: WarActionContext,
+ statName: WarStatName,
+ value: number | [number, number],
+ aux?: unknown
+ ) => number | [number, number])
+ | undefined;
getWarPowerMultiplier?:
- | ((
- context: WarActionContext,
- unit: WarUnit,
- oppose: WarUnit
- ) => [number, number])
- | undefined;
+ | ((
+ context: WarActionContext,
+ unit: WarUnit,
+ oppose: WarUnit
+ ) => [number, number])
+ | undefined;
}
export class WarActionPipeline {
@@ -80,36 +80,36 @@ export class WarActionPipeline(
+ onCalcStat(
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'] {
- let current = value;
+ statName: WarStatName,
+ value: T,
+ aux?: unknown
+ ): T {
+ let current: number | [number, number] = value;
for (const module of this.modules) {
if (!module.onCalcStat) {
continue;
}
- current = module.onCalcStat(context, statName, current as never, aux as never) as never;
+ current = module.onCalcStat(context, statName, current, aux);
}
- return current;
+ return current as T;
}
- onCalcOpposeStat(
+ onCalcOpposeStat(
context: WarActionContext,
- statName: T,
- value: WarStatBundleMap[T]['value'],
- aux?: WarStatBundleMap[T]['aux']
- ): WarStatBundleMap[T]['return'] {
- let current = value;
+ statName: WarStatName,
+ value: T,
+ aux?: unknown
+ ): T {
+ let current: number | [number, number] = value;
for (const module of this.modules) {
if (!module.onCalcOpposeStat) {
continue;
}
- current = module.onCalcOpposeStat(context, statName, current as never, aux as never) as never;
+ current = module.onCalcOpposeStat(context, statName, current, aux);
}
- return current;
+ return current as T;
}
getWarPowerMultiplier(
diff --git a/packages/logic/src/war/units.ts b/packages/logic/src/war/units.ts
index 4b81451..6e4e128 100644
--- a/packages/logic/src/war/units.ts
+++ b/packages/logic/src/war/units.ts
@@ -466,8 +466,8 @@ export class WarUnitGeneral<
const baseTurnTime = this.isAttacker()
? getMetaString(this.general.meta, META_TURN_TIME)
: oppose instanceof WarUnitGeneral
- ? getMetaString(oppose.general.meta, META_TURN_TIME)
- : getMetaString(this.general.meta, META_TURN_TIME);
+ ? getMetaString(oppose.general.meta, META_TURN_TIME)
+ : getMetaString(this.general.meta, META_TURN_TIME);
if (!baseTurnTime) {
return;
}
@@ -480,8 +480,9 @@ export class WarUnitGeneral<
public override getMaxPhase(): number {
const base = this.getCrewType().speed;
+ const aux = { isAttacker: this.isAttacker() };
const context = this.getActionContext();
- const phase = this.actionPipeline.onCalcStat(context, 'initWarPhase', base, { isAttacker: this.isAttacker() });
+ const phase = this.actionPipeline.onCalcStat(context, 'initWarPhase', base, aux);
return phase + this.bonusPhase;
}
@@ -506,16 +507,12 @@ export class WarUnitGeneral<
return strength;
}
- private resolveOpposeStatValue(statName: WarStatName, value: number, aux?: any): number {
+ private resolveOpposeStatValue(statName: WarStatName, value: number, aux?: Record): number {
const oppose = this.getOppose();
if (!(oppose instanceof WarUnitGeneral)) {
return value;
}
- const result = oppose.getActionPipeline().onCalcOpposeStat(this.getActionContext(), statName, value, aux);
- if (typeof result === 'number') {
- return result;
- }
- return value;
+ return oppose.getActionPipeline().onCalcOpposeStat(this.getActionContext(), statName, value, aux);
}
public override getDex(crewType: WarCrewType): number {
@@ -530,10 +527,8 @@ export class WarUnitGeneral<
};
const statName = toDexStatName(armType);
let dex = this.actionPipeline.onCalcStat(this.getActionContext(), statName, base, aux);
- if (typeof dex === 'number') {
- dex = this.resolveOpposeStatValue(statName, dex, aux);
- }
- return typeof dex === 'number' ? dex : base;
+ dex = this.resolveOpposeStatValue(statName, dex, aux);
+ return dex;
}
public override getComputedAttack(): number {
@@ -583,8 +578,8 @@ export class WarUnitGeneral<
const mainStat = this.resolveMainStat(armType);
const coef =
armType === this.config.armTypes.wizard ||
- armType === this.config.armTypes.siege ||
- armType === this.config.armTypes.misc
+ armType === this.config.armTypes.siege ||
+ armType === this.config.armTypes.misc
? 0.4
: 0.5;