mirror of https://github.com/bra1n/townsquare.git
player management, better controls, town info
This commit is contained in:
parent
7974e2f131
commit
ed56801ad6
188
src/App.vue
188
src/App.vue
|
@ -1,51 +1,35 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<ul class="info">
|
||||
<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>
|
||||
<TownInfo :players="players"></TownInfo>
|
||||
<TownSquare
|
||||
v-if="players.length >= 5"
|
||||
:is-public="isPublic"
|
||||
:players="players"
|
||||
:roles="roles"
|
||||
></TownSquare>
|
||||
<div class="controls">
|
||||
<button v-on:click="togglePublic">Toggle</button>
|
||||
<button v-on:click="addPlayer" v-bind:disabled="players.length >= 20">
|
||||
Add Player
|
||||
</button>
|
||||
<button v-on:click="togglePublic" v-bind:disabled="players.length <= 0">
|
||||
Remove Player
|
||||
</button>
|
||||
<button v-on:click="togglePublic">Select Roles</button>
|
||||
<button v-on:click="togglePublic">Randomize Roles</button>
|
||||
<font-awesome-icon icon="cogs" @click="isControlOpen = !isControlOpen"/>
|
||||
<ul v-if="isControlOpen">
|
||||
<li v-on:click="togglePublic">
|
||||
Toggle Grimoire
|
||||
</li>
|
||||
<li v-on:click="addPlayer" v-if="players.length < 20">
|
||||
Add Player
|
||||
</li>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TownSquare from "./components/TownSquare.vue";
|
||||
import TownSquare from "./components/TownSquare";
|
||||
import TownInfo from "./components/TownInfo";
|
||||
import rolesJSON from "./roles";
|
||||
import gameJSON from "./game";
|
||||
|
||||
const roles = new Map(
|
||||
rolesJSON
|
||||
|
@ -55,44 +39,27 @@ const roles = new Map(
|
|||
|
||||
export default {
|
||||
components: {
|
||||
TownSquare
|
||||
},
|
||||
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
|
||||
};
|
||||
}
|
||||
TownSquare,
|
||||
TownInfo
|
||||
},
|
||||
data: () => ({
|
||||
isPublic: true,
|
||||
isControlOpen: false,
|
||||
players: [
|
||||
{
|
||||
name: "Steffen",
|
||||
role: roles.get("baron"),
|
||||
reminders: [{ role: "imp", name: "Die" }]
|
||||
},
|
||||
{ name: "Tino", role: roles.get("harlot"), reminders: [] },
|
||||
{ name: "Basti", role: roles.get("chef"), reminders: [] },
|
||||
{ name: "Bernd", role: roles.get("ravenkeeper"), reminders: [] },
|
||||
{ name: "Tim", role: roles.get("drunk"), reminders: [] },
|
||||
{ name: "Yann", role: roles.get("librarian"), reminders: [] },
|
||||
{ name: "Marie", role: roles.get("empath"), reminders: [] },
|
||||
{ name: "Bogdan", role: roles.get("scarletwoman"), reminders: [] },
|
||||
{ name: "Sean", role: roles.get("recluse"), reminders: [] },
|
||||
{ name: "Petra", role: roles.get("undertaker"), reminders: [] }
|
||||
// {
|
||||
// name: "Steffen",
|
||||
// role: roles.get("baron"),
|
||||
// reminders: [{ role: "imp", name: "Die" }]
|
||||
// },
|
||||
// { name: "Tino", role: roles.get("harlot"), reminders: [] },
|
||||
// { name: "Basti", role: roles.get("chef"), reminders: [] },
|
||||
// { name: "Bernd", role: roles.get("ravenkeeper"), reminders: [] },
|
||||
// { name: "Tim", role: roles.get("drunk"), reminders: [] },
|
||||
// { name: "Yann", role: roles.get("librarian"), reminders: [] },
|
||||
// { name: "Marie", role: roles.get("empath"), reminders: [] },
|
||||
// { name: "Bogdan", role: roles.get("scarletwoman"), reminders: [] },
|
||||
// { name: "Sean", role: roles.get("recluse"), reminders: [] },
|
||||
// { name: "Petra", role: roles.get("undertaker"), reminders: [] }
|
||||
],
|
||||
roles,
|
||||
set: "TB"
|
||||
|
@ -100,6 +67,7 @@ export default {
|
|||
methods: {
|
||||
togglePublic() {
|
||||
this.isPublic = !this.isPublic;
|
||||
this.isControlOpen = false;
|
||||
},
|
||||
addPlayer() {
|
||||
const name = prompt("Player name");
|
||||
|
@ -110,14 +78,20 @@ export default {
|
|||
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>
|
||||
|
||||
<style lang="scss">
|
||||
@import "vars.scss";
|
||||
|
||||
@font-face {
|
||||
font-family: "Papyrus";
|
||||
src: url("assets/fonts/papyrus.eot"); /* IE9*/
|
||||
|
@ -158,56 +132,30 @@ body {
|
|||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.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-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;
|
||||
text-align: right;
|
||||
padding: 10px;
|
||||
svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
ul {
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 10px black;
|
||||
li {
|
||||
padding: 5px 10px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
margin-bottom: 1px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,12 @@
|
|||
<div class="ability" v-if="player.role.ability">
|
||||
{{ player.role.ability }}
|
||||
</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>
|
||||
<template v-if="player.reminders">
|
||||
<div
|
||||
|
@ -238,9 +243,19 @@ export default {
|
|||
.name {
|
||||
font-size: 120%;
|
||||
line-height: 120%;
|
||||
text-shadow: -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000,
|
||||
2px 2px 0 #000, 0 0 10px rgba(0, 0, 0, 0.75);
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 1))
|
||||
drop-shadow(0 0 1px rgba(0, 0, 0, 1))
|
||||
drop-shadow(0 0 1px rgba(0, 0, 0, 1));
|
||||
cursor: pointer;
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
&:hover span {
|
||||
display: inline-block;
|
||||
&:hover {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***** Ability text *****/
|
||||
|
|
|
@ -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>
|
|
@ -9,6 +9,7 @@
|
|||
:is-public="isPublic"
|
||||
@add-reminder="openReminderModal"
|
||||
@set-role="openRoleModal"
|
||||
@remove-player="removePlayer"
|
||||
></Player>
|
||||
</ul>
|
||||
<Modal v-show="availableReminders.length" @close="closeModal">
|
||||
|
@ -51,7 +52,20 @@ export default {
|
|||
Modal,
|
||||
Player
|
||||
},
|
||||
props: ["isPublic", "players", "roles"],
|
||||
props: {
|
||||
isPublic: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
players: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
roles: {
|
||||
type: Map,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedPlayer: false,
|
||||
|
@ -96,6 +110,11 @@ export default {
|
|||
this.selectedPlayer = false;
|
||||
this.availableReminders = [];
|
||||
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 {
|
||||
@include on-circle($item-count: $i);
|
||||
}
|
||||
|
|
14
src/main.js
14
src/main.js
|
@ -6,11 +6,21 @@ import {
|
|||
faHeartbeat,
|
||||
faVoteYea,
|
||||
faUserFriends,
|
||||
faUser
|
||||
faUser,
|
||||
faTimesCircle,
|
||||
faCogs
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
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);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ $token: 150px;
|
|||
$townsfolk: #1f65ff;
|
||||
$outsider: #46d5ff;
|
||||
$minion: #ff6900;
|
||||
$demon: #ff0000;
|
||||
$demon: #ce0100;
|
||||
$traveller: #cc04ff;
|
||||
|
||||
$roles:
|
||||
|
|
Loading…
Reference in New Issue