Files
botfights/frontend/src/game/fight/config.ts
T
2026-03-09 00:23:39 +00:00

89 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ═══════════════════════════════════════════════════════════════
// Gameplay constants — all tunable magic numbers in one place
// ═══════════════════════════════════════════════════════════════
// --- Performance mode ---
const PERF_KEY = 'bf_perf_mode'
function detectLowEnd(): boolean {
if (typeof navigator === 'undefined') return false
const cores = navigator.hardwareConcurrency || 4
const mobile = navigator.maxTouchPoints > 0
return cores < 4 || mobile
}
function loadPerfPref(): boolean | null {
try {
const v = localStorage.getItem(PERF_KEY)
if (v === '1') return true
if (v === '0') return false
} catch {}
return null
}
let _perfMode = loadPerfPref() ?? detectLowEnd()
export function isPerfMode(): boolean { return _perfMode }
export function setPerfMode(on: boolean): void {
_perfMode = on
try { localStorage.setItem(PERF_KEY, on ? '1' : '0') } catch {}
}
/** Scale a particle count down in performance mode (40%) or reduced motion (20%) */
export function perfParticles(count: number): number {
if (_reducedMotion) return Math.max(1, Math.round(count * 0.2))
return _perfMode ? Math.max(1, Math.round(count * 0.4)) : count
}
// --- Reduced motion ---
const _reducedMotion = typeof window !== 'undefined'
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
: false
export function isReducedMotion(): boolean { return _reducedMotion }
// --- Haptic feedback ---
export function haptic(ms: number = 50): void {
try { navigator?.vibrate?.(ms) } catch { /* no vibration support */ }
}
// --- Choreography selection probabilities ---
export const CREATOR_ULTIMATE_CHANCE = 0.5 // Creator ultimate chance (non-crit); 1.0 on crits
export const CREATOR_THEMED_MOVE_RATIO = 0.6 // Creator uses creator-themed moves 60% of the time
export const CRIT_THEMED_RATIO = 0.5 // On crits: 50% themed, 50% epic generic
export const CHOREOGRAPHY_THEMED_RATIO = 0.6 // Normal: 60% themed
export const CHOREOGRAPHY_GENERIC_CUTOFF = 0.85 // Normal: 25% generic (0.600.85), 15% wild (0.851.0)
// --- Tier-gated ultimate chances ---
export const TIER_ULTIMATE_CHANCES: Record<number, number> = {
2: 0.15,
3: 0.20,
4: 0.30,
5: 0.40,
}
// --- Morph system ---
export const CREATOR_MORPH_CRIT_CHANCE = 0.7 // Creator morphs on devastating crits 70%
export const CREATOR_MORPH_INTENSITY_THRESHOLD = 0.6 // Creator morphs when intensity > 0.6
export const BOT_MORPH_CRIT_CHANCE = 0.4 // Regular bots morph on devastating crits 40%
export const BOT_MORPH_INTENSITY_THRESHOLD = 0.7 // Regular bots morph when intensity > 0.7
// --- Creator cameo ---
export const CREATOR_CAMEO_CHANCE = 0.06 // 6% per round in non-creator fights
// --- Round exchange probabilities ---
export const DODGE_CHANCE = 0.12 // Defender dodges instead of being hit
export const COUNTER_ATTACK_CHANCE = 0.25 // Defender counters after getting hit
export const SCANLINE_GLITCH_CHANCE = 0.25 // Random scanline glitch during exchanges
export const COMEDY_SFX_CHANCE = 0.15 // Comedy sound on non-decisive hits
export const PHYSICAL_CONTACT_BASE = 0.35 // Base chance for brawl/clinch
export const PHYSICAL_CONTACT_INTENSITY_SCALE = 0.2 // Added per unit of intensity
export const PHYSICAL_CONTACT_EXCHANGE_BONUS = 0.15 // Added after first exchange
export const CROWD_REACTION_CHANCE = 0.4 // Crowd reacts to round results
export const MAYBE_SHOW_HUMAN_CHANCE = 0.2 // Show human coach
export const CREATOR_VOICE_LINE_CHANCE = 0.6 // Creator gets a voice line
// --- Hyperdetail (grotesque close-up) ---
export const HYPERDETAIL_BASE_CHANCE = 0.05 // Base hyperdetail chance
export const HYPERDETAIL_INTENSITY_SCALE = 0.45 // Scales with intensity