import { defineCrashGame, type CrashGameDefinition } from "@spinza/game-core"; /** * Spinza Risk Games — ten cash-out games sharing one provably-fair engine. * Every game: P(crash ≥ x) = 0.96 / x. Curves and events only change pacing. */ const RULES_COMMON = [ "Place a bet and start the round. The multiplier begins at 1.00× and climbs.", "Press the big button at any moment to lock in your bet × the current multiplier.", "If the round ends before you cash out, the bet is lost.", "Optional auto cash-out settles automatically at your target multiplier.", "Every round is provably fair: the crash point is committed (SHA-256) before the round starts and revealed after it ends.", ]; export const skyfall = defineCrashGame({ slug: "skyfall", name: "Skyfall", version: "1.0.0", tagline: "How high before the sky runs out?", description: "A jet climbs through clouds, storms and the stratosphere into open space. The multiplier rises with the altitude — cash out before the aircraft vanishes.", theme: "aviation ascent", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "exp", k: 0.075 }, events: { chance: 0.35, max: 1, window: [3, 18], kinds: [{ id: "tailwind", label: "Tailwind", factor: 1.8, duration: [2, 4], weight: 1 }] }, milestones: [ { multiplier: 1.5, label: "Cloud layer" }, { multiplier: 3, label: "Storm front" }, { multiplier: 8, label: "Stratosphere" }, { multiplier: 25, label: "Edge of space" }, { multiplier: 100, label: "Orbit" }, ], presentation: { scene: "sky", palette: { primary: "#7dd3fc", secondary: "#fbbf24", glow: "#bae6fd", bg: "#08111f", surface: "#0f2540" }, verb: "CASH OUT", unit: "m", unitScale: 1200, ambience: "lunar" }, rules: [...RULES_COMMON, "A Tailwind event speeds the climb for a few seconds without changing the odds."], }); export const deepDive = defineCrashGame({ slug: "deep-dive", name: "Deep Dive", version: "1.0.0", tagline: "The abyss pays. The abyss also implodes.", description: "A research submarine sinks into the ocean. 1,000 m is ×2, 3,000 m is ×5, the abyss is ×20 and beyond. Surface before the hull gives in. Leviathans sometimes drag you deeper, faster.", theme: "deep-sea descent", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "exp", k: 0.07 }, events: { chance: 0.3, max: 2, window: [4, 20], kinds: [{ id: "leviathan", label: "Leviathan current", factor: 2.2, duration: [1.5, 3], weight: 1 }] }, milestones: [ { multiplier: 2, label: "1,000 m — twilight zone" }, { multiplier: 5, label: "3,000 m — midnight zone" }, { multiplier: 20, label: "Abyssal plain" }, { multiplier: 80, label: "Hadal trench" }, ], presentation: { scene: "ocean", palette: { primary: "#22d3ee", secondary: "#34d399", glow: "#67e8f9", bg: "#03111c", surface: "#062a3a" }, verb: "SURFACE", unit: "m", unitScale: 500, ambience: "ocean" }, rules: [...RULES_COMMON, "Leviathan currents briefly accelerate the descent — a pacing event only."], }); export const rocketRun = defineCrashGame({ slug: "rocket-run", name: "Rocket Run", version: "1.0.0", tagline: "Mars or bust.", description: "A rocket leaves the pad for Mars. Every second adds to the multiplier and some runs reach absurd heights — until an engine failure, a collision or an overheat ends it instantly. Secure the payload whenever you like.", theme: "space launch", rtp: 0.96, maxMultiplier: 10000, volatility: "extreme", curve: { type: "exp", k: 0.095 }, events: { chance: 0.25, max: 1, window: [2, 14], kinds: [{ id: "afterburner", label: "Afterburner", factor: 2, duration: [1.5, 3], weight: 1 }] }, milestones: [ { multiplier: 2, label: "Max-Q" }, { multiplier: 5, label: "Stage separation" }, { multiplier: 15, label: "Escape velocity" }, { multiplier: 60, label: "Trans-Mars injection" }, { multiplier: 300, label: "Mars orbit" }, ], presentation: { scene: "rocket", palette: { primary: "#fb923c", secondary: "#f472b6", glow: "#fdba74", bg: "#0a0612", surface: "#1b0f2a" }, verb: "SECURE PAYLOAD", unit: "km", unitScale: 40, ambience: "space" }, rules: [...RULES_COMMON, "Afterburner windows speed up the climb for a moment."], }); export const bankHeist = defineCrashGame({ slug: "bank-heist", name: "Bank Heist", version: "1.0.0", tagline: "The bag keeps filling. The sirens keep coming.", description: "You are inside the vault and the bag of fictional cash keeps growing: ×1.1, ×1.4, ×2, ×3… Stay longer for more, but the police can arrive at any second. Escape before they do and the multiplier is yours.", theme: "heist", rtp: 0.96, maxMultiplier: 2500, volatility: "medium", curve: { type: "exp", k: 0.062 }, events: { chance: 0.3, max: 1, window: [3, 16], kinds: [{ id: "jammer", label: "Signal jammer", factor: 1.6, duration: [2, 4], weight: 1 }] }, milestones: [ { multiplier: 1.4, label: "Teller drawers" }, { multiplier: 2, label: "Safe deposit boxes" }, { multiplier: 4, label: "Main vault" }, { multiplier: 12, label: "Diamond room" }, { multiplier: 50, label: "Federal reserve" }, ], presentation: { scene: "bank", palette: { primary: "#c9a961", secondary: "#ef4444", glow: "#e8cf8f", bg: "#0b0a08", surface: "#1b1811" }, verb: "ESCAPE NOW", unit: "bags", unitScale: 1, ambience: "heist" }, rules: [...RULES_COMMON, "Signal jammer windows fill the bag faster for a few seconds."], }); export const volcano = defineCrashGame({ slug: "volcano", name: "Volcano", version: "1.0.0", tagline: "Deeper crystals. Rising lava.", description: "An explorer descends into a live volcano to harvest crystals. The deeper, the richer — but the lava level rises unpredictably. Trigger EVACUATE before the eruption.", theme: "volcanic descent", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "exp", k: 0.08 }, events: { chance: 0.3, max: 1, window: [3, 15], kinds: [{ id: "vein", label: "Crystal vein", factor: 1.9, duration: [1.5, 3], weight: 1 }] }, milestones: [ { multiplier: 1.5, label: "Ash caves" }, { multiplier: 3, label: "Obsidian galleries" }, { multiplier: 8, label: "Crystal chamber" }, { multiplier: 30, label: "Magma core" }, ], presentation: { scene: "volcano", palette: { primary: "#ff5c3d", secondary: "#fbbf24", glow: "#ff8a5c", bg: "#120604", surface: "#2a0c07" }, verb: "EVACUATE", unit: "m", unitScale: 60, ambience: "fire" }, rules: [...RULES_COMMON, "Crystal veins speed up the harvest briefly."], }); export const blackHole = defineCrashGame({ slug: "black-hole", name: "Black Hole", version: "1.0.0", tagline: "Time slows. The multiplier doesn't.", description: "Your ship drifts toward an event horizon. The multiplier creeps at first, then explodes as space-time bends: ×10 becomes ×15, ×25, ×50 in a heartbeat. WARP OUT before you are pulled in.", theme: "relativistic descent", rtp: 0.96, maxMultiplier: 10000, volatility: "extreme", curve: { type: "power", a: 0.02, p: 2.6 }, milestones: [ { multiplier: 1.5, label: "Accretion disk" }, { multiplier: 4, label: "Photon sphere" }, { multiplier: 15, label: "Spaghettification" }, { multiplier: 60, label: "Event horizon" }, ], presentation: { scene: "blackhole", palette: { primary: "#a78bfa", secondary: "#f0abfc", glow: "#c4b5fd", bg: "#050308", surface: "#120a24" }, verb: "WARP OUT", unit: "km", unitScale: 1000, ambience: "void" }, rules: [...RULES_COMMON, "The curve accelerates sharply near the horizon — the same odds, much faster."], }); export const freefall = defineCrashGame({ slug: "freefall", name: "Freefall", version: "1.0.0", tagline: "Pull late. Not too late.", description: "A skydiver leaps from the edge of the atmosphere. The reward grows during the fall — slowly at altitude, brutally fast near the ground. Open the chute in time or lose the round.", theme: "skydiving", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "power", a: 0.05, p: 2.1 }, events: { chance: 0.25, max: 1, window: [3, 14], kinds: [{ id: "thermal", label: "Thermal", factor: 0.5, duration: [2, 3], weight: 1 }] }, milestones: [ { multiplier: 1.3, label: "Terminal velocity" }, { multiplier: 3, label: "Cloud deck" }, { multiplier: 10, label: "Treetops" }, { multiplier: 40, label: "Ground rush" }, ], presentation: { scene: "freefall", palette: { primary: "#60a5fa", secondary: "#f97316", glow: "#93c5fd", bg: "#07101e", surface: "#0e2140" }, verb: "OPEN CHUTE", unit: "m", unitScale: -300, ambience: "lunar" }, rules: [...RULES_COMMON, "Thermal updrafts slow the fall for a moment — more time to decide."], }); export const coreMeltdown = defineCrashGame({ slug: "core-meltdown", name: "Core Meltdown", version: "1.0.0", tagline: "Stable… stable… SHUT DOWN.", description: "An experimental reactor produces energy as long as it stays stable. Temperature climbs; the multiplier climbs with it. Cooling events can buy you time. Shut down before the limit or lose the batch.", theme: "reactor control room", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "exp", k: 0.07 }, events: { chance: 0.45, max: 2, window: [2, 18], kinds: [{ id: "coolant", label: "Coolant surge", factor: 0.45, duration: [2, 3.5], weight: 3 }, { id: "spike", label: "Power spike", factor: 1.8, duration: [1, 2], weight: 1 }] }, milestones: [ { multiplier: 1.5, label: "Nominal" }, { multiplier: 3, label: "Elevated" }, { multiplier: 8, label: "Critical" }, { multiplier: 25, label: "Containment stress" }, ], presentation: { scene: "reactor", palette: { primary: "#a3e635", secondary: "#facc15", glow: "#bef264", bg: "#070c06", surface: "#111c0e" }, verb: "SHUT DOWN", unit: "°C", unitScale: 90, ambience: "reactor" }, rules: [...RULES_COMMON, "Coolant surges slow the temperature climb; power spikes speed it up."], }); export const stormChase = defineCrashGame({ slug: "storm-chase", name: "Storm Chase", version: "1.0.0", tagline: "Drive into the wall cloud.", description: "You race toward a giant tornado. The closer to the core, the higher the multiplier — but the storm can turn and swallow the truck without warning. ESCAPE while the road is still there.", theme: "storm chasing", rtp: 0.96, maxMultiplier: 5000, volatility: "high", curve: { type: "exp", k: 0.078 }, events: { chance: 0.3, max: 1, window: [3, 15], kinds: [{ id: "gust", label: "Rear-flank gust", factor: 1.9, duration: [1.5, 3], weight: 1 }] }, milestones: [ { multiplier: 1.5, label: "Outflow" }, { multiplier: 3, label: "Debris field" }, { multiplier: 8, label: "Wall cloud" }, { multiplier: 30, label: "Vortex" }, ], presentation: { scene: "storm", palette: { primary: "#94a3b8", secondary: "#a3e635", glow: "#cbd5e1", bg: "#0a0d12", surface: "#1a212c" }, verb: "ESCAPE", unit: "m", unitScale: -400, ambience: "reactor" }, rules: [...RULES_COMMON, "Rear-flank gusts pull you toward the core faster for a moment."], }); export const elevator999 = defineCrashGame({ slug: "elevator-999", name: "Elevator 999", version: "1.0.0", tagline: "Every floor is a decision.", description: "An elevator climbs an endless tower. Each floor raises the multiplier; you may step out and cash out at any floor. The elevator can fail at any moment. Floors 25, 50, 100 and 250 are express zones where the climb accelerates.", theme: "infinite tower", rtp: 0.96, maxMultiplier: 10000, volatility: "high", curve: { type: "steps", stepSeconds: 0.55, base: 1.05 }, milestones: [ { multiplier: Math.pow(1.05, 25), label: "Floor 25 — Sky lobby" }, { multiplier: Math.pow(1.05, 50), label: "Floor 50 — Observation deck" }, { multiplier: Math.pow(1.05, 100), label: "Floor 100 — Cloud gardens" }, { multiplier: Math.pow(1.05, 250), label: "Floor 250 — Stratos suite" }, ], presentation: { scene: "elevator", palette: { primary: "#e8cf8f", secondary: "#38bdf8", glow: "#f3e2ad", bg: "#08090d", surface: "#151821" }, verb: "STEP OUT", unit: "floor", unitScale: 1, ambience: "obsidian" }, rules: [...RULES_COMMON, "The multiplier grows 5% per floor (1.05× compounded). Special floors mark express zones."], }); export const CRASH_GAMES: CrashGameDefinition[] = [skyfall, deepDive, rocketRun, bankHeist, volcano, blackHole, freefall, coreMeltdown, stormChase, elevator999]; export const CRASH_BY_SLUG = new Map(CRASH_GAMES.map((g) => [g.slug, g]));