mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
add bots to a game
This commit is contained in:
@@ -81,7 +81,8 @@ export const globals = {
|
||||
PLAYER: 'player',
|
||||
TEMPORARY_MODERATOR: 'temp mod',
|
||||
KILLED_PLAYER: 'killed',
|
||||
SPECTATOR: 'spectator'
|
||||
SPECTATOR: 'spectator',
|
||||
BOT: 'bot'
|
||||
},
|
||||
ENVIRONMENT: {
|
||||
LOCAL: 'local',
|
||||
@@ -92,6 +93,7 @@ export const globals = {
|
||||
moderator: ' \uD83D\uDC51',
|
||||
'temp mod': ' \uD83C\uDFAE\uD83D\uDC51',
|
||||
spectator: ' \uD83D\uDC7B',
|
||||
killed: '\uD83D\uDC80'
|
||||
killed: '\uD83D\uDC80',
|
||||
bot: '\uD83E\uDD16'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
export class Game {
|
||||
constructor (deck, hasTimer, hasDedicatedModerator, moderatorName, timerParams = null) {
|
||||
constructor (deck, hasTimer, hasDedicatedModerator, moderatorName, timerParams = null, isTestGame = false) {
|
||||
this.deck = deck;
|
||||
this.hasTimer = hasTimer;
|
||||
this.timerParams = timerParams;
|
||||
this.hasDedicatedModerator = hasDedicatedModerator;
|
||||
this.moderatorName = moderatorName;
|
||||
this.isTestGame = isTestGame;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,13 @@ export const HTMLFragments = {
|
||||
<div>
|
||||
<input type="text" id="moderator-name" autocomplete='given-name' placeholder="enter your name...">
|
||||
</div>
|
||||
<div>
|
||||
<label for="test-game">Populate the game with bots?</label>
|
||||
<select id="test-game">
|
||||
<option value="no" selected>No</option>
|
||||
<option value="yes">Yes</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>`,
|
||||
START_GAME_PROMPT:
|
||||
`<div>
|
||||
@@ -120,7 +127,7 @@ export const HTMLFragments = {
|
||||
TRANSFER_MOD_MODAL:
|
||||
`<div id='transfer-mod-modal-background' class='modal-background'></div>
|
||||
<div tabindex='-1' id='transfer-mod-modal' class='modal'>
|
||||
<h3>Transfer Mod Powers 👑</h3>
|
||||
<h2>Select a new moderator 👑</h2>
|
||||
<div id='transfer-mod-modal-content'></div>
|
||||
<div class='modal-button-container'>
|
||||
<button id='close-mod-transfer-modal-button' class='app-button cancel'>Cancel</button>
|
||||
|
||||
@@ -130,7 +130,8 @@ export class GameCreationStepManager {
|
||||
this.currentGame.hasTimer,
|
||||
this.currentGame.hasDedicatedModerator,
|
||||
this.currentGame.moderatorName,
|
||||
this.currentGame.timerParams
|
||||
this.currentGame.timerParams,
|
||||
this.currentGame.isTestGame
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -304,6 +305,12 @@ function renderNameStep (containerId, step, game, steps) {
|
||||
const nameInput = document.querySelector('#moderator-name');
|
||||
nameInput.value = game.moderatorName;
|
||||
nameInput.addEventListener('keyup', steps['4'].forwardHandler);
|
||||
|
||||
const testGameInput = document.getElementById('test-game');
|
||||
testGameInput.onchange = (event) => {
|
||||
game.isTestGame = testGameInput.value === 'yes';
|
||||
};
|
||||
testGameInput.value = game.isTestGame ? 'yes' : 'no';
|
||||
}
|
||||
|
||||
function renderModerationTypeStep (game, containerId, stepNumber) {
|
||||
@@ -390,22 +397,28 @@ function renderReviewAndCreateStep (containerId, stepNumber, game, deckManager)
|
||||
|
||||
div.innerHTML =
|
||||
'<div>' +
|
||||
"<label for='mod-name'>Your name</label>" +
|
||||
"<label for='mod-name'>Your name:</label>" +
|
||||
"<div id='mod-name' class='review-option'></div>" +
|
||||
'</div>' +
|
||||
'<div>' +
|
||||
"<label for='mod-option'>Moderation</label>" +
|
||||
"<label for='test-game'>Populate game with bots?</label>" +
|
||||
"<div id='test-game' class='review-option'></div>" +
|
||||
'</div>' +
|
||||
'<div>' +
|
||||
"<label for='mod-option'>Moderation:</label>" +
|
||||
"<div id='mod-option' class='review-option'></div>" +
|
||||
'</div>' +
|
||||
'<div>' +
|
||||
"<label for='timer-option'>Timer</label>" +
|
||||
"<label for='timer-option'>Timer:</label>" +
|
||||
"<div id='timer-option' class='review-option'></div>" +
|
||||
'</div>' +
|
||||
'<div>' +
|
||||
"<label id='roles-option-label' for='roles-option'>Game Deck</label>" +
|
||||
"<label id='roles-option-label' for='roles-option'>Game Deck:</label>" +
|
||||
"<div id='roles-option' class='review-option'></div>" +
|
||||
'</div>';
|
||||
|
||||
div.querySelector('#test-game').innerText = game.isTestGame ? 'Yes' : 'No';
|
||||
|
||||
div.querySelector('#mod-option').innerText = game.hasDedicatedModerator
|
||||
? "Dedicated Moderator - don't deal me a card."
|
||||
: 'Temporary Moderator - deal me into the game.';
|
||||
|
||||
@@ -28,8 +28,7 @@ export class Ended {
|
||||
const modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null;
|
||||
renderGroupOfPlayers(
|
||||
this.stateBucket.currentGameState.people.filter(
|
||||
p => p.userType === globals.USER_TYPES.PLAYER
|
||||
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
p => (p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR)
|
||||
|| p.killed
|
||||
),
|
||||
this.stateBucket.currentGameState.accessCode,
|
||||
|
||||
@@ -101,8 +101,7 @@ export class InProgress {
|
||||
: null;
|
||||
this.renderGroupOfPlayers(
|
||||
this.stateBucket.currentGameState.people.filter(
|
||||
p => p.userType === globals.USER_TYPES.PLAYER
|
||||
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
p => (p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR)
|
||||
|| p.killed
|
||||
),
|
||||
this.killPlayerHandlers,
|
||||
@@ -168,7 +167,9 @@ export class InProgress {
|
||||
if (killedPerson) {
|
||||
killedPerson.out = true;
|
||||
killedPerson.killed = true;
|
||||
killedPerson.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||
killedPerson.userType = killedPerson.userType === globals.USER_TYPES.BOT
|
||||
? globals.USER_TYPES.KILLED_BOT
|
||||
: globals.USER_TYPES.KILLED_PLAYER;
|
||||
if (this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR) {
|
||||
toast(killedPerson.name + ' killed.', 'success', true, true, 'medium');
|
||||
this.renderPlayersWithRoleAndAlignmentInfo(this.stateBucket.currentGameState.status === globals.STATUS.ENDED);
|
||||
@@ -253,14 +254,12 @@ export class InProgress {
|
||||
});
|
||||
const teamGood = this.stateBucket.currentGameState.people.filter(
|
||||
(p) => p.alignment === globals.ALIGNMENT.GOOD
|
||||
&& (p.userType === globals.USER_TYPES.PLAYER
|
||||
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
&& ((p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR)
|
||||
|| p.killed)
|
||||
|
||||
);
|
||||
const teamEvil = this.stateBucket.currentGameState.people.filter((p) => p.alignment === globals.ALIGNMENT.EVIL
|
||||
&& (p.userType === globals.USER_TYPES.PLAYER
|
||||
|| p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
&& ((p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR)
|
||||
|| p.killed)
|
||||
);
|
||||
this.renderGroupOfPlayers(
|
||||
@@ -385,7 +384,8 @@ export class InProgress {
|
||||
);
|
||||
|
||||
if (document.querySelectorAll('.potential-moderator').length === 0) {
|
||||
document.getElementById('transfer-mod-modal-content').innerText = 'There is nobody available to transfer to.';
|
||||
document.getElementById('transfer-mod-modal-content').innerText =
|
||||
'There is nobody available to transfer to. Only spectators or killed players (who are not bots) can be mods.';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ export class Lobby {
|
||||
const lobbyPlayersContainer = this.container.querySelector('#lobby-players');
|
||||
const sorted = this.stateBucket.currentGameState.people.sort(
|
||||
function (a, b) {
|
||||
if (a.userType === globals.USER_TYPES.MODERATOR) {
|
||||
if (a.userType === globals.USER_TYPES.MODERATOR || a.userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
@@ -92,7 +92,7 @@ export class Lobby {
|
||||
lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name, person.userType));
|
||||
}
|
||||
const playerCount = this.stateBucket.currentGameState.people.filter(
|
||||
p => p.userType === globals.USER_TYPES.PLAYER || p.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|
||||
p => p.userType !== globals.USER_TYPES.MODERATOR && p.userType !== globals.USER_TYPES.SPECTATOR
|
||||
).length;
|
||||
document.querySelector("label[for='lobby-players']").innerText =
|
||||
'Participants (' + playerCount + '/' + this.stateBucket.currentGameState.gameSize + ' Players)';
|
||||
@@ -194,7 +194,7 @@ function renderLobbyPerson (name, userType) {
|
||||
personNameEl.innerText = name;
|
||||
personTypeEl.innerText = userType + globals.USER_TYPE_ICONS[userType];
|
||||
el.classList.add('lobby-player');
|
||||
if (userType === globals.USER_TYPES.MODERATOR) {
|
||||
if (userType === globals.USER_TYPES.MODERATOR || userType === globals.USER_TYPES.TEMPORARY_MODERATOR) {
|
||||
el.classList.add('moderator');
|
||||
}
|
||||
|
||||
|
||||
@@ -209,6 +209,12 @@ a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
border-radius: 5px;
|
||||
border: 2px solid #d7d7d7;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
textarea, input {
|
||||
font-family: 'signika-negative', sans-serif;
|
||||
font-size: 16px;
|
||||
@@ -572,7 +578,8 @@ input {
|
||||
}
|
||||
|
||||
.good, .compact-card.good .card-role {
|
||||
color: #5f7cfb;
|
||||
color: #5f7cfb !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.good-players, #deck-good {
|
||||
@@ -584,7 +591,8 @@ input {
|
||||
}
|
||||
|
||||
.evil, .compact-card.evil .card-role {
|
||||
color: #e73333;
|
||||
color: #dd2929 !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@keyframes placeholder {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #2d2c38;
|
||||
background-color: #16141e;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 25em;
|
||||
|
||||
@@ -314,6 +314,15 @@ option {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#step-4 div:nth-child(2) {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
#step-4 label[for="test-game"] {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#step-4 input {
|
||||
padding: 15px 5px;
|
||||
width: 95%;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #171522;
|
||||
background-color: #000000;
|
||||
color: #e7e7e7;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
@@ -19,6 +19,12 @@
|
||||
|
||||
.potential-moderator {
|
||||
margin: 0.5em auto;
|
||||
border: 2px solid #46455299;
|
||||
background: #4645523b;
|
||||
}
|
||||
|
||||
#transfer-mod-modal h2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#lobby-players {
|
||||
@@ -615,14 +621,14 @@ label[for='moderator'] {
|
||||
|
||||
canvas {
|
||||
border-radius: 5px;
|
||||
margin: 1em;
|
||||
margin: 20px 5px;
|
||||
}
|
||||
|
||||
.game-player {
|
||||
border-left: 3px solid #21ba45;
|
||||
display: flex;
|
||||
color: #d7d7d7;
|
||||
background-color: #171522;
|
||||
color: #f1f1f1;
|
||||
background-color: #000000;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
justify-content: space-between;
|
||||
@@ -714,6 +720,7 @@ canvas {
|
||||
|
||||
.game-player-role {
|
||||
min-width: 7em;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
|
||||
.game-player.killed {
|
||||
@@ -800,9 +807,10 @@ canvas {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
min-height: 25em;
|
||||
background-color: #3b3a4a;
|
||||
border: 1px solid #46455299;
|
||||
background: #4645523b;
|
||||
max-width: 35em;
|
||||
min-width: 17em;
|
||||
min-width: 19em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,9 @@ const globals = {
|
||||
PLAYER: 'player',
|
||||
TEMPORARY_MODERATOR: 'temp mod',
|
||||
KILLED_PLAYER: 'killed',
|
||||
SPECTATOR: 'spectator'
|
||||
KILLED_BOT: 'killed bot',
|
||||
SPECTATOR: 'spectator',
|
||||
BOT: 'bot'
|
||||
},
|
||||
ERROR_MESSAGE: {
|
||||
GAME_IS_FULL: 'This game is full',
|
||||
|
||||
@@ -9,7 +9,8 @@ class Game {
|
||||
hasDedicatedModerator,
|
||||
originalModeratorId,
|
||||
createTime,
|
||||
timerParams = null
|
||||
timerParams = null,
|
||||
isTestGame = false
|
||||
) {
|
||||
this.accessCode = accessCode;
|
||||
this.status = status;
|
||||
@@ -26,7 +27,7 @@ class Game {
|
||||
this.previousModeratorId = null;
|
||||
this.createTime = createTime;
|
||||
this.timerParams = timerParams;
|
||||
this.isFull = this.gameSize === 1 && !this.hasDedicatedModerator;
|
||||
this.isFull = (this.gameSize === 1 && !this.hasDedicatedModerator) || isTestGame;
|
||||
this.timeRemaining = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,19 @@ class GameCreationRequest {
|
||||
hasTimer,
|
||||
timerParams,
|
||||
moderatorName,
|
||||
hasDedicatedModerator
|
||||
hasDedicatedModerator,
|
||||
isTestGame
|
||||
) {
|
||||
this.deck = deck;
|
||||
this.hasTimer = hasTimer;
|
||||
this.timerParams = timerParams;
|
||||
this.moderatorName = moderatorName;
|
||||
this.hasDedicatedModerator = hasDedicatedModerator;
|
||||
this.isTestGame = isTestGame;
|
||||
}
|
||||
|
||||
static validate = (gameParams) => {
|
||||
const expectedKeys = ['deck', 'hasTimer', 'timerParams', 'moderatorName', 'hasDedicatedModerator'];
|
||||
const expectedKeys = ['deck', 'hasTimer', 'timerParams', 'moderatorName', 'hasDedicatedModerator', 'isTestGame'];
|
||||
if (gameParams === null
|
||||
|| typeof gameParams !== 'object'
|
||||
|| expectedKeys.some((key) => !Object.keys(gameParams).includes(key))
|
||||
@@ -31,6 +33,7 @@ class GameCreationRequest {
|
||||
|
||||
function valid (gameParams) {
|
||||
return typeof gameParams.hasTimer === 'boolean'
|
||||
&& typeof gameParams.isTestGame === 'boolean'
|
||||
&& typeof gameParams.hasDedicatedModerator === 'boolean'
|
||||
&& typeof gameParams.moderatorName === 'string'
|
||||
&& gameParams.moderatorName.length > 0
|
||||
|
||||
@@ -86,7 +86,9 @@ const Events = [
|
||||
stateChange: async (game, socketArgs, vars) => {
|
||||
const person = game.people.find((person) => person.id === socketArgs.personId);
|
||||
if (person && !person.out) {
|
||||
person.userType = globals.USER_TYPES.KILLED_PLAYER;
|
||||
person.userType = person.userType === globals.USER_TYPES.BOT
|
||||
? globals.USER_TYPES.KILLED_BOT
|
||||
: globals.USER_TYPES.KILLED_PLAYER;
|
||||
person.out = true;
|
||||
person.killed = true;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,10 @@ class GameManager {
|
||||
gameParams.hasTimer,
|
||||
gameParams.timerParams,
|
||||
gameParams.moderatorName,
|
||||
gameParams.hasDedicatedModerator
|
||||
gameParams.hasDedicatedModerator,
|
||||
gameParams.isTestGame
|
||||
);
|
||||
console.log(req.isTestGame);
|
||||
const newAccessCode = await this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL);
|
||||
if (newAccessCode === null) {
|
||||
return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE);
|
||||
@@ -76,14 +78,15 @@ class GameManager {
|
||||
const newGame = new Game(
|
||||
newAccessCode,
|
||||
globals.STATUS.LOBBY,
|
||||
initializePeopleForGame(req.deck, moderator, this.shuffle),
|
||||
initializePeopleForGame(req.deck, moderator, this.shuffle, req.isTestGame),
|
||||
req.deck,
|
||||
req.hasTimer,
|
||||
moderator.id,
|
||||
req.hasDedicatedModerator,
|
||||
moderator.id,
|
||||
new Date().toJSON(),
|
||||
req.timerParams
|
||||
req.timerParams,
|
||||
req.isTestGame
|
||||
);
|
||||
await this.eventManager.publisher.set(newAccessCode, JSON.stringify(newGame), {
|
||||
EX: globals.STALE_GAME_SECONDS
|
||||
@@ -242,6 +245,10 @@ class GameManager {
|
||||
game.people[i].userType = globals.USER_TYPES.PLAYER;
|
||||
game.people[i].out = false;
|
||||
}
|
||||
if (game.people[i].userType === globals.USER_TYPES.KILLED_BOT) {
|
||||
game.people[i].userType = globals.USER_TYPES.BOT;
|
||||
game.people[i].out = false;
|
||||
}
|
||||
game.people[i].revealed = false;
|
||||
game.people[i].killed = false;
|
||||
if (game.people[i].gameRole) {
|
||||
@@ -314,7 +321,7 @@ function initializeModerator (name, hasDedicatedModerator) {
|
||||
return new Person(createRandomId(), createRandomId(), name, userType);
|
||||
}
|
||||
|
||||
function initializePeopleForGame (uniqueRoles, moderator, shuffle) {
|
||||
function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame) {
|
||||
const people = [];
|
||||
|
||||
const cards = [];
|
||||
@@ -335,10 +342,11 @@ function initializePeopleForGame (uniqueRoles, moderator, shuffle) {
|
||||
createRandomId(),
|
||||
createRandomId(),
|
||||
UsernameGenerator.generate(),
|
||||
globals.USER_TYPES.PLAYER,
|
||||
isTestGame ? globals.USER_TYPES.BOT : globals.USER_TYPES.PLAYER,
|
||||
cards[j].role,
|
||||
cards[j].description,
|
||||
cards[j].team
|
||||
cards[j].team,
|
||||
isTestGame
|
||||
);
|
||||
person.customRole = cards[j].custom;
|
||||
person.hasEnteredName = false;
|
||||
|
||||
Reference in New Issue
Block a user