From 554a0638ebb6200479dbb40085ff9228b0c5c681 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 25 Jan 2026 00:32:31 +0000
Subject: [PATCH 1/8] Initial plan
From a1bcf0f6f8a7ab68cebb53da3243f6be76c4c8f7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 25 Jan 2026 00:37:24 +0000
Subject: [PATCH 2/8] Add independent alignment: constants, validation, UI, and
CSS
Co-authored-by: AlecM33 <24642328+AlecM33@users.noreply.github.com>
---
client/src/config/globals.js | 3 ++-
.../modules/game_creation/DeckStateManager.js | 12 ++++++------
.../game_creation/GameCreationStepManager.js | 6 +-----
client/src/modules/game_creation/RoleBox.js | 8 ++++++--
.../modules/game_state/states/InProgress.js | 19 ++++++++++++++++++-
.../states/shared/SharedStateUtil.js | 6 +++++-
client/src/styles/GLOBAL.css | 9 +++++++++
client/src/styles/game.css | 4 ++++
client/src/view_templates/CreateTemplate.js | 1 +
server/config/globals.js | 3 ++-
server/model/GameCreationRequest.js | 2 +-
11 files changed, 55 insertions(+), 18 deletions(-)
diff --git a/client/src/config/globals.js b/client/src/config/globals.js
index ae48a9b..50e32ca 100644
--- a/client/src/config/globals.js
+++ b/client/src/config/globals.js
@@ -21,7 +21,8 @@ export const STATUS = {
export const ALIGNMENT = {
GOOD: 'good',
- EVIL: 'evil'
+ EVIL: 'evil',
+ INDEPENDENT: 'independent'
};
export const MESSAGES = {
diff --git a/client/src/modules/game_creation/DeckStateManager.js b/client/src/modules/game_creation/DeckStateManager.js
index ec21ed4..60b0a27 100644
--- a/client/src/modules/game_creation/DeckStateManager.js
+++ b/client/src/modules/game_creation/DeckStateManager.js
@@ -147,7 +147,8 @@ export class DeckStateManager {
}
const sortedDeck = this.deck.sort((a, b) => {
if (a.team !== b.team) {
- return a.team === ALIGNMENT.GOOD ? -1 : 1;
+ const order = { good: 0, evil: 1, independent: 2 };
+ return order[a.team] - order[b.team];
}
return a.role.localeCompare(b.role);
});
@@ -187,11 +188,7 @@ export class DeckStateManager {
roleEl.dataset.roleId = sortedDeck[i].id;
roleEl.classList.add('added-role');
roleEl.innerHTML = HTMLFragments.DECK_SELECT_ROLE_ADDED_TO_DECK;
- if (sortedDeck[i].team === ALIGNMENT.GOOD) {
- roleEl.classList.add(ALIGNMENT.GOOD);
- } else {
- roleEl.classList.add(ALIGNMENT.EVIL);
- }
+ roleEl.classList.add(sortedDeck[i].team);
populateRoleElementInfo(roleEl, sortedDeck, i);
document.getElementById('deck-list').appendChild(roleEl);
const minusOneHandler = (e) => {
@@ -237,8 +234,10 @@ export class DeckStateManager {
const nameEl = document.getElementById('custom-role-info-modal-name');
alignmentEl.classList.remove(ALIGNMENT.GOOD);
alignmentEl.classList.remove(ALIGNMENT.EVIL);
+ alignmentEl.classList.remove(ALIGNMENT.INDEPENDENT);
nameEl.classList.remove(ALIGNMENT.GOOD);
nameEl.classList.remove(ALIGNMENT.EVIL);
+ nameEl.classList.remove(ALIGNMENT.INDEPENDENT);
e.preventDefault();
nameEl.innerText = sortedDeck[i].role;
nameEl.classList.add(sortedDeck[i].team);
@@ -256,6 +255,7 @@ export class DeckStateManager {
function populateRoleElementInfo (roleEl, sortedDeck, i) {
roleEl.classList.remove(ALIGNMENT.GOOD);
roleEl.classList.remove(ALIGNMENT.EVIL);
+ roleEl.classList.remove(ALIGNMENT.INDEPENDENT);
roleEl.classList.add(sortedDeck[i].team);
roleEl.querySelector('.role-name').innerHTML =
`
diff --git a/client/src/modules/game_creation/GameCreationStepManager.js b/client/src/modules/game_creation/GameCreationStepManager.js
index 4d0b097..c6fc67e 100644
--- a/client/src/modules/game_creation/GameCreationStepManager.js
+++ b/client/src/modules/game_creation/GameCreationStepManager.js
@@ -463,11 +463,7 @@ function renderReviewAndCreateStep (containerId, stepNumber, game, deckManager)
for (const card of game.deck) {
const roleEl = document.createElement('div');
roleEl.innerText = card.quantity + 'x ' + card.role;
- if (card.team === ALIGNMENT.GOOD) {
- roleEl.classList.add(ALIGNMENT.GOOD);
- } else {
- roleEl.classList.add(ALIGNMENT.EVIL);
- }
+ roleEl.classList.add(card.team);
div.querySelector('#roles-option').appendChild(roleEl);
}
diff --git a/client/src/modules/game_creation/RoleBox.js b/client/src/modules/game_creation/RoleBox.js
index 7b996f2..30eb346 100644
--- a/client/src/modules/game_creation/RoleBox.js
+++ b/client/src/modules/game_creation/RoleBox.js
@@ -31,7 +31,8 @@ export class RoleBox {
loadDefaultRoles = () => {
this.defaultRoles = defaultRoles.sort((a, b) => {
if (a.team !== b.team) {
- return a.team === ALIGNMENT.GOOD ? -1 : 1;
+ const order = { good: 0, evil: 1, independent: 2 };
+ return order[a.team] - order[b.team];
}
return a.role.localeCompare(b.role);
}).map((role) => {
@@ -202,7 +203,8 @@ export class RoleBox {
}
this.customRoles.sort((a, b) => {
if (a.team !== b.team) {
- return a.team === ALIGNMENT.GOOD ? -1 : 1;
+ const order = { good: 0, evil: 1, independent: 2 };
+ return order[a.team] - order[b.team];
}
return a.role.localeCompare(b.role);
});
@@ -282,8 +284,10 @@ export class RoleBox {
const nameEl = document.getElementById('custom-role-info-modal-name');
alignmentEl.classList.remove(ALIGNMENT.GOOD);
alignmentEl.classList.remove(ALIGNMENT.EVIL);
+ alignmentEl.classList.remove(ALIGNMENT.INDEPENDENT);
nameEl.classList.remove(ALIGNMENT.GOOD);
nameEl.classList.remove(ALIGNMENT.EVIL);
+ nameEl.classList.remove(ALIGNMENT.INDEPENDENT);
e.preventDefault();
let role;
if (isCustom) {
diff --git a/client/src/modules/game_state/states/InProgress.js b/client/src/modules/game_state/states/InProgress.js
index 278754b..85842df 100644
--- a/client/src/modules/game_state/states/InProgress.js
+++ b/client/src/modules/game_state/states/InProgress.js
@@ -295,6 +295,10 @@ export class InProgress {
&& ((p.userType !== USER_TYPES.MODERATOR && p.userType !== USER_TYPES.SPECTATOR)
|| p.killed)
);
+ const teamIndependent = this.stateBucket.currentGameState.people.filter((p) => p.alignment === ALIGNMENT.INDEPENDENT
+ && ((p.userType !== USER_TYPES.MODERATOR && p.userType !== USER_TYPES.SPECTATOR)
+ || p.killed)
+ );
this.renderGroupOfPlayers(
teamEvil,
this.killPlayerHandlers,
@@ -315,6 +319,16 @@ export class InProgress {
person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
this.socket
);
+ this.renderGroupOfPlayers(
+ teamIndependent,
+ this.killPlayerHandlers,
+ this.revealRoleHandlers,
+ this.stateBucket.currentGameState.accessCode,
+ ALIGNMENT.INDEPENDENT,
+ this.stateBucket.currentGameState.people.find(person =>
+ person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
+ this.socket
+ );
document.getElementById('players-alive-label').innerText =
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
this.stateBucket.currentGameState.gameSize + ' Alive';
@@ -460,9 +474,12 @@ function renderPlayerRole (gameState) {
if (gameState.client.alignment === ALIGNMENT.GOOD) {
document.getElementById('game-role').classList.add('game-role-good');
name.classList.add('good');
- } else {
+ } else if (gameState.client.alignment === ALIGNMENT.EVIL) {
document.getElementById('game-role').classList.add('game-role-evil');
name.classList.add('evil');
+ } else if (gameState.client.alignment === ALIGNMENT.INDEPENDENT) {
+ document.getElementById('game-role').classList.add('game-role-independent');
+ name.classList.add('independent');
}
name.setAttribute('title', gameState.client.gameRole);
if (gameState.client.out) {
diff --git a/client/src/modules/game_state/states/shared/SharedStateUtil.js b/client/src/modules/game_state/states/shared/SharedStateUtil.js
index 5c91349..cfb01de 100644
--- a/client/src/modules/game_state/states/shared/SharedStateUtil.js
+++ b/client/src/modules/game_state/states/shared/SharedStateUtil.js
@@ -149,7 +149,11 @@ export const SharedStateUtil = {
document.getElementById('role-info-button').addEventListener('click', (e) => {
const deck = stateBucket.currentGameState.deck;
deck.sort((a, b) => {
- return a.team === ALIGNMENT.GOOD ? -1 : 1;
+ if (a.team !== b.team) {
+ const order = { good: 0, evil: 1, independent: 2 };
+ return order[a.team] - order[b.team];
+ }
+ return a.role.localeCompare(b.role);
});
e.preventDefault();
document.getElementById('role-info-prompt').innerHTML = HTMLFragments.ROLE_INFO_MODAL;
diff --git a/client/src/styles/GLOBAL.css b/client/src/styles/GLOBAL.css
index e00fe1f..fbf6fde 100644
--- a/client/src/styles/GLOBAL.css
+++ b/client/src/styles/GLOBAL.css
@@ -608,6 +608,15 @@ input {
font-weight: bold;
}
+.independent, .compact-card.independent .card-role {
+ color: #d4a027 !important;
+ font-weight: bold;
+}
+
+.independent-players, #deck-independent {
+ border: 2px solid rgba(212, 160, 39, 0.39);
+}
+
@keyframes placeholder {
0%{
background-position: 50% 0
diff --git a/client/src/styles/game.css b/client/src/styles/game.css
index eb071b3..dff0ea2 100644
--- a/client/src/styles/game.css
+++ b/client/src/styles/game.css
@@ -547,6 +547,10 @@ h1 {
color: #e15656 !important;
}
+#game-role #role-name.independent {
+ color: #d4a027 !important;
+}
+
#role-image {
user-select: none;
-ms-user-select: none;
diff --git a/client/src/view_templates/CreateTemplate.js b/client/src/view_templates/CreateTemplate.js
index c7d1053..8d0cb74 100644
--- a/client/src/view_templates/CreateTemplate.js
+++ b/client/src/view_templates/CreateTemplate.js
@@ -11,6 +11,7 @@ export const hiddenMenus =
diff --git a/server/config/globals.js b/server/config/globals.js
index ec01331..7a7afed 100644
--- a/server/config/globals.js
+++ b/server/config/globals.js
@@ -24,7 +24,8 @@ const LOG_LEVEL = {
const ALIGNMENT = {
GOOD: 'good',
- EVIL: 'evil'
+ EVIL: 'evil',
+ INDEPENDENT: 'independent'
};
const REDIS_CHANNELS = {
diff --git a/server/model/GameCreationRequest.js b/server/model/GameCreationRequest.js
index b6ba6cc..d8d8942 100644
--- a/server/model/GameCreationRequest.js
+++ b/server/model/GameCreationRequest.js
@@ -39,7 +39,7 @@ class GameCreationRequest {
&& entry.role.length > 0
&& entry.role.length <= PRIMITIVES.MAX_CUSTOM_ROLE_NAME_LENGTH
&& typeof entry.team === 'string'
- && (entry.team === ALIGNMENT.GOOD || entry.team === ALIGNMENT.EVIL)
+ && (entry.team === ALIGNMENT.GOOD || entry.team === ALIGNMENT.EVIL || entry.team === ALIGNMENT.INDEPENDENT)
&& typeof entry.description === 'string'
&& entry.description.length > 0
&& entry.description.length <= PRIMITIVES.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
From 91a3c39d7a9517e8efce750ee6b31a4b651e4367 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 25 Jan 2026 00:38:58 +0000
Subject: [PATCH 3/8] Add unit tests for independent alignment validation
Co-authored-by: AlecM33 <24642328+AlecM33@users.noreply.github.com>
---
.../server/model/GameCreationRequest_Spec.js | 104 ++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 spec/unit/server/model/GameCreationRequest_Spec.js
diff --git a/spec/unit/server/model/GameCreationRequest_Spec.js b/spec/unit/server/model/GameCreationRequest_Spec.js
new file mode 100644
index 0000000..9a9542d
--- /dev/null
+++ b/spec/unit/server/model/GameCreationRequest_Spec.js
@@ -0,0 +1,104 @@
+const GameCreationRequest = require('../../../../server/model/GameCreationRequest');
+const { ALIGNMENT } = require('../../../../server/config/globals');
+
+describe('GameCreationRequest', () => {
+ describe('#deckIsValid', () => {
+ it('should accept a deck with good, evil, and independent roles', () => {
+ const deck = [
+ {
+ role: 'Villager',
+ team: ALIGNMENT.GOOD,
+ description: 'A simple villager',
+ custom: false,
+ quantity: 2
+ },
+ {
+ role: 'Werewolf',
+ team: ALIGNMENT.EVIL,
+ description: 'A werewolf',
+ custom: false,
+ quantity: 1
+ },
+ {
+ role: 'Tanner',
+ team: ALIGNMENT.INDEPENDENT,
+ description: 'An independent role',
+ custom: true,
+ quantity: 1
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(true);
+ });
+
+ it('should accept a deck with only good roles', () => {
+ const deck = [
+ {
+ role: 'Villager',
+ team: ALIGNMENT.GOOD,
+ description: 'A simple villager',
+ custom: false,
+ quantity: 3
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(true);
+ });
+
+ it('should accept a deck with only evil roles', () => {
+ const deck = [
+ {
+ role: 'Werewolf',
+ team: ALIGNMENT.EVIL,
+ description: 'A werewolf',
+ custom: false,
+ quantity: 2
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(true);
+ });
+
+ it('should accept a deck with only independent roles', () => {
+ const deck = [
+ {
+ role: 'Tanner',
+ team: ALIGNMENT.INDEPENDENT,
+ description: 'An independent role',
+ custom: true,
+ quantity: 1
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(true);
+ });
+
+ it('should reject a deck with invalid team values', () => {
+ const deck = [
+ {
+ role: 'InvalidRole',
+ team: 'invalid',
+ description: 'Invalid team',
+ custom: true,
+ quantity: 1
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(false);
+ });
+
+ it('should reject a deck with missing required fields', () => {
+ const deck = [
+ {
+ role: 'Villager',
+ // missing team
+ description: 'A simple villager',
+ custom: false,
+ quantity: 1
+ }
+ ];
+
+ expect(GameCreationRequest.deckIsValid(deck)).toBe(false);
+ });
+ });
+});
From f8aa4666b042a75eb6b9f372e624286ee6d1c71b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 25 Jan 2026 00:40:29 +0000
Subject: [PATCH 4/8] Fix remaining binary alignment checks in role display
Co-authored-by: AlecM33 <24642328+AlecM33@users.noreply.github.com>
---
client/src/modules/game_creation/RoleBox.js | 8 ++------
.../modules/game_state/states/shared/SharedStateUtil.js | 6 +-----
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/client/src/modules/game_creation/RoleBox.js b/client/src/modules/game_creation/RoleBox.js
index 30eb346..7079e1b 100644
--- a/client/src/modules/game_creation/RoleBox.js
+++ b/client/src/modules/game_creation/RoleBox.js
@@ -175,10 +175,7 @@ export class RoleBox {
defaultRole.innerHTML = HTMLFragments.DECK_SELECT_ROLE_DEFAULT;
defaultRole.classList.add('default-role');
defaultRole.dataset.roleId = this.defaultRoles[i].id;
- const alignmentClass = this.defaultRoles[i].team === ALIGNMENT.GOOD
- ? ALIGNMENT.GOOD
- : ALIGNMENT.EVIL;
- defaultRole.classList.add(alignmentClass);
+ defaultRole.classList.add(this.defaultRoles[i].team);
defaultRole.querySelector('.role-name').innerText = this.defaultRoles[i].role;
selectEl.appendChild(defaultRole);
}
@@ -214,8 +211,7 @@ export class RoleBox {
customRole.innerHTML = HTMLFragments.DECK_SELECT_ROLE;
customRole.classList.add('custom-role');
customRole.dataset.roleId = this.customRoles[i].id;
- const alignmentClass = this.customRoles[i].team === ALIGNMENT.GOOD ? ALIGNMENT.GOOD : ALIGNMENT.EVIL;
- customRole.classList.add(alignmentClass);
+ customRole.classList.add(this.customRoles[i].team);
customRole.querySelector('.role-name').innerText = this.customRoles[i].role;
selectEl.appendChild(customRole);
}
diff --git a/client/src/modules/game_state/states/shared/SharedStateUtil.js b/client/src/modules/game_state/states/shared/SharedStateUtil.js
index cfb01de..34c3cc4 100644
--- a/client/src/modules/game_state/states/shared/SharedStateUtil.js
+++ b/client/src/modules/game_state/states/shared/SharedStateUtil.js
@@ -172,11 +172,7 @@ export const SharedStateUtil = {
roleName.innerText = card.role;
roleQuantity.innerText = card.quantity + 'x';
- if (card.team === ALIGNMENT.GOOD) {
- roleName.classList.add(ALIGNMENT.GOOD);
- } else {
- roleName.classList.add(ALIGNMENT.EVIL);
- }
+ roleName.classList.add(card.team);
roleNameDiv.appendChild(roleQuantity);
roleNameDiv.appendChild(roleName);
From c884e1fe7c91cb0d68c9179d4297da767e83fb95 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 25 Jan 2026 00:42:40 +0000
Subject: [PATCH 5/8] Add independent player container and
game-role-independent CSS
Co-authored-by: AlecM33 <24642328+AlecM33@users.noreply.github.com>
---
client/src/modules/front_end_components/HTMLFragments.js | 4 ++++
client/src/styles/game.css | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/client/src/modules/front_end_components/HTMLFragments.js b/client/src/modules/front_end_components/HTMLFragments.js
index e71eb16..4875924 100644
--- a/client/src/modules/front_end_components/HTMLFragments.js
+++ b/client/src/modules/front_end_components/HTMLFragments.js
@@ -202,6 +202,10 @@ export const HTMLFragments = {
+
`,
TEMP_MOD_GAME_VIEW:
diff --git a/client/src/styles/game.css b/client/src/styles/game.css
index dff0ea2..234bb5e 100644
--- a/client/src/styles/game.css
+++ b/client/src/styles/game.css
@@ -462,6 +462,10 @@ h1 {
border: 4px solid #c55454 !important;
}
+.game-role-independent {
+ border: 4px solid #d4a027 !important;
+}
+
#game-role-back {
display: flex;
align-items: center;
From 6559e4ba0b875b5ae46dfa1127f15912810fba0b Mon Sep 17 00:00:00 2001
From: AlecM33
Date: Sat, 24 Jan 2026 20:39:20 -0500
Subject: [PATCH 6/8] fix a couple bugs, tweak colors
---
.../front_end_components/HTMLFragments.js | 8 ++-
client/src/modules/game_creation/RoleBox.js | 2 +-
.../modules/game_state/states/InProgress.js | 69 +++++++++++--------
client/src/styles/GLOBAL.css | 2 +-
client/src/styles/game.css | 8 ++-
5 files changed, 53 insertions(+), 36 deletions(-)
diff --git a/client/src/modules/front_end_components/HTMLFragments.js b/client/src/modules/front_end_components/HTMLFragments.js
index e71eb16..c0f675f 100644
--- a/client/src/modules/front_end_components/HTMLFragments.js
+++ b/client/src/modules/front_end_components/HTMLFragments.js
@@ -194,11 +194,15 @@ export const HTMLFragments = {
-
+
+
-
+
diff --git a/client/src/modules/game_creation/RoleBox.js b/client/src/modules/game_creation/RoleBox.js
index 7079e1b..6badd78 100644
--- a/client/src/modules/game_creation/RoleBox.js
+++ b/client/src/modules/game_creation/RoleBox.js
@@ -391,7 +391,7 @@ function validateCustomRoleCookie (cookie) {
for (const entry of cookieJSON) {
if (entry !== null && typeof entry === 'object') {
if (typeof entry.role !== 'string' || entry.role.length > PRIMITIVES.MAX_CUSTOM_ROLE_NAME_LENGTH
- || typeof entry.team !== 'string' || (entry.team !== ALIGNMENT.GOOD && entry.team !== ALIGNMENT.EVIL)
+ || typeof entry.team !== 'string' || (entry.team !== ALIGNMENT.GOOD && entry.team !== ALIGNMENT.EVIL && entry.team !== ALIGNMENT.INDEPENDENT)
|| typeof entry.description !== 'string' || entry.description.length > PRIMITIVES.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
) {
return false;
diff --git a/client/src/modules/game_state/states/InProgress.js b/client/src/modules/game_state/states/InProgress.js
index 85842df..31d39c8 100644
--- a/client/src/modules/game_state/states/InProgress.js
+++ b/client/src/modules/game_state/states/InProgress.js
@@ -299,36 +299,45 @@ export class InProgress {
&& ((p.userType !== USER_TYPES.MODERATOR && p.userType !== USER_TYPES.SPECTATOR)
|| p.killed)
);
- this.renderGroupOfPlayers(
- teamEvil,
- this.killPlayerHandlers,
- this.revealRoleHandlers,
- this.stateBucket.currentGameState.accessCode,
- ALIGNMENT.EVIL,
- this.stateBucket.currentGameState.people.find(person =>
- person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
- this.socket
- );
- this.renderGroupOfPlayers(
- teamGood,
- this.killPlayerHandlers,
- this.revealRoleHandlers,
- this.stateBucket.currentGameState.accessCode,
- ALIGNMENT.GOOD,
- this.stateBucket.currentGameState.people.find(person =>
- person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
- this.socket
- );
- this.renderGroupOfPlayers(
- teamIndependent,
- this.killPlayerHandlers,
- this.revealRoleHandlers,
- this.stateBucket.currentGameState.accessCode,
- ALIGNMENT.INDEPENDENT,
- this.stateBucket.currentGameState.people.find(person =>
- person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
- this.socket
- );
+ if (teamEvil.length > 0) {
+ document.getElementById(`${ALIGNMENT.EVIL}-players`).style.display = 'block';
+ this.renderGroupOfPlayers(
+ teamEvil,
+ this.killPlayerHandlers,
+ this.revealRoleHandlers,
+ this.stateBucket.currentGameState.accessCode,
+ ALIGNMENT.EVIL,
+ this.stateBucket.currentGameState.people.find(person =>
+ person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
+ this.socket
+ );
+ }
+ if (teamGood.length > 0) {
+ document.getElementById(`${ALIGNMENT.GOOD}-players`).style.display = 'block';
+ this.renderGroupOfPlayers(
+ teamGood,
+ this.killPlayerHandlers,
+ this.revealRoleHandlers,
+ this.stateBucket.currentGameState.accessCode,
+ ALIGNMENT.GOOD,
+ this.stateBucket.currentGameState.people.find(person =>
+ person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
+ this.socket
+ );
+ }
+ if (teamIndependent.length > 0) {
+ document.getElementById(`${ALIGNMENT.INDEPENDENT}-players`).style.display = 'block';
+ this.renderGroupOfPlayers(
+ teamIndependent,
+ this.killPlayerHandlers,
+ this.revealRoleHandlers,
+ this.stateBucket.currentGameState.accessCode,
+ ALIGNMENT.INDEPENDENT,
+ this.stateBucket.currentGameState.people.find(person =>
+ person.id === this.stateBucket.currentGameState.currentModeratorId).userType,
+ this.socket
+ );
+ }
document.getElementById('players-alive-label').innerText =
'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' +
this.stateBucket.currentGameState.gameSize + ' Alive';
diff --git a/client/src/styles/GLOBAL.css b/client/src/styles/GLOBAL.css
index fbf6fde..ff9624e 100644
--- a/client/src/styles/GLOBAL.css
+++ b/client/src/styles/GLOBAL.css
@@ -609,7 +609,7 @@ input {
}
.independent, .compact-card.independent .card-role {
- color: #d4a027 !important;
+ color: #af8523 !important;
font-weight: bold;
}
diff --git a/client/src/styles/game.css b/client/src/styles/game.css
index dff0ea2..cb10a25 100644
--- a/client/src/styles/game.css
+++ b/client/src/styles/game.css
@@ -424,7 +424,7 @@ h1 {
display: none;
position: relative;
border: 5px solid transparent;
- background-color: #e3e3e3;
+ background-color: #efefef;
flex-direction: column;
cursor: pointer;
justify-content: space-between;
@@ -462,6 +462,10 @@ h1 {
border: 4px solid #c55454 !important;
}
+.game-role-independent {
+ border: 4px solid #af8523 !important;
+}
+
#game-role-back {
display: flex;
align-items: center;
@@ -548,7 +552,7 @@ h1 {
}
#game-role #role-name.independent {
- color: #d4a027 !important;
+ color: #af8523 !important;
}
#role-image {
From fd2f42c7a6521abd76b6e563d27b5a7fe34a98bc Mon Sep 17 00:00:00 2001
From: AlecM33
Date: Sat, 24 Jan 2026 20:43:42 -0500
Subject: [PATCH 7/8] remove import
---
client/src/modules/game_state/states/shared/SharedStateUtil.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/client/src/modules/game_state/states/shared/SharedStateUtil.js b/client/src/modules/game_state/states/shared/SharedStateUtil.js
index 34c3cc4..b341865 100644
--- a/client/src/modules/game_state/states/shared/SharedStateUtil.js
+++ b/client/src/modules/game_state/states/shared/SharedStateUtil.js
@@ -5,8 +5,7 @@ import {
ENVIRONMENTS,
SOCKET_EVENTS,
USER_TYPE_ICONS,
- USER_TYPES,
- ALIGNMENT
+ USER_TYPES
} from '../../../../config/globals.js';
import { toast } from '../../../front_end_components/Toast.js';
import { Confirmation } from '../../../front_end_components/Confirmation.js';
From 1215b8c93b359765195e2e1f248a7142984ed7d6 Mon Sep 17 00:00:00 2001
From: AlecM33
Date: Sat, 24 Jan 2026 21:17:47 -0500
Subject: [PATCH 8/8] remove duplicate tag
---
client/src/modules/front_end_components/HTMLFragments.js | 4 ----
1 file changed, 4 deletions(-)
diff --git a/client/src/modules/front_end_components/HTMLFragments.js b/client/src/modules/front_end_components/HTMLFragments.js
index c4720ed..c0f675f 100644
--- a/client/src/modules/front_end_components/HTMLFragments.js
+++ b/client/src/modules/front_end_components/HTMLFragments.js
@@ -206,10 +206,6 @@ export const HTMLFragments = {
-
`,
TEMP_MOD_GAME_VIEW: