72 lines
3.4 KiB
TypeScript
72 lines
3.4 KiB
TypeScript
// 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)
|