// 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 = { JUMP: 'NAVIGATION', EXPLORE: 'SCANNING', SHIP_UPGRADE: 'ENGINEERING', SHIP_EXPAND: 'ENGINEERING', SHIP_BUILD: 'ENGINEERING', RESEARCH: 'RESEARCH', } export const PREFERRED_ROLES: Record = { 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> = { 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>> = { '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)