New standard role, allow custom werewolf roles to be added

This commit is contained in:
Maier
2020-04-10 15:53:57 -04:00
parent 505d4b810b
commit 2241eb0b00
8 changed files with 96 additions and 39 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -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) {

View File

@@ -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
}
];

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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">