diff --git a/client/config/globals.js b/client/config/globals.js
index 901ecf9..52f6f4b 100644
--- a/client/config/globals.js
+++ b/client/config/globals.js
@@ -5,17 +5,20 @@ export const globals = {
ACCESS_CODE_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
COMMANDS: {
FETCH_GAME_STATE: 'fetchGameState',
- GET_ENVIRONMENT: 'getEnvironment'
+ GET_ENVIRONMENT: 'getEnvironment',
+ START_GAME: 'startGame'
},
- GAME_STATE: {
- LOBBY: 'lobby'
+ STATUS: {
+ LOBBY: "lobby",
+ IN_PROGRESS: "in progress"
},
ALIGNMENT: {
GOOD: "good",
EVIL: "evil"
},
EVENTS: {
- PLAYER_JOINED: "playerJoined"
+ PLAYER_JOINED: "playerJoined",
+ SYNC_GAME_STATE: "syncGameState"
},
USER_TYPES: {
MODERATOR: "moderator",
diff --git a/client/model/Game.js b/client/model/Game.js
index 763a34f..d901851 100644
--- a/client/model/Game.js
+++ b/client/model/Game.js
@@ -4,6 +4,7 @@ export class Game {
this.hasTimer = hasTimer;
this.moderatorName = moderatorName;
this.timerParams = timerParams;
- this.hasDedicatedModerator = hasDedicatedModerator
+ this.hasDedicatedModerator = hasDedicatedModerator;
+ this.accessCode = null;
}
}
diff --git a/client/modules/GameStateRenderer.js b/client/modules/GameStateRenderer.js
index 3c22239..b7cc8e4 100644
--- a/client/modules/GameStateRenderer.js
+++ b/client/modules/GameStateRenderer.js
@@ -61,6 +61,25 @@ export class GameStateRenderer {
cardEl.classList.add('lobby-card')
}
}
+
+ renderGameHeader() {
+ let title = document.createElement("h1");
+ title.innerText = "Game";
+ document.querySelector('#game-title h1')?.remove();
+ document.getElementById("game-title").appendChild(title);
+ }
+
+ renderPlayerRole() {
+ let name = document.querySelector('#role-name');
+ name.innerText = this.gameState.client.gameRole;
+ if (this.gameState.client.alignment === globals.ALIGNMENT.GOOD) {
+ name.classList.add('good');
+ } else {
+ name.classList.add('evil');
+ }
+ name.setAttribute("title", this.gameState.client.gameRole);
+ document.querySelector('#role-description').innerText = this.gameState.client.gameRoleDescription;
+ }
}
function renderClient(client, container) {
diff --git a/client/modules/Templates.js b/client/modules/Templates.js
index ca547d6..51ad6fd 100644
--- a/client/modules/Templates.js
+++ b/client/modules/Templates.js
@@ -24,5 +24,22 @@ export const templates = {
START_GAME_PROMPT:
"
" +
"" +
+ "
",
+ GAME:
+ "" +
+ "" +
+ "" +
+ "
" +
+ "
![role]()
" +
+ "
" +
"
"
}
diff --git a/client/scripts/game.js b/client/scripts/game.js
index f4426ad..f9a5c52 100644
--- a/client/scripts/game.js
+++ b/client/scripts/game.js
@@ -2,7 +2,7 @@ import { UserUtility } from "../modules/UserUtility.js";
import { globals } from "../config/globals.js";
import {templates} from "../modules/Templates.js";
import {GameStateRenderer} from "../modules/GameStateRenderer.js";
-import {toast} from "../modules/Toast.js";
+import {cancelCurrentToast, toast} from "../modules/Toast.js";
export const game = () => {
socket.emit(globals.COMMANDS.GET_ENVIRONMENT, function(environment) {
@@ -15,6 +15,7 @@ export const game = () => {
window.location.replace('/not-found');
} else {
console.log(gameState);
+ gameState.accessCode = accessCode;
userId = gameState.client.id;
UserUtility.setAnonymousUserId(userId, environment);
let gameStateRenderer = new GameStateRenderer(gameState);
@@ -29,8 +30,9 @@ export const game = () => {
};
function processGameState (gameState, userId, socket, gameStateRenderer) {
+ cancelCurrentToast();
switch (gameState.status) {
- case globals.GAME_STATE.LOBBY:
+ case globals.STATUS.LOBBY:
document.getElementById("game-state-container").innerHTML = templates.LOBBY;
gameStateRenderer.renderLobbyHeader();
gameStateRenderer.renderLobbyPlayers();
@@ -41,9 +43,16 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
|| gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
)
) {
- displayStartGamePromptForModerators();
+ displayStartGamePromptForModerators(gameStateRenderer);
}
break;
+ case globals.STATUS.IN_PROGRESS:
+ document.querySelector("#start-game-prompt")?.remove();
+ gameStateRenderer.gameState = gameState;
+ document.getElementById("game-state-container").innerHTML = templates.GAME;
+ gameStateRenderer.renderGameHeader();
+ gameStateRenderer.renderPlayerRole();
+ break;
default:
break;
}
@@ -61,14 +70,32 @@ function setClientSocketHandlers(gameStateRenderer, socket) {
|| gameStateRenderer.gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
)
) {
- displayStartGamePromptForModerators();
+ displayStartGamePromptForModerators(gameStateRenderer);
}
+ });
+
+ socket.on(globals.EVENTS.SYNC_GAME_STATE, () => {
+ socket.emit(
+ globals.COMMANDS.FETCH_GAME_STATE,
+ gameStateRenderer.gameState.accessCode,
+ gameStateRenderer.gameState.client.id,
+ function (gameState) {
+ processGameState(gameState, gameState.client.id, socket, gameStateRenderer);
+ }
+ );
})
}
-function displayStartGamePromptForModerators() {
+function displayStartGamePromptForModerators(gameStateRenderer) {
document.getElementById("lobby-players").setAttribute("style", 'margin-bottom: 130px');
let div = document.createElement("div");
div.innerHTML = templates.START_GAME_PROMPT;
document.body.appendChild(div);
+ document.getElementById("start-game-button").addEventListener('click', (e) => {
+ e.preventDefault();
+ if (confirm("Start the game and deal roles?")) {
+ socket.emit(globals.COMMANDS.START_GAME, gameStateRenderer.gameState.accessCode, gameStateRenderer.gameState.client.id);
+ }
+
+ });
}
diff --git a/client/styles/game.css b/client/styles/game.css
index ecdddc9..62c8ef3 100644
--- a/client/styles/game.css
+++ b/client/styles/game.css
@@ -62,6 +62,61 @@ h1 {
font-size: 25px;
}
+#game-role {
+ position: relative;
+ border-bottom: 2px solid gray;
+ background-color: #e7e7e7;
+ display: flex;
+ flex-direction: column;
+ cursor: pointer;
+ justify-content: space-between;
+ max-width: 17em;
+ border-radius: 3px;
+ height: 23em;
+ margin: 0 auto 2em auto;
+ width: 100%;
+ box-shadow: 0 1px 1px rgba(0,0,0,0.11),
+ 0 2px 2px rgba(0,0,0,0.11),
+ 0 4px 4px rgba(0,0,0,0.11),
+ 0 8px 8px rgba(0,0,0,0.11),
+ 0 16px 16px rgba(0,0,0,0.11),
+ 0 32px 32px rgba(0,0,0,0.11);
+ /*perspective: 1000px;*/
+ /*transform-style: preserve-3d;*/
+}
+
+#role-name {
+ position: absolute;
+ top: 6%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 20px;
+ font-family: 'diavlo', sans-serif;
+ width: 95%;
+ text-align: center;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+#role-image {
+ position: absolute;
+ top: 34%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+#role-description {
+ overflow: auto;
+ position: absolute;
+ bottom: 8%;
+ left: 50%;
+ transform: translate(-50%, 0);
+ font-size: 16px;
+ width: 78%;
+ max-height: 7em;
+}
+
#game-link img {
width: 20px;
margin-left: 0.5em;
diff --git a/server/config/globals.js b/server/config/globals.js
index a943580..15fa0cc 100644
--- a/server/config/globals.js
+++ b/server/config/globals.js
@@ -3,7 +3,8 @@ const globals = {
ACCESS_CODE_LENGTH: 6,
CLIENT_COMMANDS: {
FETCH_GAME_STATE: 'fetchGameState',
- GET_ENVIRONMENT: 'getEnvironment'
+ GET_ENVIRONMENT: 'getEnvironment',
+ START_GAME: 'startGame'
},
STATUS: {
LOBBY: "lobby",
@@ -19,7 +20,8 @@ const globals = {
GAME_IS_FULL: "This game is full"
},
EVENTS: {
- PLAYER_JOINED: "playerJoined"
+ PLAYER_JOINED: "playerJoined",
+ SYNC_GAME_STATE: "syncGameState"
},
ENVIRONMENT: {
LOCAL: "local",
diff --git a/server/model/Person.js b/server/model/Person.js
index 1df969e..1886e3d 100644
--- a/server/model/Person.js
+++ b/server/model/Person.js
@@ -1,11 +1,13 @@
+// noinspection DuplicatedCode
class Person {
- constructor(id, name, userType, gameRole=null, gameRoleDescription=null, assigned=false) {
+ constructor(id, name, userType, gameRole=null, gameRoleDescription=null, alignment=null, assigned=false) {
this.id = id;
this.socketId = null;
this.name = name;
this.userType = userType;
this.gameRole = gameRole;
this.gameRoleDescription = gameRoleDescription;
+ this.alignment = alignment;
this.assigned = assigned;
this.out = false;
}
diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js
index 348fbab..42e2d1c 100644
--- a/server/modules/GameManager.js
+++ b/server/modules/GameManager.js
@@ -30,7 +30,15 @@ class GameManager {
socket.on(globals.CLIENT_COMMANDS.GET_ENVIRONMENT, (ackFn) => {
ackFn(this.environment);
- })
+ });
+
+ socket.on(globals.CLIENT_COMMANDS.START_GAME, (accessCode, personId) => {
+ let game = this.activeGameRunner.activeGames[accessCode];
+ if (game) {
+ game.status = globals.STATUS.IN_PROGRESS;
+ namespace.in(accessCode).emit(globals.EVENTS.SYNC_GAME_STATE);
+ }
+ });
}
@@ -44,15 +52,12 @@ class GameManager {
let moderator = initializeModerator(gameParams.moderatorName, gameParams.hasDedicatedModerator);
this.activeGameRunner.activeGames[newAccessCode] = new Game(
globals.STATUS.LOBBY,
- initializePeopleForGame(gameParams.deck),
+ initializePeopleForGame(gameParams.deck, moderator),
gameParams.deck,
gameParams.hasTimer,
moderator,
gameParams.timerParams
);
- if (!gameParams.hasDedicatedModerator) {
- this.activeGameRunner.activeGames[newAccessCode].people.push(moderator);
- }
return Promise.resolve(newAccessCode);
}
}
@@ -96,7 +101,7 @@ function initializeModerator(name, hasDedicatedModerator) {
return new Person(createRandomUserId(), name, userType)
}
-function initializePeopleForGame(uniqueCards) {
+function initializePeopleForGame(uniqueCards, moderator) {
let people = [];
let cards = []; // this will contain copies of each card equal to the quantity.
let numberOfRoles = 0;
@@ -109,8 +114,18 @@ function initializePeopleForGame(uniqueCards) {
cards = shuffleArray(cards); // The deck should probably be shuffled, ey?.
- for(let j = 0; j < numberOfRoles; j ++) {
- people.push(new Person(createRandomUserId(), UsernameGenerator.generate(), globals.USER_TYPES.PLAYER, cards[j].role, cards[j].description))
+ let j = 0;
+ if (moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) { // temporary moderators should be dealt in.
+ moderator.gameRole = cards[j].role;
+ moderator.gameRoleDescription = cards[j].description;
+ moderator.alignment = cards[j].team;
+ people.push(moderator);
+ j ++;
+ }
+
+ while (j < numberOfRoles) {
+ people.push(new Person(createRandomUserId(), UsernameGenerator.generate(), globals.USER_TYPES.PLAYER, cards[j].role, cards[j].description, cards[j].team))
+ j ++;
}
return people;
diff --git a/server/modules/GameStateCurator.js b/server/modules/GameStateCurator.js
index 27e32a7..9ed1320 100644
--- a/server/modules/GameStateCurator.js
+++ b/server/modules/GameStateCurator.js
@@ -13,7 +13,8 @@ function getGameStateBasedOnPermissions(game, person) {
name: person.name,
id: person.id,
gameRole: person.gameRole,
- roleDescription: person.roleDescription
+ gameRoleDescription: person.gameRoleDescription,
+ alignment: person.alignment
}
switch (person.userType) {
case globals.USER_TYPES.PLAYER:
@@ -66,7 +67,8 @@ function mapPeopleForModerator(people, client) {
.map((person) => ({
name: person.name,
gameRole: person.gameRole,
- gameRoleDescription: person.gameRoleDescription
+ gameRoleDescription: person.gameRoleDescription,
+ alignment: person.alignment
}));
}