feat(game): crew-costs balance module + computeDuration duration model (#44)
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Pure crew-balance module (spec §11): every tuning knob for the duration model and skill
|
||||
// progression lives here, so tuning a number means editing one file. No lib/db imports —
|
||||
// the frontend imports this for the live duration preview in the crew picker (same precedent
|
||||
// as ship-costs.ts).
|
||||
import type { TaskType } from './tasks'
|
||||
|
||||
export type SkillName = 'NAVIGATION' | 'SCANNING' | 'ENGINEERING' | 'RESEARCH'
|
||||
|
||||
export const WORK_POINTS = { EXPLORE: 4, JUMP_PER_HOP: 3, SHIP_WORK: 6, RESEARCH: 9 } as const
|
||||
|
||||
export const ACTION_SKILL: Record<TaskType, SkillName> = {
|
||||
JUMP: 'NAVIGATION',
|
||||
EXPLORE: 'SCANNING',
|
||||
SHIP_UPGRADE: 'ENGINEERING',
|
||||
SHIP_EXPAND: 'ENGINEERING',
|
||||
SHIP_BUILD: 'ENGINEERING',
|
||||
RESEARCH: 'RESEARCH',
|
||||
}
|
||||
|
||||
export const PREFERRED_ROLES: Record<TaskType, string[]> = {
|
||||
JUMP: ['PILOT', 'NAVIGATOR'],
|
||||
EXPLORE: ['SCIENTIST'],
|
||||
SHIP_UPGRADE: ['ENGINEER', 'TECHNICIAN'],
|
||||
SHIP_EXPAND: ['ENGINEER', 'TECHNICIAN'],
|
||||
SHIP_BUILD: ['ENGINEER', 'TECHNICIAN'],
|
||||
RESEARCH: ['SCIENTIST'],
|
||||
}
|
||||
|
||||
export const POWER_BANDS = [1, 1, 1, 2, 2, 3] // skill level 0..5 → power (L0–L2 → 1 · L3–L4 → 2 · L5 → 3)
|
||||
export const XP_THRESHOLDS = [5, 10, 15, 20, 25] // cumulative task completions for L1..L5 (cap 5)
|
||||
|
||||
// Role → starting skill levels (spec §6): specialists start at L2, everyone else at L0.
|
||||
export const STARTING_LEVELS: Record<string, Record<SkillName, number>> = {
|
||||
COMMANDER: { NAVIGATION: 0, SCANNING: 0, ENGINEERING: 0, RESEARCH: 0 },
|
||||
PILOT: { NAVIGATION: 2, SCANNING: 0, ENGINEERING: 0, RESEARCH: 0 },
|
||||
ENGINEER: { NAVIGATION: 0, SCANNING: 0, ENGINEERING: 2, RESEARCH: 0 },
|
||||
MEDIC: { NAVIGATION: 0, SCANNING: 0, ENGINEERING: 0, RESEARCH: 0 },
|
||||
NAVIGATOR: { NAVIGATION: 2, SCANNING: 0, ENGINEERING: 0, RESEARCH: 0 },
|
||||
SCIENTIST: { NAVIGATION: 0, SCANNING: 2, ENGINEERING: 0, RESEARCH: 2 },
|
||||
GUNNER: { NAVIGATION: 0, SCANNING: 0, ENGINEERING: 0, RESEARCH: 0 },
|
||||
TECHNICIAN: { NAVIGATION: 0, SCANNING: 0, ENGINEERING: 2, RESEARCH: 0 },
|
||||
}
|
||||
|
||||
// The lead's good trait that cancels the role-mismatch penalty (spec §5).
|
||||
export const MISMATCH_CANCEL_TRAIT = 'STEADY UNDER PRESSURE'
|
||||
|
||||
// All 15 duration traits of spec §5, keyed by the EXACT trait strings from lib/game/crew.ts.
|
||||
// Value = additive turn modifier keyed by action type or 'ANY'; empty object = no additive
|
||||
// modifier (the trait's effect is the mismatch cancel, see MISMATCH_CANCEL_TRAIT). Traits
|
||||
// with no entry (the three STANDBY combat traits and #45's outcome traits) contribute 0.
|
||||
// "SHIP work" covers all three SHIP types.
|
||||
export const TRAIT_DURATION_MODIFIERS: Record<string, Partial<Record<TaskType | 'ANY', number>>> = {
|
||||
'STEADY UNDER PRESSURE': {},
|
||||
'RECKLESS COURAGE': { JUMP: -1 },
|
||||
'CALM IN A CRISIS': { EXPLORE: -1 },
|
||||
'FIXES ANYTHING': { SHIP_UPGRADE: -1, SHIP_EXPAND: -1, SHIP_BUILD: -1 },
|
||||
'READS STARS BLIND': { JUMP: -1 },
|
||||
'QUICK HANDS': { ANY: -1 },
|
||||
'IRON WILL': { RESEARCH: -1 },
|
||||
'RIGID — SLOW TO ADAPT': { RESEARCH: 1 },
|
||||
'OVERCAUTIOUS': { ANY: 1 },
|
||||
'SLOWS THE CREW DOWN': { ANY: 1 },
|
||||
'CARELESS WITH FUSES': { SHIP_UPGRADE: 1, SHIP_EXPAND: 1, SHIP_BUILD: 1 },
|
||||
'HOARDS RATIONS': { SHIP_UPGRADE: 1, SHIP_EXPAND: 1, SHIP_BUILD: 1 },
|
||||
'FORGETS TO EAT': { EXPLORE: 1 },
|
||||
'ARGUES WITH EVERYONE': { RESEARCH: 1 },
|
||||
'DOUBTS THE CAPTAIN': { JUMP: 1 },
|
||||
}
|
||||
|
||||
export const RECRUIT_CHANCE_BASE = 0.18 // a scan finds a joining member (matches crew.ts's current CREW_CHANCE)
|
||||
export const RECRUIT_CHANCE_TALKER = 0.3 // lead with TALKS TO ANYONE (wired in PR C)
|
||||
Reference in New Issue
Block a user