// ============================================================================= // BATTLE — Top Trumps duel vs Champion // ============================================================================= const { useState } = React; function BattleScreen({ state, actions, championId }) { const champion = window.GAME_DATA.CHAMPIONS.find(c => c.id === championId); const owned = state.collection; const { CARDS:BC, STATS:BS, getCard, RARITIES:BR } = window.GAME_DATA; const ownedCards = BC.filter(c => owned[c.id]); // Phases: deck-pick → playing → done const [phase, setPhase] = useState('deck-pick'); const [yourDeck, setYourDeck] = useState([]); // card ids const [oppDeck, setOppDeck] = useState(champion.deck.slice()); const [round, setRound] = useState(0); // 0..4 const [yourScore, setYourScore] = useState(0); const [oppScore, setOppScore] = useState(0); const [yourCardRevealed, setYourCardRevealed] = useState(false); const [oppCardRevealed, setOppCardRevealed] = useState(false); const [selectedStat, setSelectedStat] = useState(null); const [roundResult, setRoundResult] = useState(null); // 'win' | 'lose' | 'draw' const [matchResult, setMatchResult] = useState(null); // 'win' | 'lose' const [history, setHistory] = useState([]); if (ownedCards.length < 5) { return (
◈ MAZO INCOMPLETO
NECESITAS 5 CARTAS
Tienes {ownedCards.length} carta{ownedCards.length===1?'':'s'} en tu colección.
Abre más sobres para formar un mazo.
); } // ─── DECK PICK PHASE ────────────────────────────────────────────────── if (phase === 'deck-pick') { const toggle = (id) => { setYourDeck(prev => prev.includes(id) ? prev.filter(x=>x!==id) : (prev.length<5 ? [...prev, id] : prev)); }; const autoPick = () => { const sorted = ownedCards.slice().sort((a,b) => BR[b.rarity].tier - BR[a.rarity].tier || b.stats.fame - a.stats.fame); setYourDeck(sorted.slice(0,5).map(c=>c.id)); }; const start = () => { // Shuffle opp deck setOppDeck(champion.deck.slice().sort(() => Math.random() - 0.5)); setYourDeck(yourDeck.slice().sort(() => Math.random() - 0.5)); setPhase('playing'); }; return (
◈ DESAFÍO · {champion.name}
ELIGE TU MAZO · {yourDeck.length}/5
{/* Your hand preview */}
{[...Array(5)].map((_, i) => { const id = yourDeck[i]; return id ? toggle(id)}/> :
SLOT {i+1}
VACÍO
; })}
TU COLECCIÓN · {ownedCards.length} CARTAS
{ownedCards.map(c => ( toggle(c.id)} /> ))}
); } // ─── PLAYING PHASE ──────────────────────────────────────────────────── const yourCardId = yourDeck[round]; const oppCardId = oppDeck[round]; const yourCard = yourCardId ? getCard(yourCardId) : null; const oppCard = oppCardId ? getCard(oppCardId) : null; const pickStat = (statKey) => { if (selectedStat || phase !== 'playing') return; setSelectedStat(statKey); setYourCardRevealed(true); // Delay opp reveal setTimeout(() => setOppCardRevealed(true), 600); // After both revealed, compute winner setTimeout(() => { const yV = window.statForCompare(statKey, yourCard.stats[statKey]); const oV = window.statForCompare(statKey, oppCard.stats[statKey]); let res; if (yV > oV) { res = 'win'; setYourScore(s => s + 1); } else if (yV < oV) { res = 'lose'; setOppScore(s => s + 1); } else res = 'draw'; setRoundResult(res); setHistory(h => [...h, { round, stat: statKey, your: yourCard.stats[statKey], opp: oppCard.stats[statKey], res }]); }, 1400); }; const nextRound = () => { const nr = round + 1; if (nr >= 5) { // Match over const finalYour = yourScore; const finalOpp = oppScore; let res; if (finalYour > finalOpp) res = 'win'; else if (finalYour < finalOpp) res = 'lose'; else res = 'draw'; setMatchResult(res); setPhase('done'); return; } setRound(nr); setSelectedStat(null); setYourCardRevealed(false); setOppCardRevealed(false); setRoundResult(null); }; // ─── DONE PHASE ──────────────────────────────────────────────────────── if (phase === 'done') { const won = matchResult === 'win'; return (
◈ DUELO · {won?'VICTORIA':'DERROTA'}
{won?'¡VENCISTE!':matchResult==='draw'?'EMPATE':'PERDISTE'}
{yourScore} vs {oppScore}
{won && !state.defeatedChamps.includes(champion.id) && (
◆ RECOMPENSA DESBLOQUEADA
+{champion.reward.credits.toLocaleString()} CRD
1× CARTA MÍTICA
{window.GAME_DATA.MYTHIC_CARDS[champion.reward.card].name}
{window.GAME_DATA.MYTHIC_CARDS[champion.reward.card].desc}
)}
{won && } {!won && }
); } // ─── PLAYING / DUEL ARENA ───────────────────────────────────────────── return (
{/* Result banner overlay */} {roundResult && (
{roundResult === 'win' ? '+1' : roundResult === 'lose' ? '−1' : '='}
)}
RETADOR
{yourScore} / {oppScore}
RONDA {round+1} / 5 · BEST OF 5
{champion.name}
{champion.title}
{/* YOUR CARD */}
{yourCard && }
VS
{/* OPP CARD */}
{oppCard && }
{/* Stat picker */} {!selectedStat && (
ELIGE UN STAT. El mayor valor gana la ronda.
{Object.values(BS).map(stat => ( ))}
)} {selectedStat && roundResult && (
{BS[selectedStat].label}: {window.fmtStat(selectedStat, yourCard.stats[selectedStat])} {' '}vs{' '} {window.fmtStat(selectedStat, oppCard.stats[selectedStat])}
)} {selectedStat && !roundResult && (
◈ COMPARANDO {BS[selectedStat].label}...
)}
); } function RoundLog({ history, championName }) { if (!history.length) return null; return (
◈ REPLAY · 5 RONDAS
{history.map((r, i) => (
R{i+1} {window.GAME_DATA.STATS[r.stat].label} {window.fmtStat(r.stat, r.your)} vs {window.fmtStat(r.stat, r.opp)} {r.res==='win'?'GANADA':r.res==='lose'?'PERDIDA':'EMPATE'}
))}
); } window.BattleScreen = BattleScreen;