wip: 바보 젬3플. type 재정의 준비

This commit is contained in:
2026-01-05 18:43:09 +00:00
parent 27f7b8e894
commit 6bddbc3aa0
7 changed files with 254 additions and 167 deletions
+52 -50
View File
@@ -1,7 +1,9 @@
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,
@@ -16,58 +18,58 @@ export interface GeneralActionModule<TriggerState extends GeneralTriggerState =
getInfo?: (() => string) | undefined;
getPreTurnExecuteTriggerList?:
| ((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null)
| undefined;
| ((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null)
| undefined;
onCalcDomestic?:
| ((
context: GeneralActionContext<TriggerState>,
turnType: TriggerDomesticActionType,
varType: TriggerDomesticVarType,
value: number,
aux?: unknown
) => number)
| undefined;
| ((
context: GeneralActionContext<TriggerState>,
turnType: TriggerDomesticActionType,
varType: TriggerDomesticVarType,
value: number,
aux?: unknown
) => number)
| undefined;
onCalcStat?:
| ((
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
) => number)
| undefined;
| (<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
) => GeneralStatBundleMap[T]['return'])
| undefined;
onCalcOpposeStat?:
| ((
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
) => number)
| undefined;
| (<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
) => GeneralStatBundleMap[T]['return'])
| undefined;
onCalcStrategic?:
| ((
context: GeneralActionContext<TriggerState>,
turnType: TriggerStrategicActionType,
varType: TriggerStrategicVarType,
value: number
) => number)
| undefined;
| ((
context: GeneralActionContext<TriggerState>,
turnType: TriggerStrategicActionType,
varType: TriggerStrategicVarType,
value: number
) => number)
| undefined;
onCalcNationalIncome?:
| ((context: GeneralActionContext<TriggerState>, type: TriggerNationalIncomeType, amount: number) => number)
| undefined;
| ((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;
| ((
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> {
@@ -107,12 +109,12 @@ export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = Ge
return current;
}
onCalcStat(
onCalcStat<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
): number {
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'] {
let current = value;
for (const module of this.modules) {
if (!module.onCalcStat) {
@@ -123,12 +125,12 @@ export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = Ge
return current;
}
onCalcOpposeStat(
onCalcOpposeStat<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
): number {
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'] {
let current = value;
for (const module of this.modules) {
if (!module.onCalcOpposeStat) {
+44 -26
View File
@@ -2,6 +2,7 @@ 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,
@@ -10,6 +11,7 @@ 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';
@@ -64,7 +66,7 @@ export class TraitGeneralActionRouter<
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry<TriggerState>
) {}
) { }
private getModule(context: GeneralActionContext<TriggerState>): TraitModule<TriggerState> | null {
const key = resolveTraitKey(context, this.kind);
@@ -87,24 +89,32 @@ export class TraitGeneralActionRouter<
return module?.onCalcDomestic?.(context, turnType, varType, value, aux) ?? value;
}
onCalcStat(
onCalcStat<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
): number {
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'] {
const module = this.getModule(context);
return module?.onCalcStat?.(context, statName, value, aux) ?? value;
const onCalcStat = module?.onCalcStat;
if (onCalcStat) {
return onCalcStat(context, statName, value as never, aux as never) as never;
}
return value;
}
onCalcOpposeStat(
onCalcOpposeStat<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: GeneralStatName,
value: number,
aux?: unknown
): number {
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'] {
const module = this.getModule(context);
return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value;
const onCalcOpposeStat = module?.onCalcOpposeStat;
if (onCalcOpposeStat) {
return onCalcOpposeStat(context, statName, value as never, aux as never) as never;
}
return value;
}
onCalcStrategic(
@@ -145,7 +155,7 @@ export class TraitWarActionRouter<
constructor(
private readonly kind: TraitKind,
private readonly registry: TraitModuleRegistry<TriggerState>
) {}
) { }
private getModule(context: WarActionContext<TriggerState>): TraitModule<TriggerState> | null {
const key = resolveTraitKey(context, this.kind);
@@ -162,24 +172,32 @@ export class TraitWarActionRouter<
return module?.getBattlePhaseTriggerList?.(context) ?? null;
}
onCalcStat(
onCalcStat<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: WarStatName,
value: number | [number, number],
aux?: unknown
): number | [number, number] {
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'] {
const module = this.getModule(context);
return module?.onCalcStat?.(context, statName, value, aux) ?? value;
const onCalcStat = module?.onCalcStat;
if (onCalcStat) {
return onCalcStat(context, statName, value as never, aux as never) as never;
}
return value;
}
onCalcOpposeStat(
onCalcOpposeStat<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: WarStatName,
value: number | [number, number],
aux?: unknown
): number | [number, number] {
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'] {
const module = this.getModule(context);
return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value;
const onCalcOpposeStat = module?.onCalcOpposeStat;
if (onCalcOpposeStat) {
return onCalcOpposeStat(context, statName, value as never, aux as never) as never;
}
return value;
}
getWarPowerMultiplier(
+29 -12
View File
@@ -13,24 +13,41 @@ export interface TraitSpec {
kind: TraitKind;
}
import type {
GeneralStatName,
GeneralStatBundleMap,
WarStatName,
WarStatBundleMap,
} from '../types.js';
export interface TraitOnCalcStat<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
(context: GeneralActionContext<TriggerState>, statName: GeneralStatName, value: number, aux?: unknown): number;
(
<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'];
<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: WarStatName,
value: number | [number, number],
aux?: unknown
): number | [number, number];
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'];
}
export interface TraitOnCalcOpposeStat<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
(context: GeneralActionContext<TriggerState>, statName: GeneralStatName, value: number, aux?: unknown): number;
(
<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'];
<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: WarStatName,
value: number | [number, number],
aux?: unknown
): number | [number, number];
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'];
}
export type TraitModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> = TraitSpec &
+71 -14
View File
@@ -1,3 +1,6 @@
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 = '판매' | '구매';
@@ -28,17 +31,71 @@ export type TriggerNationalIncomeType = 'gold' | 'rice';
export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication';
export type WarStatName =
| GeneralStatName
| 'cityBattleOrder'
| 'initWarPhase'
| 'bonusTrain'
| 'bonusAtmos'
| 'warCriticalRatio'
| 'warAvoidRatio'
| 'killRice'
| 'criticalDamageRange'
| 'warMagicSuccessDamage'
| 'warMagicTrialProb'
| 'warMagicSuccessProb'
| `dex${number}`;
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<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'];
<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'];
}
export interface TraitOnCalcOpposeStat<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
<T extends GeneralStatName>(
context: GeneralActionContext<TriggerState>,
statName: T,
value: GeneralStatBundleMap[T]['value'],
aux?: GeneralStatBundleMap[T]['aux']
): GeneralStatBundleMap[T]['return'];
<T extends WarStatName>(
context: WarActionContext<TriggerState>,
statName: T,
value: WarStatBundleMap[T]['value'],
aux?: WarStatBundleMap[T]['aux']
): WarStatBundleMap[T]['return'];
}
export type TriggerActionType = '장비매매';