Implement main game mechanic

This commit is contained in:
2025-03-01 00:18:01 +01:00
parent 0a4a9a9d0e
commit 7d7dd263fe
8 changed files with 991 additions and 65 deletions

198
server/controller/game.js Normal file
View File

@ -0,0 +1,198 @@
const roomController = require('./room');
const SONGS = [
{ id: 1, title: "Black Steam", artist: "Carrot Quest GmbH", coverUrl: "https://mir-s3-cdn-cf.behance.net/project_modules/1400/fe529a64193929.5aca8500ba9ab.jpg" },
{ id: 2, title: "Sunset Dreams", artist: "Ocean Waves", coverUrl: "https://place-hold.it/500x500/" },
{ id: 3, title: "Neon Nights", artist: "Electric Avenue", coverUrl: "https://place-hold.it/500x500/" },
{ id: 4, title: "Mountain Echo", artist: "Wild Terrain", coverUrl: "https://place-hold.it/500x500/" },
{ id: 5, title: "Urban Jungle", artist: "City Dwellers", coverUrl: "https://place-hold.it/500x500/" },
{ id: 6, title: "Cosmic Journey", artist: "Stargazers", coverUrl: "https://place-hold.it/500x500/" }
];
const gameStates = {};
const initializeGameState = (roomId) => {
if (!gameStates[roomId]) {
gameStates[roomId] = {
round: 0,
phase: 'waiting',
roles: {},
selectedSong: null,
scores: {},
songOptions: [],
guessResults: {},
currentComposer: null,
roundStartTime: null,
phaseTimeLimit: {
composing: 30,
guessing: 30
},
lastFrequency: 440,
};
const users = roomController.getRoomUsers(roomId);
users.forEach(user => {
gameStates[roomId].scores[user.id] = 0;
});
}
return gameStates[roomId];
};
const startNewRound = (roomId) => {
const gameState = gameStates[roomId];
if (!gameState) return false;
gameState.round += 1;
gameState.phase = 'composing';
gameState.guessResults = {};
gameState.roundStartTime = Date.now();
const users = roomController.getRoomUsers(roomId);
if (users.length < 2) return false;
console.log(`Starting round ${gameState.round} in room ${roomId} with ${users.length} users`);
gameState.roles = {};
if (gameState.round === 1 || !gameState.currentComposer) {
const composerIndex = Math.floor(Math.random() * users.length);
gameState.currentComposer = users[composerIndex].id;
} else {
const currentIndex = users.findIndex(user => user.id === gameState.currentComposer);
if (currentIndex === -1) {
const composerIndex = Math.floor(Math.random() * users.length);
gameState.currentComposer = users[composerIndex].id;
} else {
const nextIndex = (currentIndex + 1) % users.length;
gameState.currentComposer = users[nextIndex].id;
}
}
users.forEach(user => {
gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser';
console.log(`User ${user.name} (${user.id}) assigned role: ${gameState.roles[user.id]}`);
});
gameState.selectedSong = SONGS[Math.floor(Math.random() * SONGS.length)];
const songOptions = [...SONGS].sort(() => Math.random() - 0.5).slice(0, 5);
if (!songOptions.includes(gameState.selectedSong)) {
songOptions[Math.floor(Math.random() * songOptions.length)] = gameState.selectedSong;
}
gameState.songOptions = songOptions;
return true;
};
const getTimeRemaining = (roomId) => {
const gameState = gameStates[roomId];
if (!gameState || !gameState.roundStartTime) return 0;
const phaseDuration = gameState.phaseTimeLimit[gameState.phase] * 1000;
const timeElapsed = Date.now() - gameState.roundStartTime;
const timeRemaining = Math.max(0, phaseDuration - timeElapsed);
return Math.ceil(timeRemaining / 1000);
};
const advancePhase = (roomId) => {
const gameState = gameStates[roomId];
if (!gameState) return false;
if (gameState.phase === 'composing') {
gameState.phase = 'guessing';
gameState.roundStartTime = Date.now();
return true;
} else if (gameState.phase === 'guessing') {
gameState.phase = 'results';
return true;
} else if (gameState.phase === 'results') {
return startNewRound(roomId);
}
return false;
};
const updateFrequency = (roomId, frequency) => {
if (!gameStates[roomId]) return false;
gameStates[roomId].lastFrequency = frequency;
return true;
};
const getCurrentFrequency = (roomId) => {
return gameStates[roomId]?.lastFrequency || 440;
};
const submitGuess = (roomId, userId, songId) => {
const gameState = gameStates[roomId];
if (!gameState || gameState.phase !== 'guessing' || gameState.roles[userId] !== 'guesser') {
return false;
}
const isCorrect = gameState.selectedSong.id === songId;
gameState.guessResults[userId] = {
songId,
isCorrect,
points: isCorrect ? 10 : 0
};
if (isCorrect) {
gameState.scores[userId] = (gameState.scores[userId] || 0) + 10;
}
return {
isCorrect,
correctSong: gameState.selectedSong,
points: isCorrect ? 10 : 0
};
};
const getRoundResults = (roomId) => {
const gameState = gameStates[roomId];
if (!gameState) return null;
return {
round: gameState.round,
selectedSong: gameState.selectedSong,
guessResults: gameState.guessResults,
scores: gameState.scores
};
};
const getRoles = (roomId) => {
return gameStates[roomId]?.roles || {};
};
const getUserRole = (roomId, userId) => {
return gameStates[roomId]?.roles[userId] || null;
};
const getSongOptions = (roomId) => {
return gameStates[roomId]?.songOptions || [];
};
const getSelectedSong = (roomId) => {
return gameStates[roomId]?.selectedSong || null;
};
const cleanupGameState = (roomId) => {
delete gameStates[roomId];
};
module.exports = {
initializeGameState,
startNewRound,
getTimeRemaining,
advancePhase,
updateFrequency,
getCurrentFrequency,
submitGuess,
getRoundResults,
getRoles,
getUserRole,
getSongOptions,
getSelectedSong,
cleanupGameState
};