mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 07:47:50 +01:00
Merge pull request #10 from AlecM33/enhancements
New standard role, allow custom werewolf roles to be added
This commit is contained in:
BIN
assets/images/roles-small/DreamWolf.png
Normal file
BIN
assets/images/roles-small/DreamWolf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/images/roles/DreamWolf.png
Normal file
BIN
assets/images/roles/DreamWolf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -64,10 +64,10 @@ function teamWon(game) {
|
||||
let totalAlive = 0;
|
||||
let hunterAlive = false;
|
||||
for (const player of game.players) {
|
||||
if (player.card.role !== "Werewolf" && !player.dead) {
|
||||
if (!player.card.isTypeOfWerewolf && !player.dead) {
|
||||
villagersAlive ++;
|
||||
}
|
||||
if (player.card.role === "Werewolf" && !player.dead) {
|
||||
if (player.card.isTypeOfWerewolf && !player.dead) {
|
||||
wolvesAlive ++;
|
||||
}
|
||||
if (player.card.role === "Hunter" && !player.dead) {
|
||||
|
||||
@@ -3,50 +3,55 @@ export const cards = [
|
||||
role: "Villager",
|
||||
team: "good",
|
||||
description: "During the day, find the wolves and kill them.",
|
||||
powerRole: false
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Werewolf",
|
||||
team: "evil",
|
||||
description: "During the night, choose a villager to kill. Don't get killed.",
|
||||
powerRole: false
|
||||
isTypeOfWerewolf: true
|
||||
},
|
||||
{
|
||||
role: "Dream Wolf",
|
||||
team: "evil",
|
||||
description: "If a Werewolf dies, you become a Werewolf. You do not wake up with the Werewolves until this happens.",
|
||||
isTypeOfWerewolf: true
|
||||
},
|
||||
{
|
||||
role: "Minion",
|
||||
team: "evil",
|
||||
description: "You are an evil villager - you know who the wolves are, and you want them to win.",
|
||||
powerRole: true
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Seer",
|
||||
team: "good",
|
||||
description: "During each night, choose one person. The moderator will tell you whether that player is a wolf.",
|
||||
powerRole: true
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Shadow",
|
||||
team: "evil",
|
||||
description: "If the Seer checks you, the Seer dies that night instead of whoever the wolves chose to kill. Reveal" +
|
||||
" yourself to the moderator.",
|
||||
powerRole: true
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Hunter",
|
||||
team: "good",
|
||||
description: "If you are alive with a wolf at the end of the game, you best the wolf, and the village wins.",
|
||||
powerRole: true
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Sorcerer",
|
||||
team: "good",
|
||||
description: "Once a game, change who the wolves are going to kill to someone else, including yourself. You will" +
|
||||
" see who is going to die each night until you use this power.",
|
||||
powerRole: true
|
||||
description: "Once a game, change who the wolves are going to kill to someone else, including yourself.",
|
||||
isTypeOfWerewolf: false
|
||||
},
|
||||
{
|
||||
role: "Mason",
|
||||
team: "good",
|
||||
description: "Masons know who other Masons are. Wake them up to see each other on the first night.",
|
||||
powerRole: true
|
||||
isTypeOfWerewolf: false
|
||||
}
|
||||
];
|
||||
|
||||
@@ -2,7 +2,7 @@ import {utility} from './util.js'
|
||||
|
||||
const socket = io();
|
||||
|
||||
const standardRoles = ["Villager", "Werewolf", "Seer", "Shadow", "Hunter", "Mason", "Minion", "Sorcerer"];
|
||||
const standardRoles = ["Villager", "Werewolf", "Seer", "Shadow", "Hunter", "Mason", "Minion", "Sorcerer", "Dream Wolf"];
|
||||
let clock;
|
||||
let currentGame = null;
|
||||
let lastGameState = null;
|
||||
@@ -83,7 +83,13 @@ function triggerEntranceAnimation(selector, entranceClass, exitClass, image) {
|
||||
transitionEl.exitClass = exitClass;
|
||||
transitionEl.offsetWidth;
|
||||
if (image && standardRoles.includes(currentGame.killedRole)) {
|
||||
transitionEl.setAttribute("src", "../assets/images/roles/" + currentGame.killedRole + ".png");
|
||||
transitionEl.classList.remove("killed-role-custom");
|
||||
transitionEl.setAttribute("src", "../assets/images/roles/" + currentGame.killedRole.replace(/\s/g, '') + ".png");
|
||||
} else {
|
||||
if (image) {
|
||||
transitionEl.setAttribute("src", "../assets/images/custom.svg");
|
||||
transitionEl.setAttribute("class", "killed-role-custom");
|
||||
}
|
||||
}
|
||||
transitionEl.classList.add(entranceClass);
|
||||
}
|
||||
@@ -125,17 +131,20 @@ function renderEndSplash() {
|
||||
currentGame.winningTeam === "village"
|
||||
? document.getElementById("end-container").innerHTML ="<div class='winner-header'><p class='winner-village'>Village</p> wins!</div>"
|
||||
: document.getElementById("end-container").innerHTML ="<div class='winner-header'><p class='winner-wolf'>Wolves</p>win!</div>";
|
||||
const wolfContainer = document.createElement("div");
|
||||
wolfContainer.setAttribute("id", "wolves");
|
||||
let wolfContent = "<div class='evil-header'><span>The</span><p class='evil-subheader'>evil</p> <span>players were:</span></div>";
|
||||
const rosterContainer = document.createElement("div");
|
||||
rosterContainer.setAttribute("id", "roster");
|
||||
document.getElementById("end-container").innerHTML += "<div class='roster-header'>Here's what everyone was:</div>";
|
||||
let rosterContent = "";
|
||||
for (const player of currentGame.players) {
|
||||
if (player.card.team === "evil") {
|
||||
wolfContent += "<div class='evil-list-item'>" + player.name + ": " + player.card.role + "</div>"
|
||||
}
|
||||
rosterContent += "<div class='roster-list-item'>";
|
||||
rosterContent += standardRoles.includes(player.card.role)
|
||||
? "<img alt='' src='/assets/images/roles-small/" + player.card.role.replace(/\s/g, '') + ".png' />"
|
||||
: "<img alt='' class='card-image-custom' src='/assets/images/custom.svg' />";
|
||||
rosterContent += player.name + ": " + player.card.role + "</div>"
|
||||
}
|
||||
wolfContent += "<a href='/'><button class='app-btn'>Home</button></a>";
|
||||
wolfContainer.innerHTML = wolfContent;
|
||||
document.getElementById("end-container").appendChild(wolfContainer);
|
||||
rosterContainer.innerHTML = rosterContent;
|
||||
document.getElementById("end-container").appendChild(rosterContainer);
|
||||
document.getElementById("end-container").innerHTML += "<a href='/'><button class='app-btn'>Home</button></a>";
|
||||
|
||||
}
|
||||
|
||||
@@ -200,7 +209,7 @@ function renderGame() {
|
||||
function renderPlayerCard(player) {
|
||||
const card = player.card;
|
||||
const cardArt = standardRoles.includes(card.role) ?
|
||||
"<img alt='" + card.role + "' src='../assets/images/roles/" + card.role + ".png' />"
|
||||
"<img alt='" + card.role + "' src='../assets/images/roles/" + card.role.replace(/\s/g, '') + ".png' />"
|
||||
: "<div class='placeholder'>Custom Role</div>";
|
||||
const cardClass = player.card.team === "good" ? "game-card-inner village" : "game-card-inner wolf";
|
||||
const playerCard = document.createElement("div");
|
||||
|
||||
@@ -2,17 +2,17 @@ import {cards} from './cards.js'
|
||||
import {utility} from './util.js'
|
||||
|
||||
const socket = io();
|
||||
const finishedArtArray = ["Villager", "Werewolf", "Seer", "Shadow", "Hunter", "Mason", "Minion", "Sorcerer"];
|
||||
const finishedArtArray = ["Villager", "Werewolf", "Seer", "Shadow", "Hunter", "Mason", "Minion", "Sorcerer", "Dream Wolf"];
|
||||
|
||||
// important declarations
|
||||
class Card {
|
||||
constructor(role, team, description, powerRole) {
|
||||
constructor(role, team, description, isTypeOfWerewolf) {
|
||||
this.id = null;
|
||||
this.role = role;
|
||||
this.isTypeOfWerewolf = isTypeOfWerewolf;
|
||||
this.team = team;
|
||||
this.description = description;
|
||||
this.quantity = 0;
|
||||
this.powerRole = powerRole;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ window.onload = function() {
|
||||
|
||||
function renderAvailableCards() {
|
||||
for (let i = 0; i < cards.length; i ++) {
|
||||
const newCard = new Card(cards[i].role, cards[i].team, cards[i].description, cards[i].powerRole);
|
||||
const newCard = new Card(cards[i].role, cards[i].team, cards[i].description, cards[i].isTypeOfWerewolf);
|
||||
// put card info in the informational role description modal
|
||||
const modalRole = document.createElement("div");
|
||||
modalRole.setAttribute("class", "modal-role");
|
||||
@@ -61,7 +61,7 @@ function renderAvailableCards() {
|
||||
roleImage = "<img alt='No art' class='card-image-custom' src='/assets/images/custom.svg' />";
|
||||
} else {
|
||||
roleImage = finishedArtArray.includes(cards[i].role) ?
|
||||
"<img alt='No art' src='/assets/images/roles-small/" + cards[i].role + ".png' />"
|
||||
"<img alt='No art' src='/assets/images/roles-small/" + cards[i].role.replace(/\s/g, '') + ".png' />"
|
||||
: "<span>Art soon.</span>";
|
||||
}
|
||||
modalRole.innerHTML =
|
||||
@@ -96,7 +96,7 @@ function renderAvailableCards() {
|
||||
"</div>";
|
||||
cardContainer.innerHTML = cards[i].custom
|
||||
? cardContainer.innerHTML += "<img class='card-image card-image-custom' src='../assets/images/custom.svg' alt='" + newCard.role + "'/>"
|
||||
: cardContainer.innerHTML +="<img class='card-image' src='../assets/images/roles-small/" + newCard.role + ".png' alt='" + newCard.role + "'/>";
|
||||
: cardContainer.innerHTML +="<img class='card-image' src='../assets/images/roles-small/" + newCard.role.replace(/\s/g, '') + ".png' alt='" + newCard.role + "'/>";
|
||||
cardContainer.innerHTML +=
|
||||
"<div class='card-bottom'>" +
|
||||
"<p>-</p>" +
|
||||
@@ -113,6 +113,7 @@ function renderAvailableCards() {
|
||||
cardBottom.quantityEl = cardQuantity;
|
||||
}
|
||||
renderCustomCard();
|
||||
resetCardQuantities();
|
||||
}
|
||||
|
||||
function renderCustomCard() {
|
||||
@@ -141,7 +142,7 @@ function addCustomCardToRoles(e) {
|
||||
role: document.getElementById("custom-role-name").value,
|
||||
team: document.getElementById("custom-role-team").value,
|
||||
description: document.getElementById("custom-role-desc").value,
|
||||
powerRole: document.getElementById("custom-role-power").checked,
|
||||
isTypeOfWerewolf: document.getElementById("custom-role-wolf").checked,
|
||||
custom: true
|
||||
};
|
||||
cards.push(newCard);
|
||||
@@ -203,7 +204,7 @@ function buildDeckFromQuantities() {
|
||||
let playerDeck = [];
|
||||
for (const card of fullDeck) {
|
||||
for (let i = 0; i < card.quantity; i++) {
|
||||
let newCard = new Card(card.role, card.team, card.description, card.powerRole);
|
||||
let newCard = new Card(card.role, card.team, card.description, card.isTypeOfWerewolf);
|
||||
newCard.id = utility.generateID();
|
||||
playerDeck.push(newCard);
|
||||
}
|
||||
|
||||
@@ -911,10 +911,16 @@ label {
|
||||
}
|
||||
|
||||
#game-card img {
|
||||
width: 230px;
|
||||
top: 15px;
|
||||
width: 215px;
|
||||
top: 35px;
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
user-drag: none;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
@@ -957,6 +963,8 @@ label {
|
||||
padding: 0.5em;
|
||||
font-size: 0.8em;
|
||||
color: #464552;
|
||||
max-height: 68px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
@@ -1058,6 +1066,13 @@ label {
|
||||
margin: 0 auto;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#end-container #roster {
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#end-container .winner-header {
|
||||
@@ -1065,6 +1080,7 @@ label {
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-size: 30px;
|
||||
margin: 10px 0 30px 0;
|
||||
}
|
||||
|
||||
#end-container .evil-subheader {
|
||||
@@ -1074,6 +1090,28 @@ label {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#end-container .roster-list-item {
|
||||
background-color: #40464a;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
width: 33%;
|
||||
min-width: 13em;
|
||||
margin: 0.3em;
|
||||
}
|
||||
|
||||
#end-container .roster-header {
|
||||
font-size: 25px;
|
||||
margin-bottom: 1em;
|
||||
|
||||
}
|
||||
|
||||
#end-container .roster-list-item img {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
#end-container .evil-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1084,8 +1122,8 @@ label {
|
||||
|
||||
#end-container p {
|
||||
font-weight: bold;
|
||||
margin-right: 0.3em;
|
||||
font-size: 50px;
|
||||
margin: 0 0.3em 0 0;
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
#end-container button {
|
||||
@@ -1233,6 +1271,11 @@ label {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.killed-role-custom {
|
||||
width: 190px;
|
||||
padding: 95px;
|
||||
}
|
||||
|
||||
@keyframes slide-fade-in-top {
|
||||
0% {
|
||||
opacity: 0;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h2>Add a role for this game only.</h2>
|
||||
<h3 class="disclaimer">Warning: If your role changes the victory condition (like the Hunter), the game will not detect the new condition.</h3>
|
||||
<form id="custom-role-form">
|
||||
<label for="custom-role-name">Name</label>
|
||||
<input id="custom-role-name" type="text" required/>
|
||||
@@ -38,8 +37,8 @@
|
||||
<option value="evil">Evil</option>
|
||||
</select>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="custom-role-power">
|
||||
<label for="custom-role-power">Power Role?</label>
|
||||
<input type="checkbox" id="custom-role-wolf">
|
||||
<label for="custom-role-wolf">Is this role a type of Werewolf?</label>
|
||||
</div>
|
||||
<br><br>
|
||||
<input type="submit" class="app-btn" value="Add Role">
|
||||
|
||||
Reference in New Issue
Block a user