Files
core2026/packages/logic/src/inheritance/inheritBuff.ts
T

123 lines
4.1 KiB
TypeScript

import type {
TriggerDomesticActionType,
TriggerDomesticVarType,
WarStatName,
} from '@sammo-ts/logic/actionModules/types.js';
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
import { asRecord, parseJson } from '@sammo-ts/common';
export type InheritBuffType =
| 'warAvoidRatio'
| 'warCriticalRatio'
| 'warMagicTrialProb'
| 'domesticSuccessProb'
| 'domesticFailProb'
| 'warAvoidRatioOppose'
| 'warCriticalRatioOppose'
| 'warMagicTrialProbOppose';
const DOMESTIC_TARGETS = new Set<TriggerDomesticActionType>([
'상업',
'농업',
'치안',
'성벽',
'수비',
'민심',
'인구',
'기술',
]);
const readBuffLevel = (buff: Record<string, unknown>, key: InheritBuffType): number => {
const compatibilityKey = key === 'domesticSuccessProb' ? 'success' : key === 'domesticFailProb' ? 'fail' : null;
const raw = buff[key] ?? (compatibilityKey ? buff[compatibilityKey] : undefined);
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
return 0;
}
return Math.max(0, Math.min(5, Math.floor(raw)));
};
const parseInheritBuff = (value: unknown): Record<string, unknown> => {
if (typeof value === 'string') {
const parsed = parseJson<Record<string, unknown>>(value);
return parsed ?? {};
}
return asRecord(value);
};
const resolveBuffRecord = (context: {
general: { meta: Record<string, unknown>; triggerState: { meta: Record<string, unknown> } };
}): Record<string, unknown> => {
const fromTrigger = parseInheritBuff(context.general.triggerState.meta.inheritBuff);
if (Object.keys(fromTrigger).length > 0) {
return fromTrigger;
}
return parseInheritBuff(context.general.meta.inheritBuff);
};
const applyDomesticBuff = (
buff: Record<string, unknown>,
turnType: TriggerDomesticActionType,
varType: TriggerDomesticVarType,
value: number
): number => {
if (!DOMESTIC_TARGETS.has(turnType)) {
return value;
}
if (varType === 'success') {
const level = readBuffLevel(buff, 'domesticSuccessProb');
return value + level * 0.01;
}
if (varType === 'fail') {
const level = readBuffLevel(buff, 'domesticFailProb');
return value - level * 0.01;
}
return value;
};
const applyWarBuff = (buff: Record<string, unknown>, statName: WarStatName, value: number | [number, number]) => {
if (typeof value !== 'number') {
return value;
}
if (statName === 'warAvoidRatio') {
return value + readBuffLevel(buff, 'warAvoidRatio') * 0.01;
}
if (statName === 'warCriticalRatio') {
return value + readBuffLevel(buff, 'warCriticalRatio') * 0.01;
}
if (statName === 'warMagicTrialProb') {
return value + readBuffLevel(buff, 'warMagicTrialProb') * 0.01;
}
return value;
};
const applyOpposeWarBuff = (buff: Record<string, unknown>, statName: WarStatName, value: number | [number, number]) => {
if (typeof value !== 'number') {
return value;
}
if (statName === 'warAvoidRatio') {
return value - readBuffLevel(buff, 'warAvoidRatioOppose') * 0.01;
}
if (statName === 'warCriticalRatio') {
return value - readBuffLevel(buff, 'warCriticalRatioOppose') * 0.01;
}
if (statName === 'warMagicTrialProb') {
return value - readBuffLevel(buff, 'warMagicTrialProbOppose') * 0.01;
}
return value;
};
export const createInheritBuffModules = (): { general: GeneralActionModule; war: WarActionModule } => {
const general: GeneralActionModule = {
onCalcDomestic: (context, turnType, varType, value) =>
applyDomesticBuff(resolveBuffRecord(context), turnType, varType, value),
};
const war: WarActionModule = {
onCalcStat: (context, statName, value) => applyWarBuff(resolveBuffRecord(context), statName, value),
onCalcOpposeStat: (context, statName, value) => applyOpposeWarBuff(resolveBuffRecord(context), statName, value),
};
return { general, war };
};