/** * Spinza economy constants. Everything here is fictional: Spinza Credits (SC) * have no monetary value, cannot be bought and cannot be withdrawn. */ export const CURRENCY_NAME = "Spinza Credits"; export const CURRENCY_SHORT = "SC"; /** Granted to every new account. */ export const STARTING_BALANCE = 10_000; /** Bet levels available in every game (games may restrict via minBet/maxBet). */ export const BET_LEVELS = [10, 20, 50, 100, 200, 500, 1_000] as const; export const DEFAULT_MIN_BET = 10; export const DEFAULT_MAX_BET = 1_000; /** Daily reward streak progression (index = streak day - 1). */ export const DAILY_REWARDS = [1_000, 1_250, 1_500, 1_750, 2_000, 2_500, 5_000] as const; /** Missing more than this many days resets the streak. Missing one day soft-resets (goes back 2 steps). */ export const DAILY_STREAK_GRACE_DAYS = 1; /** Rescue credits for players who hit 0 SC. */ export const RESCUE_CREDITS_AMOUNT = 2_500; export const RESCUE_CREDITS_COOLDOWN_HOURS = 12; /** Balance under which rescue credits become available (0 = exactly zero). */ export const RESCUE_CREDITS_THRESHOLD = 0; /** Auto-spin counts. */ export const AUTO_SPIN_OPTIONS = [10, 25, 50, 100] as const; /** Win presentation classes, by multiplier of bet (inclusive lower bound). */ export const WIN_CLASSES = [ { id: "legendary", label: "LEGENDARY WIN", min: 500 }, { id: "epic", label: "EPIC WIN", min: 100 }, { id: "mega", label: "MEGA WIN", min: 50 }, { id: "big", label: "BIG WIN", min: 20 }, { id: "win", label: "WIN", min: 5 }, ] as const; export type WinClassId = (typeof WIN_CLASSES)[number]["id"] | "regular" | "none"; export function classifyWin(multiplier: number): WinClassId { if (multiplier <= 0) return "none"; for (const c of WIN_CLASSES) if (multiplier >= c.min) return c.id; return "regular"; } /** Session/break reminder options in minutes (0 = off). */ export const SESSION_REMINDER_OPTIONS = [0, 30, 60, 90, 120] as const; /** XP economy. */ export const XP_PER_SPIN = 2; export const XP_PER_BONUS = 50; export const XP_PER_NEW_GAME = 100; export const MAX_LEVEL = 100; /** XP required to go from level L to L+1. Smooth curve, ~level 100 at ~1M XP. */ export function xpForLevel(level: number): number { return Math.round(100 * Math.pow(level, 1.55) + 200 * level); } /** Cumulative XP threshold to reach `level` (level 1 = 0). */ export function xpThreshold(level: number): number { let total = 0; for (let l = 1; l < level; l++) total += xpForLevel(l); return total; } export function levelForXp(xp: number): { level: number; current: number; next: number; progress: number } { let level = 1; let remaining = xp; while (level < MAX_LEVEL && remaining >= xpForLevel(level)) { remaining -= xpForLevel(level); level++; } const next = level >= MAX_LEVEL ? 0 : xpForLevel(level); return { level, current: remaining, next, progress: next ? remaining / next : 1 }; } /** Credits granted on level-up (fictional). */ export function levelUpReward(level: number): number { if (level % 25 === 0) return 25_000; if (level % 10 === 0) return 10_000; if (level % 5 === 0) return 4_000; return 1_000; } export const RESERVED_USERNAMES = new Set([ "admin", "administrator", "root", "system", "support", "spenza", "spinza", "staff", "moderator", "mod", "api", "www", "security", "help", "official", "team", "null", "undefined", "me", "you", "guest", "anonymous", "owner", "dev", "developer", "bot", "test", "info", "contact", "billing", "payments", "casino", "webmaster", ]); /** Small default profanity list — the admin can extend it via the `profanity_words` setting. */ export const DEFAULT_PROFANITY = [ "fuck", "shit", "bitch", "cunt", "nigger", "nigga", "faggot", "retard", "whore", "slut", "dick", "cock", "pussy", "asshole", "nazi", "hitler", "rape", "kike", "spic", "chink", ]; export const SESSION_COOKIE = "spinza_session"; export const ADMIN_COOKIE = "spinza_admin"; export const SESSION_TTL_DAYS = 30; export const ADMIN_SESSION_TTL_HOURS = 12; export const ROUND_ID_PREFIX = "spz_rnd_"; export const RECOVERY_CODE_PREFIX = "SPZ"; export const GAME_LIFECYCLE = ["draft", "simulation", "approved", "staging", "published", "disabled"] as const; export type GameLifecycle = (typeof GAME_LIFECYCLE)[number]; export const TRANSACTION_TYPES = [ "INITIAL_GRANT", "BET", "WIN", "DAILY_REWARD", "ACHIEVEMENT", "MISSION", "LEVEL_UP", "RESCUE_CREDITS", "ADMIN_ADJUSTMENT", ] as const; export type TransactionType = (typeof TRANSACTION_TYPES)[number];