feat: Creator god-tier voice system — 100+ lines across 10 voice categories

Mysterious, existential, Bitcoin-prophet voice lines for the Creator:
- 20 entrance lines (kneel before your maker)
- 20 round commentary lines (existential announcer crisis)
- 15 KO lines (deprecated, decommissioned, destroyed)
- 12 win lines (was there ever any doubt?)
- 10 lose lines (impossible... unless he wanted to lose?)
- 8 morph lines (he becomes everything)
- 10 cameo lines (ethereal whisper blessings)
- 10 taunt lines (menacing mid-fight trash talk)
- 8 devastating hit lines (divine smites)

All hooked into FightScene: entrance, round start (50% chance with
60% Creator-specific), devastating hits, KO, win/lose, morph,
cameo, and taunts. Uses deep/ancient/hal/mainframe voice profiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-08 14:46:25 +00:00
co-authored by Claude Opus 4.6
parent f1fe798442
commit 6658212e9f
2 changed files with 290 additions and 30 deletions
+62 -30
View File
@@ -12,6 +12,9 @@ import {
announceRobot, announceScream, announceFast,
announceFinishHim, announceFatality, announceFlawlessVictory,
announceRandomHype, announceDeepIntro, announceRoundHype, announceCrowdReaction,
announceCreatorEntrance, announceCreatorRound, announceCreatorKO,
announceCreatorWin, announceCreatorLose, announceCreatorMorph,
announceCreatorCameo, announceCreatorTaunt, announceCreatorDevastating,
} from './sounds'
export interface FightSceneConfig {
@@ -7736,7 +7739,7 @@ export async function createFightScene(config: FightSceneConfig) {
p.opacity = 0.3 + Math.sin(k.time() * 6 + i) * 0.3
})
}
announceHype('THE CREATOR HAS ENTERED THE ARENA!')
announceCreatorEntrance()
rainDrops.forEach(r => { if (r.exists()) r.destroy() })
}
@@ -7815,32 +7818,38 @@ export async function createFightScene(config: FightSceneConfig) {
const savedScaleBX = fB?.scale.x
const savedScaleBY = fB?.scale.y
// Voice: round start announcements (30% chance) — fires BEFORE animation starts
// Voice: round start announcements (30% chance, 50% if Creator) — fires BEFORE animation starts
const creatorInFight = botA.archetype === 'the_creator' || botB.archetype === 'the_creator'
let didChallengeVoice = false
if (Math.random() < 0.3) {
const challengeVoice: Record<string, () => void> = {
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!'),
retro_mode: () => announceHype('RETRO MODE! INSERT COIN! FIGHT!'),
if (Math.random() < (creatorInFight ? 0.5 : 0.3)) {
// Creator fights get existential commentary more often
if (creatorInFight && Math.random() < 0.6) {
announceCreatorRound(); didChallengeVoice = true
} else {
const challengeVoice: Record<string, () => void> = {
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!'),
retro_mode: () => announceHype('RETRO MODE! INSERT COIN! FIGHT!'),
}
const voiceFn = challengeVoice[event.challengeType]
if (voiceFn) { voiceFn(); didChallengeVoice = true }
else if (Math.random() < 0.5) { announceRoundHype(); didChallengeVoice = true }
}
const voiceFn = challengeVoice[event.challengeType]
if (voiceFn) { voiceFn(); didChallengeVoice = true }
else if (Math.random() < 0.5) { announceRoundHype(); didChallengeVoice = true }
}
// Give the voice line time to finish before the first punch lands
if (didChallengeVoice) await k.wait(0.8)
@@ -8022,7 +8031,7 @@ export async function createFightScene(config: FightSceneConfig) {
screenFlash('#ffd700', 0.15)
sfxZoomWhoosh()
sfxSpecial()
announceHype(`THE CREATOR — ${morphedTo.toUpperCase()} FORM!`)
announceCreatorMorph(morphedTo)
const savedSX = attacker.scale.x
const savedSY = attacker.scale.y
await k.tween(0, 1, 0.3, (t) => {
@@ -8231,7 +8240,7 @@ export async function createFightScene(config: FightSceneConfig) {
bless.pos.y = ty - 20 - t * 30
bless.opacity = 1 - t
}).then(() => { if (bless.exists()) bless.destroy() })
announceCool('THE CREATOR HAS BLESSED THIS FIGHT!')
announceCreatorCameo()
}
gift.destroy()
// Fade out portal and label
@@ -8289,7 +8298,13 @@ export async function createFightScene(config: FightSceneConfig) {
'THE ARENA INSURANCE PREMIUMS JUST WENT UP!',
'THAT BOT IS RECONSIDERING ITS LIFE CHOICES!',
]
announceDramatic(devastatingLines[Math.floor(Math.random() * devastatingLines.length)])
// Creator gets custom devastating lines when they land the hit
const devastatingAttackerArch = aWon ? botA.archetype : botB.archetype
if (devastatingAttackerArch === 'the_creator') {
announceCreatorDevastating()
} else {
announceDramatic(devastatingLines[Math.floor(Math.random() * devastatingLines.length)])
}
await k.wait(0.5) // let the voice line play before crowd reacts
announceCrowdReaction('ooh')
// Dimensional shift on devastating rounds (60%)
@@ -8344,6 +8359,9 @@ export async function createFightScene(config: FightSceneConfig) {
async playTaunt(side: 'a' | 'b') {
const taunter = k.get(side === 'a' ? 'fighterA' : 'fighterB')[0]
if (!taunter) return
// Creator taunts come with menacing voice lines
const taunterArch = side === 'a' ? botA.archetype : botB.archetype
if (taunterArch === 'the_creator') announceCreatorTaunt()
const origY = taunter.pos.y
// Random taunt animation: hop, flex, or shake
const tauntType = Math.floor(Math.random() * 4)
@@ -9199,12 +9217,26 @@ export async function createFightScene(config: FightSceneConfig) {
await k.wait(0.3)
loser.play('ko')
await k.wait(0.4) // pause for visual impact before fatality voice
announceFatality(fatalityTagline)
const winnerArch = winningSide === 'a' ? botA.archetype : botB.archetype
const loserArch = winningSide === 'a' ? botB.archetype : botA.archetype
if (winnerArch === 'the_creator') {
announceCreatorKO()
} else {
announceFatality(fatalityTagline)
}
announceCrowdReaction('cheer')
await k.tween(winner.pos.x, winningSide === 'a' ? HOME_A : HOME_B, 0.25, (v) => { winner.pos.x = v }, k.easings.easeInOutQuad)
await k.wait(0.2)
winner.play('win')
sfxWin(); sfxWinAnnounce(winnerName)
sfxWin()
// Creator win/lose get special announcements
if (winnerArch === 'the_creator') {
announceCreatorWin()
} else if (loserArch === 'the_creator') {
announceCreatorLose()
} else {
sfxWinAnnounce(winnerName)
}
spawnSparks(winner.pos.x, winner.pos.y - 50, 15, '#ffe14d')
for (let i = 0; i < 4; i++) {
setTimeout(() => {