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:
2026-01-03 08:01:04 +00:00
parent eb361e1bed
commit 64953e39a5
29 changed files with 1250 additions and 28 deletions
+81
View File
@@ -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';