player management, better controls, town info

This commit is contained in:
Steffen 2020-04-05 22:54:15 +02:00
parent 7974e2f131
commit ed56801ad6
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
6 changed files with 249 additions and 128 deletions

View File

@ -1,51 +1,35 @@
<template> <template>
<div id="app"> <div id="app">
<ul class="info"> <TownInfo :players="players"></TownInfo>
<li>
{{ players.length }} <font-awesome-icon icon="users" />
{{ teams.alive }} <font-awesome-icon icon="heartbeat" />
{{ teams.votes }} <font-awesome-icon icon="vote-yea" />
</li>
<li>
{{ teams.townsfolk }}
<span class="townsfolk"><font-awesome-icon icon="user-friends"/></span>
{{ teams.outsiders }}
<span class="outsider"><font-awesome-icon v-bind:icon="teams.outsiders > 1 ? 'user-friends' : 'user'"/></span>
{{ teams.minions }}
<span class="minion"><font-awesome-icon v-bind:icon="teams.minions > 1 ? 'user-friends' : 'user'"/></span>
{{ teams.demons }}
<span class="demon"><font-awesome-icon v-bind:icon="teams.demons > 1 ? 'user-friends' : 'user'"/></span>
<template v-if="teams.travellers">
{{ teams.travellers }}
<span class="traveller"
><font-awesome-icon v-bind:icon="teams.travellers > 1 ? 'user-friends' : 'user'"/></span>
</template>
</li>
</ul>
<TownSquare <TownSquare
v-if="players.length >= 5"
:is-public="isPublic" :is-public="isPublic"
:players="players" :players="players"
:roles="roles" :roles="roles"
></TownSquare> ></TownSquare>
<div class="controls"> <div class="controls">
<button v-on:click="togglePublic">Toggle</button> <font-awesome-icon icon="cogs" @click="isControlOpen = !isControlOpen"/>
<button v-on:click="addPlayer" v-bind:disabled="players.length >= 20"> <ul v-if="isControlOpen">
Add Player <li v-on:click="togglePublic">
</button> Toggle Grimoire
<button v-on:click="togglePublic" v-bind:disabled="players.length <= 0"> </li>
Remove Player <li v-on:click="addPlayer" v-if="players.length < 20">
</button> Add Player
<button v-on:click="togglePublic">Select Roles</button> </li>
<button v-on:click="togglePublic">Randomize Roles</button> <li v-on:click="togglePublic" v-if="players.length > 4">
Select Roles
</li>
<li v-on:click="randomizeSeatings" v-if="players.length > 2">
Randomize Seatings
</li>
</ul>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import TownSquare from "./components/TownSquare.vue"; import TownSquare from "./components/TownSquare";
import TownInfo from "./components/TownInfo";
import rolesJSON from "./roles"; import rolesJSON from "./roles";
import gameJSON from "./game";
const roles = new Map( const roles = new Map(
rolesJSON rolesJSON
@ -55,44 +39,27 @@ const roles = new Map(
export default { export default {
components: { components: {
TownSquare TownSquare,
}, TownInfo
computed: {
teams: function() {
const nontravellers = this.players.filter(
player => player.role.team !== "traveller"
).length;
const alive = this.players.filter(player => player.hasDied !== true)
.length;
return {
...gameJSON[nontravellers - 5],
travellers: this.players.length - nontravellers,
alive,
votes:
alive +
this.players.filter(
player => player.hasDied === true && player.hasVoted !== true
).length
};
}
}, },
data: () => ({ data: () => ({
isPublic: true, isPublic: true,
isControlOpen: false,
players: [ players: [
{ // {
name: "Steffen", // name: "Steffen",
role: roles.get("baron"), // role: roles.get("baron"),
reminders: [{ role: "imp", name: "Die" }] // reminders: [{ role: "imp", name: "Die" }]
}, // },
{ name: "Tino", role: roles.get("harlot"), reminders: [] }, // { name: "Tino", role: roles.get("harlot"), reminders: [] },
{ name: "Basti", role: roles.get("chef"), reminders: [] }, // { name: "Basti", role: roles.get("chef"), reminders: [] },
{ name: "Bernd", role: roles.get("ravenkeeper"), reminders: [] }, // { name: "Bernd", role: roles.get("ravenkeeper"), reminders: [] },
{ name: "Tim", role: roles.get("drunk"), reminders: [] }, // { name: "Tim", role: roles.get("drunk"), reminders: [] },
{ name: "Yann", role: roles.get("librarian"), reminders: [] }, // { name: "Yann", role: roles.get("librarian"), reminders: [] },
{ name: "Marie", role: roles.get("empath"), reminders: [] }, // { name: "Marie", role: roles.get("empath"), reminders: [] },
{ name: "Bogdan", role: roles.get("scarletwoman"), reminders: [] }, // { name: "Bogdan", role: roles.get("scarletwoman"), reminders: [] },
{ name: "Sean", role: roles.get("recluse"), reminders: [] }, // { name: "Sean", role: roles.get("recluse"), reminders: [] },
{ name: "Petra", role: roles.get("undertaker"), reminders: [] } // { name: "Petra", role: roles.get("undertaker"), reminders: [] }
], ],
roles, roles,
set: "TB" set: "TB"
@ -100,6 +67,7 @@ export default {
methods: { methods: {
togglePublic() { togglePublic() {
this.isPublic = !this.isPublic; this.isPublic = !this.isPublic;
this.isControlOpen = false;
}, },
addPlayer() { addPlayer() {
const name = prompt("Player name"); const name = prompt("Player name");
@ -110,14 +78,20 @@ export default {
reminders: [] reminders: []
}); });
} }
},
randomizeSeatings() {
if (confirm("Are you sure you want to randomize seatings?")) {
this.players = this.players
.map(a => [Math.random(), a])
.sort((a, b) => a[0] - b[0])
.map(a => a[1]);
}
} }
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
@import "vars.scss";
@font-face { @font-face {
font-family: "Papyrus"; font-family: "Papyrus";
src: url("assets/fonts/papyrus.eot"); /* IE9*/ src: url("assets/fonts/papyrus.eot"); /* IE9*/
@ -158,56 +132,30 @@ body {
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
} text-align: right;
padding: 10px;
.info { svg {
position: absolute; cursor: pointer;
display: flex; }
left: 50%; ul {
top: 50%; display: flex;
width: 20%; list-style-type: none;
height: 20%; padding: 0;
margin-left: -10%; margin: 0;
margin-top: -5%; flex-direction: column;
padding: 0; border-radius: 10px;
align-items: center; overflow: hidden;
align-content: center; box-shadow: 0 0 10px black;
justify-content: center; li {
flex-wrap: wrap; padding: 5px 10px;
background: url("assets/demon-head.png") center center no-repeat; color: white;
background-size: auto 100%; text-align: center;
background: rgba(0, 0, 0, 0.7);
li { margin-bottom: 1px;
display: block; cursor: pointer;
white-space: nowrap; &:hover {
font-weight: bold; background-color: red;
text-shadow: 0 0 2px black; }
text-align: center;
padding: 0 5px;
width: 100%;
svg {
margin-right: 10px;
}
.townsfolk {
color: $townsfolk;
}
.outsider {
color: $outsider;
}
.minion {
color: $minion;
}
.demon {
color: $demon;
}
.traveller {
color: $traveller;
}
.alive,
.votes {
color: #aaa;
} }
} }
} }

View File

@ -22,7 +22,12 @@
<div class="ability" v-if="player.role.ability"> <div class="ability" v-if="player.role.ability">
{{ player.role.ability }} {{ player.role.ability }}
</div> </div>
<div class="name" @click="changeName">{{ player.name }}</div> <div class="name" @click="changeName">
{{ player.name }}
<span class="remove" @click.stop="$emit('remove-player', player)">
<font-awesome-icon icon="times-circle" />
</span>
</div>
</div> </div>
<template v-if="player.reminders"> <template v-if="player.reminders">
<div <div
@ -238,9 +243,19 @@ export default {
.name { .name {
font-size: 120%; font-size: 120%;
line-height: 120%; line-height: 120%;
text-shadow: -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, filter: drop-shadow(0 0 1px rgba(0, 0, 0, 1))
2px 2px 0 #000, 0 0 10px rgba(0, 0, 0, 0.75); drop-shadow(0 0 1px rgba(0, 0, 0, 1))
drop-shadow(0 0 1px rgba(0, 0, 0, 1));
cursor: pointer; cursor: pointer;
span {
display: none;
}
&:hover span {
display: inline-block;
&:hover {
color: red;
}
}
} }
/***** Ability text *****/ /***** Ability text *****/

129
src/components/TownInfo.vue Normal file
View File

@ -0,0 +1,129 @@
<template>
<ul class="info">
<li v-if="players.length < 5">Please add more players!</li>
<li>
{{ players.length }} <font-awesome-icon class="players" icon="users" />
{{ teams.alive }} <font-awesome-icon class="alive" icon="heartbeat" />
{{ teams.votes }} <font-awesome-icon class="votes" icon="vote-yea" />
</li>
<li v-if="players.length >= 5">
{{ teams.townsfolk }}
<font-awesome-icon class="townsfolk" icon="user-friends" />
{{ teams.outsiders }}
<font-awesome-icon
class="outsider"
v-bind:icon="teams.outsiders > 1 ? 'user-friends' : 'user'"
/>
{{ teams.minions }}
<font-awesome-icon
class="minion"
v-bind:icon="teams.minions > 1 ? 'user-friends' : 'user'"
/>
{{ teams.demons }}
<font-awesome-icon
class="demon"
v-bind:icon="teams.demons > 1 ? 'user-friends' : 'user'"
/>
<template v-if="teams.travellers">
{{ teams.travellers }}
<font-awesome-icon
class="traveller"
v-bind:icon="teams.travellers > 1 ? 'user-friends' : 'user'"
/>
</template>
</li>
</ul>
</template>
<script>
import gameJSON from "./../game";
export default {
props: {
players: {
type: Array,
required: true
}
},
computed: {
teams: function() {
const nontravellers = this.players.filter(
player => player.role.team !== "traveller"
).length;
const alive = this.players.filter(player => player.hasDied !== true)
.length;
return {
...gameJSON[nontravellers - 5],
travellers: this.players.length - nontravellers,
alive,
votes:
alive +
this.players.filter(
player => player.hasDied === true && player.hasVoted !== true
).length
};
}
}
};
</script>
<style lang="scss">
@import "../vars.scss";
.info {
position: absolute;
display: flex;
left: 50%;
top: 50%;
width: 20%;
height: 20%;
margin-left: -10%;
margin-top: -5%;
padding: 0;
align-items: center;
align-content: center;
justify-content: center;
flex-wrap: wrap;
background: url("../assets/demon-head.png") center center no-repeat;
background-size: auto 100%;
li {
display: block;
white-space: nowrap;
font-weight: bold;
text-align: center;
padding: 0 5px;
width: 100%;
filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.7));
svg {
margin-right: 10px;
}
.players {
color: #00f700;
}
.alive {
color: #ff4a50;
}
.votes {
color: #1cfff2;
}
.townsfolk {
color: $townsfolk;
}
.outsider {
color: $outsider;
}
.minion {
color: $minion;
}
.demon {
color: $demon;
}
.traveller {
color: $traveller;
}
}
}
</style>

View File

@ -9,6 +9,7 @@
:is-public="isPublic" :is-public="isPublic"
@add-reminder="openReminderModal" @add-reminder="openReminderModal"
@set-role="openRoleModal" @set-role="openRoleModal"
@remove-player="removePlayer"
></Player> ></Player>
</ul> </ul>
<Modal v-show="availableReminders.length" @close="closeModal"> <Modal v-show="availableReminders.length" @close="closeModal">
@ -51,7 +52,20 @@ export default {
Modal, Modal,
Player Player
}, },
props: ["isPublic", "players", "roles"], props: {
isPublic: {
type: Boolean,
required: true
},
players: {
type: Array,
required: true
},
roles: {
type: Map,
required: true
}
},
data() { data() {
return { return {
selectedPlayer: false, selectedPlayer: false,
@ -96,6 +110,11 @@ export default {
this.selectedPlayer = false; this.selectedPlayer = false;
this.availableReminders = []; this.availableReminders = [];
this.availableRoles = []; this.availableRoles = [];
},
removePlayer(player) {
if (confirm(`Do you really want to remove ${player.name}?`)) {
this.players.splice(this.players.indexOf(player), 1);
}
} }
} }
}; };
@ -174,7 +193,7 @@ export default {
} }
} }
@for $i from 5 through 20 { @for $i from 1 through 20 {
.circle.size-#{$i} li { .circle.size-#{$i} li {
@include on-circle($item-count: $i); @include on-circle($item-count: $i);
} }

View File

@ -6,11 +6,21 @@ import {
faHeartbeat, faHeartbeat,
faVoteYea, faVoteYea,
faUserFriends, faUserFriends,
faUser faUser,
faTimesCircle,
faCogs
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
library.add(faUsers, faHeartbeat, faVoteYea, faUserFriends, faUser); library.add(
faUsers,
faHeartbeat,
faVoteYea,
faUserFriends,
faUser,
faTimesCircle,
faCogs
);
Vue.component("font-awesome-icon", FontAwesomeIcon); Vue.component("font-awesome-icon", FontAwesomeIcon);

View File

@ -2,7 +2,7 @@ $token: 150px;
$townsfolk: #1f65ff; $townsfolk: #1f65ff;
$outsider: #46d5ff; $outsider: #46d5ff;
$minion: #ff6900; $minion: #ff6900;
$demon: #ff0000; $demon: #ce0100;
$traveller: #cc04ff; $traveller: #cc04ff;
$roles: $roles: