Files
Connect-5/index.html
DeNNiiInc bcf3b0a032 FEATURE: Migrate username storage from localStorage to IndexedDB
- Created storage.js wrapper with IndexedDB support
- Automatic fallback to localStorage if IndexedDB unavailable
- Updated all username storage calls to use async API
- Better performance and more storage capacity
- Improved PWA compatibility

Benefits:
- 50MB+ storage vs 5-10MB localStorage
- Async API doesn't block main thread
- Better for future features (game history, stats, etc.)
2025-12-14 12:15:16 +11:00

302 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Connect-5 - Premium Gomoku Game" />
<title>Connect-5 - Premium Gomoku Game</title>
<link rel="icon" type="image/png" href="Logo.png" />
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="multiplayer-styles.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<!-- Socket.io Client -->
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
</head>
<body>
<div class="container">
<header class="header">
<div class="header-content">
<h1 class="title">
<img src="Logo.png" alt="BCT Logo" class="title-icon" />
Connect-5
</h1>
<p class="subtitle">Premium Gomoku Experience</p>
<a
href="https://www.youtube.com/@beyondcloudtechnology"
target="_blank"
rel="noopener noreferrer"
class="youtube-link"
>
<svg class="youtube-icon" viewBox="0 0 24 24" fill="currentColor">
<path
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
/>
</svg>
Watch on YouTube @beyondcloudtechnology
</a>
</div>
</header>
<main class="game-container">
<!-- Game Mode Toggle -->
<div class="mode-selector">
<button class="mode-btn active" id="localModeBtn" onclick="toggleGameMode('local')">
🎮 Local Play
</button>
<button class="mode-btn" id="multiplayerModeBtn" onclick="toggleGameMode('multiplayer')" disabled>
🌐 Multiplayer
</button>
</div>
<!-- Local Game Controls -->
<div id="gameControls" class="controls-panel">
<div class="size-selector">
<label for="boardSize">Board Size:</label>
<div class="size-buttons">
<button class="size-btn active" data-size="15">15×15</button>
<button class="size-btn" data-size="20">20×20</button>
<button class="size-btn" data-size="25">25×25</button>
<button class="size-btn" data-size="50">50×50</button>
</div>
</div>
<div class="game-info">
<div class="turn-indicator">
<span class="label">Current Turn:</span>
<div class="player-display">
<span class="player-marker" id="currentPlayer">X</span>
</div>
</div>
<div class="score-display">
<div class="score-item">
<span class="score-label">Player X</span>
<span class="score-value" id="scoreX">0</span>
</div>
<div class="score-item">
<span class="score-label">Player O</span>
<span class="score-value" id="scoreO">0</span>
</div>
</div>
</div>
<button class="reset-btn" id="resetBtn">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"
/>
</svg>
New Game
</button>
</div>
<div class="board-wrapper">
<div class="board" id="gameBoard"></div>
</div>
<div class="status-message" id="statusMessage">
Player X starts the game
</div>
<!-- Multiplayer Panel -->
<div id="multiplayerPanel" class="multiplayer-panel" style="display: none;">
<div class="player-stats-card">
<h3>Your Stats</h3>
<div class="stats-grid">
<div class="stat-item">
<span class="stat-label">Player:</span>
<span class="stat-value" id="playerUsername">-</span>
</div>
<div class="stat-item">
<span class="stat-label">Wins:</span>
<span class="stat-value" id="playerWins">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Losses:</span>
<span class="stat-value" id="playerLosses">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Draws:</span>
<span class="stat-value" id="playerDraws">0</span>
</div>
</div>
</div>
<div class="board-size-selector-mp">
<h3>Select Board Size</h3>
<div class="size-buttons">
<button class="size-btn-mp active" data-size="15">15×15</button>
<button class="size-btn-mp" data-size="20">20×20</button>
<button class="size-btn-mp" data-size="25">25×25</button>
<button class="size-btn-mp" data-size="50">50×50</button>
</div>
</div>
<div class="active-players-card">
<h3>Online Players</h3>
<div id="activePlayersList" class="players-list">
<div class="loading">Loading players...</div>
</div>
</div>
<button class="return-btn" onclick="toggleGameMode('local')">
← Return to Local Play
</button>
</div>
</main>
<footer class="footer">
<p>© 2025 Beyond Cloud Technology. All rights reserved.</p>
</footer>
</div>
<div class="victory-overlay" id="victoryOverlay">
<div class="victory-content">
<h2 class="victory-title" id="victoryTitle">Player X Wins!</h2>
<p class="victory-subtitle">Five in a row achieved!</p>
<button class="play-again-btn" id="playAgainBtn">Play Again</button>
</div>
</div>
<!-- Username Modal -->
<div class="modal-overlay" id="usernameModal">
<div class="modal-content username-modal">
<h2>Enter Your Username</h2>
<p class="modal-subtitle">Choose a family-friendly name (3-20 characters)</p>
<input type="text" id="usernameInput" placeholder="Your username" maxlength="20" />
<div id="usernameError" class="error-message" style="display: none;"></div>
<button class="submit-btn" onclick="submitUsername()">
Join Multiplayer
</button>
</div>
</div>
<script src="storage.js"></script>
<script src="multiplayer.js"></script>
<script src="game.js"></script>
<script>
// Game mode toggling
function toggleGameMode(mode) {
const localBtn = document.getElementById('localModeBtn');
const multiplayerBtn = document.getElementById('multiplayerModeBtn');
const gameControls = document.getElementById('gameControls');
const multiplayerPanel = document.getElementById('multiplayerPanel');
const boardWrapper = document.querySelector('.board-wrapper');
const statusMessage = document.getElementById('statusMessage');
if (mode === 'local') {
localBtn.classList.add('active');
multiplayerBtn.classList.remove('active');
gameControls.style.display = 'grid';
multiplayerPanel.style.display = 'none';
boardWrapper.style.display = 'flex';
statusMessage.style.display = 'block';
// Reset to local mode
if (window.multiplayerClient) {
window.multiplayerClient.isMultiplayer = false;
}
} else {
localBtn.classList.remove('active');
multiplayerBtn.classList.add('active');
gameControls.style.display = 'none';
multiplayerPanel.style.display = 'block';
boardWrapper.style.display = 'none';
statusMessage.style.display = 'none';
// Initialize multiplayer if not already
if (!window.multiplayerClient) {
if (!window.game) {
console.log('⏳ Waiting for game to initialize...');
// Poll for game to be ready
const checkGame = setInterval(() => {
if (window.game) {
clearInterval(checkGame);
console.log('✅ Game ready, initializing multiplayer...');
window.multiplayerClient = new MultiplayerClient(window.game);
window.multiplayerClient.connect();
}
}, 100); // Check every 100ms
return;
}
window.multiplayerClient = new MultiplayerClient(window.game);
window.multiplayerClient.connect();
}
}
}
// Submit username
function submitUsername() {
const input = document.getElementById('usernameInput');
const error = document.getElementById('usernameError');
const username = input.value.trim();
if (!username) {
error.textContent = 'Please enter a username';
error.style.display = 'block';
return;
}
if (username.length < 3 || username.length > 20) {
error.textContent = 'Username must be 3-20 characters';
error.style.display = 'block';
return;
}
if (!/^[a-zA-Z0-9_-]+$/.test(username)) {
error.textContent = 'Only letters, numbers, underscores, and hyphens allowed';
error.style.display = 'block';
return;
}
error.style.display = 'none';
if (window.multiplayerClient) {
window.multiplayerClient.registerPlayer(username);
} else {
console.error("Multiplayer client not initialized");
error.textContent = "Error: Multiplayer not initialized. Refresh page.";
error.style.display = 'block';
}
}
// Change username
function changeUsername() {
// Clear saved username from localStorage
localStorage.removeItem('connect5_username');
// Show username modal
const modal = document.getElementById('usernameModal');
if (modal) {
modal.classList.add('active');
// Clear the input field
document.getElementById('usernameInput').value = '';
}
}
// Allow Enter key to submit username
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('usernameInput');
if (input) {
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
submitUsername();
}
});
}
});
</script>
</body>
</html>