feat: eslint 적용 및 관련 코드 일괄 수정
This commit is contained in:
@@ -69,9 +69,7 @@ export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = Ge
|
||||
this.modules = modules.filter(Boolean) as GeneralActionModule<TriggerState>[];
|
||||
}
|
||||
|
||||
getPreTurnExecuteTriggerList(
|
||||
context: GeneralActionContext<TriggerState>
|
||||
): GeneralTriggerCaller<TriggerState> {
|
||||
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>): GeneralTriggerCaller<TriggerState> {
|
||||
const triggerCaller = new GeneralTriggerCaller<TriggerState>();
|
||||
|
||||
for (const module of this.modules) {
|
||||
|
||||
@@ -3,9 +3,7 @@ import type { RandomGenerator } from '@sammo-ts/common';
|
||||
import type { WorldStateRepository } from '@sammo-ts/logic/ports/world.js';
|
||||
import { TriggerCaller, type Trigger } from './core.js';
|
||||
|
||||
export interface GeneralWorldView<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export interface GeneralWorldView<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
listGenerals(): General<TriggerState>[];
|
||||
listGeneralsByCity?(cityId: number): General<TriggerState>[];
|
||||
}
|
||||
@@ -19,9 +17,7 @@ export interface GeneralSkillActivation {
|
||||
activate(...keys: string[]): void;
|
||||
}
|
||||
|
||||
export const createGeneralSkillActivation = <
|
||||
TriggerState extends GeneralTriggerState
|
||||
>(
|
||||
export const createGeneralSkillActivation = <TriggerState extends GeneralTriggerState>(
|
||||
general: General<TriggerState>
|
||||
): GeneralSkillActivation => ({
|
||||
has: (key: string) => Boolean(general.triggerState.flags[key]),
|
||||
@@ -40,15 +36,14 @@ export interface GeneralActionContext<TriggerState extends GeneralTriggerState =
|
||||
rng?: RandomGenerator;
|
||||
}
|
||||
|
||||
export interface GeneralTriggerContext<TriggerState extends GeneralTriggerState = GeneralTriggerState>
|
||||
extends GeneralActionContext<TriggerState> {
|
||||
export interface GeneralTriggerContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionContext<TriggerState> {
|
||||
rng: RandomGenerator;
|
||||
skill: GeneralSkillActivation;
|
||||
}
|
||||
|
||||
export const createGeneralTriggerContext = <
|
||||
TriggerState extends GeneralTriggerState
|
||||
>(
|
||||
export const createGeneralTriggerContext = <TriggerState extends GeneralTriggerState>(
|
||||
context: GeneralActionContext<TriggerState> & { rng: RandomGenerator }
|
||||
): GeneralTriggerContext<TriggerState> => ({
|
||||
...context,
|
||||
@@ -58,19 +53,19 @@ export const createGeneralTriggerContext = <
|
||||
export type GeneralTrigger<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
Env extends Record<string, unknown> = Record<string, unknown>,
|
||||
Arg = unknown
|
||||
Arg = unknown,
|
||||
> = Trigger<GeneralTriggerContext<TriggerState>, Env, Arg>;
|
||||
|
||||
export class GeneralTriggerCaller<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
Env extends Record<string, unknown> = Record<string, unknown>,
|
||||
Arg = unknown
|
||||
Arg = unknown,
|
||||
> extends TriggerCaller<GeneralTriggerContext<TriggerState>, Env, Arg> {}
|
||||
|
||||
export abstract class BaseGeneralTrigger<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
Env extends Record<string, unknown> = Record<string, unknown>,
|
||||
Arg = unknown
|
||||
Arg = unknown,
|
||||
> implements GeneralTrigger<TriggerState, Env, Arg> {
|
||||
public abstract readonly priority: number;
|
||||
|
||||
@@ -80,9 +75,5 @@ export abstract class BaseGeneralTrigger<
|
||||
return `${this.priority}_${this.constructor.name}_${this.general.id}`;
|
||||
}
|
||||
|
||||
abstract action(
|
||||
context: GeneralTriggerContext<TriggerState>,
|
||||
env: Env,
|
||||
arg?: Arg
|
||||
): Env;
|
||||
abstract action(context: GeneralTriggerContext<TriggerState>, env: Env, arg?: Arg): Env;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ import { JosaUtil } from '@sammo-ts/common';
|
||||
|
||||
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import { TriggerPriority } from '@sammo-ts/logic/triggers/core.js';
|
||||
import {
|
||||
BaseGeneralTrigger,
|
||||
type GeneralTriggerContext,
|
||||
} from '@sammo-ts/logic/triggers/general.js';
|
||||
import { BaseGeneralTrigger, type GeneralTriggerContext } from '@sammo-ts/logic/triggers/general.js';
|
||||
|
||||
const HEAL_PROBABILITY = 0.5;
|
||||
const MIN_HEAL_INJURY = 10;
|
||||
@@ -20,15 +17,13 @@ const resolveCityGenerals = <TriggerState extends GeneralTriggerState>(
|
||||
}
|
||||
const list = worldView.listGeneralsByCity
|
||||
? worldView.listGeneralsByCity(general.cityId)
|
||||
: worldView.listGenerals().filter(
|
||||
(candidate) => candidate.cityId === general.cityId
|
||||
);
|
||||
: worldView.listGenerals().filter((candidate) => candidate.cityId === general.cityId);
|
||||
return list.filter((candidate) => candidate.id !== general.id);
|
||||
};
|
||||
|
||||
// 의술 특기의 도시 치료 트리거.
|
||||
export class CheUisulCityHealTrigger<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends BaseGeneralTrigger<TriggerState> {
|
||||
public readonly priority = TriggerPriority.Begin + 10;
|
||||
|
||||
@@ -36,10 +31,7 @@ export class CheUisulCityHealTrigger<
|
||||
super(general);
|
||||
}
|
||||
|
||||
action(
|
||||
context: GeneralTriggerContext<TriggerState>,
|
||||
env: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
action(context: GeneralTriggerContext<TriggerState>, env: Record<string, unknown>): Record<string, unknown> {
|
||||
const general = context.general;
|
||||
const rng = context.rng;
|
||||
const logger = context.log;
|
||||
@@ -50,17 +42,15 @@ export class CheUisulCityHealTrigger<
|
||||
logger?.push('<C>의술</>을 펼쳐 스스로 치료합니다!');
|
||||
}
|
||||
|
||||
const candidates = resolveCityGenerals(general, context).filter(
|
||||
(candidate) => {
|
||||
if (candidate.injury <= MIN_HEAL_INJURY) {
|
||||
return false;
|
||||
}
|
||||
if (general.nationId === 0) {
|
||||
return candidate.nationId === 0;
|
||||
}
|
||||
return true;
|
||||
const candidates = resolveCityGenerals(general, context).filter((candidate) => {
|
||||
if (candidate.injury <= MIN_HEAL_INJURY) {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
if (general.nationId === 0) {
|
||||
return candidate.nationId === 0;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const healed = candidates.filter(() => rng.nextBool(HEAL_PROBABILITY));
|
||||
|
||||
@@ -75,14 +65,10 @@ export class CheUisulCityHealTrigger<
|
||||
const firstName = healed[0]?.name ?? '장수';
|
||||
if (healed.length === 1) {
|
||||
const josa = JosaUtil.pick(firstName, '을');
|
||||
logger?.push(
|
||||
`<C>의술</>을 펼쳐 도시의 장수 <Y>${firstName}</>${josa} 치료합니다!`
|
||||
);
|
||||
logger?.push(`<C>의술</>을 펼쳐 도시의 장수 <Y>${firstName}</>${josa} 치료합니다!`);
|
||||
} else {
|
||||
const otherCount = healed.length - 1;
|
||||
logger?.push(
|
||||
`<C>의술</>을 펼쳐 도시의 장수들 <Y>${firstName}</> 외 <C>${otherCount}</>명을 치료합니다!`
|
||||
);
|
||||
logger?.push(`<C>의술</>을 펼쳐 도시의 장수들 <Y>${firstName}</> 외 <C>${otherCount}</>명을 치료합니다!`);
|
||||
}
|
||||
|
||||
return env;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
import { TriggerPriority } from '@sammo-ts/logic/triggers/core.js';
|
||||
import {
|
||||
BaseGeneralTrigger,
|
||||
type GeneralTriggerContext,
|
||||
} from '@sammo-ts/logic/triggers/general.js';
|
||||
import { BaseGeneralTrigger, type GeneralTriggerContext } from '@sammo-ts/logic/triggers/general.js';
|
||||
import type { General } from '@sammo-ts/logic/domain/entities.js';
|
||||
|
||||
interface ItemHealOptions {
|
||||
@@ -24,10 +21,7 @@ export class CheItemHealTrigger extends BaseGeneralTrigger {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
action(
|
||||
context: GeneralTriggerContext,
|
||||
env: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
action(context: GeneralTriggerContext, env: Record<string, unknown>): Record<string, unknown> {
|
||||
const { general } = context;
|
||||
if (general.role.items.item !== this.options.itemKey) {
|
||||
return env;
|
||||
@@ -40,9 +34,7 @@ export class CheItemHealTrigger extends BaseGeneralTrigger {
|
||||
context.skill.activate('pre.부상경감', 'pre.치료');
|
||||
|
||||
const josa = JosaUtil.pick(this.options.itemRawName, '을');
|
||||
context.log?.push(
|
||||
`<C>${this.options.itemName}</>${josa} 사용하여 치료합니다!`
|
||||
);
|
||||
context.log?.push(`<C>${this.options.itemName}</>${josa} 사용하여 치료합니다!`);
|
||||
|
||||
if (this.options.consume()) {
|
||||
general.role.items.item = null;
|
||||
|
||||
@@ -1,45 +1,25 @@
|
||||
import type {
|
||||
TraitModule,
|
||||
TraitModuleExport,
|
||||
} from '@sammo-ts/logic/triggers/special/types.js';
|
||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
||||
|
||||
export const DOMESTIC_TRAIT_KEYS = [
|
||||
'che_인덕',
|
||||
'che_발명',
|
||||
] as const;
|
||||
export const DOMESTIC_TRAIT_KEYS = ['che_인덕', 'che_발명'] as const;
|
||||
|
||||
export type DomesticTraitKey =
|
||||
(typeof DOMESTIC_TRAIT_KEYS)[number];
|
||||
export type DomesticTraitKey = (typeof DOMESTIC_TRAIT_KEYS)[number];
|
||||
|
||||
export type DomesticTraitModule = TraitModule;
|
||||
|
||||
export type DomesticTraitImporter = () => Promise<TraitModuleExport>;
|
||||
|
||||
const defaultImporters: Record<
|
||||
DomesticTraitKey,
|
||||
DomesticTraitImporter
|
||||
> = {
|
||||
const defaultImporters: Record<DomesticTraitKey, DomesticTraitImporter> = {
|
||||
che_인덕: async () => import('./che_인덕.js'),
|
||||
che_발명: async () => import('./che_발명.js'),
|
||||
};
|
||||
|
||||
export const isDomesticTraitKey = (
|
||||
value: string
|
||||
): value is DomesticTraitKey =>
|
||||
export const isDomesticTraitKey = (value: string): value is DomesticTraitKey =>
|
||||
DOMESTIC_TRAIT_KEYS.includes(value as DomesticTraitKey);
|
||||
|
||||
export class DomesticTraitLoader {
|
||||
private readonly cache = new Map<
|
||||
DomesticTraitKey,
|
||||
Promise<DomesticTraitModule>
|
||||
>();
|
||||
private readonly cache = new Map<DomesticTraitKey, Promise<DomesticTraitModule>>();
|
||||
|
||||
constructor(
|
||||
private readonly importers: Record<
|
||||
DomesticTraitKey,
|
||||
DomesticTraitImporter
|
||||
> = defaultImporters
|
||||
) {}
|
||||
constructor(private readonly importers: Record<DomesticTraitKey, DomesticTraitImporter> = defaultImporters) {}
|
||||
|
||||
async load(key: DomesticTraitKey): Promise<DomesticTraitModule> {
|
||||
const cached = this.cache.get(key);
|
||||
@@ -56,14 +36,10 @@ export class DomesticTraitLoader {
|
||||
}
|
||||
const resolved = module.traitModule;
|
||||
if (resolved.key !== key) {
|
||||
throw new Error(
|
||||
`Domestic trait key mismatch: expected ${key}, got ${resolved.key}`
|
||||
);
|
||||
throw new Error(`Domestic trait key mismatch: expected ${key}, got ${resolved.key}`);
|
||||
}
|
||||
if (resolved.kind !== 'domestic') {
|
||||
throw new Error(
|
||||
`Domestic trait kind mismatch: ${resolved.key}`
|
||||
);
|
||||
throw new Error(`Domestic trait kind mismatch: ${resolved.key}`);
|
||||
}
|
||||
return resolved;
|
||||
});
|
||||
|
||||
@@ -39,5 +39,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -39,5 +39,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -40,5 +40,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -51,5 +51,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -40,5 +40,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -40,5 +40,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -39,5 +39,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -40,5 +40,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -40,5 +40,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -39,5 +39,5 @@ export const traitModule: TraitModule = {
|
||||
return value;
|
||||
}
|
||||
return onCalcStat;
|
||||
})() as Exclude<TraitModule["onCalcStat"], undefined>,
|
||||
})() as Exclude<TraitModule['onCalcStat'], undefined>,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import type {
|
||||
TraitModule,
|
||||
TraitModuleExport,
|
||||
} from '@sammo-ts/logic/triggers/special/types.js';
|
||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
||||
|
||||
export const PERSONALITY_TRAIT_KEYS = [
|
||||
'che_안전',
|
||||
@@ -17,17 +14,13 @@ export const PERSONALITY_TRAIT_KEYS = [
|
||||
'che_은둔',
|
||||
] as const;
|
||||
|
||||
export type PersonalityTraitKey =
|
||||
(typeof PERSONALITY_TRAIT_KEYS)[number];
|
||||
export type PersonalityTraitKey = (typeof PERSONALITY_TRAIT_KEYS)[number];
|
||||
|
||||
export type PersonalityTraitModule = TraitModule;
|
||||
|
||||
export type PersonalityTraitImporter = () => Promise<TraitModuleExport>;
|
||||
|
||||
const defaultImporters: Record<
|
||||
PersonalityTraitKey,
|
||||
PersonalityTraitImporter
|
||||
> = {
|
||||
const defaultImporters: Record<PersonalityTraitKey, PersonalityTraitImporter> = {
|
||||
che_안전: async () => import('./che_안전.js'),
|
||||
che_유지: async () => import('./che_유지.js'),
|
||||
che_재간: async () => import('./che_재간.js'),
|
||||
@@ -41,23 +34,13 @@ const defaultImporters: Record<
|
||||
che_은둔: async () => import('./che_은둔.js'),
|
||||
};
|
||||
|
||||
export const isPersonalityTraitKey = (
|
||||
value: string
|
||||
): value is PersonalityTraitKey =>
|
||||
export const isPersonalityTraitKey = (value: string): value is PersonalityTraitKey =>
|
||||
PERSONALITY_TRAIT_KEYS.includes(value as PersonalityTraitKey);
|
||||
|
||||
export class PersonalityTraitLoader {
|
||||
private readonly cache = new Map<
|
||||
PersonalityTraitKey,
|
||||
Promise<PersonalityTraitModule>
|
||||
>();
|
||||
private readonly cache = new Map<PersonalityTraitKey, Promise<PersonalityTraitModule>>();
|
||||
|
||||
constructor(
|
||||
private readonly importers: Record<
|
||||
PersonalityTraitKey,
|
||||
PersonalityTraitImporter
|
||||
> = defaultImporters
|
||||
) {}
|
||||
constructor(private readonly importers: Record<PersonalityTraitKey, PersonalityTraitImporter> = defaultImporters) {}
|
||||
|
||||
async load(key: PersonalityTraitKey): Promise<PersonalityTraitModule> {
|
||||
const cached = this.cache.get(key);
|
||||
@@ -74,14 +57,10 @@ export class PersonalityTraitLoader {
|
||||
}
|
||||
const resolved = module.traitModule;
|
||||
if (resolved.key !== key) {
|
||||
throw new Error(
|
||||
`Personality trait key mismatch: expected ${key}, got ${resolved.key}`
|
||||
);
|
||||
throw new Error(`Personality trait key mismatch: expected ${key}, got ${resolved.key}`);
|
||||
}
|
||||
if (resolved.kind !== 'personality') {
|
||||
throw new Error(
|
||||
`Personality trait kind mismatch: ${resolved.key}`
|
||||
);
|
||||
throw new Error(`Personality trait kind mismatch: ${resolved.key}`);
|
||||
}
|
||||
return resolved;
|
||||
});
|
||||
|
||||
@@ -15,11 +15,7 @@ import type {
|
||||
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 { TraitKind, TraitModule, TraitModuleRegistry } from './types.js';
|
||||
|
||||
const resolveTraitKey = (
|
||||
context: {
|
||||
@@ -63,23 +59,19 @@ const resolveModule = <TriggerState extends GeneralTriggerState>(
|
||||
|
||||
// General 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터.
|
||||
export class TraitGeneralActionRouter<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionModule<TriggerState> {
|
||||
constructor(
|
||||
private readonly kind: TraitKind,
|
||||
private readonly registry: TraitModuleRegistry<TriggerState>
|
||||
) {}
|
||||
|
||||
private getModule(
|
||||
context: GeneralActionContext<TriggerState>
|
||||
): TraitModule<TriggerState> | null {
|
||||
private getModule(context: GeneralActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
||||
const key = resolveTraitKey(context, this.kind);
|
||||
return resolveModule(this.registry, this.kind, key);
|
||||
}
|
||||
|
||||
getPreTurnExecuteTriggerList(
|
||||
context: GeneralActionContext<TriggerState>
|
||||
) {
|
||||
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>) {
|
||||
const module = this.getModule(context);
|
||||
return module?.getPreTurnExecuteTriggerList?.(context) ?? null;
|
||||
}
|
||||
@@ -112,9 +104,7 @@ export class TraitGeneralActionRouter<
|
||||
aux?: unknown
|
||||
): number {
|
||||
const module = this.getModule(context);
|
||||
return (
|
||||
module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value
|
||||
);
|
||||
return module?.onCalcOpposeStat?.(context, statName, value, aux) ?? value;
|
||||
}
|
||||
|
||||
onCalcStrategic(
|
||||
@@ -143,42 +133,31 @@ export class TraitGeneralActionRouter<
|
||||
aux?: Record<string, unknown> | null
|
||||
): Record<string, unknown> | null {
|
||||
const module = this.getModule(context);
|
||||
const result = module?.onArbitraryAction?.(
|
||||
context,
|
||||
actionType,
|
||||
phase,
|
||||
aux
|
||||
);
|
||||
return result === undefined ? aux ?? null : result;
|
||||
const result = module?.onArbitraryAction?.(context, actionType, phase, aux);
|
||||
return result === undefined ? (aux ?? null) : result;
|
||||
}
|
||||
}
|
||||
|
||||
// 전투 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터.
|
||||
export class TraitWarActionRouter<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements WarActionModule<TriggerState> {
|
||||
constructor(
|
||||
private readonly kind: TraitKind,
|
||||
private readonly registry: TraitModuleRegistry<TriggerState>
|
||||
) {}
|
||||
|
||||
private getModule(
|
||||
context: WarActionContext<TriggerState>
|
||||
): TraitModule<TriggerState> | null {
|
||||
private getModule(context: WarActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
||||
const key = resolveTraitKey(context, this.kind);
|
||||
return resolveModule(this.registry, this.kind, key);
|
||||
}
|
||||
|
||||
getBattleInitTriggerList(
|
||||
context: WarActionContext<TriggerState>
|
||||
): WarTriggerCaller | null {
|
||||
getBattleInitTriggerList(context: WarActionContext<TriggerState>): WarTriggerCaller | null {
|
||||
const module = this.getModule(context);
|
||||
return module?.getBattleInitTriggerList?.(context) ?? null;
|
||||
}
|
||||
|
||||
getBattlePhaseTriggerList(
|
||||
context: WarActionContext<TriggerState>
|
||||
): WarTriggerCaller | null {
|
||||
getBattlePhaseTriggerList(context: WarActionContext<TriggerState>): WarTriggerCaller | null {
|
||||
const module = this.getModule(context);
|
||||
return module?.getBattlePhaseTriggerList?.(context) ?? null;
|
||||
}
|
||||
@@ -213,16 +192,12 @@ export class TraitWarActionRouter<
|
||||
}
|
||||
}
|
||||
|
||||
export interface TraitModuleSet<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export interface TraitModuleSet<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
general: GeneralActionModule<TriggerState>[];
|
||||
war: WarActionModule<TriggerState>[];
|
||||
}
|
||||
|
||||
export const createTraitModuleRegistry = <
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
>(options: {
|
||||
export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(options: {
|
||||
domestic?: TraitModule<TriggerState>[];
|
||||
war?: TraitModule<TriggerState>[];
|
||||
personality?: TraitModule<TriggerState>[];
|
||||
@@ -245,9 +220,7 @@ export const createTraitModuleRegistry = <
|
||||
};
|
||||
|
||||
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
|
||||
export const createTraitModules = <
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
>(
|
||||
export const createTraitModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||
registry: TraitModuleRegistry<TriggerState>
|
||||
): TraitModuleSet<TriggerState> => ({
|
||||
general: [
|
||||
|
||||
@@ -11,21 +11,15 @@ export interface TraitSpec {
|
||||
kind: TraitKind;
|
||||
}
|
||||
|
||||
export type TraitModule<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> = TraitSpec &
|
||||
export type TraitModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> = TraitSpec &
|
||||
GeneralActionModule<TriggerState> &
|
||||
WarActionModule<TriggerState>;
|
||||
|
||||
export interface TraitModuleExport<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export interface TraitModuleExport<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
traitModule: TraitModule<TriggerState>;
|
||||
}
|
||||
|
||||
export interface TraitModuleRegistry<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export interface TraitModuleRegistry<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
domestic: Map<string, TraitModule<TriggerState>>;
|
||||
war: Map<string, TraitModule<TriggerState>>;
|
||||
personality: Map<string, TraitModule<TriggerState>>;
|
||||
|
||||
@@ -13,8 +13,7 @@ export const traitModule: TraitModule = {
|
||||
getName: () => '의술',
|
||||
getInfo: () =>
|
||||
'[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)',
|
||||
getPreTurnExecuteTriggerList: (context) =>
|
||||
new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general)),
|
||||
getPreTurnExecuteTriggerList: (context) => new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general)),
|
||||
getBattlePhaseTriggerList: (context: WarActionContext) => {
|
||||
const unit = context.unit;
|
||||
if (!unit) {
|
||||
|
||||
@@ -17,12 +17,7 @@ const resolveLeadershipBonus = (
|
||||
return value + base * 0.25;
|
||||
};
|
||||
|
||||
function onCalcStat(
|
||||
context: GeneralActionContext,
|
||||
statName: GeneralStatName,
|
||||
value: number,
|
||||
aux?: unknown
|
||||
): number;
|
||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||
function onCalcStat(
|
||||
context: WarActionContext,
|
||||
statName: WarStatName,
|
||||
|
||||
@@ -1,45 +1,24 @@
|
||||
import type {
|
||||
TraitModule,
|
||||
TraitModuleExport,
|
||||
} from '@sammo-ts/logic/triggers/special/types.js';
|
||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
||||
|
||||
export const WAR_TRAIT_KEYS = [
|
||||
'che_의술',
|
||||
'che_징병',
|
||||
] as const;
|
||||
export const WAR_TRAIT_KEYS = ['che_의술', 'che_징병'] as const;
|
||||
|
||||
export type WarTraitKey =
|
||||
(typeof WAR_TRAIT_KEYS)[number];
|
||||
export type WarTraitKey = (typeof WAR_TRAIT_KEYS)[number];
|
||||
|
||||
export type WarTraitModule = TraitModule;
|
||||
|
||||
export type WarTraitImporter = () => Promise<TraitModuleExport>;
|
||||
|
||||
const defaultImporters: Record<
|
||||
WarTraitKey,
|
||||
WarTraitImporter
|
||||
> = {
|
||||
const defaultImporters: Record<WarTraitKey, WarTraitImporter> = {
|
||||
che_의술: async () => import('./che_의술.js'),
|
||||
che_징병: async () => import('./che_징병.js'),
|
||||
};
|
||||
|
||||
export const isWarTraitKey = (
|
||||
value: string
|
||||
): value is WarTraitKey =>
|
||||
WAR_TRAIT_KEYS.includes(value as WarTraitKey);
|
||||
export const isWarTraitKey = (value: string): value is WarTraitKey => WAR_TRAIT_KEYS.includes(value as WarTraitKey);
|
||||
|
||||
export class WarTraitLoader {
|
||||
private readonly cache = new Map<
|
||||
WarTraitKey,
|
||||
Promise<WarTraitModule>
|
||||
>();
|
||||
private readonly cache = new Map<WarTraitKey, Promise<WarTraitModule>>();
|
||||
|
||||
constructor(
|
||||
private readonly importers: Record<
|
||||
WarTraitKey,
|
||||
WarTraitImporter
|
||||
> = defaultImporters
|
||||
) {}
|
||||
constructor(private readonly importers: Record<WarTraitKey, WarTraitImporter> = defaultImporters) {}
|
||||
|
||||
async load(key: WarTraitKey): Promise<WarTraitModule> {
|
||||
const cached = this.cache.get(key);
|
||||
@@ -56,9 +35,7 @@ export class WarTraitLoader {
|
||||
}
|
||||
const resolved = module.traitModule;
|
||||
if (resolved.key !== key) {
|
||||
throw new Error(
|
||||
`War trait key mismatch: expected ${key}, got ${resolved.key}`
|
||||
);
|
||||
throw new Error(`War trait key mismatch: expected ${key}, got ${resolved.key}`);
|
||||
}
|
||||
if (resolved.kind !== 'war') {
|
||||
throw new Error(`War trait kind mismatch: ${resolved.key}`);
|
||||
|
||||
@@ -14,35 +14,15 @@ export type TriggerDomesticActionType =
|
||||
| '모병'
|
||||
| '단련';
|
||||
|
||||
export type TriggerDomesticVarType =
|
||||
| 'cost'
|
||||
| 'score'
|
||||
| 'success'
|
||||
| 'fail'
|
||||
| 'train'
|
||||
| 'atmos'
|
||||
| 'rice'
|
||||
| 'probability';
|
||||
export type TriggerDomesticVarType = 'cost' | 'score' | 'success' | 'fail' | 'train' | 'atmos' | 'rice' | 'probability';
|
||||
|
||||
export type TriggerStrategicActionType =
|
||||
| '의병모집'
|
||||
| '허보'
|
||||
| '필사즉생'
|
||||
| '백성동원'
|
||||
| '이호경식'
|
||||
| '수몰'
|
||||
| '급습';
|
||||
export type TriggerStrategicActionType = '의병모집' | '허보' | '필사즉생' | '백성동원' | '이호경식' | '수몰' | '급습';
|
||||
|
||||
export type TriggerStrategicVarType = 'delay' | 'globalDelay';
|
||||
|
||||
export type TriggerNationalIncomeType = 'gold' | 'rice';
|
||||
|
||||
export type GeneralStatName =
|
||||
| 'leadership'
|
||||
| 'strength'
|
||||
| 'intelligence'
|
||||
| 'experience'
|
||||
| 'dedication';
|
||||
export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication';
|
||||
|
||||
export type WarStatName =
|
||||
| GeneralStatName
|
||||
|
||||
Reference in New Issue
Block a user