feat: implement diplomacy system with state management and processing logic
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
DEFAULT_WAR_TERM,
|
||||
DIPLOMACY_STATE,
|
||||
processDiplomacyMonth,
|
||||
} from '../src/turn/diplomacy.js';
|
||||
import type { TurnDiplomacy } from '../src/turn/types.js';
|
||||
|
||||
const buildEntry = (
|
||||
fromNationId: number,
|
||||
toNationId: number,
|
||||
state: number,
|
||||
term: number,
|
||||
dead = 0
|
||||
): TurnDiplomacy => ({
|
||||
fromNationId,
|
||||
toNationId,
|
||||
state,
|
||||
term,
|
||||
dead,
|
||||
meta: {},
|
||||
});
|
||||
|
||||
describe('diplomacy month processing', () => {
|
||||
it('promotes declaration to war after term expires', () => {
|
||||
const entries = [
|
||||
buildEntry(1, 2, DIPLOMACY_STATE.DECLARATION, 1),
|
||||
buildEntry(2, 1, DIPLOMACY_STATE.DECLARATION, 1),
|
||||
];
|
||||
const result = processDiplomacyMonth(entries, new Map([[1, 1], [2, 1]]));
|
||||
|
||||
for (const entry of result) {
|
||||
expect(entry.state).toBe(DIPLOMACY_STATE.WAR);
|
||||
expect(entry.term).toBe(DEFAULT_WAR_TERM);
|
||||
}
|
||||
});
|
||||
|
||||
it('ends war when both terms reach zero without casualties', () => {
|
||||
const entries = [
|
||||
buildEntry(1, 2, DIPLOMACY_STATE.WAR, 1),
|
||||
buildEntry(2, 1, DIPLOMACY_STATE.WAR, 1),
|
||||
];
|
||||
const result = processDiplomacyMonth(entries, new Map([[1, 1], [2, 1]]));
|
||||
|
||||
for (const entry of result) {
|
||||
expect(entry.state).toBe(DIPLOMACY_STATE.TRADE);
|
||||
expect(entry.term).toBe(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('extends war term based on accumulated casualties', () => {
|
||||
const entries = [
|
||||
buildEntry(1, 2, DIPLOMACY_STATE.WAR, 3, 400),
|
||||
buildEntry(2, 1, DIPLOMACY_STATE.WAR, 3, 0),
|
||||
];
|
||||
const result = processDiplomacyMonth(entries, new Map([[1, 2], [2, 2]]));
|
||||
|
||||
const forward = result.find(
|
||||
(entry) => entry.fromNationId === 1 && entry.toNationId === 2
|
||||
);
|
||||
const reverse = result.find(
|
||||
(entry) => entry.fromNationId === 2 && entry.toNationId === 1
|
||||
);
|
||||
expect(forward?.term).toBe(4);
|
||||
expect(forward?.dead).toBe(0);
|
||||
expect(reverse?.term).toBe(2);
|
||||
});
|
||||
|
||||
it('expires non-aggression pact into trade', () => {
|
||||
const entries = [
|
||||
buildEntry(1, 2, DIPLOMACY_STATE.NON_AGGRESSION, 1),
|
||||
buildEntry(2, 1, DIPLOMACY_STATE.NON_AGGRESSION, 1),
|
||||
];
|
||||
const result = processDiplomacyMonth(entries, new Map([[1, 1], [2, 1]]));
|
||||
|
||||
for (const entry of result) {
|
||||
expect(entry.state).toBe(DIPLOMACY_STATE.TRADE);
|
||||
expect(entry.term).toBe(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -21,7 +21,7 @@ type ScenarioSeederPrismaClient = {
|
||||
count(): Promise<number>;
|
||||
findFirst(args: {
|
||||
where: { srcNationId: number; destNationId: number };
|
||||
}): Promise<{ stateCode: string } | null>;
|
||||
}): Promise<{ stateCode: number; term: number } | null>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -68,7 +68,9 @@ describeDb('scenario database seed', () => {
|
||||
expect(nationCount).toBe(seed.nations.length);
|
||||
expect(cityCount).toBe(seed.cities.length);
|
||||
expect(generalCount).toBe(seed.generals.length);
|
||||
expect(diplomacyCount).toBe(seed.diplomacy.length);
|
||||
expect(diplomacyCount).toBe(
|
||||
seed.nations.length * Math.max(0, seed.nations.length - 1)
|
||||
);
|
||||
expect(generalCount).toBeGreaterThan(0);
|
||||
|
||||
if (seed.diplomacy.length > 0) {
|
||||
@@ -82,6 +84,18 @@ describeDb('scenario database seed', () => {
|
||||
expect(row).not.toBeNull();
|
||||
if (row) {
|
||||
expect(row.stateCode).toBe(sample.state);
|
||||
expect(row.term).toBe(sample.durationMonths);
|
||||
}
|
||||
const reverse = await prisma.diplomacy.findFirst({
|
||||
where: {
|
||||
srcNationId: sample.toNationId,
|
||||
destNationId: sample.fromNationId,
|
||||
},
|
||||
});
|
||||
expect(reverse).not.toBeNull();
|
||||
if (reverse) {
|
||||
expect(reverse.stateCode).toBe(sample.state);
|
||||
expect(reverse.term).toBe(sample.durationMonths);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user