183 lines
5.3 KiB
JavaScript
183 lines
5.3 KiB
JavaScript
const { GameEngine } = require('../game/GameEngine');
|
|
const { buildStarterDeck, STARTER_DECKS, ALL_CARDS, CARD_DB } = require('../cards');
|
|
|
|
class GameManager {
|
|
constructor() {
|
|
this.rooms = new Map();
|
|
this.playerRooms = new Map();
|
|
this.games = new Map();
|
|
}
|
|
|
|
createRoom(hostId, hostName, roomName) {
|
|
const roomId = `room_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
const room = {
|
|
id: roomId,
|
|
name: roomName || `${hostName}'s Game`,
|
|
hostId,
|
|
players: [{ id: hostId, name: hostName, deck: null, ready: false }],
|
|
status: 'waiting',
|
|
gameId: null,
|
|
maxPlayers: 2,
|
|
};
|
|
this.rooms.set(roomId, room);
|
|
this.playerRooms.set(hostId, roomId);
|
|
return room;
|
|
}
|
|
|
|
joinRoom(roomId, playerId, playerName) {
|
|
const room = this.rooms.get(roomId);
|
|
if (!room) return { error: 'Room not found' };
|
|
if (room.status !== 'waiting') return { error: 'Game already in progress' };
|
|
if (room.players.length >= room.maxPlayers) return { error: 'Room is full' };
|
|
if (room.players.find((p) => p.id === playerId)) return { error: 'Already in room' };
|
|
|
|
room.players.push({ id: playerId, name: playerName, deck: null, ready: false });
|
|
this.playerRooms.set(playerId, roomId);
|
|
return { success: true, room };
|
|
}
|
|
|
|
leaveRoom(playerId) {
|
|
const roomId = this.playerRooms.get(playerId);
|
|
if (!roomId) return { error: 'Not in a room' };
|
|
|
|
const room = this.rooms.get(roomId);
|
|
if (!room) {
|
|
this.playerRooms.delete(playerId);
|
|
return { error: 'Room not found' };
|
|
}
|
|
|
|
room.players = room.players.filter((p) => p.id !== playerId);
|
|
this.playerRooms.delete(playerId);
|
|
|
|
if (room.players.length === 0) {
|
|
this.rooms.delete(roomId);
|
|
if (room.gameId) this.games.delete(room.gameId);
|
|
return { success: true, roomDeleted: true, roomId };
|
|
}
|
|
|
|
if (room.hostId === playerId) {
|
|
room.hostId = room.players[0].id;
|
|
}
|
|
|
|
return { success: true, room };
|
|
}
|
|
|
|
selectDeck(playerId, deckColor) {
|
|
const roomId = this.playerRooms.get(playerId);
|
|
if (!roomId) return { error: 'Not in a room' };
|
|
|
|
const room = this.rooms.get(roomId);
|
|
if (!room) return { error: 'Room not found' };
|
|
|
|
const player = room.players.find((p) => p.id === playerId);
|
|
if (!player) return { error: 'Player not in room' };
|
|
|
|
if (!STARTER_DECKS[deckColor]) return { error: 'Invalid deck color' };
|
|
|
|
player.deck = deckColor;
|
|
player.ready = true;
|
|
return { success: true, room };
|
|
}
|
|
|
|
selectCustomDeck(playerId, cardIds) {
|
|
const roomId = this.playerRooms.get(playerId);
|
|
if (!roomId) return { error: 'Not in a room' };
|
|
|
|
const room = this.rooms.get(roomId);
|
|
if (!room) return { error: 'Room not found' };
|
|
|
|
const player = room.players.find((p) => p.id === playerId);
|
|
if (!player) return { error: 'Player not in room' };
|
|
|
|
if (cardIds.length < 40) return { error: 'Deck must have at least 40 cards' };
|
|
if (cardIds.length > 60) return { error: 'Deck cannot exceed 60 cards' };
|
|
|
|
for (const cid of cardIds) {
|
|
if (!CARD_DB[cid]) return { error: `Invalid card id: ${cid}` };
|
|
}
|
|
|
|
const nonLandCounts = {};
|
|
for (const cid of cardIds) {
|
|
const card = CARD_DB[cid];
|
|
if (card.type !== 'land' || card.subtype !== 'basic') {
|
|
nonLandCounts[cid] = (nonLandCounts[cid] || 0) + 1;
|
|
if (nonLandCounts[cid] > 4) {
|
|
return { error: `Cannot have more than 4 copies of ${card.name}` };
|
|
}
|
|
}
|
|
}
|
|
|
|
player.deck = cardIds;
|
|
player.customDeck = true;
|
|
player.ready = true;
|
|
return { success: true, room };
|
|
}
|
|
|
|
startGame(roomId) {
|
|
const room = this.rooms.get(roomId);
|
|
if (!room) return { error: 'Room not found' };
|
|
if (room.players.length < 2) return { error: 'Need at least 2 players' };
|
|
if (!room.players.every((p) => p.ready)) return { error: 'Not all players are ready' };
|
|
|
|
const p1 = room.players[0];
|
|
const p2 = room.players[1];
|
|
|
|
const deck1 = p1.customDeck ? p1.deck : buildStarterDeck(p1.deck);
|
|
const deck2 = p2.customDeck ? p2.deck : buildStarterDeck(p2.deck);
|
|
|
|
const engine = new GameEngine(p1.id, p2.id, deck1, deck2);
|
|
const initialState = engine.startGame();
|
|
|
|
room.status = 'playing';
|
|
room.gameId = engine.id;
|
|
this.games.set(engine.id, engine);
|
|
|
|
return { success: true, gameId: engine.id, state: initialState };
|
|
}
|
|
|
|
getGame(gameId) {
|
|
return this.games.get(gameId);
|
|
}
|
|
|
|
handleGameAction(gameId, playerId, action) {
|
|
const engine = this.games.get(gameId);
|
|
if (!engine) return { error: 'Game not found' };
|
|
return engine.handleAction(playerId, action);
|
|
}
|
|
|
|
getGameState(gameId, playerId) {
|
|
const engine = this.games.get(gameId);
|
|
if (!engine) return null;
|
|
return engine.getState(playerId);
|
|
}
|
|
|
|
getRooms() {
|
|
const roomList = [];
|
|
for (const room of this.rooms.values()) {
|
|
roomList.push({
|
|
id: room.id,
|
|
name: room.name,
|
|
playerCount: room.players.length,
|
|
maxPlayers: room.maxPlayers,
|
|
status: room.status,
|
|
host: room.players.find((p) => p.id === room.hostId)?.name || 'Unknown',
|
|
});
|
|
}
|
|
return roomList;
|
|
}
|
|
|
|
getRoomDetails(roomId) {
|
|
return this.rooms.get(roomId) || null;
|
|
}
|
|
|
|
getCardList() {
|
|
return ALL_CARDS;
|
|
}
|
|
|
|
getStarterDecks() {
|
|
return STARTER_DECKS;
|
|
}
|
|
}
|
|
|
|
module.exports = { GameManager };
|