feat(game): skill XP on task completion + power bands in duration (#45)
CI / build + unit + e2e (pull_request) Successful in 2m48s
CI / build + unit + e2e (pull_request) Successful in 2m48s
This commit is contained in:
+9
-5
@@ -51,9 +51,10 @@ function traitModifier(trait: string, type: TaskType): number {
|
||||
|
||||
// duration = max(1, ceil(work / totalPower) + mismatchPenalty + traitModifierSum) — spec §4.
|
||||
// totalPower = Σ powerOf over the WHOLE team (lead + helpers); the default powerOf is the
|
||||
// constant 1 until PR B feeds the skill band. The mismatch penalty and the trait modifiers
|
||||
// apply to the LEAD only — helpers contribute power, are never penalised, and their traits do
|
||||
// not apply. `hopCount` is only meaningful for JUMP (pass 1 for the other types).
|
||||
// constant 1 — queueTask's optional powerOf param feeds the skill band instead (PR B). The
|
||||
// mismatch penalty and the trait modifiers apply to the LEAD only — helpers contribute
|
||||
// power, are never penalised, and their traits do not apply. `hopCount` is only meaningful
|
||||
// for JUMP (pass 1 for the other types).
|
||||
export function computeDuration(
|
||||
type: TaskType,
|
||||
hopCount: number,
|
||||
@@ -119,7 +120,10 @@ export interface QueueResult {
|
||||
|
||||
// Queue a task. Validation order: unknown crew (404) → busy (409) → in transit (409, all
|
||||
// types) → second jump (409) → cost (422, SHIP_* / RESEARCH only). Never advances the turn.
|
||||
export function queueTask(state: QueueState, req: QueueTaskRequest): QueueResult {
|
||||
// The optional powerOf (default: the constant 1) maps each team member to their power for
|
||||
// the stored duration — the queueing routes pass makePowerOf over the roster's skill rows
|
||||
// (PR B); callers without a skill context (tests, the immediate actions) use the default.
|
||||
export function queueTask(state: QueueState, req: QueueTaskRequest, powerOf: (m: CrewMember) => number = () => 1): QueueResult {
|
||||
const lead = state.crew.find((c) => c.id === req.leadCrewId)
|
||||
if (!lead) throw new TaskError(404, `Unknown crew member ${req.leadCrewId}`)
|
||||
const helpers: CrewDto[] = []
|
||||
@@ -168,7 +172,7 @@ export function queueTask(state: QueueState, req: QueueTaskRequest): QueueResult
|
||||
// lead chaining behind its own ACTIVE can be non-free.
|
||||
const free = (id: number) => !inStatus(id, 'ACTIVE') && !inStatus(id, 'PENDING')
|
||||
const hops = req.type === 'JUMP' ? (req.payload.hops as number) : 0
|
||||
const duration = computeDuration(req.type, hops, lead, helpers)
|
||||
const duration = computeDuration(req.type, hops, lead, helpers, powerOf)
|
||||
const status: TaskStatus = [lead, ...helpers].every((c) => free(c.id)) ? 'ACTIVE' : 'PENDING'
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user