import { randomUUID } from "node:crypto"; import { content } from "@deadhead/content"; import type { RealTime, Seed } from "@deadhead/sim"; import type { Db, Queryable } from "../db/client"; import { companies, discoveredLocations, pilots, players } from "../db/schema"; import { companyName } from "./names"; export const AVATAR_NAME = "Captain"; export interface NewPlayer { playerId: string; companyId: string; avatarId: string; } /** * Creates a fresh player in tutorial mode: starting credits, every location * that starts discovered, the avatar (level 0, unassigned), and the loaner at * Earth. The avatar's position comes from the loaner while the tutorial runs. */ export async function createPlayer( db: Db, args: { userId: string; worldSeed: Seed; now: RealTime; playerId?: string }, ): Promise { const { worldSeed, now } = args; const playerId = args.playerId ?? randomUUID(); const companyId = randomUUID(); const avatarId = randomUUID(); await db.transaction(async (tx) => { await tx.insert(players).values({ id: playerId, userId: args.userId, worldSeed, tutorialActive: true, loanerLocationId: "earth", createdAt: now, }); await createStartingState(tx, { playerId, companyId, avatarId, worldSeed, now }); }); return { playerId, companyId, avatarId }; } /** * A player's starting company (CR-001 tutorial state): starting credits, every * location that starts discovered, and the avatar at Earth beside the loaner. * Shared by guest creation and "Start a new company" (decision 0.5.74). */ export async function createStartingState( tx: Queryable, ids: { playerId: string; companyId: string; avatarId: string; worldSeed: Seed; now: RealTime }, ): Promise { const { playerId, companyId, avatarId, worldSeed, now } = ids; await tx.insert(companies).values({ id: companyId, playerId, name: companyName(worldSeed), credits: content.config.startingCredits, }); await tx .insert(discoveredLocations) .values( content.locations .filter((l) => l.startsDiscovered) .map((l) => ({ playerId, locationId: l.id, discoveredAt: now })), ); await tx.insert(pilots).values({ id: avatarId, playerId, name: AVATAR_NAME, isAvatar: true, locationId: "earth", createdAt: now, }); }