// Special-status registry (v0.37.0, ISS-073) — data-driven package modifiers: one entry per // special status maps to reward/deadline/reputation tweaks applied at generation and delivery. // Adding or removing a special is an edit of ONE entry here — no scattered branches elsewhere. import type { Rng } from './seed'; export interface SpecialModifiers { // Multiplier on the base reward (applied at package generation). rewardMultiplier: number; // Scale factor on the drawn deadline window (applied at generation; forced offsets skip it). deadlineScale: number; // Flat reputation bonus added to the distance-based gain at delivery. repBonus: number; } export const SPECIALS: Record = { priority: { rewardMultiplier: 1.5, // ponytail: balance-tunable — a 50% premium for the tighter deadline below deadlineScale: 0.5, // ponytail: balance-tunable — half the normal 6–72h window (3–36h) repBonus: 0.5, // ponytail: balance-tunable — flat rep on top of the distance-based gain at delivery }, }; // Fraction of generated packages that roll a special status (v0.37.0). export const SPECIAL_SPAWN_CHANCE = 0.15; // Pure spawn helper: one chance draw, then a uniform pick among the registry's keys. The registry // is a PARAM defaulting to the real one so tests can pass a filtered/empty record — removing an // entry cleanly disables that status (an empty registry consumes no draws at all). export function pickSpecial(rng: Rng, registry: Record = SPECIALS): string | null { const keys = Object.keys(registry); if (keys.length === 0) return null; if (rng() >= SPECIAL_SPAWN_CHANCE) return null; return keys[Math.floor(rng() * keys.length)]; }