feat: add special action modules for domestic and war triggers
- Implemented '발명' and '인덕' domestic special action modules with modifiers for technology research and population management. - Added '의술' and '징병' war special action modules to enhance healing and recruitment capabilities during battles. - Created a general trigger for city healing in '의술' and integrated it with the war action pipeline. - Developed a comprehensive registry and loader for special action modules to streamline their usage in the game logic. - Enhanced test coverage for special action modules, ensuring correct application of modifiers and trigger functionalities.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { LogFormat } from '../../logging/types.js';
|
||||
import { TriggerPriority } from '../../triggers/core.js';
|
||||
import { BaseWarUnitTrigger, WarTriggerCaller } from '../triggers.js';
|
||||
import { WarUnitGeneral, type WarUnit } from '../units.js';
|
||||
import type { WarTriggerModule } from './types.js';
|
||||
|
||||
// 의술: 치료 시도
|
||||
class AttemptTrigger extends BaseWarUnitTrigger {
|
||||
constructor(unit: WarUnit) {
|
||||
super(unit, TriggerPriority.Pre + 350);
|
||||
}
|
||||
|
||||
protected actionWar(
|
||||
self: WarUnit,
|
||||
_oppose: WarUnit,
|
||||
_selfEnv: Record<string, unknown>,
|
||||
_opposeEnv: Record<string, unknown>
|
||||
): boolean {
|
||||
if (!(self instanceof WarUnitGeneral)) {
|
||||
return true;
|
||||
}
|
||||
if (self.hasActivatedSkill('치료')) {
|
||||
return true;
|
||||
}
|
||||
if (self.hasActivatedSkill('치료불가')) {
|
||||
return true;
|
||||
}
|
||||
if (!self.rng.nextBool(0.4)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.activateSkill('치료');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 의술: 치료 발동
|
||||
class ActivateTrigger extends BaseWarUnitTrigger {
|
||||
constructor(unit: WarUnit) {
|
||||
super(unit, TriggerPriority.Post + 550);
|
||||
}
|
||||
|
||||
protected actionWar(
|
||||
self: WarUnit,
|
||||
oppose: WarUnit,
|
||||
selfEnv: Record<string, unknown>,
|
||||
_opposeEnv: Record<string, unknown>
|
||||
): boolean {
|
||||
if (!self.hasActivatedSkill('치료')) {
|
||||
return true;
|
||||
}
|
||||
if (selfEnv['치료발동']) {
|
||||
return true;
|
||||
}
|
||||
selfEnv['치료발동'] = true;
|
||||
|
||||
oppose
|
||||
.getLogger()
|
||||
.pushGeneralBattleDetailLog(
|
||||
'상대가 <R>치료</>했다!',
|
||||
LogFormat.PLAIN
|
||||
);
|
||||
self
|
||||
.getLogger()
|
||||
.pushGeneralBattleDetailLog('<C>치료</>했다!', LogFormat.PLAIN);
|
||||
|
||||
oppose.multiplyWarPowerMultiply(0.7);
|
||||
if (self instanceof WarUnitGeneral) {
|
||||
self.getGeneral().injury = 0;
|
||||
}
|
||||
|
||||
this.processConsumableItem();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const triggerModule: WarTriggerModule = {
|
||||
key: 'che_의술',
|
||||
name: '의술',
|
||||
info: '[전투] 페이즈마다 치료 발동(아군 피해 30% 감소, 부상 회복)',
|
||||
createTriggerList: (unit) =>
|
||||
new WarTriggerCaller(
|
||||
new AttemptTrigger(unit),
|
||||
new ActivateTrigger(unit)
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { LogFormat } from '../../logging/types.js';
|
||||
import { TriggerPriority } from '../../triggers/core.js';
|
||||
import { BaseWarUnitTrigger, WarTriggerCaller } from '../triggers.js';
|
||||
import { WarUnitGeneral, type WarUnit } from '../units.js';
|
||||
import type { WarTriggerModule } from './types.js';
|
||||
|
||||
// 기본 필살: 시도 단계
|
||||
class AttemptTrigger extends BaseWarUnitTrigger {
|
||||
constructor(unit: WarUnit) {
|
||||
super(unit, TriggerPriority.Pre + 120);
|
||||
}
|
||||
|
||||
protected actionWar(
|
||||
self: WarUnit,
|
||||
_oppose: WarUnit,
|
||||
_selfEnv: Record<string, unknown>,
|
||||
_opposeEnv: Record<string, unknown>
|
||||
): boolean {
|
||||
if (!(self instanceof WarUnitGeneral)) {
|
||||
return true;
|
||||
}
|
||||
if (self.hasActivatedSkill('특수')) {
|
||||
return true;
|
||||
}
|
||||
if (self.hasActivatedSkill('필살불가')) {
|
||||
return true;
|
||||
}
|
||||
if (!self.rng.nextBool(self.getComputedCriticalRatio())) {
|
||||
return true;
|
||||
}
|
||||
self.activateSkill('필살시도', '필살');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 기본 필살: 발동 단계
|
||||
class ActivateTrigger extends BaseWarUnitTrigger {
|
||||
constructor(unit: WarUnit) {
|
||||
super(unit, TriggerPriority.Post + 400);
|
||||
}
|
||||
|
||||
protected actionWar(
|
||||
self: WarUnit,
|
||||
oppose: WarUnit,
|
||||
selfEnv: Record<string, unknown>,
|
||||
_opposeEnv: Record<string, unknown>
|
||||
): boolean {
|
||||
if (!self.hasActivatedSkill('필살')) {
|
||||
return true;
|
||||
}
|
||||
if (selfEnv['필살발동']) {
|
||||
return true;
|
||||
}
|
||||
selfEnv['필살발동'] = true;
|
||||
|
||||
oppose
|
||||
.getLogger()
|
||||
.pushGeneralBattleDetailLog('상대의 <R>필살</>공격!</>', LogFormat.PLAIN);
|
||||
self
|
||||
.getLogger()
|
||||
.pushGeneralBattleDetailLog('<C>필살</>공격!</>', LogFormat.PLAIN);
|
||||
|
||||
self.multiplyWarPowerMultiply(self.criticalDamage());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const triggerModule: WarTriggerModule = {
|
||||
key: 'che_필살',
|
||||
name: '필살',
|
||||
info: '[전투] 페이즈마다 확률로 필살 발동',
|
||||
createTriggerList: (unit) =>
|
||||
new WarTriggerCaller(
|
||||
new AttemptTrigger(unit),
|
||||
new ActivateTrigger(unit)
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import type { WarTriggerModule, WarTriggerModuleExport } from './types.js';
|
||||
import type { WarTriggerRegistry } from '../triggers.js';
|
||||
|
||||
export const WAR_TRIGGER_KEYS = [
|
||||
'che_필살',
|
||||
'che_의술',
|
||||
] as const;
|
||||
|
||||
export type WarTriggerKey =
|
||||
(typeof WAR_TRIGGER_KEYS)[number];
|
||||
|
||||
export type WarTriggerImporter = () => Promise<WarTriggerModuleExport>;
|
||||
|
||||
const defaultImporters: Record<WarTriggerKey, WarTriggerImporter> = {
|
||||
che_필살: async () => import('./che_필살.js'),
|
||||
che_의술: async () => import('./che_의술.js'),
|
||||
};
|
||||
|
||||
export const isWarTriggerKey = (value: string): value is WarTriggerKey =>
|
||||
WAR_TRIGGER_KEYS.includes(value as WarTriggerKey);
|
||||
|
||||
export class WarTriggerLoader {
|
||||
private readonly cache = new Map<WarTriggerKey, Promise<WarTriggerModule>>();
|
||||
|
||||
constructor(
|
||||
private readonly importers: Record<WarTriggerKey, WarTriggerImporter> = defaultImporters
|
||||
) {}
|
||||
|
||||
async load(key: WarTriggerKey): Promise<WarTriggerModule> {
|
||||
const cached = this.cache.get(key);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const importer = this.importers[key];
|
||||
if (!importer) {
|
||||
throw new Error(`Unknown war trigger key: ${key}`);
|
||||
}
|
||||
const loading = importer().then((module) => {
|
||||
if (!('triggerModule' in module)) {
|
||||
throw new Error(`Missing triggerModule for war trigger: ${key}`);
|
||||
}
|
||||
const resolved = module.triggerModule;
|
||||
if (resolved.key !== key) {
|
||||
throw new Error(
|
||||
`War trigger key mismatch: expected ${key}, got ${resolved.key}`
|
||||
);
|
||||
}
|
||||
return resolved;
|
||||
});
|
||||
this.cache.set(key, loading);
|
||||
return loading;
|
||||
}
|
||||
}
|
||||
|
||||
export const loadWarTriggerModules = async (
|
||||
keys: WarTriggerKey[],
|
||||
loader: WarTriggerLoader = new WarTriggerLoader()
|
||||
): Promise<WarTriggerModule[]> => {
|
||||
const modules: WarTriggerModule[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const key of keys) {
|
||||
if (seen.has(key)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(key);
|
||||
modules.push(await loader.load(key));
|
||||
}
|
||||
return modules;
|
||||
};
|
||||
|
||||
export const createWarTriggerRegistry = (
|
||||
modules: WarTriggerModule[]
|
||||
): WarTriggerRegistry => {
|
||||
const registry: WarTriggerRegistry = {};
|
||||
for (const module of modules) {
|
||||
registry[module.key] = (unit) => module.createTriggerList(unit);
|
||||
}
|
||||
return registry;
|
||||
};
|
||||
|
||||
export type { WarTriggerModule, WarTriggerModuleExport } from './types.js';
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { WarTriggerCaller } from '../triggers.js';
|
||||
import type { WarUnit } from '../units.js';
|
||||
|
||||
export interface WarTriggerModule {
|
||||
key: string;
|
||||
name: string;
|
||||
info: string;
|
||||
createTriggerList(unit: WarUnit): WarTriggerCaller | null;
|
||||
}
|
||||
|
||||
export interface WarTriggerModuleExport {
|
||||
triggerModule: WarTriggerModule;
|
||||
}
|
||||
Reference in New Issue
Block a user