// =============================================================================
// 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' : '='}
)}
{yourScore}
/
{oppScore}
RONDA {round+1} / 5 · BEST OF 5
◆
{champion.name}
{champion.title}
{/* YOUR CARD */}
VS
{/* OPP CARD */}
{/* 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;