feat(game): per-type resolvers — jump/explore/ship/research effect extraction for task resolution (#44)
This commit is contained in:
+26
-4
@@ -4,6 +4,7 @@ import { persist, type GameDb } from '@/lib/db/client'
|
||||
import { EFFECTS, TECHS, techStatus, type TechDto } from './tech'
|
||||
import { ensureSave } from './save'
|
||||
import { ShipError, spendItems } from './ship'
|
||||
import type { Task, TaskType } from './tasks'
|
||||
|
||||
// Technology research: the SKILL TREE tab's read + action. Researching a tech costs inventory
|
||||
// items (oldest row first, like ship actions) plus a turn, and its unlock effect then gates or
|
||||
@@ -46,8 +47,31 @@ export async function getTechState(db: GameDb): Promise<TechDto[]> {
|
||||
})
|
||||
}
|
||||
|
||||
function syntheticTask(type: TaskType, payload: object): Task {
|
||||
return { id: 0, saveId: 0, type, payload: JSON.stringify(payload), leadCrewId: 0, helpers: [], duration: 0, remaining: 0, status: 'ACTIVE', queuedAtTurn: 0 }
|
||||
}
|
||||
|
||||
// RESEARCH — mark the payload's tech researched at the current turn. No cost here (deducted
|
||||
// at queue time — Task 3 — or by researchTech before delegating); no mission hooks (the
|
||||
// current action has none).
|
||||
export async function resolveResearchTask(db: GameDb, task: Task): Promise<void> {
|
||||
await ensureSave(db)
|
||||
const { techId } = JSON.parse(task.payload) as { techId: number }
|
||||
const [save] = await db.db.select().from(schema.saves).limit(1)
|
||||
const rows = await db.db.select().from(schema.tech)
|
||||
const target = rows.find((t) => t.id === techId)
|
||||
if (!target) throw new ResearchError(404, `Unknown tech ${techId}`)
|
||||
|
||||
const def = TECHS.find((t) => t.slug === target.slug)!
|
||||
if (target.researched) throw new ResearchError(409, `${def.name} is already researched`)
|
||||
|
||||
await db.db.update(schema.tech).set({ researched: true }).where(eq(schema.tech.id, target.id))
|
||||
await db.db.insert(schema.events).values({ saveId: save.id, turn: save.turn, type: 'research', message: `Researched ${def.name} (cost: ${def.costQty}× ${def.costKind === 'resource' ? 'resources' : 'parts'})`, createdAt: new Date().toISOString() })
|
||||
await persist(db)
|
||||
}
|
||||
|
||||
// Research one tech: validates prerequisites (409, naming what is missing) and the cost (422),
|
||||
// spends it from the cargo hold, marks it researched, costs a turn and writes an event.
|
||||
// spends it from the cargo hold, then delegates the unlock to the resolver at the new turn.
|
||||
export async function researchTech(db: GameDb, techId: number): Promise<TechDto[]> {
|
||||
await ensureSave(db)
|
||||
const [save] = await db.db.select().from(schema.saves).limit(1)
|
||||
@@ -70,10 +94,8 @@ export async function researchTech(db: GameDb, techId: number): Promise<TechDto[
|
||||
}
|
||||
|
||||
const turn = save.turn + 1
|
||||
await db.db.update(schema.tech).set({ researched: true }).where(eq(schema.tech.id, target.id))
|
||||
await db.db.update(schema.saves).set({ turn }).where(eq(schema.saves.id, save.id))
|
||||
await db.db.insert(schema.events).values({ saveId: save.id, turn, type: 'research', message: `Researched ${def.name} (cost: ${def.costQty}× ${def.costKind === 'resource' ? 'resources' : 'parts'})`, createdAt: new Date().toISOString() })
|
||||
await persist(db)
|
||||
await resolveResearchTask(db, syntheticTask('RESEARCH', { techId }))
|
||||
|
||||
return getTechState(db)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user