diff --git a/src/client/dev-dist/sw.js b/src/client/dev-dist/sw.js index 52659b8..6d8fe6d 100644 --- a/src/client/dev-dist/sw.js +++ b/src/client/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-5a5d9309'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.c9el36ma12" + "revision": "0.5drsp6r8gnc" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/src/client/src/modules/cube/CubeManager.tsx b/src/client/src/modules/cube/CubeManager.tsx index 66e4d3d..7ad8c05 100644 --- a/src/client/src/modules/cube/CubeManager.tsx +++ b/src/client/src/modules/cube/CubeManager.tsx @@ -305,9 +305,9 @@ export const CubeManager: React.FC = ({ packs, setPacks, avail const handleStartSoloTest = async () => { if (packs.length === 0) return; - // Validate Lands + // Validate Lands - Warn but allow proceed (server will handle it or deck builder will be landless) if (!availableLands || availableLands.length === 0) { - if (!confirm("No basic lands detected in the current pool. The generated deck will have 0 lands. Continue?")) { + if (!confirm("No basic lands detected in the current pool. Decks might be invalid. Continue?")) { return; } } @@ -315,49 +315,18 @@ export const CubeManager: React.FC = ({ packs, setPacks, avail setLoading(true); try { - // Collect all cards - const allCards = packs.flatMap(p => p.cards); - - // Random Deck Construction Logic - // 1. Separate lands and non-lands (Exclude existing Basic Lands from spells to be safe) - const spells = allCards.filter(c => !c.typeLine?.includes('Basic Land') && !c.typeLine?.includes('Land')); - - // 2. Select 23 Spells randomly - const deckSpells: any[] = []; - const spellPool = [...spells]; - - // Fisher-Yates Shuffle - for (let i = spellPool.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [spellPool[i], spellPool[j]] = [spellPool[j], spellPool[i]]; - } - - // Take up to 23 spells, or all if fewer - deckSpells.push(...spellPool.slice(0, Math.min(23, spellPool.length))); - - // 3. Select 17 Lands (or fill to 40) - const deckLands: any[] = []; - const landCount = 40 - deckSpells.length; // Aim for 40 cards total - - if (availableLands.length > 0) { - for (let i = 0; i < landCount; i++) { - const land = availableLands[Math.floor(Math.random() * availableLands.length)]; - deckLands.push(land); - } - } - - const fullDeck = [...deckSpells, ...deckLands]; - - // Emit socket event const playerId = localStorage.getItem('player_id') || 'tester-' + Date.now(); const playerName = localStorage.getItem('player_name') || 'Tester'; if (!socketService.socket.connected) socketService.connect(); + // Emit new start_solo_test event + // Now sends PACKS and LANDS instead of a constructed DECK const response = await socketService.emitPromise('start_solo_test', { playerId, playerName, - deck: fullDeck + packs, + basicLands: availableLands }); if (response.success) { @@ -369,7 +338,7 @@ export const CubeManager: React.FC = ({ packs, setPacks, avail onGoToLobby(); }, 100); } else { - alert("Failed to start test game: " + response.message); + alert("Failed to start solo draft: " + response.message); } } catch (e: any) { @@ -793,10 +762,10 @@ export const CubeManager: React.FC = ({ packs, setPacks, avail onClick={handleReset} disabled={loading} className={`w-full mt-4 py-2.5 px-4 rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-2 ${loading - ? 'opacity-50 cursor-not-allowed text-slate-600 border border-transparent' - : confirmClear - ? 'bg-red-600 text-white border border-red-500 shadow-md animate-pulse' - : 'text-red-400 border border-red-900/30 hover:bg-red-950/30 hover:border-red-500/50 hover:text-red-300 shadow-sm' + ? 'opacity-50 cursor-not-allowed text-slate-600 border border-transparent' + : confirmClear + ? 'bg-red-600 text-white border border-red-500 shadow-md animate-pulse' + : 'text-red-400 border border-red-900/30 hover:bg-red-950/30 hover:border-red-500/50 hover:text-red-300 shadow-sm' }`} title="Clear all data and start over" > diff --git a/src/client/src/modules/lobby/GameRoom.tsx b/src/client/src/modules/lobby/GameRoom.tsx index 17debe1..246dbf8 100644 --- a/src/client/src/modules/lobby/GameRoom.tsx +++ b/src/client/src/modules/lobby/GameRoom.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { socketService } from '../../services/SocketService'; -import { Users, MessageSquare, Send, Copy, Check, Layers, LogOut, Bell, BellOff, X } from 'lucide-react'; +import { Users, MessageSquare, Send, Copy, Check, Layers, LogOut, Bell, BellOff, X, Bot } from 'lucide-react'; import { Modal } from '../../components/Modal'; import { useToast } from '../../components/Toast'; import { GameView } from '../game/GameView'; @@ -14,6 +14,7 @@ interface Player { isHost: boolean; role: 'player' | 'spectator'; isOffline?: boolean; + isBot?: boolean; } interface ChatMessage { @@ -283,7 +284,13 @@ export const GameRoom: React.FC = ({ room: initialRoom, currentPl > Start Draft - + )} @@ -426,8 +433,8 @@ export const GameRoom: React.FC = ({ room: initialRoom, currentPl return (
-
- {p.name.substring(0, 2).toUpperCase()} +
+ {p.isBot ? : p.name.substring(0, 2).toUpperCase()}
@@ -436,6 +443,7 @@ export const GameRoom: React.FC = ({ room: initialRoom, currentPl {p.role} {p.isHost && • Host} + {p.isBot && • Bot} {isReady && room.status === 'deck_building' && • Ready} {p.isOffline && • Offline} @@ -456,6 +464,17 @@ export const GameRoom: React.FC = ({ room: initialRoom, currentPl )} + {isMeHost && p.isBot && ( + + )} {isMe && (