mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 07:47:50 +01:00
redesign how players are added and how cards are dealt
This commit is contained in:
@@ -82,7 +82,8 @@ router.patch('/:code/players', async function (req, res) {
|
||||
gameManager.joinGame(game, req.body.playerName, inUseCookie, req.body.joinAsSpectator).then((data) => {
|
||||
res.status(200).send({ cookie: data, environment: gameManager.environment });
|
||||
}).catch((data) => {
|
||||
res.status(data.status).send(data.reason);
|
||||
console.error(data);
|
||||
res.status(data.status || 500).send(data.reason);
|
||||
});
|
||||
} else {
|
||||
res.status(404).send();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const globals = require('../config/globals');
|
||||
const GameStateCurator = require('./GameStateCurator');
|
||||
const UsernameGenerator = require('./UsernameGenerator');
|
||||
const GameCreationRequest = require('../model/GameCreationRequest');
|
||||
const EVENT_IDS = globals.EVENT_IDS;
|
||||
|
||||
@@ -31,23 +30,8 @@ const Events = [
|
||||
(person) => person.id === socketArgs.personId && person.assigned === true
|
||||
);
|
||||
if (toBeClearedIndex >= 0) {
|
||||
const toBeCleared = game.people[toBeClearedIndex];
|
||||
if (toBeCleared.userType === globals.USER_TYPES.SPECTATOR) {
|
||||
game.people.splice(toBeClearedIndex, 1);
|
||||
} else {
|
||||
toBeCleared.assigned = false;
|
||||
toBeCleared.socketId = null;
|
||||
toBeCleared.cookie = (() => {
|
||||
let id = '';
|
||||
for (let i = 0; i < globals.INSTANCE_ID_LENGTH; i ++) {
|
||||
id += globals.INSTANCE_ID_CHAR_POOL[Math.floor(Math.random() * globals.INSTANCE_ID_CHAR_POOL.length)];
|
||||
}
|
||||
return id;
|
||||
})();
|
||||
toBeCleared.hasEnteredName = false;
|
||||
toBeCleared.name = UsernameGenerator.generate();
|
||||
game.isFull = vars.gameManager.isGameFull(game);
|
||||
}
|
||||
game.people.splice(toBeClearedIndex, 1);
|
||||
game.isFull = vars.gameManager.isGameFull(game);
|
||||
}
|
||||
},
|
||||
communicate: async (game, socketArgs, vars) => {
|
||||
@@ -126,6 +110,7 @@ const Events = [
|
||||
stateChange: async (game, socketArgs, vars) => {
|
||||
if (game.isFull) {
|
||||
game.status = globals.STATUS.IN_PROGRESS;
|
||||
vars.gameManager.deal(game);
|
||||
if (game.hasTimer) {
|
||||
game.timerParams.paused = true;
|
||||
await vars.timerManager.runTimer(game, vars.gameManager.namespace, vars.eventManager, vars.gameManager);
|
||||
|
||||
@@ -76,7 +76,7 @@ class GameManager {
|
||||
const newGame = new Game(
|
||||
newAccessCode,
|
||||
globals.STATUS.LOBBY,
|
||||
initializePeopleForGame(req.deck, moderator, this.shuffle, req.isTestGame),
|
||||
null,
|
||||
req.deck,
|
||||
req.hasTimer,
|
||||
moderator.id,
|
||||
@@ -86,6 +86,7 @@ class GameManager {
|
||||
req.timerParams,
|
||||
req.isTestGame
|
||||
);
|
||||
newGame.people = initializePeopleForGame(req.deck, moderator, this.shuffle, req.isTestGame, newGame.gameSize);
|
||||
await this.eventManager.publisher.set(newAccessCode, JSON.stringify(newGame), {
|
||||
EX: globals.STALE_GAME_SECONDS
|
||||
});
|
||||
@@ -142,7 +143,7 @@ class GameManager {
|
||||
checkAvailability = async (code) => {
|
||||
const game = await this.getActiveGame(code.toUpperCase().trim());
|
||||
if (game) {
|
||||
return Promise.resolve({ accessCode: code, playerCount: getGameSize(game.deck), timerParams: game.timerParams });
|
||||
return Promise.resolve({ accessCode: code, playerCount: game.gameSize, timerParams: game.timerParams });
|
||||
} else {
|
||||
return Promise.resolve(404);
|
||||
}
|
||||
@@ -180,40 +181,62 @@ class GameManager {
|
||||
&& game.people.filter(person => person.userType === globals.USER_TYPES.SPECTATOR).length === globals.MAX_SPECTATORS
|
||||
) {
|
||||
return Promise.reject({ status: 400, reason: 'There are too many people already spectating.' });
|
||||
} else if (joinAsSpectator) {
|
||||
} else if (joinAsSpectator || this.isGameFull(game)) {
|
||||
console.log('game is full');
|
||||
return await addSpectator(game, name, this.logger, this.namespace, this.eventManager, this.instanceId, this.refreshGame);
|
||||
}
|
||||
const unassignedPerson = this.findPersonByField(game, 'id', game.currentModeratorId).assigned === false
|
||||
? this.findPersonByField(game, 'id', game.currentModeratorId)
|
||||
: game.people.find((person) => person.assigned === false && person.userType === globals.USER_TYPES.PLAYER);
|
||||
if (unassignedPerson) {
|
||||
this.logger.trace('request from client to join game. Assigning: ' + unassignedPerson.name);
|
||||
unassignedPerson.assigned = true;
|
||||
unassignedPerson.name = name;
|
||||
game.isFull = this.isGameFull(game);
|
||||
await this.refreshGame(game);
|
||||
this.namespace.in(game.accessCode).emit(
|
||||
globals.EVENTS.PLAYER_JOINED,
|
||||
GameStateCurator.mapPerson(unassignedPerson),
|
||||
game.isFull
|
||||
);
|
||||
await this.eventManager.publisher?.publish(
|
||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
||||
this.eventManager.createMessageToPublish(
|
||||
game.accessCode,
|
||||
globals.EVENT_IDS.PLAYER_JOINED,
|
||||
this.instanceId,
|
||||
JSON.stringify(unassignedPerson)
|
||||
)
|
||||
);
|
||||
return Promise.resolve(unassignedPerson.cookie);
|
||||
let moderator, newPlayer;
|
||||
const isModeratorJoining = this.findPersonByField(game, 'id', game.currentModeratorId).assigned === false;
|
||||
if (isModeratorJoining) {
|
||||
moderator = this.findPersonByField(game, 'id', game.currentModeratorId);
|
||||
this.logger.trace('Moderator joining. Assigning: ' + name);
|
||||
moderator.assigned = true;
|
||||
moderator.name = name;
|
||||
} else {
|
||||
if (game.people.filter(person => person.userType === globals.USER_TYPES.SPECTATOR).length === globals.MAX_SPECTATORS) {
|
||||
return Promise.reject({ status: 400, reason: 'This game has reached the maximum number of players and spectators.' });
|
||||
}
|
||||
return await addSpectator(game, name, this.logger, this.namespace, this.eventManager, this.instanceId, this.refreshGame);
|
||||
newPlayer = new Person(
|
||||
createRandomId(),
|
||||
createRandomId(),
|
||||
name,
|
||||
globals.USER_TYPES.PLAYER,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
game.isTestGame
|
||||
);
|
||||
newPlayer.assigned = true;
|
||||
game.people.push(newPlayer);
|
||||
}
|
||||
};
|
||||
game.isFull = this.isGameFull(game);
|
||||
await this.refreshGame(game);
|
||||
this.namespace.in(game.accessCode).emit(
|
||||
globals.EVENTS.PLAYER_JOINED,
|
||||
GameStateCurator.mapPerson(moderator || newPlayer),
|
||||
game.isFull
|
||||
);
|
||||
await this.eventManager.publisher?.publish(
|
||||
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
|
||||
this.eventManager.createMessageToPublish(
|
||||
game.accessCode,
|
||||
globals.EVENT_IDS.PLAYER_JOINED,
|
||||
this.instanceId,
|
||||
JSON.stringify(moderator || newPlayer)
|
||||
)
|
||||
);
|
||||
return Promise.resolve(moderator?.cookie || newPlayer?.cookie);
|
||||
}
|
||||
|
||||
prepareDeck (deck) {
|
||||
const cards = [];
|
||||
for (const card of deck) {
|
||||
for (let i = 0; i < card.quantity; i ++) {
|
||||
cards.push(card);
|
||||
}
|
||||
}
|
||||
|
||||
this.shuffle(cards);
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
restartGame = async (game, namespace, status = globals.STATUS.IN_PROGRESS) => {
|
||||
// kill any outstanding timer threads
|
||||
@@ -227,17 +250,6 @@ class GameManager {
|
||||
delete this.timerManager.timerThreads[game.accessCode];
|
||||
}
|
||||
|
||||
// re-shuffle the deck
|
||||
const cards = [];
|
||||
for (const card of game.deck) {
|
||||
for (let i = 0; i < card.quantity; i ++) {
|
||||
cards.push(card);
|
||||
}
|
||||
}
|
||||
|
||||
this.shuffle(cards);
|
||||
|
||||
// make sure no players are marked as out or revealed, and give them new cards.
|
||||
for (let i = 0; i < game.people.length; i ++) {
|
||||
if (game.people[i].userType === globals.USER_TYPES.KILLED_PLAYER) {
|
||||
game.people[i].userType = globals.USER_TYPES.PLAYER;
|
||||
@@ -247,30 +259,19 @@ class GameManager {
|
||||
game.people[i].userType = globals.USER_TYPES.BOT;
|
||||
game.people[i].out = false;
|
||||
}
|
||||
if (game.people[i].gameRole && game.people[i].id === game.currentModeratorId && game.people[i].userType === globals.USER_TYPES.MODERATOR) {
|
||||
game.people[i].userType = globals.USER_TYPES.TEMPORARY_MODERATOR;
|
||||
game.people[i].out = false;
|
||||
}
|
||||
game.people[i].revealed = false;
|
||||
game.people[i].killed = false;
|
||||
if (game.people[i].gameRole) {
|
||||
game.people[i].gameRole = cards[i].role;
|
||||
game.people[i].gameRoleDescription = cards[i].description;
|
||||
game.people[i].alignment = cards[i].team;
|
||||
if (game.people[i].id === game.currentModeratorId && game.people[i].userType === globals.USER_TYPES.MODERATOR) {
|
||||
game.people[i].userType = globals.USER_TYPES.TEMPORARY_MODERATOR;
|
||||
game.people[i].out = false;
|
||||
}
|
||||
}
|
||||
game.people[i].gameRole = null;
|
||||
game.people[i].gameRoleDescription = null;
|
||||
game.people[i].alignment = null;
|
||||
game.people[i].customRole = null;
|
||||
}
|
||||
|
||||
if (status === globals.STATUS.IN_PROGRESS) {
|
||||
game.status = globals.STATUS.IN_PROGRESS;
|
||||
if (game.hasTimer) {
|
||||
game.timerParams.paused = true;
|
||||
game.timerParams.timeRemaining = convertFromHoursToMilliseconds(game.timerParams.hours) +
|
||||
convertFromMinutesToMilliseconds(game.timerParams.minutes);
|
||||
await this.timerManager.runTimer(game, namespace, this.eventManager, this);
|
||||
}
|
||||
} else {
|
||||
game.status = globals.STATUS.LOBBY;
|
||||
}
|
||||
game.status = globals.STATUS.LOBBY;
|
||||
|
||||
await this.refreshGame(game);
|
||||
await this.eventManager.publisher?.publish(
|
||||
@@ -302,12 +303,24 @@ class GameManager {
|
||||
return array;
|
||||
};
|
||||
|
||||
deal = () => {
|
||||
|
||||
deal = (game) => {
|
||||
const cards = this.prepareDeck(game.deck);
|
||||
let i = 0;
|
||||
for (const person of game.people.filter(person => person.userType === globals.USER_TYPES.PLAYER
|
||||
|| person.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
|| person.userType === globals.USER_TYPES.BOT)
|
||||
) {
|
||||
person.gameRole = cards[i].role;
|
||||
person.customRole = cards[i].custom;
|
||||
person.gameRoleDescription = cards[i].description;
|
||||
person.alignment = cards[i].team;
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
|
||||
isGameFull = (game) => {
|
||||
return !game.people.find((person) => person.userType === globals.USER_TYPES.PLAYER && person.assigned === false);
|
||||
return game.people.filter(person => person.userType === globals.USER_TYPES.PLAYER
|
||||
|| person.userType === globals.USER_TYPES.TEMPORARY_MODERATOR).length === game.gameSize;
|
||||
}
|
||||
|
||||
findPersonByField = (game, fieldName, value) => {
|
||||
@@ -326,46 +339,29 @@ function initializeModerator (name, hasDedicatedModerator) {
|
||||
return new Person(createRandomId(), createRandomId(), name, userType);
|
||||
}
|
||||
|
||||
function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame) {
|
||||
function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame, gameSize) {
|
||||
const people = [];
|
||||
|
||||
const cards = [];
|
||||
for (const role of uniqueRoles) {
|
||||
for (let i = 0; i < role.quantity; i ++) {
|
||||
cards.push(role);
|
||||
if (isTestGame) {
|
||||
let j = 0;
|
||||
const number = moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
? gameSize - 1
|
||||
: gameSize;
|
||||
while (j < number) {
|
||||
const person = new Person(
|
||||
createRandomId(),
|
||||
createRandomId(),
|
||||
UsernameGenerator.generate(),
|
||||
globals.USER_TYPES.BOT,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
isTestGame
|
||||
);
|
||||
people.push(person);
|
||||
j ++;
|
||||
}
|
||||
}
|
||||
|
||||
shuffle(cards); // this shuffles in-place.
|
||||
|
||||
let j = 0;
|
||||
const number = moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
? cards.length - 1
|
||||
: cards.length;
|
||||
while (j < number) {
|
||||
const person = new Person(
|
||||
createRandomId(),
|
||||
createRandomId(),
|
||||
UsernameGenerator.generate(),
|
||||
isTestGame ? globals.USER_TYPES.BOT : globals.USER_TYPES.PLAYER,
|
||||
cards[j].role,
|
||||
cards[j].description,
|
||||
cards[j].team,
|
||||
isTestGame
|
||||
);
|
||||
person.customRole = cards[j].custom;
|
||||
person.hasEnteredName = false;
|
||||
people.push(person);
|
||||
j ++;
|
||||
}
|
||||
|
||||
if (moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
moderator.gameRole = cards[cards.length - 1].role;
|
||||
moderator.customRole = cards[cards.length - 1].custom;
|
||||
moderator.gameRoleDescription = cards[cards.length - 1].description;
|
||||
moderator.alignment = cards[cards.length - 1].team;
|
||||
}
|
||||
|
||||
people.push(moderator);
|
||||
|
||||
return people;
|
||||
@@ -384,15 +380,6 @@ function isNameTaken (game, name) {
|
||||
return game.people.find((person) => person.name.toLowerCase().trim() === processedName);
|
||||
}
|
||||
|
||||
function getGameSize (cards) {
|
||||
let quantity = 0;
|
||||
for (const card of cards) {
|
||||
quantity += card.quantity;
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
async function addSpectator (game, name, logger, namespace, eventManager, instanceId, refreshGame) {
|
||||
const spectator = new Person(
|
||||
createRandomId(),
|
||||
|
||||
Reference in New Issue
Block a user