feat: add troop model and integrate troop handling in game logic
This commit is contained in:
@@ -121,6 +121,7 @@ export const seedScenarioToDatabase = async (
|
|||||||
await prisma.event.deleteMany();
|
await prisma.event.deleteMany();
|
||||||
await prisma.diplomacy.deleteMany();
|
await prisma.diplomacy.deleteMany();
|
||||||
await prisma.general.deleteMany();
|
await prisma.general.deleteMany();
|
||||||
|
await prisma.troop.deleteMany();
|
||||||
await prisma.city.deleteMany();
|
await prisma.city.deleteMany();
|
||||||
await prisma.nation.deleteMany();
|
await prisma.nation.deleteMany();
|
||||||
await prisma.worldState.deleteMany();
|
await prisma.worldState.deleteMany();
|
||||||
@@ -239,6 +240,16 @@ export const seedScenarioToDatabase = async (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seed.troops.length > 0) {
|
||||||
|
await prisma.troop.createMany({
|
||||||
|
data: seed.troops.map((troop) => ({
|
||||||
|
troopLeaderId: troop.id,
|
||||||
|
nationId: troop.nationId,
|
||||||
|
name: troop.name,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (seed.diplomacy.length > 0) {
|
if (seed.diplomacy.length > 0) {
|
||||||
await prisma.diplomacy.createMany({
|
await prisma.diplomacy.createMany({
|
||||||
data: seed.diplomacy.map((row) => ({
|
data: seed.diplomacy.map((row) => ({
|
||||||
|
|||||||
@@ -121,6 +121,21 @@ const buildNationUpdate = (
|
|||||||
meta: asJson(nation.meta),
|
meta: asJson(nation.meta),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const buildTroopUpdate = (
|
||||||
|
troop: ReturnType<InMemoryTurnWorld['consumeDirtyState']>['troops'][number]
|
||||||
|
): Prisma.TroopUpdateInput => ({
|
||||||
|
nationId: troop.nationId,
|
||||||
|
name: troop.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildTroopCreate = (
|
||||||
|
troop: ReturnType<InMemoryTurnWorld['consumeDirtyState']>['troops'][number]
|
||||||
|
): Prisma.TroopCreateManyInput => ({
|
||||||
|
troopLeaderId: troop.id,
|
||||||
|
nationId: troop.nationId,
|
||||||
|
name: troop.name,
|
||||||
|
});
|
||||||
|
|
||||||
const buildLogCreateData = (
|
const buildLogCreateData = (
|
||||||
entry: LogEntryDraft,
|
entry: LogEntryDraft,
|
||||||
context: { year: number; month: number; at: Date }
|
context: { year: number; month: number; at: Date }
|
||||||
@@ -161,8 +176,15 @@ export const createDatabaseTurnHooks = async (
|
|||||||
const hooks: TurnDaemonHooks = {
|
const hooks: TurnDaemonHooks = {
|
||||||
flushChanges: async () => {
|
flushChanges: async () => {
|
||||||
const state = world.getState();
|
const state = world.getState();
|
||||||
const { generals, cities, nations, logs, createdGenerals } =
|
const {
|
||||||
world.consumeDirtyState();
|
generals,
|
||||||
|
cities,
|
||||||
|
nations,
|
||||||
|
troops,
|
||||||
|
logs,
|
||||||
|
createdGenerals,
|
||||||
|
createdTroops,
|
||||||
|
} = world.consumeDirtyState();
|
||||||
|
|
||||||
await connector.prisma.worldState.update({
|
await connector.prisma.worldState.update({
|
||||||
where: { id: state.id },
|
where: { id: state.id },
|
||||||
@@ -177,12 +199,20 @@ export const createDatabaseTurnHooks = async (
|
|||||||
const createdIds = new Set(
|
const createdIds = new Set(
|
||||||
createdGenerals.map((general) => general.id)
|
createdGenerals.map((general) => general.id)
|
||||||
);
|
);
|
||||||
|
const createdTroopIds = new Set(
|
||||||
|
createdTroops.map((troop) => troop.id)
|
||||||
|
);
|
||||||
|
|
||||||
if (createdGenerals.length > 0) {
|
if (createdGenerals.length > 0) {
|
||||||
await connector.prisma.general.createMany({
|
await connector.prisma.general.createMany({
|
||||||
data: createdGenerals.map(buildGeneralCreate),
|
data: createdGenerals.map(buildGeneralCreate),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (createdTroops.length > 0) {
|
||||||
|
await connector.prisma.troop.createMany({
|
||||||
|
data: createdTroops.map(buildTroopCreate),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
...generals
|
...generals
|
||||||
@@ -205,6 +235,14 @@ export const createDatabaseTurnHooks = async (
|
|||||||
data: buildNationUpdate(nation),
|
data: buildNationUpdate(nation),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
...troops
|
||||||
|
.filter((troop) => !createdTroopIds.has(troop.id))
|
||||||
|
.map((troop) =>
|
||||||
|
connector.prisma.troop.update({
|
||||||
|
where: { troopLeaderId: troop.id },
|
||||||
|
data: buildTroopUpdate(troop),
|
||||||
|
})
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (logs.length > 0) {
|
if (logs.length > 0) {
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import type { City, LogEntryDraft, Nation, TurnSchedule } from '@sammo-ts/logic';
|
import type {
|
||||||
|
City,
|
||||||
|
LogEntryDraft,
|
||||||
|
Nation,
|
||||||
|
Troop,
|
||||||
|
TurnSchedule,
|
||||||
|
} from '@sammo-ts/logic';
|
||||||
import { getNextTurnAt } from '@sammo-ts/logic';
|
import { getNextTurnAt } from '@sammo-ts/logic';
|
||||||
|
|
||||||
import type { TurnCheckpoint } from '../lifecycle/types.js';
|
import type { TurnCheckpoint } from '../lifecycle/types.js';
|
||||||
@@ -22,9 +28,11 @@ export interface GeneralTurnResult {
|
|||||||
generals: Array<{ id: number; patch: Partial<TurnGeneral> }>;
|
generals: Array<{ id: number; patch: Partial<TurnGeneral> }>;
|
||||||
cities: Array<{ id: number; patch: Partial<City> }>;
|
cities: Array<{ id: number; patch: Partial<City> }>;
|
||||||
nations: Array<{ id: number; patch: Partial<Nation> }>;
|
nations: Array<{ id: number; patch: Partial<Nation> }>;
|
||||||
|
troops: Array<{ id: number; patch: Partial<Troop> }>;
|
||||||
};
|
};
|
||||||
created?: {
|
created?: {
|
||||||
generals: TurnGeneral[];
|
generals: TurnGeneral[];
|
||||||
|
troops?: Troop[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +149,11 @@ const applyNationPatch = (base: Nation, patch: Partial<Nation>): Nation => ({
|
|||||||
meta: patch.meta ? { ...base.meta, ...patch.meta } : base.meta,
|
meta: patch.meta ? { ...base.meta, ...patch.meta } : base.meta,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const applyTroopPatch = (base: Troop, patch: Partial<Troop>): Troop => ({
|
||||||
|
...base,
|
||||||
|
...patch,
|
||||||
|
});
|
||||||
|
|
||||||
export class InMemoryTurnWorld {
|
export class InMemoryTurnWorld {
|
||||||
// DB에서 읽어온 월드 상태를 메모리에 고정해 턴 처리를 담당한다.
|
// DB에서 읽어온 월드 상태를 메모리에 고정해 턴 처리를 담당한다.
|
||||||
private readonly schedule: TurnSchedule;
|
private readonly schedule: TurnSchedule;
|
||||||
@@ -149,10 +162,13 @@ export class InMemoryTurnWorld {
|
|||||||
private readonly generals = new Map<number, TurnGeneral>();
|
private readonly generals = new Map<number, TurnGeneral>();
|
||||||
private readonly cities = new Map<number, City>();
|
private readonly cities = new Map<number, City>();
|
||||||
private readonly nations = new Map<number, Nation>();
|
private readonly nations = new Map<number, Nation>();
|
||||||
|
private readonly troops = new Map<number, Troop>();
|
||||||
private readonly dirtyGeneralIds = new Set<number>();
|
private readonly dirtyGeneralIds = new Set<number>();
|
||||||
private readonly dirtyCityIds = new Set<number>();
|
private readonly dirtyCityIds = new Set<number>();
|
||||||
private readonly dirtyNationIds = new Set<number>();
|
private readonly dirtyNationIds = new Set<number>();
|
||||||
|
private readonly dirtyTroopIds = new Set<number>();
|
||||||
private readonly createdGeneralIds = new Set<number>();
|
private readonly createdGeneralIds = new Set<number>();
|
||||||
|
private readonly createdTroopIds = new Set<number>();
|
||||||
private readonly logs: LogEntryDraft[] = [];
|
private readonly logs: LogEntryDraft[] = [];
|
||||||
private checkpoint?: TurnCheckpoint;
|
private checkpoint?: TurnCheckpoint;
|
||||||
private state: TurnWorldState;
|
private state: TurnWorldState;
|
||||||
@@ -180,6 +196,9 @@ export class InMemoryTurnWorld {
|
|||||||
for (const nation of snapshot.nations) {
|
for (const nation of snapshot.nations) {
|
||||||
this.nations.set(nation.id, { ...nation });
|
this.nations.set(nation.id, { ...nation });
|
||||||
}
|
}
|
||||||
|
for (const troop of snapshot.troops) {
|
||||||
|
this.troops.set(troop.id, { ...troop });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getState(): TurnWorldState {
|
getState(): TurnWorldState {
|
||||||
@@ -198,6 +217,10 @@ export class InMemoryTurnWorld {
|
|||||||
return this.nations.get(id) ?? null;
|
return this.nations.get(id) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTroopById(id: number): Troop | null {
|
||||||
|
return this.troops.get(id) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
listGenerals(): TurnGeneral[] {
|
listGenerals(): TurnGeneral[] {
|
||||||
return Array.from(this.generals.values()).map((general) => ({
|
return Array.from(this.generals.values()).map((general) => ({
|
||||||
...general,
|
...general,
|
||||||
@@ -214,6 +237,12 @@ export class InMemoryTurnWorld {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listTroops(): Troop[] {
|
||||||
|
return Array.from(this.troops.values()).map((troop) => ({
|
||||||
|
...troop,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
setLastTurnTime(turnTime: Date): void {
|
setLastTurnTime(turnTime: Date): void {
|
||||||
const meta = {
|
const meta = {
|
||||||
...this.state.meta,
|
...this.state.meta,
|
||||||
@@ -326,6 +355,14 @@ export class InMemoryTurnWorld {
|
|||||||
);
|
);
|
||||||
this.dirtyNationIds.add(patch.id);
|
this.dirtyNationIds.add(patch.id);
|
||||||
}
|
}
|
||||||
|
for (const patch of result.patches.troops) {
|
||||||
|
const target = this.troops.get(patch.id);
|
||||||
|
if (!target) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.troops.set(patch.id, applyTroopPatch(target, patch.patch));
|
||||||
|
this.dirtyTroopIds.add(patch.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (result.created) {
|
if (result.created) {
|
||||||
for (const createdGeneral of result.created.generals) {
|
for (const createdGeneral of result.created.generals) {
|
||||||
@@ -336,6 +373,16 @@ export class InMemoryTurnWorld {
|
|||||||
this.dirtyGeneralIds.add(createdGeneral.id);
|
this.dirtyGeneralIds.add(createdGeneral.id);
|
||||||
this.createdGeneralIds.add(createdGeneral.id);
|
this.createdGeneralIds.add(createdGeneral.id);
|
||||||
}
|
}
|
||||||
|
if (result.created.troops) {
|
||||||
|
for (const createdTroop of result.created.troops) {
|
||||||
|
if (this.troops.has(createdTroop.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.troops.set(createdTroop.id, { ...createdTroop });
|
||||||
|
this.dirtyTroopIds.add(createdTroop.id);
|
||||||
|
this.createdTroopIds.add(createdTroop.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextTurnAt;
|
return nextTurnAt;
|
||||||
@@ -380,8 +427,10 @@ export class InMemoryTurnWorld {
|
|||||||
generals: TurnGeneral[];
|
generals: TurnGeneral[];
|
||||||
cities: City[];
|
cities: City[];
|
||||||
nations: Nation[];
|
nations: Nation[];
|
||||||
|
troops: Troop[];
|
||||||
logs: LogEntryDraft[];
|
logs: LogEntryDraft[];
|
||||||
createdGenerals: TurnGeneral[];
|
createdGenerals: TurnGeneral[];
|
||||||
|
createdTroops: Troop[];
|
||||||
} {
|
} {
|
||||||
const generals = Array.from(this.dirtyGeneralIds)
|
const generals = Array.from(this.dirtyGeneralIds)
|
||||||
.map((id) => this.generals.get(id))
|
.map((id) => this.generals.get(id))
|
||||||
@@ -395,13 +444,29 @@ export class InMemoryTurnWorld {
|
|||||||
const nations = Array.from(this.dirtyNationIds)
|
const nations = Array.from(this.dirtyNationIds)
|
||||||
.map((id) => this.nations.get(id))
|
.map((id) => this.nations.get(id))
|
||||||
.filter((nation): nation is Nation => Boolean(nation));
|
.filter((nation): nation is Nation => Boolean(nation));
|
||||||
|
const troops = Array.from(this.dirtyTroopIds)
|
||||||
|
.map((id) => this.troops.get(id))
|
||||||
|
.filter((troop): troop is Troop => Boolean(troop));
|
||||||
|
const createdTroops = Array.from(this.createdTroopIds)
|
||||||
|
.map((id) => this.troops.get(id))
|
||||||
|
.filter((troop): troop is Troop => Boolean(troop));
|
||||||
const logs = this.logs.splice(0, this.logs.length);
|
const logs = this.logs.splice(0, this.logs.length);
|
||||||
|
|
||||||
this.dirtyGeneralIds.clear();
|
this.dirtyGeneralIds.clear();
|
||||||
this.dirtyCityIds.clear();
|
this.dirtyCityIds.clear();
|
||||||
this.dirtyNationIds.clear();
|
this.dirtyNationIds.clear();
|
||||||
|
this.dirtyTroopIds.clear();
|
||||||
this.createdGeneralIds.clear();
|
this.createdGeneralIds.clear();
|
||||||
|
this.createdTroopIds.clear();
|
||||||
|
|
||||||
return { generals, cities, nations, logs, createdGenerals };
|
return {
|
||||||
|
generals,
|
||||||
|
cities,
|
||||||
|
nations,
|
||||||
|
troops,
|
||||||
|
logs,
|
||||||
|
createdGenerals,
|
||||||
|
createdTroops,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
ScenarioConfig,
|
ScenarioConfig,
|
||||||
ScenarioDiplomacy,
|
ScenarioDiplomacy,
|
||||||
ScenarioMeta,
|
ScenarioMeta,
|
||||||
|
Troop,
|
||||||
} from '@sammo-ts/logic';
|
} from '@sammo-ts/logic';
|
||||||
import {
|
import {
|
||||||
AssignmentActionDefinition,
|
AssignmentActionDefinition,
|
||||||
@@ -605,6 +606,7 @@ export const createReservedTurnHandler = (options: {
|
|||||||
generals: [] as Array<{ id: number; patch: Partial<TurnGeneral> }>,
|
generals: [] as Array<{ id: number; patch: Partial<TurnGeneral> }>,
|
||||||
cities: [] as Array<{ id: number; patch: Partial<City> }>,
|
cities: [] as Array<{ id: number; patch: Partial<City> }>,
|
||||||
nations: [] as Array<{ id: number; patch: Partial<Nation> }>,
|
nations: [] as Array<{ id: number; patch: Partial<Nation> }>,
|
||||||
|
troops: [] as Array<{ id: number; patch: Partial<Troop> }>,
|
||||||
};
|
};
|
||||||
const created: TurnGeneral[] = [];
|
const created: TurnGeneral[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type {
|
|||||||
ScenarioConfig,
|
ScenarioConfig,
|
||||||
ScenarioDiplomacy,
|
ScenarioDiplomacy,
|
||||||
ScenarioMeta,
|
ScenarioMeta,
|
||||||
|
Troop,
|
||||||
UnitSetDefinition,
|
UnitSetDefinition,
|
||||||
WorldSnapshot,
|
WorldSnapshot,
|
||||||
} from '@sammo-ts/logic';
|
} from '@sammo-ts/logic';
|
||||||
@@ -25,7 +26,10 @@ export interface TurnGeneral extends General {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TurnWorldSnapshot
|
export interface TurnWorldSnapshot
|
||||||
extends Omit<WorldSnapshot, 'generals' | 'cities' | 'nations'> {
|
extends Omit<
|
||||||
|
WorldSnapshot,
|
||||||
|
'generals' | 'cities' | 'nations' | 'troops'
|
||||||
|
> {
|
||||||
scenarioConfig: ScenarioConfig;
|
scenarioConfig: ScenarioConfig;
|
||||||
scenarioMeta?: ScenarioMeta;
|
scenarioMeta?: ScenarioMeta;
|
||||||
map: MapDefinition;
|
map: MapDefinition;
|
||||||
@@ -36,6 +40,7 @@ export interface TurnWorldSnapshot
|
|||||||
generals: TurnGeneral[];
|
generals: TurnGeneral[];
|
||||||
cities: City[];
|
cities: City[];
|
||||||
nations: Nation[];
|
nations: Nation[];
|
||||||
|
troops: Troop[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TurnWorldLoadResult {
|
export interface TurnWorldLoadResult {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type {
|
|||||||
General as PrismaGeneral,
|
General as PrismaGeneral,
|
||||||
Nation as PrismaNation,
|
Nation as PrismaNation,
|
||||||
Prisma,
|
Prisma,
|
||||||
|
Troop as PrismaTroop,
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { createPostgresConnector } from '@sammo-ts/infra';
|
import { createPostgresConnector } from '@sammo-ts/infra';
|
||||||
@@ -13,6 +14,7 @@ import type {
|
|||||||
ScenarioConfig,
|
ScenarioConfig,
|
||||||
ScenarioDiplomacy,
|
ScenarioDiplomacy,
|
||||||
ScenarioMeta,
|
ScenarioMeta,
|
||||||
|
Troop,
|
||||||
TriggerValue,
|
TriggerValue,
|
||||||
} from '@sammo-ts/logic';
|
} from '@sammo-ts/logic';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@@ -216,6 +218,12 @@ const mapDiplomacyRow = (row: PrismaDiplomacy): ScenarioDiplomacy => ({
|
|||||||
durationMonths: row.term,
|
durationMonths: row.term,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mapTroopRow = (row: PrismaTroop): Troop => ({
|
||||||
|
id: row.troopLeaderId,
|
||||||
|
nationId: row.nationId,
|
||||||
|
name: row.name,
|
||||||
|
});
|
||||||
|
|
||||||
export const loadTurnWorldFromDatabase = async (
|
export const loadTurnWorldFromDatabase = async (
|
||||||
options: TurnWorldLoaderOptions
|
options: TurnWorldLoaderOptions
|
||||||
): Promise<TurnWorldLoadResult> => {
|
): Promise<TurnWorldLoadResult> => {
|
||||||
@@ -233,12 +241,14 @@ export const loadTurnWorldFromDatabase = async (
|
|||||||
cityRows,
|
cityRows,
|
||||||
nationRows,
|
nationRows,
|
||||||
diplomacyRows,
|
diplomacyRows,
|
||||||
|
troopRows,
|
||||||
eventRows,
|
eventRows,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
prisma.general.findMany(),
|
prisma.general.findMany(),
|
||||||
prisma.city.findMany(),
|
prisma.city.findMany(),
|
||||||
prisma.nation.findMany(),
|
prisma.nation.findMany(),
|
||||||
prisma.diplomacy.findMany(),
|
prisma.diplomacy.findMany(),
|
||||||
|
prisma.troop.findMany(),
|
||||||
prisma.event.findMany({
|
prisma.event.findMany({
|
||||||
orderBy: [{ priority: 'desc' }, { id: 'asc' }],
|
orderBy: [{ priority: 'desc' }, { id: 'asc' }],
|
||||||
}),
|
}),
|
||||||
@@ -248,6 +258,7 @@ export const loadTurnWorldFromDatabase = async (
|
|||||||
const cities = cityRows.map(mapCityRow);
|
const cities = cityRows.map(mapCityRow);
|
||||||
const nations = nationRows.map(mapNationRow);
|
const nations = nationRows.map(mapNationRow);
|
||||||
const diplomacy = diplomacyRows.map(mapDiplomacyRow);
|
const diplomacy = diplomacyRows.map(mapDiplomacyRow);
|
||||||
|
const troops = troopRows.map(mapTroopRow);
|
||||||
|
|
||||||
const scenarioConfig = mapScenarioConfig(worldState.config);
|
const scenarioConfig = mapScenarioConfig(worldState.config);
|
||||||
const mapName = scenarioConfig.environment?.mapName ?? 'che';
|
const mapName = scenarioConfig.environment?.mapName ?? 'che';
|
||||||
@@ -305,6 +316,7 @@ export const loadTurnWorldFromDatabase = async (
|
|||||||
nations,
|
nations,
|
||||||
cities,
|
cities,
|
||||||
generals,
|
generals,
|
||||||
|
troops,
|
||||||
diplomacy,
|
diplomacy,
|
||||||
events,
|
events,
|
||||||
initialEvents,
|
initialEvents,
|
||||||
|
|||||||
@@ -147,6 +147,14 @@ model General {
|
|||||||
@@map("general")
|
@@map("general")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Troop {
|
||||||
|
troopLeaderId Int @id @map("troop_leader")
|
||||||
|
nationId Int @map("nation")
|
||||||
|
name String
|
||||||
|
|
||||||
|
@@map("troop")
|
||||||
|
}
|
||||||
|
|
||||||
model GeneralTurn {
|
model GeneralTurn {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
generalId Int @map("general_id")
|
generalId Int @map("general_id")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
export type GeneralId = number;
|
export type GeneralId = number;
|
||||||
export type CityId = number;
|
export type CityId = number;
|
||||||
export type NationId = number;
|
export type NationId = number;
|
||||||
|
export type TroopId = number;
|
||||||
|
|
||||||
export type ColorCode = string;
|
export type ColorCode = string;
|
||||||
|
|
||||||
@@ -95,3 +96,9 @@ export interface Nation {
|
|||||||
typeCode: string;
|
typeCode: string;
|
||||||
meta: Record<string, TriggerValue>;
|
meta: Record<string, TriggerValue>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Troop {
|
||||||
|
id: TroopId;
|
||||||
|
nationId: NationId;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { City, General, Nation } from '../domain/entities.js';
|
import type { City, General, Nation, Troop } from '../domain/entities.js';
|
||||||
import type { ScenarioConfig } from '../scenario/types.js';
|
import type { ScenarioConfig } from '../scenario/types.js';
|
||||||
import type { ScenarioMeta } from '../world/types.js';
|
import type { ScenarioMeta } from '../world/types.js';
|
||||||
|
|
||||||
@@ -6,11 +6,13 @@ import type { ScenarioMeta } from '../world/types.js';
|
|||||||
export interface WorldStateSnapshotSource<
|
export interface WorldStateSnapshotSource<
|
||||||
GeneralType extends General = General,
|
GeneralType extends General = General,
|
||||||
CityType extends City = City,
|
CityType extends City = City,
|
||||||
NationType extends Nation = Nation
|
NationType extends Nation = Nation,
|
||||||
|
TroopType extends Troop = Troop
|
||||||
> {
|
> {
|
||||||
listGenerals(): Promise<GeneralType[]>;
|
listGenerals(): Promise<GeneralType[]>;
|
||||||
listCities(): Promise<CityType[]>;
|
listCities(): Promise<CityType[]>;
|
||||||
listNations(): Promise<NationType[]>;
|
listNations(): Promise<NationType[]>;
|
||||||
|
listTroops(): Promise<TroopType[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScenarioConfigSource {
|
export interface ScenarioConfigSource {
|
||||||
|
|||||||
@@ -676,6 +676,7 @@ export const buildScenarioBootstrap = (
|
|||||||
nations: seedNations,
|
nations: seedNations,
|
||||||
cities: seedCities,
|
cities: seedCities,
|
||||||
generals: allGeneralSeeds,
|
generals: allGeneralSeeds,
|
||||||
|
troops: [],
|
||||||
diplomacy: scenario.diplomacy,
|
diplomacy: scenario.diplomacy,
|
||||||
events: scenario.events,
|
events: scenario.events,
|
||||||
initialEvents: scenario.initialEvents,
|
initialEvents: scenario.initialEvents,
|
||||||
@@ -689,6 +690,7 @@ export const buildScenarioBootstrap = (
|
|||||||
nations: domainNations,
|
nations: domainNations,
|
||||||
cities: domainCities,
|
cities: domainCities,
|
||||||
generals: allGenerals,
|
generals: allGenerals,
|
||||||
|
troops: [],
|
||||||
diplomacy: scenario.diplomacy,
|
diplomacy: scenario.diplomacy,
|
||||||
events: scenario.events,
|
events: scenario.events,
|
||||||
initialEvents: scenario.initialEvents,
|
initialEvents: scenario.initialEvents,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { City, General, Nation } from '../domain/entities.js';
|
import type { City, General, Nation, Troop } from '../domain/entities.js';
|
||||||
import type { ScenarioConfig, ScenarioDiplomacy } from '../scenario/types.js';
|
import type { ScenarioConfig, ScenarioDiplomacy } from '../scenario/types.js';
|
||||||
import type { ScenarioConfigSource, WorldStateSnapshotSource } from '../ports/worldSnapshot.js';
|
import type { ScenarioConfigSource, WorldStateSnapshotSource } from '../ports/worldSnapshot.js';
|
||||||
import type {
|
import type {
|
||||||
@@ -11,9 +11,15 @@ import type {
|
|||||||
export interface WorldSnapshotLoadInput<
|
export interface WorldSnapshotLoadInput<
|
||||||
GeneralType extends General = General,
|
GeneralType extends General = General,
|
||||||
CityType extends City = City,
|
CityType extends City = City,
|
||||||
NationType extends Nation = Nation
|
NationType extends Nation = Nation,
|
||||||
|
TroopType extends Troop = Troop
|
||||||
> {
|
> {
|
||||||
worldSource: WorldStateSnapshotSource<GeneralType, CityType, NationType>;
|
worldSource: WorldStateSnapshotSource<
|
||||||
|
GeneralType,
|
||||||
|
CityType,
|
||||||
|
NationType,
|
||||||
|
TroopType
|
||||||
|
>;
|
||||||
scenarioConfig?: ScenarioConfig;
|
scenarioConfig?: ScenarioConfig;
|
||||||
scenarioMeta?: ScenarioMeta;
|
scenarioMeta?: ScenarioMeta;
|
||||||
scenarioSource?: ScenarioConfigSource;
|
scenarioSource?: ScenarioConfigSource;
|
||||||
@@ -28,9 +34,15 @@ export interface WorldSnapshotLoadInput<
|
|||||||
export const loadWorldSnapshot = async <
|
export const loadWorldSnapshot = async <
|
||||||
GeneralType extends General,
|
GeneralType extends General,
|
||||||
CityType extends City,
|
CityType extends City,
|
||||||
NationType extends Nation
|
NationType extends Nation,
|
||||||
|
TroopType extends Troop
|
||||||
>(
|
>(
|
||||||
input: WorldSnapshotLoadInput<GeneralType, CityType, NationType>
|
input: WorldSnapshotLoadInput<
|
||||||
|
GeneralType,
|
||||||
|
CityType,
|
||||||
|
NationType,
|
||||||
|
TroopType
|
||||||
|
>
|
||||||
): Promise<WorldSnapshot> => {
|
): Promise<WorldSnapshot> => {
|
||||||
const { worldSource, scenarioSource } = input;
|
const { worldSource, scenarioSource } = input;
|
||||||
|
|
||||||
@@ -47,10 +59,11 @@ export const loadWorldSnapshot = async <
|
|||||||
? await scenarioSource.loadScenarioMeta()
|
? await scenarioSource.loadScenarioMeta()
|
||||||
: undefined);
|
: undefined);
|
||||||
|
|
||||||
const [generals, cities, nations] = await Promise.all([
|
const [generals, cities, nations, troops] = await Promise.all([
|
||||||
worldSource.listGenerals(),
|
worldSource.listGenerals(),
|
||||||
worldSource.listCities(),
|
worldSource.listCities(),
|
||||||
worldSource.listNations(),
|
worldSource.listNations(),
|
||||||
|
worldSource.listTroops(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -61,6 +74,7 @@ export const loadWorldSnapshot = async <
|
|||||||
nations,
|
nations,
|
||||||
cities,
|
cities,
|
||||||
generals,
|
generals,
|
||||||
|
troops,
|
||||||
diplomacy: input.diplomacy ?? [],
|
diplomacy: input.diplomacy ?? [],
|
||||||
events: input.events ?? [],
|
events: input.events ?? [],
|
||||||
initialEvents: input.initialEvents ?? [],
|
initialEvents: input.initialEvents ?? [],
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import type { City, General, Nation, StatBlock } from '../domain/entities.js';
|
import type {
|
||||||
|
City,
|
||||||
|
General,
|
||||||
|
Nation,
|
||||||
|
StatBlock,
|
||||||
|
Troop,
|
||||||
|
} from '../domain/entities.js';
|
||||||
import type {
|
import type {
|
||||||
ScenarioConfig,
|
ScenarioConfig,
|
||||||
ScenarioDiplomacy,
|
ScenarioDiplomacy,
|
||||||
@@ -136,6 +142,7 @@ export interface WorldSeedPayload {
|
|||||||
nations: NationSeed[];
|
nations: NationSeed[];
|
||||||
cities: CitySeed[];
|
cities: CitySeed[];
|
||||||
generals: GeneralSeed[];
|
generals: GeneralSeed[];
|
||||||
|
troops: Troop[];
|
||||||
diplomacy: ScenarioDiplomacy[];
|
diplomacy: ScenarioDiplomacy[];
|
||||||
events: unknown[];
|
events: unknown[];
|
||||||
initialEvents: unknown[];
|
initialEvents: unknown[];
|
||||||
@@ -149,6 +156,7 @@ export interface WorldSnapshot {
|
|||||||
nations: Nation[];
|
nations: Nation[];
|
||||||
cities: City[];
|
cities: City[];
|
||||||
generals: General[];
|
generals: General[];
|
||||||
|
troops: Troop[];
|
||||||
diplomacy: ScenarioDiplomacy[];
|
diplomacy: ScenarioDiplomacy[];
|
||||||
events: unknown[];
|
events: unknown[];
|
||||||
initialEvents: unknown[];
|
initialEvents: unknown[];
|
||||||
|
|||||||
Reference in New Issue
Block a user