fix(engine): preserve core monthly event arguments
This commit is contained in:
@@ -141,29 +141,11 @@ const processIncomeForNation = (
|
||||
|
||||
let income = 0;
|
||||
if (type === 'gold') {
|
||||
income = getGoldIncome(
|
||||
incomeContext,
|
||||
nationCities,
|
||||
officerCounts,
|
||||
nation.capitalCityId ?? 0,
|
||||
nation.level
|
||||
);
|
||||
income = getGoldIncome(incomeContext, nationCities, officerCounts, nation.capitalCityId ?? 0, nation.level);
|
||||
} else {
|
||||
income =
|
||||
getRiceIncome(
|
||||
incomeContext,
|
||||
nationCities,
|
||||
officerCounts,
|
||||
nation.capitalCityId ?? 0,
|
||||
nation.level
|
||||
) +
|
||||
getWallIncome(
|
||||
incomeContext,
|
||||
nationCities,
|
||||
officerCounts,
|
||||
nation.capitalCityId ?? 0,
|
||||
nation.level
|
||||
);
|
||||
getRiceIncome(incomeContext, nationCities, officerCounts, nation.capitalCityId ?? 0, nation.level) +
|
||||
getWallIncome(incomeContext, nationCities, officerCounts, nation.capitalCityId ?? 0, nation.level);
|
||||
}
|
||||
|
||||
const incomeValue = roundResource(income);
|
||||
@@ -185,7 +167,8 @@ const processIncomeForNation = (
|
||||
}
|
||||
|
||||
const incomeText = incomeValue.toLocaleString();
|
||||
const incomeLog = type === 'gold' ? `이번 수입은 금 <C>${incomeText}</>입니다.` : `이번 수입은 쌀 <C>${incomeText}</>입니다.`;
|
||||
const incomeLog =
|
||||
type === 'gold' ? `이번 수입은 금 <C>${incomeText}</>입니다.` : `이번 수입은 쌀 <C>${incomeText}</>입니다.`;
|
||||
for (const general of nationGenerals) {
|
||||
const pay = Math.round(getBill(general.dedication) * ratio);
|
||||
if (type === 'gold') {
|
||||
@@ -208,72 +191,67 @@ const processIncomeForNation = (
|
||||
}
|
||||
};
|
||||
|
||||
export interface IncomeHandler extends TurnCalendarHandler {
|
||||
runResource(resource: 'gold' | 'rice'): void;
|
||||
}
|
||||
|
||||
export const createIncomeHandler = (options: {
|
||||
getWorld: () => InMemoryTurnWorld | null;
|
||||
scenarioConfig: ScenarioConfig;
|
||||
nationTraits: Map<string, NationTraitModule>;
|
||||
}): TurnCalendarHandler => {
|
||||
}): IncomeHandler => {
|
||||
const constValues = asRecord(options.scenarioConfig.const);
|
||||
const baseGold = resolveNumber(constValues, ['baseGold', 'basegold'], 0);
|
||||
const baseRice = resolveNumber(constValues, ['baseRice', 'baserice'], 0);
|
||||
|
||||
const handler: TurnCalendarHandler = {
|
||||
const runResource = (type: 'gold' | 'rice'): void => {
|
||||
const world = options.getWorld();
|
||||
if (!world) {
|
||||
return;
|
||||
}
|
||||
const nations = world.listNations();
|
||||
const generals = world.listGenerals();
|
||||
const cities = world.listCities();
|
||||
|
||||
const byNation: Map<number, TurnGeneral[]> = new Map();
|
||||
for (const general of generals) {
|
||||
const bucket = byNation.get(general.nationId) ?? [];
|
||||
bucket.push(general);
|
||||
byNation.set(general.nationId, bucket);
|
||||
}
|
||||
|
||||
for (const nation of nations) {
|
||||
const nationGenerals = byNation.get(nation.id) ?? [];
|
||||
const officerCounts = buildOfficerCountMap(nationGenerals);
|
||||
processIncomeForNation(
|
||||
world,
|
||||
nation,
|
||||
nationGenerals,
|
||||
cities,
|
||||
officerCounts,
|
||||
options.nationTraits,
|
||||
type,
|
||||
type === 'gold' ? baseGold : baseRice
|
||||
);
|
||||
}
|
||||
|
||||
const logger = new ActionLogger();
|
||||
if (type === 'gold') {
|
||||
logger.pushGlobalHistoryLog('<W><b>【지급】</b></>봄이 되어 봉록에 따라 자금이 지급됩니다.');
|
||||
} else {
|
||||
logger.pushGlobalHistoryLog('<W><b>【지급】</b></>가을이 되어 봉록에 따라 군량이 지급됩니다.');
|
||||
}
|
||||
pushLogs(world, logger.flush());
|
||||
};
|
||||
|
||||
const handler: IncomeHandler = {
|
||||
runResource,
|
||||
onMonthChanged: (context: TurnCalendarContext) => {
|
||||
const world = options.getWorld();
|
||||
if (!world) {
|
||||
return;
|
||||
if (context.currentMonth === 1) {
|
||||
runResource('gold');
|
||||
} else if (context.currentMonth === 7) {
|
||||
runResource('rice');
|
||||
}
|
||||
const month = context.currentMonth;
|
||||
if (month !== 1 && month !== 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nations = world.listNations();
|
||||
const generals = world.listGenerals();
|
||||
const cities = world.listCities();
|
||||
|
||||
const byNation: Map<number, TurnGeneral[]> = new Map();
|
||||
for (const general of generals) {
|
||||
const bucket = byNation.get(general.nationId) ?? [];
|
||||
bucket.push(general);
|
||||
byNation.set(general.nationId, bucket);
|
||||
}
|
||||
|
||||
for (const nation of nations) {
|
||||
const nationGenerals = byNation.get(nation.id) ?? [];
|
||||
const officerCounts = buildOfficerCountMap(nationGenerals);
|
||||
if (month === 1) {
|
||||
processIncomeForNation(
|
||||
world,
|
||||
nation,
|
||||
nationGenerals,
|
||||
cities,
|
||||
officerCounts,
|
||||
options.nationTraits,
|
||||
'gold',
|
||||
baseGold
|
||||
);
|
||||
} else if (month === 7) {
|
||||
processIncomeForNation(
|
||||
world,
|
||||
nation,
|
||||
nationGenerals,
|
||||
cities,
|
||||
officerCounts,
|
||||
options.nationTraits,
|
||||
'rice',
|
||||
baseRice
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const logger = new ActionLogger();
|
||||
if (month === 1) {
|
||||
logger.pushGlobalHistoryLog('<W><b>【지급】</b></>봄이 되어 봉록에 따라 자금이 지급됩니다.');
|
||||
} else if (month === 7) {
|
||||
logger.pushGlobalHistoryLog('<W><b>【지급】</b></>가을이 되어 봉록에 따라 군량이 지급됩니다.');
|
||||
}
|
||||
pushLogs(world, logger.flush());
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic';
|
||||
|
||||
import type { IncomeHandler } from './incomeHandler.js';
|
||||
import type { InMemoryTurnWorld } from './inMemoryWorld.js';
|
||||
import type { MonthlyEventActionHandler } from './monthlyEventHandler.js';
|
||||
|
||||
const parseLogFormat = (value: unknown): LogFormat => {
|
||||
if (value === undefined) {
|
||||
return LogFormat.YEAR_MONTH;
|
||||
}
|
||||
if (
|
||||
typeof value !== 'number' ||
|
||||
!Number.isInteger(value) ||
|
||||
value < LogFormat.RAWTEXT ||
|
||||
value > LogFormat.NOTICE_YEAR_MONTH
|
||||
) {
|
||||
throw new Error('NoticeToHistoryLog format must be an integer from 0 through 8.');
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export const createProcessIncomeActionHandler = (incomeHandler: IncomeHandler): MonthlyEventActionHandler => {
|
||||
return (args) => {
|
||||
const resource = args[0];
|
||||
if (resource !== 'gold' && resource !== 'rice') {
|
||||
throw new Error('ProcessIncome resource must be gold or rice.');
|
||||
}
|
||||
incomeHandler.runResource(resource);
|
||||
};
|
||||
};
|
||||
|
||||
export const createNoticeToHistoryLogHandler = (options: {
|
||||
getWorld: () => InMemoryTurnWorld | null;
|
||||
}): MonthlyEventActionHandler => {
|
||||
return (args) => {
|
||||
const text = args[0];
|
||||
if (typeof text !== 'string') {
|
||||
throw new Error('NoticeToHistoryLog message must be a string.');
|
||||
}
|
||||
const world = options.getWorld();
|
||||
if (!world) {
|
||||
return;
|
||||
}
|
||||
world.pushLog({
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.HISTORY,
|
||||
text,
|
||||
format: parseLogFormat(args[1]),
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const createNewYearHandler = (options: {
|
||||
getWorld: () => InMemoryTurnWorld | null;
|
||||
}): MonthlyEventActionHandler => {
|
||||
return (_args, environment) => {
|
||||
const world = options.getWorld();
|
||||
if (!world) {
|
||||
return;
|
||||
}
|
||||
for (const general of world.listGenerals()) {
|
||||
const belong = general.meta.belong;
|
||||
world.updateGeneral(general.id, {
|
||||
age: general.age + 1,
|
||||
meta: {
|
||||
...general.meta,
|
||||
...(general.nationId !== 0
|
||||
? { belong: typeof belong === 'number' && Number.isFinite(belong) ? belong + 1 : 1 }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
world.pushLog({
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.ACTION,
|
||||
text: `<C>${environment.year}</>년이 되었습니다.`,
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const createResetOfficerLockHandler = (options: {
|
||||
getWorld: () => InMemoryTurnWorld | null;
|
||||
}): MonthlyEventActionHandler => {
|
||||
return () => {
|
||||
const world = options.getWorld();
|
||||
if (!world) {
|
||||
return;
|
||||
}
|
||||
for (const nation of world.listNations()) {
|
||||
world.updateNation(nation.id, { meta: { ...nation.meta, chief_set: 0 } });
|
||||
}
|
||||
for (const city of world.listCities()) {
|
||||
world.updateCity(city.id, { meta: { ...city.meta, officer_set: 0 } });
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
LogCategory,
|
||||
LogScope,
|
||||
loadActionModuleBundle,
|
||||
type TurnCommandProfile,
|
||||
type TurnSchedule,
|
||||
} from '@sammo-ts/logic';
|
||||
import { loadActionModuleBundle, type TurnCommandProfile, type TurnSchedule } from '@sammo-ts/logic';
|
||||
import { buildGameEventChannel, type RealtimeEvent } from '@sammo-ts/common';
|
||||
import { createGamePostgresConnector, createRedisConnector, resolveRedisConfigFromEnv } from '@sammo-ts/infra';
|
||||
import { NATION_TRAIT_KEYS, NationTraitLoader, loadNationTraitModules } from '@sammo-ts/logic';
|
||||
@@ -73,6 +67,12 @@ import { createFinishNationBettingHandler, createOpenNationBettingHandler } from
|
||||
import { createScoutBlockHandler } from './monthlyScoutBlockAction.js';
|
||||
import { createAddGlobalBetrayHandler, createAssignGeneralSpecialityHandler } from './monthlySpecialityBetrayAction.js';
|
||||
import { createLostUniqueItemHandler, createMergeInheritPointRankHandler } from './monthlyUniqueInheritAction.js';
|
||||
import {
|
||||
createNewYearHandler,
|
||||
createNoticeToHistoryLogHandler,
|
||||
createProcessIncomeActionHandler,
|
||||
createResetOfficerLockHandler,
|
||||
} from './monthlyCoreEventAction.js';
|
||||
import { buildCommandEnv } from './reservedTurnCommands.js';
|
||||
import { DatabaseTurnDaemonLease, TurnDaemonLeaseUnavailableError } from '../lifecycle/databaseTurnDaemonLease.js';
|
||||
|
||||
@@ -390,59 +390,10 @@ const createTurnDaemonRuntimeWithLease = async (
|
||||
getWorld: () => worldRef,
|
||||
})
|
||||
);
|
||||
eventActions.set('ProcessIncome', async (_args, environment) => {
|
||||
await incomeHandler.onMonthChanged?.({
|
||||
previousYear: environment.month === 1 ? environment.year - 1 : environment.year,
|
||||
previousMonth: environment.month === 1 ? 12 : environment.month - 1,
|
||||
currentYear: environment.year,
|
||||
currentMonth: environment.month,
|
||||
turnTime: environment.turnTime,
|
||||
});
|
||||
});
|
||||
eventActions.set('NoticeToHistoryLog', (args) => {
|
||||
const text = args[0];
|
||||
if (typeof text !== 'string' || !worldRef) {
|
||||
return;
|
||||
}
|
||||
worldRef.pushLog({
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.HISTORY,
|
||||
text,
|
||||
});
|
||||
});
|
||||
eventActions.set('NewYear', (_args, environment) => {
|
||||
if (!worldRef) {
|
||||
return;
|
||||
}
|
||||
for (const general of worldRef.listGenerals()) {
|
||||
const belong = general.meta.belong;
|
||||
worldRef.updateGeneral(general.id, {
|
||||
age: general.age + 1,
|
||||
meta: {
|
||||
...general.meta,
|
||||
...(general.nationId !== 0
|
||||
? { belong: typeof belong === 'number' && Number.isFinite(belong) ? belong + 1 : 1 }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
worldRef.pushLog({
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.ACTION,
|
||||
text: `<C>${environment.year}</>년이 되었습니다.`,
|
||||
});
|
||||
});
|
||||
eventActions.set('ResetOfficerLock', () => {
|
||||
if (!worldRef) {
|
||||
return;
|
||||
}
|
||||
for (const nation of worldRef.listNations()) {
|
||||
worldRef.updateNation(nation.id, { meta: { ...nation.meta, chief_set: 0 } });
|
||||
}
|
||||
for (const city of worldRef.listCities()) {
|
||||
worldRef.updateCity(city.id, { meta: { ...city.meta, officer_set: 0 } });
|
||||
}
|
||||
});
|
||||
eventActions.set('ProcessIncome', createProcessIncomeActionHandler(incomeHandler));
|
||||
eventActions.set('NoticeToHistoryLog', createNoticeToHistoryLogHandler({ getWorld: () => worldRef }));
|
||||
eventActions.set('NewYear', createNewYearHandler({ getWorld: () => worldRef }));
|
||||
eventActions.set('ResetOfficerLock', createResetOfficerLockHandler({ getWorld: () => worldRef }));
|
||||
const monthlyEventHandler = createMonthlyEventHandler({
|
||||
getWorld: () => worldRef,
|
||||
startYear: snapshot.scenarioMeta?.startYear ?? state.currentYear,
|
||||
|
||||
Reference in New Issue
Block a user