SPB Git forge

spb/spinza

Public
8commits 1branches 0releases
1.6 MBsize
maindefault branch
16 days agolast push
TypeScript 97.6% SQL 1.4% JavaScript 0.5%
12.3 KB · 239 lines typescript
Raw Blame History
1import { defineCrashGame, type CrashGameDefinition } from "@spinza/game-core";23/**4 * Spinza Risk Games — ten cash-out games sharing one provably-fair engine.5 * Every game: P(crash ≥ x) = 0.96 / x. Curves and events only change pacing.6 */78const RULES_COMMON = [9  "Place a bet and start the round. The multiplier begins at 1.00× and climbs.",10  "Press the big button at any moment to lock in your bet × the current multiplier.",11  "If the round ends before you cash out, the bet is lost.",12  "Optional auto cash-out settles automatically at your target multiplier.",13  "Every round is provably fair: the crash point is committed (SHA-256) before the round starts and revealed after it ends.",14];1516export const skyfall = defineCrashGame({17  slug: "skyfall",18  name: "Skyfall",19  version: "1.0.0",20  tagline: "How high before the sky runs out?",21  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.",22  theme: "aviation ascent",23  rtp: 0.96,24  maxMultiplier: 5000,25  volatility: "high",26  curve: { type: "exp", k: 0.075 },27  events: { chance: 0.35, max: 1, window: [3, 18], kinds: [{ id: "tailwind", label: "Tailwind", factor: 1.8, duration: [2, 4], weight: 1 }] },28  milestones: [29    { multiplier: 1.5, label: "Cloud layer" },30    { multiplier: 3, label: "Storm front" },31    { multiplier: 8, label: "Stratosphere" },32    { multiplier: 25, label: "Edge of space" },33    { multiplier: 100, label: "Orbit" },34  ],35  presentation: { scene: "sky", palette: { primary: "#7dd3fc", secondary: "#fbbf24", glow: "#bae6fd", bg: "#08111f", surface: "#0f2540" }, verb: "CASH OUT", unit: "m", unitScale: 1200, ambience: "lunar" },36  rules: [...RULES_COMMON, "A Tailwind event speeds the climb for a few seconds without changing the odds."],37});3839export const deepDive = defineCrashGame({40  slug: "deep-dive",41  name: "Deep Dive",42  version: "1.0.0",43  tagline: "The abyss pays. The abyss also implodes.",44  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.",45  theme: "deep-sea descent",46  rtp: 0.96,47  maxMultiplier: 5000,48  volatility: "high",49  curve: { type: "exp", k: 0.07 },50  events: { chance: 0.3, max: 2, window: [4, 20], kinds: [{ id: "leviathan", label: "Leviathan current", factor: 2.2, duration: [1.5, 3], weight: 1 }] },51  milestones: [52    { multiplier: 2, label: "1,000 m — twilight zone" },53    { multiplier: 5, label: "3,000 m — midnight zone" },54    { multiplier: 20, label: "Abyssal plain" },55    { multiplier: 80, label: "Hadal trench" },56  ],57  presentation: { scene: "ocean", palette: { primary: "#22d3ee", secondary: "#34d399", glow: "#67e8f9", bg: "#03111c", surface: "#062a3a" }, verb: "SURFACE", unit: "m", unitScale: 500, ambience: "ocean" },58  rules: [...RULES_COMMON, "Leviathan currents briefly accelerate the descent — a pacing event only."],59});6061export const rocketRun = defineCrashGame({62  slug: "rocket-run",63  name: "Rocket Run",64  version: "1.0.0",65  tagline: "Mars or bust.",66  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.",67  theme: "space launch",68  rtp: 0.96,69  maxMultiplier: 10000,70  volatility: "extreme",71  curve: { type: "exp", k: 0.095 },72  events: { chance: 0.25, max: 1, window: [2, 14], kinds: [{ id: "afterburner", label: "Afterburner", factor: 2, duration: [1.5, 3], weight: 1 }] },73  milestones: [74    { multiplier: 2, label: "Max-Q" },75    { multiplier: 5, label: "Stage separation" },76    { multiplier: 15, label: "Escape velocity" },77    { multiplier: 60, label: "Trans-Mars injection" },78    { multiplier: 300, label: "Mars orbit" },79  ],80  presentation: { scene: "rocket", palette: { primary: "#fb923c", secondary: "#f472b6", glow: "#fdba74", bg: "#0a0612", surface: "#1b0f2a" }, verb: "SECURE PAYLOAD", unit: "km", unitScale: 40, ambience: "space" },81  rules: [...RULES_COMMON, "Afterburner windows speed up the climb for a moment."],82});8384export const bankHeist = defineCrashGame({85  slug: "bank-heist",86  name: "Bank Heist",87  version: "1.0.0",88  tagline: "The bag keeps filling. The sirens keep coming.",89  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.",90  theme: "heist",91  rtp: 0.96,92  maxMultiplier: 2500,93  volatility: "medium",94  curve: { type: "exp", k: 0.062 },95  events: { chance: 0.3, max: 1, window: [3, 16], kinds: [{ id: "jammer", label: "Signal jammer", factor: 1.6, duration: [2, 4], weight: 1 }] },96  milestones: [97    { multiplier: 1.4, label: "Teller drawers" },98    { multiplier: 2, label: "Safe deposit boxes" },99    { multiplier: 4, label: "Main vault" },100    { multiplier: 12, label: "Diamond room" },101    { multiplier: 50, label: "Federal reserve" },102  ],103  presentation: { scene: "bank", palette: { primary: "#c9a961", secondary: "#ef4444", glow: "#e8cf8f", bg: "#0b0a08", surface: "#1b1811" }, verb: "ESCAPE NOW", unit: "bags", unitScale: 1, ambience: "heist" },104  rules: [...RULES_COMMON, "Signal jammer windows fill the bag faster for a few seconds."],105});106107export const volcano = defineCrashGame({108  slug: "volcano",109  name: "Volcano",110  version: "1.0.0",111  tagline: "Deeper crystals. Rising lava.",112  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.",113  theme: "volcanic descent",114  rtp: 0.96,115  maxMultiplier: 5000,116  volatility: "high",117  curve: { type: "exp", k: 0.08 },118  events: { chance: 0.3, max: 1, window: [3, 15], kinds: [{ id: "vein", label: "Crystal vein", factor: 1.9, duration: [1.5, 3], weight: 1 }] },119  milestones: [120    { multiplier: 1.5, label: "Ash caves" },121    { multiplier: 3, label: "Obsidian galleries" },122    { multiplier: 8, label: "Crystal chamber" },123    { multiplier: 30, label: "Magma core" },124  ],125  presentation: { scene: "volcano", palette: { primary: "#ff5c3d", secondary: "#fbbf24", glow: "#ff8a5c", bg: "#120604", surface: "#2a0c07" }, verb: "EVACUATE", unit: "m", unitScale: 60, ambience: "fire" },126  rules: [...RULES_COMMON, "Crystal veins speed up the harvest briefly."],127});128129export const blackHole = defineCrashGame({130  slug: "black-hole",131  name: "Black Hole",132  version: "1.0.0",133  tagline: "Time slows. The multiplier doesn't.",134  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.",135  theme: "relativistic descent",136  rtp: 0.96,137  maxMultiplier: 10000,138  volatility: "extreme",139  curve: { type: "power", a: 0.02, p: 2.6 },140  milestones: [141    { multiplier: 1.5, label: "Accretion disk" },142    { multiplier: 4, label: "Photon sphere" },143    { multiplier: 15, label: "Spaghettification" },144    { multiplier: 60, label: "Event horizon" },145  ],146  presentation: { scene: "blackhole", palette: { primary: "#a78bfa", secondary: "#f0abfc", glow: "#c4b5fd", bg: "#050308", surface: "#120a24" }, verb: "WARP OUT", unit: "km", unitScale: 1000, ambience: "void" },147  rules: [...RULES_COMMON, "The curve accelerates sharply near the horizon — the same odds, much faster."],148});149150export const freefall = defineCrashGame({151  slug: "freefall",152  name: "Freefall",153  version: "1.0.0",154  tagline: "Pull late. Not too late.",155  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.",156  theme: "skydiving",157  rtp: 0.96,158  maxMultiplier: 5000,159  volatility: "high",160  curve: { type: "power", a: 0.05, p: 2.1 },161  events: { chance: 0.25, max: 1, window: [3, 14], kinds: [{ id: "thermal", label: "Thermal", factor: 0.5, duration: [2, 3], weight: 1 }] },162  milestones: [163    { multiplier: 1.3, label: "Terminal velocity" },164    { multiplier: 3, label: "Cloud deck" },165    { multiplier: 10, label: "Treetops" },166    { multiplier: 40, label: "Ground rush" },167  ],168  presentation: { scene: "freefall", palette: { primary: "#60a5fa", secondary: "#f97316", glow: "#93c5fd", bg: "#07101e", surface: "#0e2140" }, verb: "OPEN CHUTE", unit: "m", unitScale: -300, ambience: "lunar" },169  rules: [...RULES_COMMON, "Thermal updrafts slow the fall for a moment — more time to decide."],170});171172export const coreMeltdown = defineCrashGame({173  slug: "core-meltdown",174  name: "Core Meltdown",175  version: "1.0.0",176  tagline: "Stable… stable… SHUT DOWN.",177  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.",178  theme: "reactor control room",179  rtp: 0.96,180  maxMultiplier: 5000,181  volatility: "high",182  curve: { type: "exp", k: 0.07 },183  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 }] },184  milestones: [185    { multiplier: 1.5, label: "Nominal" },186    { multiplier: 3, label: "Elevated" },187    { multiplier: 8, label: "Critical" },188    { multiplier: 25, label: "Containment stress" },189  ],190  presentation: { scene: "reactor", palette: { primary: "#a3e635", secondary: "#facc15", glow: "#bef264", bg: "#070c06", surface: "#111c0e" }, verb: "SHUT DOWN", unit: "°C", unitScale: 90, ambience: "reactor" },191  rules: [...RULES_COMMON, "Coolant surges slow the temperature climb; power spikes speed it up."],192});193194export const stormChase = defineCrashGame({195  slug: "storm-chase",196  name: "Storm Chase",197  version: "1.0.0",198  tagline: "Drive into the wall cloud.",199  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.",200  theme: "storm chasing",201  rtp: 0.96,202  maxMultiplier: 5000,203  volatility: "high",204  curve: { type: "exp", k: 0.078 },205  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 }] },206  milestones: [207    { multiplier: 1.5, label: "Outflow" },208    { multiplier: 3, label: "Debris field" },209    { multiplier: 8, label: "Wall cloud" },210    { multiplier: 30, label: "Vortex" },211  ],212  presentation: { scene: "storm", palette: { primary: "#94a3b8", secondary: "#a3e635", glow: "#cbd5e1", bg: "#0a0d12", surface: "#1a212c" }, verb: "ESCAPE", unit: "m", unitScale: -400, ambience: "reactor" },213  rules: [...RULES_COMMON, "Rear-flank gusts pull you toward the core faster for a moment."],214});215216export const elevator999 = defineCrashGame({217  slug: "elevator-999",218  name: "Elevator 999",219  version: "1.0.0",220  tagline: "Every floor is a decision.",221  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.",222  theme: "infinite tower",223  rtp: 0.96,224  maxMultiplier: 10000,225  volatility: "high",226  curve: { type: "steps", stepSeconds: 0.55, base: 1.05 },227  milestones: [228    { multiplier: Math.pow(1.05, 25), label: "Floor 25 — Sky lobby" },229    { multiplier: Math.pow(1.05, 50), label: "Floor 50 — Observation deck" },230    { multiplier: Math.pow(1.05, 100), label: "Floor 100 — Cloud gardens" },231    { multiplier: Math.pow(1.05, 250), label: "Floor 250 — Stratos suite" },232  ],233  presentation: { scene: "elevator", palette: { primary: "#e8cf8f", secondary: "#38bdf8", glow: "#f3e2ad", bg: "#08090d", surface: "#151821" }, verb: "STEP OUT", unit: "floor", unitScale: 1, ambience: "obsidian" },234  rules: [...RULES_COMMON, "The multiplier grows 5% per floor (1.05× compounded). Special floors mark express zones."],235});236237export const CRASH_GAMES: CrashGameDefinition[] = [skyfall, deepDive, rocketRun, bankHeist, volcano, blackHole, freefall, coreMeltdown, stormChase, elevator999];238export const CRASH_BY_SLUG = new Map(CRASH_GAMES.map((g) => [g.slug, g]));239