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:
co-authored by
Claude Opus 4.6
parent
f1fe798442
commit
6658212e9f
@@ -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(() => {
|
||||
|
||||
Reference in New Issue
Block a user