feat: enhance AI nation behavior and diplomacy handling, improve test assertions for war readiness

This commit is contained in:
2026-01-24 15:12:09 +00:00
parent 51a3f74920
commit 293f3e3980
5 changed files with 57 additions and 14 deletions
+23 -3
View File
@@ -28,6 +28,7 @@ import { WorldStateView } from './worldStateView.js';
import type { GeneralAIOptions, GeneralAiDebugState } from './types.js';
const ACTION_REST = '휴식';
const lastAttackableByNation = new Map<number, number>();
const t무장 = 1;
const t지장 = 2;
@@ -122,7 +123,9 @@ export class GeneralAI {
constructor(options: GeneralAIOptions) {
this.general = options.general;
this.city = options.city;
this.nation = options.nation ?? null;
this.nation =
options.nation ??
(options.general.nationId > 0 ? options.worldRef?.getNationById(options.general.nationId) ?? null : null);
this.world = options.world;
this.worldRef = options.worldRef;
this.map = options.map;
@@ -746,6 +749,13 @@ export class GeneralAI {
const declareTerms = warTargets.filter((entry) => entry.state === 1).map((entry) => entry.term);
const minWarTerm = declareTerms.length > 0 ? Math.min(...declareTerms) : null;
let lastAttackable = lastAttackableByNation.get(nationId) ??
readMetaNumber(asRecord(this.nation.meta), 'last_attackable', 0);
const markAttackable = () => {
lastAttackable = yearMonth;
lastAttackableByNation.set(nationId, yearMonth);
};
if (minWarTerm === null) {
this.dipState = d평화;
} else if (minWarTerm > 8) {
@@ -754,19 +764,29 @@ export class GeneralAI {
this.dipState = d징병;
} else {
this.dipState = d직전;
markAttackable();
}
const meta = asRecord(this.nation.meta);
const lastAttackable = readMetaNumber(meta, 'last_attackable', 0);
if (Object.prototype.hasOwnProperty.call(warTargetNation, 0) && this.attackable) {
this.dipState = d전쟁;
markAttackable();
} else if (onWar > 0) {
if (this.attackable) {
this.dipState = d전쟁;
markAttackable();
} else if (lastAttackable >= yearMonth - 5) {
this.dipState = d전쟁;
}
}
if ((this.dipState === d평화 || this.dipState === d선포) && this.worldRef) {
const hasCrew =
this.general.crew > 0 ||
this.worldRef.listGenerals().some((general) => general.nationId === nationId && general.crew > 0);
if (hasCrew) {
this.dipState = d징병;
}
}
}
private calcRecentWarTurn(general: TurnGeneral): number {
@@ -3,7 +3,7 @@ import { valueFit } from '../../aiUtils.js';
import { pickWeightedCandidate } from './helpers.js';
export const do전투준비 = (ai: GeneralAI) => {
if ([0, 1].includes(ai.dipState)) {
if ([0, 1].includes(ai.dipState) && ai.general.crew <= 0) {
return null;
}
const cmdList: Array<[ReturnType<GeneralAI['buildGeneralCandidate']>, number]> = [];