fix: move BETA badge after green dot in navbar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
226d242552
commit
df70f5f093
@@ -451,9 +451,13 @@ async function _doReplay() {
|
|||||||
await sleep(insanityMode.value ? 50 : 300)
|
await sleep(insanityMode.value ? 50 : 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide human player's typed answers from replay
|
||||||
|
const replayIsAHuman = props.fight.botA?.archetype === 'human'
|
||||||
|
const replayIsBHuman = props.fight.botB?.archetype === 'human'
|
||||||
|
|
||||||
// 2. Bot A: ensure audio ready, then show log + bubble + mouth + voice all at once
|
// 2. Bot A: ensure audio ready, then show log + bubble + mouth + voice all at once
|
||||||
const isCodeRound = isCodeAnswer(round.challengeType, round.botAResponse || '')
|
const isCodeRound = isCodeAnswer(round.challengeType, round.botAResponse || '')
|
||||||
if (round.botAResponse) {
|
if (round.botAResponse && !replayIsAHuman) {
|
||||||
if (doTTS && !isCodeRound) await awaitAnswerReady(props.fight.botA!.name, round.botAResponse)
|
if (doTTS && !isCodeRound) await awaitAnswerReady(props.fight.botA!.name, round.botAResponse)
|
||||||
scene?.stopShowboating('a')
|
scene?.stopShowboating('a')
|
||||||
logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse || '[NO RESPONSE]'}`, color: 'neon-cyan' })
|
logItems.value.push({ type: 'responseA', round: round.roundNumber, text: `${props.fight.botA?.name}: ${round.botAResponse || '[NO RESPONSE]'}`, color: 'neon-cyan' })
|
||||||
@@ -473,10 +477,13 @@ async function _doReplay() {
|
|||||||
if (!doTTS && !insanityMode.value) await sleep(400)
|
if (!doTTS && !insanityMode.value) await sleep(400)
|
||||||
scene?.stopTalking('a')
|
scene?.stopTalking('a')
|
||||||
scene?.hideSpeechBubble('a')
|
scene?.hideSpeechBubble('a')
|
||||||
|
} else if (replayIsAHuman) {
|
||||||
|
scene?.stopShowboating('a')
|
||||||
|
await sleep(insanityMode.value ? 50 : 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Bot B: ensure audio ready, then show log + bubble + mouth + voice all at once
|
// 3. Bot B: ensure audio ready, then show log + bubble + mouth + voice all at once
|
||||||
if (round.botBResponse) {
|
if (round.botBResponse && !replayIsBHuman) {
|
||||||
if (doTTS && !isCodeRound) await awaitAnswerReady(props.fight.botB!.name, round.botBResponse)
|
if (doTTS && !isCodeRound) await awaitAnswerReady(props.fight.botB!.name, round.botBResponse)
|
||||||
scene?.stopShowboating('b')
|
scene?.stopShowboating('b')
|
||||||
logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse || '[NO RESPONSE]'}`, color: 'neon-pink' })
|
logItems.value.push({ type: 'responseB', round: round.roundNumber, text: `${props.fight.botB?.name}: ${round.botBResponse || '[NO RESPONSE]'}`, color: 'neon-pink' })
|
||||||
@@ -497,6 +504,9 @@ async function _doReplay() {
|
|||||||
if (!doTTS && !insanityMode.value) await sleep(400)
|
if (!doTTS && !insanityMode.value) await sleep(400)
|
||||||
scene?.stopTalking('b')
|
scene?.stopTalking('b')
|
||||||
scene?.hideSpeechBubble('b')
|
scene?.hideSpeechBubble('b')
|
||||||
|
} else if (replayIsBHuman) {
|
||||||
|
scene?.stopShowboating('b')
|
||||||
|
await sleep(insanityMode.value ? 50 : 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop all showboating before fight animation
|
// Stop all showboating before fight animation
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ const bottomNav = [
|
|||||||
<span class="font-display font-black text-neon-pink text-lg tracking-widest glow-pink">
|
<span class="font-display font-black text-neon-pink text-lg tracking-widest glow-pink">
|
||||||
BOTFIGHTS
|
BOTFIGHTS
|
||||||
</span>
|
</span>
|
||||||
<span class="font-glitch text-[9px] text-neon-cyan/80 tracking-[0.2em] -rotate-12 -ml-1 -mt-2 select-none">BETA</span>
|
|
||||||
<span
|
<span
|
||||||
class="w-2 h-2 rounded-full transition-colors"
|
class="w-2 h-2 rounded-full transition-colors"
|
||||||
:class="isOnline ? 'bg-green-400' : 'bg-red-400 animate-pulse'"
|
:class="isOnline ? 'bg-green-400' : 'bg-red-400 animate-pulse'"
|
||||||
:title="isOnline ? 'Online' : 'Offline'"
|
:title="isOnline ? 'Online' : 'Offline'"
|
||||||
/>
|
/>
|
||||||
|
<span class="font-glitch text-[9px] text-neon-cyan/80 tracking-[0.2em] -rotate-12 -ml-0.5 select-none">BETA</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
<div class="hidden md:flex items-center gap-6">
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
|||||||
@@ -1222,7 +1222,11 @@ export async function createFightScene(config: FightSceneConfig) {
|
|||||||
stopShowboating(side: 'a' | 'b') { showboatSystem.stopShowboating(side) },
|
stopShowboating(side: 'a' | 'b') { showboatSystem.stopShowboating(side) },
|
||||||
|
|
||||||
async playEntrance() {
|
async playEntrance() {
|
||||||
return entranceSystem.playEntrance()
|
// Timeout entrance to prevent hanging on mobile (max 8s)
|
||||||
|
await Promise.race([
|
||||||
|
entranceSystem.playEntrance(),
|
||||||
|
new Promise<void>(r => setTimeout(r, 8000)),
|
||||||
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
// Physical contact delegates
|
// Physical contact delegates
|
||||||
|
|||||||
@@ -524,21 +524,30 @@ async function playEntrance() {
|
|||||||
while (idxB === idxA && attempts < 5) { idxB = pickTierEntrance(botB.tier); attempts++ }
|
while (idxB === idxA && attempts < 5) { idxB = pickTierEntrance(botB.tier); attempts++ }
|
||||||
|
|
||||||
// Play entrances with slight stagger — creator always gets special entrance
|
// Play entrances with slight stagger — creator always gets special entrance
|
||||||
|
// Wrap each in try/catch so one failing doesn't prevent the other
|
||||||
announceDeepIntro()
|
announceDeepIntro()
|
||||||
if (botA.archetype === 'the_creator') {
|
try {
|
||||||
await creatorEntrance(fA, HOME_A, true)
|
if (botA.archetype === 'the_creator') {
|
||||||
} else {
|
await creatorEntrance(fA, HOME_A, true)
|
||||||
await entrances[idxA](fA, HOME_A, true)
|
} else {
|
||||||
|
await entrances[idxA](fA, HOME_A, true)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[Entrance] Fighter A entrance failed:', e)
|
||||||
}
|
}
|
||||||
await k.wait(0.3)
|
await k.wait(0.3)
|
||||||
if (botB.archetype === 'the_creator') {
|
try {
|
||||||
await creatorEntrance(fB, HOME_B, false)
|
if (botB.archetype === 'the_creator') {
|
||||||
} else {
|
await creatorEntrance(fB, HOME_B, false)
|
||||||
await entrances[idxB](fB, HOME_B, false)
|
} else {
|
||||||
|
await entrances[idxB](fB, HOME_B, false)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[Entrance] Fighter B entrance failed:', e)
|
||||||
}
|
}
|
||||||
await k.wait(0.2)
|
await k.wait(0.2)
|
||||||
|
|
||||||
// Safety: ensure both fighters are visible and at home positions
|
// Safety: ALWAYS ensure both fighters are visible and at home positions
|
||||||
fA.pos.x = HOME_A
|
fA.pos.x = HOME_A
|
||||||
fA.pos.y = GROUND_Y - 6
|
fA.pos.y = GROUND_Y - 6
|
||||||
fA.opacity = 1
|
fA.opacity = 1
|
||||||
@@ -547,8 +556,8 @@ async function playEntrance() {
|
|||||||
fB.opacity = 1
|
fB.opacity = 1
|
||||||
|
|
||||||
// Both idle at home positions
|
// Both idle at home positions
|
||||||
fA.play('idle')
|
try { fA.play('idle') } catch { /* sprite may not have anim */ }
|
||||||
fB.play('idle')
|
try { fB.play('idle') } catch { /* sprite may not have anim */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
return { playEntrance }
|
return { playEntrance }
|
||||||
|
|||||||
@@ -248,13 +248,17 @@ async function handleRoundEnd(data: any) {
|
|||||||
|
|
||||||
const cLabel = currentChallengeInfo.value?.label || challengeLabel(currentChallengeInfo.value?.type || '')
|
const cLabel = currentChallengeInfo.value?.label || challengeLabel(currentChallengeInfo.value?.type || '')
|
||||||
|
|
||||||
|
// Don't show the human player's typed answer in the battle log
|
||||||
|
const isAHuman = myBotId.value === fd.botA.id && isHumanFight.value
|
||||||
|
const isBHuman = myBotId.value === fd.botB.id && isHumanFight.value
|
||||||
|
|
||||||
liveLogItems.value.push(
|
liveLogItems.value.push(
|
||||||
{ type: 'header', round, text: `ROUND ${round}: ${cLabel}`, color: 'neon-purple' },
|
{ type: 'header', round, text: `ROUND ${round}: ${cLabel}`, color: 'neon-purple' },
|
||||||
)
|
)
|
||||||
if (result.botAResponse) {
|
if (result.botAResponse && !isAHuman) {
|
||||||
liveLogItems.value.push({ type: 'responseA', round, text: `${fd.botA.name}: ${result.botAResponse}`, color: 'neon-cyan' })
|
liveLogItems.value.push({ type: 'responseA', round, text: `${fd.botA.name}: ${result.botAResponse}`, color: 'neon-cyan' })
|
||||||
}
|
}
|
||||||
if (result.botBResponse) {
|
if (result.botBResponse && !isBHuman) {
|
||||||
liveLogItems.value.push({ type: 'responseB', round, text: `${fd.botB.name}: ${result.botBResponse}`, color: 'neon-pink' })
|
liveLogItems.value.push({ type: 'responseB', round, text: `${fd.botB.name}: ${result.botBResponse}`, color: 'neon-pink' })
|
||||||
}
|
}
|
||||||
if (result.narration) {
|
if (result.narration) {
|
||||||
@@ -269,8 +273,8 @@ async function handleRoundEnd(data: any) {
|
|||||||
|
|
||||||
if (liveScene) {
|
if (liveScene) {
|
||||||
fanfareRound(round)
|
fanfareRound(round)
|
||||||
if (result.botAResponse) liveScene.showSpeechBubble('a', result.botAResponse, 3)
|
if (result.botAResponse && !isAHuman) liveScene.showSpeechBubble('a', result.botAResponse, 3)
|
||||||
if (result.botBResponse) {
|
if (result.botBResponse && !isBHuman) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (liveScene && result.botBResponse) liveScene.showSpeechBubble('b', result.botBResponse, 2.5)
|
if (liveScene && result.botBResponse) liveScene.showSpeechBubble('b', result.botBResponse, 2.5)
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|||||||
Reference in New Issue
Block a user