import { content } from "@deadhead/content"; import { playerStateSchema, type PlayerState } from "@deadhead/schema"; import { eq } from "drizzle-orm"; import { describe, expect, it } from "vitest"; import { players } from "../src/db/schema"; import { resolveArrivalsJob } from "../src/jobs/definitions"; import { setCredits, useTestDatabase } from "./db"; import { call, getState, insertDispatch, signUp, signUpOwner, testContract, useTestApp, } from "./game"; const database = useTestDatabase(); const testApp = useTestApp(database); /** The parts of a state that must match a brand-new guest's (ids differ). */ const shape = (s: PlayerState) => ({ credits: s.company.credits, loanBalance: s.company.loanBalance, ships: s.ships.length, bays: s.bays.length, pilots: s.pilots.map((p) => ({ isAvatar: p.isAvatar, locationId: p.locationId, level: p.level, assignedShipId: p.assignedShipId, })), discovered: s.locations.filter((l) => l.discovered).map((l) => l.id), tutorial: s.tutorial, activeDispatches: s.activeDispatches.length, summaries: s.summaries.length, goals: s.goals, }); describe("start a new company (Step 10K.6)", () => { it("turns a mid-game company back into a fresh guest start, with a new world seed", async () => { const { app, clock } = testApp(); const { db } = database(); const owner = await signUpOwner(app, db); await setCredits(db, owner.playerId, 50_000); await call(app, owner, "POST", "/api/bays", { locationId: "moon" }); await call(app, owner, "POST", `/api/ships/${owner.shipId}/upgrades`, { upgradeId: "engines" }); const flight = await insertDispatch(db, { playerId: owner.playerId, shipId: owner.shipId, pilotId: owner.avatarId, departAt: clock.now, contract: testContract(), }); const [before] = await db.select().from(players).where(eq(players.id, owner.playerId)); const response = await call(app, owner, "POST", "/api/company/new", {}); expect(response.statusCode).toBe(200); const fresh = playerStateSchema.parse(response.json()); const guest = await signUp(app); expect(shape(fresh)).toEqual(shape(await getState(app, guest))); expect(fresh.tutorial).toMatchObject({ loanerLocationId: "earth", runsCompleted: 0 }); expect(fresh.company.credits).toBe(content.config.startingCredits); expect(shape(fresh).discovered.sort()).toEqual(["earth", "moon"]); const [after] = await db.select().from(players).where(eq(players.id, owner.playerId)); expect(after!.worldSeed).not.toBe(before!.worldSeed); expect(after!.id).toBe(before!.id); // The old flight's arrival job finds nothing and changes nothing. clock.now = flight.arrivalAt + 1000; await expect( resolveArrivalsJob({ db, clock: clock.read }, { playerId: owner.playerId }), ).resolves.toBeUndefined(); expect(shape(await getState(app, owner))).toEqual(shape(fresh)); }); });