feat: Implement solo draft mode with bot players and automated deck building.

This commit is contained in:
2025-12-20 14:48:06 +01:00
parent fd20c3cfb2
commit a3e45b13ce
7 changed files with 301 additions and 86 deletions

View File

@@ -423,6 +423,30 @@ io.on('connection', (socket) => {
}
});
socket.on('add_bot', ({ roomId }) => {
const context = getContext();
if (!context || !context.player.isHost) return; // Verify host
const updatedRoom = roomManager.addBot(roomId);
if (updatedRoom) {
io.to(roomId).emit('room_update', updatedRoom);
console.log(`Bot added to room ${roomId}`);
} else {
socket.emit('error', { message: 'Failed to add bot (Room full?)' });
}
});
socket.on('remove_bot', ({ roomId, botId }) => {
const context = getContext();
if (!context || !context.player.isHost) return; // Verify host
const updatedRoom = roomManager.removeBot(roomId, botId);
if (updatedRoom) {
io.to(roomId).emit('room_update', updatedRoom);
console.log(`Bot ${botId} removed from room ${roomId}`);
}
});
// Secure helper to get player context
const getContext = () => roomManager.getPlayerBySocket(socket.id);
@@ -441,7 +465,7 @@ io.on('connection', (socket) => {
// return;
}
const draft = draftManager.createDraft(room.id, room.players.map(p => p.id), room.packs);
const draft = draftManager.createDraft(room.id, room.players.map(p => ({ id: p.id, isBot: !!p.isBot })), room.packs, room.basicLands);
room.status = 'drafting';
io.to(room.id).emit('room_update', room);
@@ -461,6 +485,24 @@ io.on('connection', (socket) => {
if (draft.status === 'deck_building') {
room.status = 'deck_building';
io.to(room.id).emit('room_update', room);
// Logic to Sync Bot Readiness (Decks built by DraftManager)
const currentRoom = roomManager.getRoom(room.id); // Get latest room state
if (currentRoom) {
Object.values(draft.players).forEach(draftPlayer => {
if (draftPlayer.isBot && draftPlayer.deck) {
const roomPlayer = currentRoom.players.find(rp => rp.id === draftPlayer.id);
if (roomPlayer && !roomPlayer.ready) {
// Mark Bot Ready!
const updatedRoom = roomManager.setPlayerReady(room.id, draftPlayer.id, draftPlayer.deck);
if (updatedRoom) {
io.to(room.id).emit('room_update', updatedRoom);
console.log(`Bot ${draftPlayer.id} marked ready with deck (${draftPlayer.deck.length} cards).`);
}
}
}
});
}
}
}
});
@@ -511,40 +553,25 @@ io.on('connection', (socket) => {
}
});
socket.on('start_solo_test', ({ playerId, playerName, deck }, callback) => {
// Solo test is a separate creation flow, doesn't require existing context
const room = roomManager.createRoom(playerId, playerName, []);
room.status = 'playing';
socket.on('start_solo_test', ({ playerId, playerName, packs, basicLands }, callback) => { // Updated signature
// Solo test -> 1 Human + 7 Bots + Start Draft
console.log(`Starting Solo Draft for ${playerName}`);
const room = roomManager.createRoom(playerId, playerName, packs, basicLands || [], socket.id);
socket.join(room.id);
const game = gameManager.createGame(room.id, room.players);
if (Array.isArray(deck)) {
deck.forEach((card: any) => {
gameManager.addCardToGame(room.id, {
ownerId: playerId,
controllerId: playerId,
oracleId: card.id,
name: card.name,
imageUrl: card.image || card.image_uris?.normal || card.card_faces?.[0]?.image_uris?.normal || "",
zone: 'library',
typeLine: card.typeLine || card.type_line || '',
oracleText: card.oracleText || card.oracle_text || '',
manaCost: card.manaCost || card.mana_cost || '',
keywords: card.keywords || [],
power: card.power,
toughness: card.toughness,
damageMarked: 0,
controlledSinceTurn: 0
});
});
// Add 7 Bots
for (let i = 0; i < 7; i++) {
roomManager.addBot(room.id);
}
// Initialize Game State (Draw Hands)
const engine = new RulesEngine(game);
engine.startGame();
// Start Draft
const draft = draftManager.createDraft(room.id, room.players.map(p => ({ id: p.id, isBot: !!p.isBot })), room.packs, room.basicLands);
room.status = 'drafting';
callback({ success: true, room, game });
callback({ success: true, room, draftState: draft });
io.to(room.id).emit('room_update', room);
io.to(room.id).emit('game_update', game);
io.to(room.id).emit('draft_update', draft);
});
socket.on('start_game', ({ decks }) => {