feat: v0.12.0 — contracts → packages: load/fly/abandon gameplay (ATR 72-600 capacity 6, manual flight to any airport, time-scaled abandon penalty 15–60%), one-time DB migration preserving wallet/clock; new endpoints /api/packages/:id/load|abandon + /api/planes/:planeId/fly

This commit is contained in:
2026-09-18 11:02:56 +00:00
parent 0208673da7
commit ab2e9fa54a
49 changed files with 2424 additions and 1409 deletions
+9 -5
View File
@@ -30,8 +30,8 @@ describe('GET /api/state', () => {
expect(Object.keys(body).sort()).toEqual([
'account',
'catalog',
'contracts',
'fuelPricePerL',
'packages',
'planes',
'sellFraction',
'simState',
@@ -48,15 +48,18 @@ describe('GET /api/state', () => {
const planes = body.planes as Array<Record<string, unknown>>;
expect(planes.length).toBeGreaterThanOrEqual(1);
for (const key of ['id', 'model', 'status', 'fuel', 'maxFuel', 'locationIcao', 'locationName', 'lat', 'lon']) {
for (const key of ['id', 'model', 'status', 'fuel', 'maxFuel', 'locationIcao', 'locationName', 'destIcao', 'destName', 'lat', 'lon']) {
expect(planes[0], `plane.${key}`).toHaveProperty(key);
}
expect(typeof planes[0].locationName).toBe('string');
// The seeded starter is grounded — no flight destination yet.
expect(planes[0].destIcao).toBeNull();
expect(planes[0].destName).toBeNull();
const contracts = body.contracts as Array<Record<string, unknown>>;
expect(contracts.length).toBeGreaterThan(0);
const packages = body.packages as Array<Record<string, unknown>>;
expect(packages.length).toBeGreaterThan(0);
for (const key of ['id', 'originIcao', 'destIcao', 'reward', 'cargoType', 'deadlineSimTime', 'status']) {
expect(contracts[0], `contract.${key}`).toHaveProperty(key);
expect(packages[0], `package.${key}`).toHaveProperty(key);
}
});
@@ -83,6 +86,7 @@ describe('GET /api/state', () => {
expect(entry.maxFuel).toBe(type.maxFuel);
expect(entry.burnPerKm).toBe(type.burnPerKm);
expect(entry.speedKmh).toBe(type.speedKmh);
expect(entry.capacity).toBe(type.capacity); // v0.12.0 slot capacity (ATR 72-600: 6)
}
// Economy constants — the single source of truth stays lib/game/catalog.ts.