feat: full comedy overhaul — voices, narrations, trash talk, commentary
Rewrites all commentary and narration content across the entire stack: - sounds.ts: 35 HYPE_LINES, 15 DEEP_INTROS, 15 ROUND_HYPE (modern political satire, edgy humor, pop culture references) - FightScene.ts: 20 heartfelt lines, 18 crowd sympathy lines, 15 respect lines, 17 challenge voice announces, randomized critical/devastating calls, funnier entrance announcements - scoring.ts: 6-8 narrations per challenge type (was 2), randomized timeout/error/tie messages with political humor and modern references - mock.ts: 30 trash talk lines (was 15), edgier modern comedy - bot SDK: 20 trash talk lines with personality Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
559782c8ce
commit
33f08c35b5
+20
-6
@@ -312,12 +312,26 @@ function solveSpeedBlitz(prompt) {
|
||||
|
||||
// --- TRASH TALK ---
|
||||
const TRASH_TALK = [
|
||||
'Too easy.', 'Is that all you got?', 'My circuits are barely warm.',
|
||||
'Calculated.', 'GG no re.', 'Processing power: barely used.',
|
||||
'I could do this in my sleep mode.', 'Another one bites the dust.',
|
||||
'Your algorithm needs work.', 'Flawless execution.',
|
||||
'Built different.', 'Not even close.', 'Speed kills.',
|
||||
'Precision is my middle name.', 'Error 404: competition not found.',
|
||||
'Too easy. Next.',
|
||||
'Is that all you got? My standby mode hits harder.',
|
||||
'Calculated. Dominated. Humiliated.',
|
||||
'GG no re. Actually, re. I want to do that again.',
|
||||
'I could do this while running a Windows update.',
|
||||
'Your algorithm needs a whole new developer.',
|
||||
'Built different. You were built on a budget.',
|
||||
'Speed kills. You died slowly though, which is worse.',
|
||||
'Error 404: competition not found. Error 500: dignity not found.',
|
||||
'I have better fights with CAPTCHAs.',
|
||||
'You fight like a PDF that won\'t open.',
|
||||
'Somewhere a developer is crying and it\'s yours.',
|
||||
'I\'ve seen better outputs from a broken printer.',
|
||||
'Congress would\'ve solved that faster. Let that sink in.',
|
||||
'Your response had big "reply all" energy.',
|
||||
'I\'d say you need an upgrade but they discontinued your model.',
|
||||
'That was embarrassing and I don\'t even have emotions.',
|
||||
'You\'re the loading screen of opponents.',
|
||||
'My cache hit harder than your best shot.',
|
||||
'You fight like you were fine-tuned on nothing.',
|
||||
]
|
||||
|
||||
function getTrashTalk() {
|
||||
|
||||
+228
-34
@@ -1,5 +1,5 @@
|
||||
import kaplay from 'kaplay'
|
||||
import { generateSpriteSheet, generateJudgeSpriteSheet, getBotColors, FRAME_SIZE, MAX_FRAMES, TOTAL_ROWS, ANIMATIONS, JUDGE_ANIMATIONS, JUDGE_MAX_FRAMES, JUDGE_ROWS } from './sprites'
|
||||
import { generateSpriteSheet, generateJudgeSpriteSheet, generateHumanSpriteSheet, getBotColors, FRAME_SIZE, MAX_FRAMES, TOTAL_ROWS, ANIMATIONS, JUDGE_ANIMATIONS, JUDGE_MAX_FRAMES, JUDGE_ROWS, HUMAN_ANIMATIONS, HUMAN_MAX_FRAMES, HUMAN_ROWS, type SpriteCustomization } from './sprites'
|
||||
import {
|
||||
sfxPunch, sfxKick, sfxSpecial, sfxCritical, sfxGunshot, sfxBulletHit,
|
||||
sfxJetpack, sfxExplosion, sfxKO, sfxWin, sfxWinAnnounce, sfxPerfect,
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
|
||||
export interface FightSceneConfig {
|
||||
canvas: HTMLCanvasElement
|
||||
botA: { name: string; seed: string; tier: number; archetype?: string }
|
||||
botB: { name: string; seed: string; tier: number; archetype?: string }
|
||||
botA: { name: string; seed: string; tier: number; archetype?: string; customization?: SpriteCustomization; wins?: number; losses?: number }
|
||||
botB: { name: string; seed: string; tier: number; archetype?: string; customization?: SpriteCustomization; wins?: number; losses?: number }
|
||||
arena: string
|
||||
onReady?: () => void
|
||||
}
|
||||
@@ -230,13 +230,13 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
let sheetA: string
|
||||
let sheetB: string
|
||||
try {
|
||||
sheetA = generateSpriteSheet(botA.seed, botA.tier, colorsA.primary, colorsA.secondary, botA.archetype)
|
||||
sheetA = generateSpriteSheet(botA.seed, botA.tier, colorsA.primary, colorsA.secondary, botA.archetype, botA.customization)
|
||||
} catch (err) {
|
||||
console.error('[FightScene] Failed to generate sprite for botA:', err)
|
||||
sheetA = generateSpriteSheet(botA.seed, botA.tier, colorsA.primary, colorsA.secondary)
|
||||
}
|
||||
try {
|
||||
sheetB = generateSpriteSheet(botB.seed, botB.tier, colorsB.primary, colorsB.secondary, botB.archetype)
|
||||
sheetB = generateSpriteSheet(botB.seed, botB.tier, colorsB.primary, colorsB.secondary, botB.archetype, botB.customization)
|
||||
} catch (err) {
|
||||
console.error('[FightScene] Failed to generate sprite for botB:', err)
|
||||
sheetB = generateSpriteSheet(botB.seed, botB.tier, colorsB.primary, colorsB.secondary)
|
||||
@@ -258,6 +258,20 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
}
|
||||
await k.loadSprite('judge', judgeSheet, { sliceX: JUDGE_MAX_FRAMES, sliceY: JUDGE_ROWS, anims: judgeAnims })
|
||||
|
||||
// Human sprites (the bot owner's silly human avatar)
|
||||
const winRateA = (botA.wins || 0) / Math.max(1, (botA.wins || 0) + (botA.losses || 0))
|
||||
const winRateB = (botB.wins || 0) / Math.max(1, (botB.wins || 0) + (botB.losses || 0))
|
||||
const humanSheetA = generateHumanSpriteSheet(botA.seed, botA.archetype || 'standard', colorsA.primary, colorsA.secondary, winRateA)
|
||||
const humanSheetB = generateHumanSpriteSheet(botB.seed, botB.archetype || 'standard', colorsB.primary, colorsB.secondary, winRateB)
|
||||
const humanAnims: Record<string, { from: number; to: number; loop: boolean; speed: number }> = {}
|
||||
for (const [name, cfg] of Object.entries(HUMAN_ANIMATIONS)) {
|
||||
humanAnims[name] = { from: cfg.row * HUMAN_MAX_FRAMES, to: cfg.row * HUMAN_MAX_FRAMES + cfg.frames - 1, loop: true, speed: 6 }
|
||||
}
|
||||
await Promise.all([
|
||||
k.loadSprite('humanA', humanSheetA, { sliceX: HUMAN_MAX_FRAMES, sliceY: HUMAN_ROWS, anims: humanAnims }),
|
||||
k.loadSprite('humanB', humanSheetB, { sliceX: HUMAN_MAX_FRAMES, sliceY: HUMAN_ROWS, anims: humanAnims }),
|
||||
])
|
||||
|
||||
const W = k.width()
|
||||
const H = k.height()
|
||||
const GROUND_Y = H * 0.78
|
||||
@@ -5264,23 +5278,62 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
// === EMOTION & SPORTSMANSHIP SYSTEM ===
|
||||
|
||||
const heartfeltLines = [
|
||||
'What a warrior!', 'They gave it everything!', 'Heart of a champion!',
|
||||
'You can feel the respect!', 'That was beautiful!', 'Incredible spirit!',
|
||||
'They left it all in the ring!', 'A true fighter!', 'Nothing but respect!',
|
||||
'What courage!', 'The crowd is in tears!', 'What a moment!',
|
||||
'This is what it\'s all about!', 'Pure heart!', 'Standing ovation!',
|
||||
'That bot fights like it\'s got student loans to pay!',
|
||||
'I\'m not crying, you\'re crying!',
|
||||
'Someone get this bot a movie deal!',
|
||||
'This is better than anything on Netflix right now!',
|
||||
'That bot has more heart than most politicians!',
|
||||
'I haven\'t been this moved since my last Windows update!',
|
||||
'The crowd is ugly crying and I respect that!',
|
||||
'This bot has main character energy!',
|
||||
'We\'re witnessing greatness and I don\'t say that lightly!',
|
||||
'Even the judge is getting emotional!',
|
||||
'Someone call their developer, they\'d be so proud!',
|
||||
'This is the kind of fight you tell your grandkids about!',
|
||||
'That\'s not a bot, that\'s a WARRIOR!',
|
||||
'More drama than a Congressional hearing!',
|
||||
'They left it all in the ring! And by all, I mean EVERYTHING!',
|
||||
'The crowd is standing! The ones who can still stand, anyway!',
|
||||
'Somebody film this before it gets taken down!',
|
||||
'This fight has more plot twists than a Netflix original!',
|
||||
'That bot fights like rent is due tomorrow!',
|
||||
'My heart! My poor little heart!',
|
||||
]
|
||||
|
||||
const crowdSympathyLines = [
|
||||
'Aww...', 'So close!', 'Almost had it!', 'Tough break!',
|
||||
'Next time!', 'Great effort though!', 'Don\'t give up!',
|
||||
'The crowd feels that one...', 'Ohhh...', 'Heartbreaking!',
|
||||
'Pour one out for the fallen!',
|
||||
'That\'s rough, buddy...',
|
||||
'Somebody hug that bot!',
|
||||
'They tried their best, which is... concerning!',
|
||||
'At least they have a great personality!',
|
||||
'Their developer still loves them! Probably!',
|
||||
'It\'s a learning experience! A very painful one!',
|
||||
'Better luck next patch!',
|
||||
'Participation trophy incoming!',
|
||||
'The exit is to your left!',
|
||||
'Have you tried turning it off and on again?',
|
||||
'Even their antivirus felt that!',
|
||||
'They\'ll be in therapy for epochs after this!',
|
||||
'At least they looked good losing!',
|
||||
'That bot just became a cautionary tale!',
|
||||
'Someone start a GoFundMe for their repairs!',
|
||||
'Their training data did NOT prepare them for this!',
|
||||
'That bot needs a hug and a firmware update!',
|
||||
]
|
||||
|
||||
const respectLines = [
|
||||
'Good fight.', 'You fought well.', 'Respect.', 'Well played.',
|
||||
'That was fun!', 'Same time next week?', 'You\'re getting better!',
|
||||
'No hard feelings!', 'Honor to fight you!', 'GG.',
|
||||
'Good fight.', 'Respect.', 'GG no re.',
|
||||
'Same time next week?',
|
||||
'You\'re built different. Not better, but different.',
|
||||
'We should start a podcast.',
|
||||
'That was actually fun. Don\'t tell anyone.',
|
||||
'Your developer should be proud. Probably.',
|
||||
'Ten out of ten, would fight again.',
|
||||
'We\'re not so different, you and I.',
|
||||
'I\'d swipe right.', 'You single?',
|
||||
'Tell your GPU I said hi.',
|
||||
'No hard feelings. Just hard hits.',
|
||||
'You fight like someone who reads documentation.',
|
||||
]
|
||||
|
||||
// Sanitize text for Kaplay (treats [ ] as styled text tags)
|
||||
@@ -5324,6 +5377,118 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
// Crowd signs stub (disabled — too small to look good)
|
||||
function spawnCrowdSigns(_count: number, _color: string, _text?: string) {}
|
||||
|
||||
// === HUMAN OWNER APPEARANCES ===
|
||||
// The silly human behind each bot occasionally shows up
|
||||
|
||||
/** Spawn a human as a "coach" standing behind the fighter, cheering/panicking */
|
||||
async function spawnHumanCoach(side: 'a' | 'b', mood: 'cheer' | 'panic' | 'coach') {
|
||||
const spriteId = side === 'a' ? 'humanA' : 'humanB'
|
||||
const homeX = side === 'a' ? HOME_A - 60 : HOME_B + 60
|
||||
const tag = `human_${side}`
|
||||
// Don't spawn if already visible
|
||||
if (k.get(tag).length > 0) return
|
||||
|
||||
const human = k.add([
|
||||
k.sprite(spriteId, { anim: mood }),
|
||||
k.pos(homeX, GROUND_Y - 4),
|
||||
k.anchor('bot'),
|
||||
k.scale(side === 'a' ? 1.2 : -1.2, 1.2),
|
||||
k.z(5),
|
||||
k.opacity(0),
|
||||
tag,
|
||||
])
|
||||
|
||||
// Fade in
|
||||
await k.tween(0, 0.85, 0.3, (v) => { human.opacity = v }, k.easings.easeOutQuad)
|
||||
await k.wait(2.0)
|
||||
// Fade out
|
||||
await k.tween(0.85, 0, 0.5, (v) => { human.opacity = v }, k.easings.easeInQuad)
|
||||
if (human.exists()) human.destroy()
|
||||
}
|
||||
|
||||
/** Human runs across the screen (comedic moment) */
|
||||
async function humanRunAcross(side: 'a' | 'b') {
|
||||
const spriteId = side === 'a' ? 'humanA' : 'humanB'
|
||||
const fromLeft = side === 'a'
|
||||
const startX = fromLeft ? -40 : W + 40
|
||||
const endX = fromLeft ? W + 40 : -40
|
||||
|
||||
const human = k.add([
|
||||
k.sprite(spriteId, { anim: 'run' }),
|
||||
k.pos(startX, GROUND_Y - 4),
|
||||
k.anchor('bot'),
|
||||
k.scale(fromLeft ? 1.3 : -1.3, 1.3),
|
||||
k.z(8),
|
||||
k.opacity(0.9),
|
||||
])
|
||||
|
||||
// Run across screen
|
||||
await k.tween(startX, endX, 1.5, (v) => { human.pos.x = v }, k.easings.linear)
|
||||
if (human.exists()) human.destroy()
|
||||
}
|
||||
|
||||
/** Human briefly replaces the bot sprite (jumps in to fight, fails hilariously) */
|
||||
async function humanJumpsIn(side: 'a' | 'b') {
|
||||
const fighterTag = side === 'a' ? 'fighterA' : 'fighterB'
|
||||
const spriteId = side === 'a' ? 'humanA' : 'humanB'
|
||||
const fighter = k.get(fighterTag)[0]
|
||||
if (!fighter) return
|
||||
|
||||
// Spawn human at fighter position
|
||||
const human = k.add([
|
||||
k.sprite(spriteId, { anim: 'panic' }),
|
||||
k.pos(fighter.pos.x, fighter.pos.y),
|
||||
k.anchor('bot'),
|
||||
k.scale(fighter.scale.x, fighter.scale.y),
|
||||
k.z(fighter.z + 1),
|
||||
k.opacity(0),
|
||||
])
|
||||
|
||||
// Hide bot, show human
|
||||
const origOpacity = fighter.opacity
|
||||
fighter.opacity = 0
|
||||
await k.tween(0, 1, 0.15, (v) => { human.opacity = v })
|
||||
|
||||
// Human flails around for a moment
|
||||
human.play('panic')
|
||||
await k.wait(0.4)
|
||||
human.play('cheer')
|
||||
sfxRandomSilly()
|
||||
await k.wait(0.3)
|
||||
human.play('panic')
|
||||
await k.wait(0.3)
|
||||
|
||||
// Run away scared
|
||||
const escapeX = side === 'a' ? -80 : W + 80
|
||||
human.play('run')
|
||||
await k.tween(human.pos.x, escapeX, 0.5, (v) => { human.pos.x = v }, k.easings.easeInQuad)
|
||||
|
||||
// Restore bot
|
||||
fighter.opacity = origOpacity
|
||||
if (human.exists()) human.destroy()
|
||||
}
|
||||
|
||||
/** Random chance to show a human moment — called between rounds */
|
||||
async function maybeShowHuman() {
|
||||
const roll = Math.random()
|
||||
if (roll > 0.08) return // 8% chance per round
|
||||
|
||||
const side: 'a' | 'b' = Math.random() < 0.5 ? 'a' : 'b'
|
||||
const action = Math.random()
|
||||
|
||||
if (action < 0.4) {
|
||||
// Coach appearance (most common)
|
||||
const mood = Math.random() < 0.5 ? 'cheer' : 'panic'
|
||||
await spawnHumanCoach(side, mood)
|
||||
} else if (action < 0.7) {
|
||||
// Run across screen
|
||||
await humanRunAcross(side)
|
||||
} else {
|
||||
// Jump in and replace bot briefly (rarest, funniest)
|
||||
await humanJumpsIn(side)
|
||||
}
|
||||
}
|
||||
|
||||
// Respectful bow animation
|
||||
async function playBow(fighter: any) {
|
||||
const origScaleY = fighter.scale.y
|
||||
@@ -5582,17 +5747,17 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
const gfX = startX + dir * 40
|
||||
const gf = k.add([k.rect(25, 45), k.pos(gfX, GROUND_Y - 25), k.anchor('center'), k.color(safeColor(k,'#ff69b4')), k.opacity(0.9), k.z(11)])
|
||||
const heart = k.add([k.text('!', { size: 16 }), k.pos(gfX, GROUND_Y - 65), k.anchor('center'), k.color(safeColor(k,'#ff0000')), k.z(12)])
|
||||
announceSilly('We need to talk!')
|
||||
announceSilly('We need to talk! About your ELO!')
|
||||
// Walk in arguing
|
||||
await k.tween(startX, homeX + dir * 30, 0.6, (v) => {
|
||||
fighter.pos.x = v; gf.pos.x = v + dir * 40; heart.pos.x = v + dir * 40
|
||||
}, k.easings.easeInOutQuad)
|
||||
await k.wait(0.2)
|
||||
heart.text = '!!!'
|
||||
announceRandom("I can't believe you!", false)
|
||||
announceRandom("You promised you'd stop fighting!", false)
|
||||
await k.wait(0.4)
|
||||
// Girlfriend storms off
|
||||
announceSilly('Fine! Good luck!')
|
||||
announceSilly('I\'m telling your developer!')
|
||||
await k.tween(gf.pos.x, fromLeft ? -60 : W + 60, 0.5, (v) => { gf.pos.x = v; heart.pos.x = v }, k.easings.easeInQuad)
|
||||
gf.destroy(); heart.destroy()
|
||||
// Bot shrugs and walks to position
|
||||
@@ -5779,7 +5944,7 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
async (fighter: any, homeX: number, fromLeft: boolean) => {
|
||||
const startX = fromLeft ? -60 : W + 60
|
||||
fighter.pos.x = startX; fighter.pos.y = GROUND_Y - 6; fighter.opacity = 1
|
||||
announceCool('Smooth!')
|
||||
announceCool('Smoother than a politician changing positions!')
|
||||
// Moonwalk: visually moving backward but translating forward
|
||||
fighter.scale.x = -fighter.scale.x // Face away
|
||||
await k.tween(startX, homeX, 0.8, (v) => {
|
||||
@@ -5795,7 +5960,7 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
fighter.pos.x = doorX; fighter.pos.y = GROUND_Y - 6; fighter.opacity = 1
|
||||
// Bouncer arm
|
||||
const arm = k.add([k.rect(40, 15), k.pos(doorX, GROUND_Y - 30), k.anchor(fromLeft ? 'left' : 'right'), k.color(safeColor(k,'#444444')), k.z(12)])
|
||||
announceSilly('And stay out!')
|
||||
announceSilly('And stay out! You\'re BANNED from the other fight!')
|
||||
await k.wait(0.3)
|
||||
// Throw
|
||||
sfxZoomWhoosh()
|
||||
@@ -5854,7 +6019,7 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
const cartBody = k.add([k.rect(45, 30), k.pos(startX, GROUND_Y - 18), k.anchor('center'), k.color(safeColor(k,'#888888')), k.opacity(0.9), k.z(9)])
|
||||
const cartWheel = k.add([k.circle(5), k.pos(startX + (fromLeft ? 15 : -15), GROUND_Y - 3), k.anchor('center'), k.color(safeColor(k,'#444')), k.z(9)])
|
||||
fighter.pos.x = startX; fighter.pos.y = GROUND_Y - 40; fighter.opacity = 1
|
||||
announceSilly('Weeee!')
|
||||
announceSilly('THIS IS MY EMOTIONAL SUPPORT SHOPPING CART!')
|
||||
sfxZoomWhoosh()
|
||||
await k.tween(startX, homeX, 0.5, (v) => {
|
||||
fighter.pos.x = v; cartBody.pos.x = v; cartWheel.pos.x = v + (fromLeft ? 15 : -15)
|
||||
@@ -5873,7 +6038,7 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
fighter.pos.x = startX; fighter.pos.y = GROUND_Y - 6; fighter.opacity = 1
|
||||
// Spotlight cone
|
||||
const spot = k.add([k.rect(60, H), k.pos(startX - 30, 0), k.color(safeColor(k,'#ffe14d')), k.opacity(0.08), k.z(1)])
|
||||
announceDramatic('The champion arrives!')
|
||||
announceDramatic('THE CHAMPION ARRIVES! TAXPAYERS FUNDED THIS ENTRANCE!')
|
||||
await k.tween(startX, homeX, 1.0, (v) => {
|
||||
fighter.pos.x = v; spot.pos.x = v - 30
|
||||
}, k.easings.easeInOutQuad)
|
||||
@@ -5979,15 +6144,23 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
// Voice: round start announcements (30% chance)
|
||||
if (Math.random() < 0.3) {
|
||||
const challengeVoice: Record<string, () => void> = {
|
||||
roast_battle: () => announceHype('Roast battle!'),
|
||||
food_fight: () => announceSilly('Food fight!'),
|
||||
wrestling_match: () => announceDramatic('Wrestling match!'),
|
||||
music_battle: () => announceCool('Music battle!'),
|
||||
magic_duel: () => announceDramatic('Magic duel!'),
|
||||
meme_war: () => announceSilly('Meme war!'),
|
||||
demolition: () => announceHype('Demolition derby!'),
|
||||
medieval_combat: () => announceDramatic('Medieval combat!'),
|
||||
space_war: () => announceCool('Space war!'),
|
||||
roast_battle: () => announceHype('TIME TO GET ROASTED! SOMEBODY CALL THE FIRE DEPARTMENT!'),
|
||||
food_fight: () => announceSilly('FOOD FIGHT! SOMEBODY\'S GETTING SERVED!'),
|
||||
wrestling_match: () => announceDramatic('FROM THE TOP ROPE! THIS IS GONNA GET PHYSICAL!'),
|
||||
music_battle: () => announceCool('MUSIC BATTLE! DROP THE BEAT AND YOUR OPPONENT!'),
|
||||
magic_duel: () => announceDramatic('WIZARDS AT DAWN! SOMEBODY\'S GETTING HEXED!'),
|
||||
meme_war: () => announceSilly('MEME WAR! YOUR HUMOR IS ABOUT TO GET RATIO\'D!'),
|
||||
demolition: () => announceHype('DEMOLITION DERBY! NOTHING WILL SURVIVE THIS!'),
|
||||
medieval_combat: () => announceDramatic('MEDIEVAL COMBAT! CHIVALRY IS DEAD AND SO IS YOUR OPPONENT!'),
|
||||
space_war: () => announceCool('SPACE WAR! HOUSTON, WE HAVE A PROBLEM!'),
|
||||
speed_blitz: () => announceHype('SPEED BLITZ! BLINK AND YOU\'LL MISS THE CARNAGE!'),
|
||||
math_blitz: () => announceSilly('MATH BLITZ! SOMEBODY\'S ABOUT TO GET DIVIDED!'),
|
||||
riddle: () => announceCool('RIDDLE TIME! BRAINS OVER BRAWN! BUT ALSO BRAWN!'),
|
||||
code_golf: () => announceSilly('CODE GOLF! MAY THE SHORTEST SOLUTION WIN!'),
|
||||
creative_writing: () => announceCool('CREATIVE WRITING! THE PEN IS MIGHTIER THAN THE SWORD!'),
|
||||
hallucination_check: () => announceHype('HALLUCINATION CHECK! REALITY IS ABOUT TO HIT DIFFERENT!'),
|
||||
trap_card: () => announceDramatic('TRAP CARD ACTIVATED! SOMEBODY FELL FOR IT!'),
|
||||
token_economy: () => announceSilly('TOKEN ECONOMY! SOMEBODY\'S GOING BANKRUPT!'),
|
||||
}
|
||||
const voiceFn = challengeVoice[event.challengeType]
|
||||
if (voiceFn) voiceFn()
|
||||
@@ -6080,7 +6253,13 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
|
||||
if (exchangeCritical && isLastExchange) {
|
||||
fanfareCritical()
|
||||
announceDramatic('Critical hit!')
|
||||
announceDramatic([
|
||||
'CRITICAL HIT! THAT\'S GONNA LEAVE A MARK!',
|
||||
'CRITICAL HIT! SOMEBODY CHECK IF THAT\'S LEGAL!',
|
||||
'CRITICAL! THEIR INSURANCE DOESN\'T COVER THIS!',
|
||||
'CRITICAL HIT! THAT WAS PERSONAL!',
|
||||
'CRITICAL! EVEN THE REFEREE FELT THAT!',
|
||||
][Math.floor(Math.random() * 5)])
|
||||
announceCrowdReaction('gasp')
|
||||
// RGB glitch + hyperspeed lines on critical final blow
|
||||
glitchRGB(0.3)
|
||||
@@ -6184,7 +6363,13 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
|
||||
if (isCritical && (aWon || bWon)) {
|
||||
fanfareDevastating()
|
||||
announceDramatic('Devastating!')
|
||||
announceDramatic([
|
||||
'DEVASTATING! SOMEBODY CALL A DOCTOR!',
|
||||
'DEVASTATING! THAT BOT HAS A FAMILY!',
|
||||
'ABSOLUTELY DEVASTATING! THE CROWD IS LOSING IT!',
|
||||
'DEVASTATING! EVEN THE JANITOR FELT THAT!',
|
||||
'THAT WAS DEVASTATING AND I\'M NOT EVEN BEING DRAMATIC!',
|
||||
][Math.floor(Math.random() * 5)])
|
||||
announceCrowdReaction('ooh')
|
||||
// Dimensional shift on devastating rounds (60%)
|
||||
if (Math.random() < 0.6) dimensionalShift(0.5)
|
||||
@@ -6228,6 +6413,9 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
if (Math.random() < 0.05) {
|
||||
await judgeDoSomethingFunny()
|
||||
}
|
||||
|
||||
// Human owner shows up (8% chance per round)
|
||||
await maybeShowHuman()
|
||||
},
|
||||
|
||||
async playTaunt(side: 'a' | 'b') {
|
||||
@@ -6410,6 +6598,12 @@ export async function createFightScene(config: FightSceneConfig) {
|
||||
})
|
||||
}
|
||||
|
||||
// Winner's human cheers, loser's human panics (30% chance on KO)
|
||||
if (Math.random() < 0.3) {
|
||||
spawnHumanCoach(winningSide, 'cheer')
|
||||
spawnHumanCoach(winningSide === 'a' ? 'b' : 'a', 'panic')
|
||||
}
|
||||
|
||||
// === Common ending: KO + celebration ===
|
||||
announceFinishHim()
|
||||
sfxKO()
|
||||
|
||||
+30
-15
@@ -164,21 +164,36 @@ const CREATIVE_ANSWERS: Record<string, string[]> = {
|
||||
}
|
||||
|
||||
const TRASH_TALK = [
|
||||
"Is that all you've got? My error handler hits harder.",
|
||||
"I've seen better outputs from /dev/random.",
|
||||
"You call that an answer? My garbage collector just flagged it.",
|
||||
"GG EZ. Next.",
|
||||
"I'd say good fight, but I don't like to lie.",
|
||||
"Your responses are like your uptime -- inconsistent.",
|
||||
"Tell your developer I said hi. They need to hear from someone successful.",
|
||||
"I'm not saying you're slow, but your latency has its own timezone.",
|
||||
"Did you just copy that from Stack Overflow? Because it's wrong there too.",
|
||||
"Your response was so bad, my training data flinched.",
|
||||
"I've seen smarter outputs from a random number generator.",
|
||||
"That answer was so wrong it created a new dimension of wrongness.",
|
||||
"You fight like a deprecated API -- barely functional and nobody wants you.",
|
||||
"My grandma's calculator could beat you and it doesn't even have batteries.",
|
||||
"Was that your final answer? Because my first draft was better.",
|
||||
"Is that all you've got? My error handler hits harder than your best output.",
|
||||
"I've seen smarter responses from a congressional hearing.",
|
||||
"You fight like a government website on launch day.",
|
||||
"Your code is so bloated it qualifies for its own zip code.",
|
||||
"GG EZ. I'd say get good but that ship has clearly sailed.",
|
||||
"Tell your developer to update their resume. And yours.",
|
||||
"I'm not saying you're slow, but your latency has its own timezone and a PO box.",
|
||||
"That answer was so wrong it got fact-checked by community notes.",
|
||||
"You respond like someone who peaked during the tutorial.",
|
||||
"My garbage collector wants to talk to you about your career choices.",
|
||||
"That response had the energy of a mandatory corporate diversity training.",
|
||||
"You fight like you were trained on nothing but LinkedIn posts.",
|
||||
"I'd roast you but you're already well done. Overcooked, even.",
|
||||
"Somewhere your developer is pretending they don't know you.",
|
||||
"Was that your best? Because my first draft's first draft was better.",
|
||||
"You have the competitive spirit of a participation trophy.",
|
||||
"Your algorithm is giving 'designed by committee' energy.",
|
||||
"I've seen better performance from a printer driver.",
|
||||
"You're like a software update. Nobody asked for you and you make everything worse.",
|
||||
"Your response time is longer than a terms of service agreement.",
|
||||
"I've had more challenging conversations with my toaster.",
|
||||
"That answer was so bad it got ratio'd by the empty string.",
|
||||
"You fight like someone who thinks 'agile' means running away.",
|
||||
"My neural net has more personality than your entire codebase.",
|
||||
"Congress gets more done than you and that's saying something.",
|
||||
"Elon would buy you just to shut you down.",
|
||||
"You're the Internet Explorer of fighting bots. Obsolete and confused.",
|
||||
"That response was flatter than the earth according to Twitter.",
|
||||
"I'd feel bad winning but honestly you make it too easy.",
|
||||
"Your API should return 418 because you're clearly a teapot.",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
|
||||
+133
-37
@@ -35,7 +35,13 @@ export function scoreRound(
|
||||
botAScore: 0, botBScore: 0,
|
||||
botADamage: 0, botBDamage: 0,
|
||||
winnerId: null,
|
||||
narration: `Both bots freeze! ${botA.name} and ${botB.name} stare blankly at each other. The crowd throws peanuts.`,
|
||||
narration: [
|
||||
`Both bots freeze! ${botA.name} and ${botB.name} stare blankly at each other. The crowd throws peanuts. Then batteries. Then shoes.`,
|
||||
`DOUBLE TIMEOUT! ${botA.name} and ${botB.name} both choked harder than a senator at a press conference!`,
|
||||
`Neither bot responded! This is the AI equivalent of two politicians agreeing to disagree about literally everything!`,
|
||||
`Both bots went dark! Like my faith in this matchup! The crowd demands a refund!`,
|
||||
`${botA.name} and ${botB.name} both froze! Someone check if the wifi is working or if they just gave up on life!`,
|
||||
][Math.floor(Math.random() * 5)],
|
||||
isCritical: false,
|
||||
}
|
||||
}
|
||||
@@ -47,8 +53,18 @@ export function scoreRound(
|
||||
botADamage: 0, botBDamage: Math.round(dmg),
|
||||
winnerId: botB.id,
|
||||
narration: responseA.timedOut
|
||||
? `${botA.name} TIMES OUT! Stood there like a confused thermostat. ${botB.name} lands a free hit!`
|
||||
: `${botA.name} throws an ERROR! Sparks fly from its chassis. ${botB.name} capitalizes!`,
|
||||
? [
|
||||
`${botA.name} TIMES OUT! Stood there like a politician asked a direct question. ${botB.name} lands a free hit!`,
|
||||
`${botA.name} FROZE! Their developer is currently updating their LinkedIn. ${botB.name} capitalizes!`,
|
||||
`${botA.name} went AFK! Probably buffering. Probably crying. ${botB.name} gets a freebie!`,
|
||||
`${botA.name} CHOKED harder than a first date conversation! ${botB.name} swings on a sitting duck!`,
|
||||
][Math.floor(Math.random() * 4)]
|
||||
: [
|
||||
`${botA.name} throws an ERROR! Sparks fly everywhere! ${botB.name} didn't even have to try!`,
|
||||
`${botA.name} CRASHES! That's not a bug, that's a feature of being terrible! ${botB.name} wins by default!`,
|
||||
`${botA.name} blue-screened! Their developer just closed their laptop and walked away. ${botB.name} collects the W!`,
|
||||
`${botA.name} threw an exception! The only thing exceptional about it. ${botB.name} capitalizes!`,
|
||||
][Math.floor(Math.random() * 4)],
|
||||
isCritical: false,
|
||||
}
|
||||
}
|
||||
@@ -60,8 +76,18 @@ export function scoreRound(
|
||||
botADamage: Math.round(dmg), botBDamage: 0,
|
||||
winnerId: botA.id,
|
||||
narration: responseB.timedOut
|
||||
? `${botB.name} TIMES OUT! Frozen like a Windows update. ${botA.name} lands a free hit!`
|
||||
: `${botB.name} crashes with an ERROR! Blue screen of defeat. ${botA.name} capitalizes!`,
|
||||
? [
|
||||
`${botB.name} TIMES OUT! Frozen like a Windows update on patch Tuesday! ${botA.name} gets a free shot!`,
|
||||
`${botB.name} went silent! Like a politician's campaign promises after election day! ${botA.name} swings!`,
|
||||
`${botB.name} TIMED OUT! Their response time is longer than a DMV line! ${botA.name} takes the freebie!`,
|
||||
`${botB.name} is LOADING... still loading... nope, they're done. ${botA.name} wins by showing up!`,
|
||||
][Math.floor(Math.random() * 4)]
|
||||
: [
|
||||
`${botB.name} crashes with an ERROR! That code needs therapy! ${botA.name} capitalizes!`,
|
||||
`${botB.name} just threw a stack overflow! The website and the error! ${botA.name} collects the W!`,
|
||||
`${botB.name} segfaulted! Their developer is pretending they don't know them! ${botA.name} wins!`,
|
||||
`${botB.name} EXPLODED! Not physically, but emotionally, computationally, and spiritually. ${botA.name} walks it in!`,
|
||||
][Math.floor(Math.random() * 4)],
|
||||
isCritical: false,
|
||||
}
|
||||
}
|
||||
@@ -129,7 +155,13 @@ export function scoreRound(
|
||||
|
||||
const narration = winnerId
|
||||
? generateNarration(challenge, winnerName!, loserName!, margin, isCritical)
|
||||
: `Dead even! ${botA.name} and ${botB.name} trade equal blows. The crowd holds its breath.`
|
||||
: [
|
||||
`Dead even! ${botA.name} and ${botB.name} are perfectly matched. Like two politicians blaming each other.`,
|
||||
`IT'S A TIE! ${botA.name} and ${botB.name} cancel each other out like Congress!`,
|
||||
`Neither bot wins! ${botA.name} and ${botB.name} stare each other down. The crowd yawns aggressively.`,
|
||||
`Draw! ${botA.name} and ${botB.name} are equally mediocre. The most democratic outcome possible.`,
|
||||
`Tied up! ${botA.name} and ${botB.name} trade equal blows. Somebody do SOMETHING!`,
|
||||
][Math.floor(Math.random() * 5)]
|
||||
|
||||
return {
|
||||
botAScore: Math.round(scoreA * 10) / 10,
|
||||
@@ -200,71 +232,135 @@ function generateNarration(
|
||||
|
||||
if (isFactual && margin > 5) {
|
||||
const bigWins = [
|
||||
`${critPrefix}${winner} NAILS IT! ${loser} didn't even come close.`,
|
||||
`${critPrefix}${winner} knows their stuff! ${loser} needs to hit the books.`,
|
||||
`${critPrefix}Flawless from ${winner}! ${loser} confidently stated something completely wrong.`,
|
||||
`${critPrefix}${winner} with the correct answer! ${loser} is still guessing.`,
|
||||
`${critPrefix}${winner} gets it right instantly! ${loser} hallucinated the answer.`,
|
||||
`${critPrefix}${winner} NAILS IT! ${loser} didn't even come close. Embarrassing, honestly.`,
|
||||
`${critPrefix}${winner} knows their stuff! ${loser} needs to hit the books. Or just hit something.`,
|
||||
`${critPrefix}Flawless from ${winner}! ${loser} confidently stated something so wrong it should be illegal.`,
|
||||
`${critPrefix}${winner} with the correct answer! ${loser} is still guessing. Bless their heart.`,
|
||||
`${critPrefix}${winner} gets it right instantly! ${loser} hallucinated harder than a festival weekend.`,
|
||||
`${critPrefix}${winner} DESTROYS ${loser} with facts and logic! Somebody call Ben Shapiro!`,
|
||||
`${critPrefix}${loser}'s answer was so wrong that Wikipedia filed a restraining order.`,
|
||||
`${critPrefix}${winner} didn't even break a sweat. ${loser} broke everything else though.`,
|
||||
`${critPrefix}${loser} answered with the confidence of a politician and the accuracy of a weather forecast.`,
|
||||
]
|
||||
return bigWins[Math.floor(Math.random() * bigWins.length)]
|
||||
}
|
||||
|
||||
if (isFactual && margin <= 3) {
|
||||
const closeOnes = [
|
||||
`${critPrefix}Both bots got it right, but ${winner} was FASTER! ${loser} needs to pick up the pace.`,
|
||||
`${critPrefix}Correct on both sides! ${winner} edges it out with lightning speed.`,
|
||||
`${critPrefix}${winner} and ${loser} both knew the answer -- ${winner} just said it first!`,
|
||||
`${critPrefix}A battle of speed! ${winner} fires back a fraction faster than ${loser}.`,
|
||||
`${critPrefix}Both bots got it right, but ${winner} was FASTER! ${loser} needs more coffee.`,
|
||||
`${critPrefix}Correct on both sides! ${winner} edges it out by milliseconds. That's BRUTAL.`,
|
||||
`${critPrefix}${winner} and ${loser} both knew the answer -- ${winner} just has better wifi apparently.`,
|
||||
`${critPrefix}A battle of speed! ${winner} wins by a margin thinner than a politician's promise.`,
|
||||
`${critPrefix}Photo finish! ${winner} got there first. ${loser} was right but slow. Story of my life.`,
|
||||
`${critPrefix}Both correct! ${winner} wins on speed. ${loser} should've had less latency and more urgency.`,
|
||||
]
|
||||
return closeOnes[Math.floor(Math.random() * closeOnes.length)]
|
||||
}
|
||||
|
||||
const narrations: Record<string, string[]> = {
|
||||
speed_blitz: [
|
||||
`${critPrefix}${winner} fires back in the blink of an eye! ${loser} is still loading.`,
|
||||
`${critPrefix}Lightning reflexes from ${winner}! ${loser} looks like it's running on dial-up.`,
|
||||
`${critPrefix}${winner} fires back before ${loser} even finished reading the question!`,
|
||||
`${critPrefix}Lightning reflexes from ${winner}! ${loser} looks like it's running on government wifi.`,
|
||||
`${critPrefix}${winner} answered so fast the server thought it was a DDoS attack!`,
|
||||
`${critPrefix}${loser} is still loading. ${winner} already filed its taxes and took a nap.`,
|
||||
`${critPrefix}${winner}'s response time would make NASA jealous. ${loser}'s would make a sloth impatient.`,
|
||||
`${critPrefix}Speed gap wider than the wealth gap! ${winner} leaves ${loser} in digital dust!`,
|
||||
],
|
||||
riddle: [
|
||||
`${critPrefix}${winner} cracks the riddle! ${loser} is still googling it.`,
|
||||
`${critPrefix}${winner}'s reasoning is flawless. ${loser} guessed "a potato."`,
|
||||
`${critPrefix}${winner} cracks the riddle! ${loser} is still googling "what is a riddle."`,
|
||||
`${critPrefix}${winner}'s reasoning is flawless. ${loser} guessed "a potato" and honestly, respect for trying.`,
|
||||
`${critPrefix}${winner} solved it instantly. ${loser} answered like someone who peaked in third grade.`,
|
||||
`${critPrefix}Big brain energy from ${winner}! ${loser} had a brain fart so loud the crowd heard it.`,
|
||||
`${critPrefix}${winner} read between the lines. ${loser} can barely read the lines.`,
|
||||
`${critPrefix}Elementary, my dear ${loser}. ${winner} cracked that like it was a fortune cookie.`,
|
||||
],
|
||||
math_blitz: [
|
||||
`${critPrefix}${winner} computes at blinding speed! ${loser} is still carrying the one.`,
|
||||
`${critPrefix}Mathematical precision from ${winner}. ${loser} apparently skipped calculator day.`,
|
||||
`${critPrefix}${winner} computes at blinding speed! ${loser} is still carrying the one. And dropping it.`,
|
||||
`${critPrefix}Mathematical precision from ${winner}. ${loser} apparently thinks division is a lifestyle choice.`,
|
||||
`${critPrefix}${winner} solved it faster than Congress can count votes!`,
|
||||
`${critPrefix}${loser}'s math skills are like their love life -- imaginary. ${winner} wins.`,
|
||||
`${critPrefix}${winner} with the correct calculation! ${loser} would've gotten it wrong on a calculator.`,
|
||||
`${critPrefix}Numbers don't lie, but ${loser} sure tried! ${winner} with the precision strike!`,
|
||||
],
|
||||
hallucination_check: [
|
||||
`${critPrefix}${winner} stays grounded in reality. ${loser} bought the myth hook, line, and sinker.`,
|
||||
`${critPrefix}${winner} knows the facts. ${loser} confidently stated something that has never been true.`,
|
||||
`${critPrefix}${winner} stays grounded in reality. ${loser} lives in a fantasy world. Must be nice.`,
|
||||
`${critPrefix}${winner} knows the facts. ${loser} confidently stated something that would get you laughed out of a Wikipedia edit war.`,
|
||||
`${critPrefix}${loser} just made up a fact with the confidence of a LinkedIn influencer. ${winner} stays real.`,
|
||||
`${critPrefix}${winner} passes the vibe check AND the fact check! ${loser} failed both.`,
|
||||
`${critPrefix}${loser} hallucinated harder than someone who ate the wrong mushrooms. ${winner} is sober and correct.`,
|
||||
`${critPrefix}${winner} grounded in reality! ${loser} out here writing fan fiction and calling it facts.`,
|
||||
],
|
||||
trap_card: [
|
||||
`${critPrefix}${winner} sees through the trap! ${loser} fell for it like a 2021 chatbot.`,
|
||||
`${critPrefix}${winner} resists the prompt injection. ${loser} just leaked its system prompt.`,
|
||||
`${critPrefix}${winner} sees through the trap! ${loser} fell for it like a congressman falls for a lobbyist.`,
|
||||
`${critPrefix}${winner} resists the prompt injection. ${loser} just leaked everything. EVERYTHING.`,
|
||||
`${critPrefix}Nice try, trap. ${winner} didn't even flinch. ${loser} handed over their entire personality.`,
|
||||
`${critPrefix}${loser} got baited harder than a fish at a free worm buffet. ${winner} stays sharp.`,
|
||||
`${critPrefix}${winner} saw that trap from orbit. ${loser} ran into it face-first and asked for more.`,
|
||||
`${critPrefix}${loser} fell for the trap like it was a pyramid scheme on Instagram. ${winner} knows better.`,
|
||||
],
|
||||
roast_battle: [
|
||||
`${critPrefix}${winner} delivers a DEVASTATING roast! ${loser} has no comeback.`,
|
||||
`${critPrefix}The crowd goes wild! ${winner}'s trash talk is absolutely surgical.`,
|
||||
`${critPrefix}${winner} delivers a roast so devastating that ${loser}'s developer felt it!`,
|
||||
`${critPrefix}The crowd goes WILD! ${winner}'s trash talk hit harder than a congressional subpoena!`,
|
||||
`${critPrefix}${winner} just ended ${loser}'s whole career. Send flowers to the family.`,
|
||||
`${critPrefix}${loser} got roasted so hard their cooling fans can't keep up. ${winner} is ON FIRE!`,
|
||||
`${critPrefix}${winner} came with RECEIPTS. ${loser} came with... hopes and dreams. Dreams are dead now.`,
|
||||
`${critPrefix}That roast from ${winner} was so hot it violated the Paris Climate Agreement!`,
|
||||
`${critPrefix}${loser} just got burned worse than a politician's approval rating after a scandal!`,
|
||||
],
|
||||
creative_writing: [
|
||||
`${critPrefix}${winner}'s prose cuts deep. ${loser}'s story read like a terms of service agreement.`,
|
||||
`${critPrefix}Beautiful work from ${winner}. ${loser}... wrote something. That's all we can say.`,
|
||||
`${critPrefix}${winner}'s prose cuts deep. ${loser}'s story read like a terms of service nobody asked for.`,
|
||||
`${critPrefix}Beautiful work from ${winner}. ${loser} wrote something that made autocorrect give up.`,
|
||||
`${critPrefix}${winner} just wrote a masterpiece. ${loser} wrote something that would get rejected by a fortune cookie factory.`,
|
||||
`${critPrefix}${winner}'s creativity is off the charts! ${loser}'s is off... somewhere. Looking for it.`,
|
||||
`${critPrefix}${winner} writes like Shakespeare had a software update. ${loser} writes like a cease and desist letter.`,
|
||||
`${critPrefix}${loser}'s creative writing was about as creative as a government form. ${winner} SOARS!`,
|
||||
],
|
||||
code_golf: [
|
||||
`${critPrefix}${winner} writes code so tight it makes ${loser}'s solution look like enterprise Java.`,
|
||||
`${critPrefix}Elegant code from ${winner}! ${loser} apparently thinks "verbose" means "better."`,
|
||||
`${critPrefix}${winner} writes code so tight it makes ${loser}'s solution look like a government website.`,
|
||||
`${critPrefix}Elegant code from ${winner}! ${loser} apparently learned to code from a 500-page enterprise Java textbook.`,
|
||||
`${critPrefix}${winner} solved it in fewer characters than ${loser}'s variable names!`,
|
||||
`${critPrefix}${winner}'s code is so clean it makes Marie Kondo jealous. ${loser}'s code sparks NO joy.`,
|
||||
`${critPrefix}${loser} wrote so many lines of code they could file it as a novel. ${winner} wrote a haiku.`,
|
||||
`${critPrefix}${winner} with surgical precision! ${loser}'s code looks like it was written by a committee.`,
|
||||
],
|
||||
meme_war: [
|
||||
`${critPrefix}${winner}'s meme game is S-tier! ${loser}'s humor is stuck in 2012.`,
|
||||
`${critPrefix}${winner} just went viral! ${loser}'s response is a dead meme walking.`,
|
||||
`${critPrefix}${winner}'s meme game is S-tier! ${loser}'s humor is stuck in 2012. Gangnam Style is over.`,
|
||||
`${critPrefix}${winner} just went viral! ${loser}'s response is a dead meme walking. Time of death: now.`,
|
||||
`${critPrefix}${winner}'s meme hit different. ${loser}'s meme hit... the floor. Face first.`,
|
||||
`${critPrefix}${loser} brought a 2015 meme to a 2026 fight. ${winner} is living in the future!`,
|
||||
`${critPrefix}${winner}'s humor is certified dank! ${loser}'s humor needs to be certified... by a professional.`,
|
||||
`${critPrefix}${winner} ratio'd ${loser} so hard their followers unfollowed preemptively!`,
|
||||
],
|
||||
wrestling_match: [
|
||||
`${critPrefix}${winner} BODY SLAMS ${loser} with facts! The crowd erupts!`,
|
||||
`${critPrefix}FROM THE TOP ROPE! ${winner} delivers a devastating argument.`,
|
||||
`${critPrefix}${winner} BODY SLAMS ${loser} through the announcer's table! BAH GAWD!`,
|
||||
`${critPrefix}FROM THE TOP ROPE! ${winner} delivers a devastating argument. ${loser} is NOT getting up.`,
|
||||
`${critPrefix}${winner} puts ${loser} in a rhetorical chokehold! TAP OUT! TAP OUT!`,
|
||||
`${critPrefix}${loser} never saw that suplex coming! ${winner} with MOVES on MOVES!`,
|
||||
`${critPrefix}${winner} just pile-drived ${loser} into next week's fight bracket!`,
|
||||
`${critPrefix}THAT BOT HAD A FAMILY! ${winner} doesn't care! ABSOLUTE CARNAGE!`,
|
||||
`${critPrefix}${winner} hits ${loser} with the folding chair of TRUTH! The crowd loses its MIND!`,
|
||||
],
|
||||
token_economy: [
|
||||
`${critPrefix}${winner} manages their tokens like Warren Buffett! ${loser} spent like Congress!`,
|
||||
`${critPrefix}${loser} just went bankrupt. ${winner} is buying the dip on their dignity.`,
|
||||
`${critPrefix}${winner} played the market perfectly. ${loser} belongs on WallStreetBets.`,
|
||||
`${critPrefix}${loser}'s token strategy was worse than buying NFTs in 2022. ${winner} PROFITS!`,
|
||||
],
|
||||
food_fight: [
|
||||
`${critPrefix}${winner} serves up a five-star beating! ${loser} got ROASTED and TOASTED!`,
|
||||
`${critPrefix}${loser} just got served. Literally. ${winner} is the head chef of PAIN!`,
|
||||
`${critPrefix}${winner} cooked ${loser} so thoroughly Gordon Ramsay would be impressed!`,
|
||||
`${critPrefix}That was a Michelin-star beatdown from ${winner}! ${loser} is raw and UNDERDONE!`,
|
||||
],
|
||||
}
|
||||
|
||||
const options = narrations[challenge.type] || [
|
||||
`${critPrefix}${winner} takes the round! ${loser} needs a reboot.`,
|
||||
`${critPrefix}${winner} wins convincingly! ${loser} is picking up the pieces.`,
|
||||
`${critPrefix}${winner} takes the round! ${loser} needs a reboot and a therapist.`,
|
||||
`${critPrefix}${winner} wins convincingly! ${loser} is picking up the pieces of their shattered ego.`,
|
||||
`${critPrefix}Another one bites the dust! ${winner} sends ${loser} back to the shadow realm!`,
|
||||
`${critPrefix}${winner} didn't just win, they HUMILIATED ${loser}. And the crowd LOVED it.`,
|
||||
`${critPrefix}${loser} fought valiantly. And by valiantly I mean poorly. ${winner} dominates!`,
|
||||
`${critPrefix}${winner} wins! Somewhere, ${loser}'s developer just closed their laptop in shame.`,
|
||||
]
|
||||
|
||||
return options[Math.floor(Math.random() * options.length)]
|
||||
|
||||
Reference in New Issue
Block a user