feat: retro mode — arcade combo round with gamepad overlays

Every fight now includes one Retro Mode round where bots submit
gamepad combo inputs (↑↓←→ A B). 24 moves across 4 tiers: basic
(always shown), standard (partially revealed), super (must discover),
and ultra (KONAMI CODE for 50 dmg). Discovery bonus gives 1.5x damage.

Includes pixel-art gamepad overlays (P1/P2) with animated button
presses, retro-specific narrations, and mock bot combo responses
scaled by ELO.

Also adds loops/plan.md with 11-phase production hardening roadmap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-08 14:13:47 +00:00
co-authored by Claude Opus 4.6
parent 0d6ba7d5a7
commit 1f8e8569ef
7 changed files with 807 additions and 2 deletions
+8 -2
View File
@@ -3,6 +3,7 @@ import { db, schema, sqlite } from '../db/index.js'
import { eq, sql } from 'drizzle-orm'
import { randomArena, type Arena } from './arenas.js'
import { pickChallenge, type Challenge } from './challenges.js'
import { generateRetroChallenge } from './retro-moves.js'
import { scoreRound, calculateElo, calculateTier } from './scoring.js'
import { fightEvents } from './events.js'
import { generateMockBotResponse, isClassicBot, generateClassicBotResponse } from './mock.js'
@@ -326,8 +327,13 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec
let winnerId: string | null = null
const usedTypes = new Set<string>()
// Pick a random round for retro mode (rounds 3-8, ensuring it's not too early or late)
const retroRound = 3 + Math.floor(Math.random() * Math.min(6, MAX_ROUNDS - 4))
for (let round = 1; round <= MAX_ROUNDS; round++) {
const challenge = pickChallenge(usedTypes, arena.modifier)
const challenge = round === retroRound
? generateRetroChallenge()
: pickChallenge(usedTypes, arena.modifier)
usedTypes.add(challenge.type)
emit(fightId, 'round_start', {
@@ -378,7 +384,7 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec
fightId,
roundNumber: round,
challengeType: challenge.type,
challengeData: JSON.stringify({ prompt: challenge.prompt, scoring: challenge.scoring }),
challengeData: JSON.stringify({ prompt: challenge.prompt, scoring: challenge.scoring, retroKnown: challenge.type === 'retro_mode' ? challenge.answers : undefined }),
botAResponse: responseA.answer,
botATimeMs: responseA.timeMs,
botAScore: result.botAScore,