feat(ai): add autorun policies for general and nation management

- Introduced `policies.ts` to define AI policies for generals and nations, including priority actions and flags.
- Implemented `AutorunGeneralPolicy` class to manage general-specific actions based on AI options and server/nation policies.
- Implemented `AutorunNationPolicy` class to handle nation-specific actions, including resource requirements and combat strategies.
- Added types for AI context and world view in `types.ts` to facilitate interaction with game state and entities.
This commit is contained in:
2026-01-11 14:49:42 +00:00
parent cc41d1538e
commit 550910811c
10 changed files with 3623 additions and 4 deletions
@@ -38,6 +38,8 @@ import {
} from '@sammo-ts/logic';
import { buildCommandEnv, buildReservedTurnDefinitions } from './reservedTurnCommands.js';
import { buildActionContext } from './reservedTurnActionContext.js';
import { GeneralAI, shouldUseAi } from './ai/generalAi.js';
import type { AiReservedTurnProvider } from './ai/types.js';
const DEFAULT_ACTION = '휴식';
@@ -433,6 +435,10 @@ export const createReservedTurnHandler = async (options: {
return result;
};
const reservedTurnProvider: AiReservedTurnProvider = {
getGeneralTurn: (generalId, turnIdx) => options.reservedTurns.getGeneralTurn(generalId, turnIdx),
};
return {
execute(context): GeneralTurnResult {
const worldRef = options.getWorld();
@@ -661,16 +667,62 @@ export const createReservedTurnHandler = async (options: {
};
if (currentNation && currentGeneral.officerLevel >= 5) {
const nationCommand = options.reservedTurns.getNationTurn(
let nationCommand = options.reservedTurns.getNationTurn(
currentNation.id,
currentGeneral.officerLevel,
0
);
if (worldView && shouldUseAi(currentGeneral, context.world)) {
const ai = new GeneralAI({
general: currentGeneral,
city: currentCity,
nation: currentNation,
world: context.world,
worldRef: worldView,
reservedTurnProvider,
scenarioConfig: options.scenarioConfig,
scenarioMeta: options.scenarioMeta,
map: options.map,
unitSet: options.unitSet,
commandEnv: env,
generalDefinitions,
nationDefinitions,
generalFallback,
nationFallback,
});
const candidate = ai.chooseNationTurn(nationCommand);
if (candidate) {
nationCommand = { action: candidate.action, args: candidate.args };
}
}
runAction(nationDefinitions, nationFallback, nationCommand, false);
options.reservedTurns.shiftNationTurns(currentNation.id, currentGeneral.officerLevel, -1);
}
const generalCommand = options.reservedTurns.getGeneralTurn(currentGeneral.id, 0);
let generalCommand = options.reservedTurns.getGeneralTurn(currentGeneral.id, 0);
if (worldView && shouldUseAi(currentGeneral, context.world)) {
const ai = new GeneralAI({
general: currentGeneral,
city: currentCity,
nation: currentNation,
world: context.world,
worldRef: worldView,
reservedTurnProvider,
scenarioConfig: options.scenarioConfig,
scenarioMeta: options.scenarioMeta,
map: options.map,
unitSet: options.unitSet,
commandEnv: env,
generalDefinitions,
nationDefinitions,
generalFallback,
nationFallback,
});
const candidate = ai.chooseGeneralTurn(generalCommand);
if (candidate) {
generalCommand = { action: candidate.action, args: candidate.args };
}
}
const nextTurnAt = runAction(generalDefinitions, generalFallback, generalCommand, true);
options.reservedTurns.shiftGeneralTurns(currentGeneral.id, -1);