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,90 @@
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
|
||||
import type { General, GeneralTriggerState } from '../../domain/entities.js';
|
||||
import { TriggerPriority } from '../core.js';
|
||||
import {
|
||||
BaseGeneralTrigger,
|
||||
type GeneralTriggerContext,
|
||||
} from '../general.js';
|
||||
|
||||
const HEAL_PROBABILITY = 0.5;
|
||||
const MIN_HEAL_INJURY = 10;
|
||||
|
||||
const resolveCityGenerals = <TriggerState extends GeneralTriggerState>(
|
||||
general: General<TriggerState>,
|
||||
context: GeneralTriggerContext<TriggerState>
|
||||
): General<TriggerState>[] => {
|
||||
const worldView = context.worldView;
|
||||
if (!worldView) {
|
||||
return [];
|
||||
}
|
||||
const list = worldView.listGeneralsByCity
|
||||
? worldView.listGeneralsByCity(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
|
||||
> extends BaseGeneralTrigger<TriggerState> {
|
||||
public readonly priority = TriggerPriority.Begin + 10;
|
||||
|
||||
public constructor(general: General<TriggerState>) {
|
||||
super(general);
|
||||
}
|
||||
|
||||
action(
|
||||
context: GeneralTriggerContext<TriggerState>,
|
||||
env: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const general = context.general;
|
||||
const rng = context.rng;
|
||||
const logger = context.log;
|
||||
|
||||
if (general.injury > 0) {
|
||||
general.injury = 0;
|
||||
context.skill.activate('pre.부상경감', 'pre.치료');
|
||||
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 healed = candidates.filter(() => rng.nextBool(HEAL_PROBABILITY));
|
||||
|
||||
for (const patient of healed) {
|
||||
patient.injury = 0;
|
||||
}
|
||||
|
||||
if (healed.length === 0) {
|
||||
return env;
|
||||
}
|
||||
|
||||
const firstName = healed[0]?.name ?? '장수';
|
||||
if (healed.length === 1) {
|
||||
const josa = JosaUtil.pick(firstName, '을');
|
||||
logger?.push(
|
||||
`<C>의술</>을 펼쳐 도시의 장수 <Y>${firstName}</>${josa} 치료합니다!`
|
||||
);
|
||||
} else {
|
||||
const otherCount = healed.length - 1;
|
||||
logger?.push(
|
||||
`<C>의술</>을 펼쳐 도시의 장수들 <Y>${firstName}</> 외 <C>${otherCount}</>명을 치료합니다!`
|
||||
);
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user