Checkpoint: Aplicación completamente funcional - Logo actualizado a 'FRANCIA OCUPADA' y botones de victoria redimensionados

This commit is contained in:
Resistencia Dev
2025-12-08 20:40:49 +01:00
parent b836c53002
commit 6a6cf7628b
15 changed files with 110 additions and 17 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 KiB

View File

@@ -680,6 +680,86 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
/>
)}
{/* FASE: ASESINO (FRANCOTIRADOR) */}
{gameState.phase === GamePhase.ASSASSIN_PHASE && (
<motion.div
className="fixed inset-0 flex flex-col items-center justify-center z-50 relative"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
{/* Imagen de fondo solo para el Francotirador */}
{currentPlayer?.role === 'francotirador' && (
<div className="absolute inset-0 z-0">
<Image
src="/assets/images/tokens/lastshot.jpg"
alt="Last Shot"
fill
className="object-cover"
priority
/>
{/* Overlay oscuro para mejorar legibilidad */}
<div className="absolute inset-0 bg-black/50" />
</div>
)}
{/* Fondo oscuro para los demás jugadores */}
{currentPlayer?.role !== 'francotirador' && (
<div className="absolute inset-0 z-0 bg-black/90" />
)}
<motion.div
className="text-center mb-8 relative z-10"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring', stiffness: 200 }}
>
<h1 className="text-6xl font-bold text-red-600 mb-4">
¡ÚLTIMA OPORTUNIDAD!
</h1>
{currentPlayer?.role === 'francotirador' ? (
<p className="text-2xl text-white drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)]">
Francotirador, elige a quién crees que es <span className="text-yellow-400 font-bold">MARLENE</span>
</p>
) : (
<p className="text-2xl text-gray-400">
El Francotirador está decidiendo...
</p>
)}
</motion.div>
{currentPlayer?.role === 'francotirador' && (
<motion.div
className="grid grid-cols-3 gap-6 max-w-4xl relative z-10"
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.5 }}
>
{gameState.players
.filter(p => p.faction === Faction.ALIADOS) // Solo jugadores Aliados
.map(player => (
<motion.button
key={player.id}
onClick={() => actions.assassinKill(player.id)}
className="bg-black/60 hover:bg-red-600/70 border-4 border-white/30 hover:border-red-500 p-6 rounded-xl transition-all backdrop-blur-sm"
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
<div className="w-32 h-32 mx-auto mb-4 rounded-full border-4 border-white/50 overflow-hidden bg-black relative shadow-2xl">
<Image
src={`/assets/images/characters/${player.avatar}`}
alt={player.name}
fill
className="object-cover"
/>
</div>
<p className="text-white font-bold text-xl drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)]">{player.name}</p>
</motion.button>
))}
</motion.div>
)}
</motion.div>
)}
{/* FASE: VICTORIA NAZIS */}
{gameState.phase === GamePhase.NAZIS_WIN && (
<VictoryScreen

View File

@@ -1,5 +1,6 @@
import { motion } from 'framer-motion';
import { useState, useEffect } from 'react';
import Image from 'next/image';
import { GameState, Faction } from '../../../shared/types';
interface VictoryScreenProps {
@@ -31,41 +32,53 @@ export default function VictoryScreen({ gameState, isHost, onRestart, onFinalize
return (
<motion.div
className="fixed inset-0 flex flex-col items-center justify-center bg-gradient-to-b from-black via-zinc-900 to-black z-50"
className="fixed inset-0 flex flex-col items-center justify-center z-50 relative"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
{/* Imagen de fondo a pantalla completa */}
<div className="absolute inset-0 z-0">
<Image
src={isNazisWin ? '/assets/images/tokens/mission_fail.png' : '/assets/images/tokens/mission_success.png'}
alt={isNazisWin ? 'Victoria Nazi' : 'Victoria Aliada'}
fill
className="object-cover"
priority
/>
{/* Overlay oscuro para mejorar legibilidad */}
<div className="absolute inset-0 bg-black/60" />
</div>
{/* Título de victoria */}
<motion.div
className="text-center mb-12"
className="text-center mb-12 relative z-10"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring', stiffness: 200, delay: 0.2 }}
>
<h1 className={`text-7xl md:text-8xl font-bold mb-4 ${isNazisWin ? 'text-red-600' : 'text-blue-500'}`}>
<h1 className={`text-7xl md:text-8xl font-bold mb-4 drop-shadow-[0_4px_8px_rgba(0,0,0,0.9)] ${isNazisWin ? 'text-red-600' : 'text-blue-500'}`}>
{isNazisWin ? '¡VICTORIA NAZI!' : '¡VICTORIA ALIADA!'}
</h1>
<p className="text-3xl text-gray-300">
<p className="text-3xl text-white drop-shadow-[0_4px_8px_rgba(0,0,0,0.9)] font-bold">
{isNazisWin ? 'Los Nazis han conquistado Francia' : 'La Resistencia ha triunfado'}
</p>
</motion.div>
{/* Información del juego */}
<motion.div
className="bg-black/50 p-8 rounded-xl border border-white/20 mb-8 max-w-2xl"
className="bg-black/70 p-8 rounded-xl border-2 border-white/30 mb-8 max-w-2xl relative z-10 backdrop-blur-sm"
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.5 }}
>
<div className="grid grid-cols-2 gap-6 text-center">
<div>
<p className="text-gray-400 text-sm uppercase mb-2">Misiones Exitosas</p>
<p className="text-gray-300 text-sm uppercase mb-2 font-bold">Misiones Exitosas</p>
<p className="text-4xl font-bold text-blue-400">
{gameState.questResults.filter(r => r === true).length}
</p>
</div>
<div>
<p className="text-gray-400 text-sm uppercase mb-2">Misiones Fracasadas</p>
<p className="text-gray-300 text-sm uppercase mb-2 font-bold">Misiones Fracasadas</p>
<p className="text-4xl font-bold text-red-400">
{gameState.questResults.filter(r => r === false).length}
</p>
@@ -76,39 +89,39 @@ export default function VictoryScreen({ gameState, isHost, onRestart, onFinalize
{/* Botones para el host */}
{isHost ? (
<motion.div
className="flex flex-col items-center gap-4"
className="flex flex-col items-center gap-4 relative z-10"
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 1 }}
>
<p className="text-yellow-500 font-bold text-xl mb-2">
Tiempo restante: {timeLeft}s
<p className="text-yellow-400 font-bold text-2xl mb-2 drop-shadow-[0_2px_4px_rgba(0,0,0,0.9)] bg-black/50 px-6 py-2 rounded-full">
Tiempo restante: {timeLeft}s
</p>
<div className="flex gap-4">
<div className="flex gap-6">
<motion.button
onClick={onRestart}
className="bg-green-600 hover:bg-green-500 text-white font-bold py-4 px-8 rounded-lg text-xl shadow-lg"
whileHover={{ scale: 1.05 }}
className="bg-green-600 hover:bg-green-500 text-white font-bold py-3 px-6 rounded-xl text-lg shadow-2xl border-2 border-green-400"
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
🔄 NUEVA PARTIDA
</motion.button>
<motion.button
onClick={onFinalize}
className="bg-red-600 hover:bg-red-500 text-white font-bold py-4 px-8 rounded-lg text-xl shadow-lg"
whileHover={{ scale: 1.05 }}
className="bg-red-600 hover:bg-red-500 text-white font-bold py-3 px-6 rounded-xl text-lg shadow-2xl border-2 border-red-400"
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
TERMINAR
</motion.button>
</div>
<p className="text-gray-500 text-sm mt-2">
<p className="text-white text-base mt-2 bg-black/60 px-6 py-2 rounded-full drop-shadow-[0_2px_4px_rgba(0,0,0,0.9)]">
Si no decides, la partida terminará automáticamente
</p>
</motion.div>
) : (
<motion.div
className="text-center"
className="text-center relative z-10"
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 1 }}