feat: 상업 투자 관련 로직 및 효과 추가, 엔진에서 더러운 상태 추적 기능 개선

This commit is contained in:
2025-12-28 18:21:47 +00:00
parent b927a30e97
commit 7124483001
2 changed files with 159 additions and 0 deletions
+62
View File
@@ -4,7 +4,10 @@ import type {
General,
GeneralRole,
GeneralTriggerState,
CityId,
GeneralId,
Nation,
NationId,
StatBlock,
} from '../domain/entities.js';
import type { GeneralActionContext } from '../triggers/general.js';
@@ -81,6 +84,14 @@ export interface GeneralActionResolution {
nextTurnAt: Date;
logs: string[];
effects: GeneralActionEffect[];
dirty?: {
general: boolean;
city: boolean;
nation: boolean;
generalId?: GeneralId;
cityId?: CityId;
nationId?: NationId;
};
}
const mergeStats = (base: StatBlock, patch: Partial<StatBlock>): StatBlock => ({
@@ -139,6 +150,39 @@ const applyNationPatch = (base: Nation, patch: Partial<Nation>): Nation => ({
meta: patch.meta ? { ...base.meta, ...patch.meta } : base.meta,
});
export const createGeneralPatchEffect = <
TriggerState extends GeneralTriggerState = GeneralTriggerState
>(
patch: Partial<General<TriggerState>>
): GeneralPatchEffect<TriggerState> => ({
type: 'general:patch',
patch,
});
export const createCityPatchEffect = (patch: Partial<City>): CityPatchEffect => ({
type: 'city:patch',
patch,
});
export const createNationPatchEffect = (
patch: Partial<Nation>
): NationPatchEffect => ({
type: 'nation:patch',
patch,
});
export const createLogEffect = (message: string): LogEffect => ({
type: 'log',
message,
});
export const createNextTurnOverrideEffect = (
nextTurnAt: Date
): NextTurnOverrideEffect => ({
type: 'schedule:override',
nextTurnAt,
});
// 행동 결과를 Effect로 모아 상태/턴 계산을 수행한다.
export const resolveGeneralAction = <
TriggerState extends GeneralTriggerState = GeneralTriggerState
@@ -153,20 +197,35 @@ export const resolveGeneralAction = <
let nextCity = context.city;
let nextNation = context.nation ?? null;
let nextTurnAtOverride: Date | null = null;
const dirty: NonNullable<GeneralActionResolution['dirty']> = {
general: false,
city: false,
nation: false,
generalId: context.general.id,
};
if (context.city) {
dirty.cityId = context.city.id;
}
if (context.nation) {
dirty.nationId = context.nation.id;
}
for (const effect of outcome.effects) {
switch (effect.type) {
case 'general:patch':
nextGeneral = applyGeneralPatch(nextGeneral, effect.patch);
dirty.general = true;
break;
case 'city:patch':
if (nextCity) {
nextCity = applyCityPatch(nextCity, effect.patch);
dirty.city = true;
}
break;
case 'nation:patch':
if (nextNation) {
nextNation = applyNationPatch(nextNation, effect.patch);
dirty.nation = true;
}
break;
case 'log':
@@ -194,6 +253,9 @@ export const resolveGeneralAction = <
if (nextCity) {
resolution.city = nextCity;
}
if (dirty.general || dirty.city || dirty.nation) {
resolution.dirty = dirty;
}
return resolution;
};