mirror of
https://github.com/bra1n/townsquare.git
synced 2025-04-04 22:24:36 +00:00
Merge branch 'develop'
This commit is contained in:
commit
6312dd4a45
11 changed files with 169 additions and 138 deletions
src
BIN
src/assets/icons/demon_info.png
Normal file
BIN
src/assets/icons/demon_info.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 23 KiB |
BIN
src/assets/icons/minion_info.png
Normal file
BIN
src/assets/icons/minion_info.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 24 KiB |
|
@ -87,7 +87,7 @@
|
||||||
Background image
|
Background image
|
||||||
<em><font-awesome-icon icon="image"/></em>
|
<em><font-awesome-icon icon="image"/></em>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="!edition.isOfficial" @click="imageOptIn">
|
<!-- <li v-if="!edition.isOfficial" @click="imageOptIn">
|
||||||
<small>Show Custom Images</small>
|
<small>Show Custom Images</small>
|
||||||
<em
|
<em
|
||||||
><font-awesome-icon
|
><font-awesome-icon
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
grimoire.isImageOptIn ? 'check-square' : 'square'
|
grimoire.isImageOptIn ? 'check-square' : 'square'
|
||||||
]"
|
]"
|
||||||
/></em>
|
/></em>
|
||||||
</li>
|
</li> -->
|
||||||
<li @click="toggleStatic">
|
<li @click="toggleStatic">
|
||||||
Disable Animations
|
Disable Animations
|
||||||
<em
|
<em
|
||||||
|
@ -134,10 +134,6 @@
|
||||||
Copy player link
|
Copy player link
|
||||||
<em><font-awesome-icon icon="copy"/></em>
|
<em><font-awesome-icon icon="copy"/></em>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="!session.isSpectator" @click="distributeRoles">
|
|
||||||
Send Characters
|
|
||||||
<em><font-awesome-icon icon="theater-masks"/></em>
|
|
||||||
</li>
|
|
||||||
<li
|
<li
|
||||||
v-if="session.voteHistory.length || !session.isSpectator"
|
v-if="session.voteHistory.length || !session.isSpectator"
|
||||||
@click="toggleModal('voteHistory')"
|
@click="toggleModal('voteHistory')"
|
||||||
|
@ -145,7 +141,7 @@
|
||||||
Vote history<em>[V]</em>
|
Vote history<em>[V]</em>
|
||||||
</li>
|
</li>
|
||||||
<li @click="leaveSession">
|
<li @click="leaveSession">
|
||||||
Leave Session
|
退出房间
|
||||||
<em>{{ session.sessionId }}</em>
|
<em>{{ session.sessionId }}</em>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -154,13 +150,13 @@
|
||||||
<template v-if="tab === 'players' && !session.isSpectator">
|
<template v-if="tab === 'players' && !session.isSpectator">
|
||||||
<!-- Users -->
|
<!-- Users -->
|
||||||
<li class="headline">Players</li>
|
<li class="headline">Players</li>
|
||||||
<li @click="addPlayer" v-if="players.length < 20">Add<em>[A]</em></li>
|
<li @click="addPlayer" v-if="players.length < 20">添加座位<em>[A]</em></li>
|
||||||
<li @click="randomizeSeatings" v-if="players.length > 2">
|
<li @click="randomizeSeatings" v-if="players.length > 2">
|
||||||
Randomize
|
随机座位
|
||||||
<em><font-awesome-icon icon="dice"/></em>
|
<em><font-awesome-icon icon="dice"/></em>
|
||||||
</li>
|
</li>
|
||||||
<li @click="clearPlayers" v-if="players.length">
|
<li @click="clearPlayers" v-if="players.length">
|
||||||
Remove all
|
移除全部座位
|
||||||
<em><font-awesome-icon icon="trash-alt"/></em>
|
<em><font-awesome-icon icon="trash-alt"/></em>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -169,22 +165,26 @@
|
||||||
<!-- Characters -->
|
<!-- Characters -->
|
||||||
<li class="headline">Characters</li>
|
<li class="headline">Characters</li>
|
||||||
<li v-if="!session.isSpectator" @click="toggleModal('edition')">
|
<li v-if="!session.isSpectator" @click="toggleModal('edition')">
|
||||||
Select Edition
|
选择剧本
|
||||||
<em>[E]</em>
|
<em>[E]</em>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
@click="toggleModal('roles')"
|
@click="toggleModal('roles')"
|
||||||
v-if="!session.isSpectator && players.length > 4"
|
v-if="!session.isSpectator && players.length > 4"
|
||||||
>
|
>
|
||||||
Choose & Assign
|
分配角色
|
||||||
<em>[C]</em>
|
<em>[C]</em>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="!session.isSpectator" @click="distributeRoles">
|
||||||
|
发送角色
|
||||||
|
<em><font-awesome-icon icon="theater-masks"/></em>
|
||||||
|
</li>
|
||||||
<li v-if="!session.isSpectator" @click="toggleModal('fabled')">
|
<li v-if="!session.isSpectator" @click="toggleModal('fabled')">
|
||||||
Add Fabled
|
传奇角色
|
||||||
<em><font-awesome-icon icon="dragon"/></em>
|
<em><font-awesome-icon icon="dragon"/></em>
|
||||||
</li>
|
</li>
|
||||||
<li @click="clearRoles" v-if="players.length">
|
<li @click="clearRoles" v-if="players.length">
|
||||||
Remove all
|
移除全部角色
|
||||||
<em><font-awesome-icon icon="trash-alt"/></em>
|
<em><font-awesome-icon icon="trash-alt"/></em>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -193,11 +193,11 @@
|
||||||
<!-- Help -->
|
<!-- Help -->
|
||||||
<li class="headline">Help</li>
|
<li class="headline">Help</li>
|
||||||
<li @click="toggleModal('reference')">
|
<li @click="toggleModal('reference')">
|
||||||
Reference Sheet
|
角色能力表
|
||||||
<em>[R]</em>
|
<em>[R]</em>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleModal('nightOrder')">
|
<li @click="toggleModal('nightOrder')">
|
||||||
Night Order Sheet
|
夜晚顺序表
|
||||||
<em>[N]</em>
|
<em>[N]</em>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleModal('gameState')">
|
<li @click="toggleModal('gameState')">
|
||||||
|
@ -253,7 +253,7 @@ export default {
|
||||||
hostSession() {
|
hostSession() {
|
||||||
if (this.session.sessionId) return;
|
if (this.session.sessionId) return;
|
||||||
const sessionId = prompt(
|
const sessionId = prompt(
|
||||||
"Enter a channel number / name for your session",
|
"输入你想要创建的房间的名称或号码",
|
||||||
Math.round(Math.random() * 10000)
|
Math.round(Math.random() * 10000)
|
||||||
);
|
);
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
|
@ -271,7 +271,7 @@ export default {
|
||||||
distributeRoles() {
|
distributeRoles() {
|
||||||
if (this.session.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
const popup =
|
const popup =
|
||||||
"Do you want to distribute assigned characters to all SEATED players?";
|
"你确定要向所有已入座的玩家发送角色吗?";
|
||||||
if (confirm(popup)) {
|
if (confirm(popup)) {
|
||||||
this.$store.commit("session/distributeRoles", true);
|
this.$store.commit("session/distributeRoles", true);
|
||||||
setTimeout(
|
setTimeout(
|
||||||
|
@ -292,7 +292,7 @@ export default {
|
||||||
joinSession() {
|
joinSession() {
|
||||||
if (this.session.sessionId) return this.leaveSession();
|
if (this.session.sessionId) return this.leaveSession();
|
||||||
let sessionId = prompt(
|
let sessionId = prompt(
|
||||||
"Enter the channel number / name of the session you want to join"
|
"输入你想要加入的房间的名称或号码"
|
||||||
);
|
);
|
||||||
if (sessionId.match(/^https?:\/\//i)) {
|
if (sessionId.match(/^https?:\/\//i)) {
|
||||||
sessionId = sessionId.split("#").pop();
|
sessionId = sessionId.split("#").pop();
|
||||||
|
@ -305,7 +305,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leaveSession() {
|
leaveSession() {
|
||||||
if (confirm("Are you sure you want to leave the active live game?")) {
|
if (confirm("你确定要离开房间吗?")) {
|
||||||
this.$store.commit("session/setSpectator", false);
|
this.$store.commit("session/setSpectator", false);
|
||||||
this.$store.commit("session/setSessionId", "");
|
this.$store.commit("session/setSessionId", "");
|
||||||
}
|
}
|
||||||
|
@ -320,13 +320,13 @@ export default {
|
||||||
},
|
},
|
||||||
randomizeSeatings() {
|
randomizeSeatings() {
|
||||||
if (this.session.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (confirm("Are you sure you want to randomize seatings?")) {
|
if (confirm("你确定要打乱座位吗?")) {
|
||||||
this.$store.dispatch("players/randomize");
|
this.$store.dispatch("players/randomize");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearPlayers() {
|
clearPlayers() {
|
||||||
if (this.session.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (confirm("Are you sure you want to remove all players?")) {
|
if (confirm("你确定要移除所有座位吗?")) {
|
||||||
// abort vote if in progress
|
// abort vote if in progress
|
||||||
if (this.session.nomination) {
|
if (this.session.nomination) {
|
||||||
this.$store.commit("session/nomination");
|
this.$store.commit("session/nomination");
|
||||||
|
@ -335,7 +335,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearRoles() {
|
clearRoles() {
|
||||||
if (confirm("Are you sure you want to remove all player roles?")) {
|
if (confirm("你确定要移除所有玩家的角色吗?")) {
|
||||||
this.$store.dispatch("players/clearRoles");
|
this.$store.dispatch("players/clearRoles");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
'no-vote': player.isVoteless,
|
'no-vote': player.isVoteless,
|
||||||
you: session.sessionId && player.id && player.id === session.playerId,
|
you: session.sessionId && player.id && player.id === session.playerId,
|
||||||
'vote-yes': session.votes[index],
|
'vote-yes': session.votes[index],
|
||||||
'vote-lock': voteLocked
|
'vote-lock': voteLocked,
|
||||||
},
|
},
|
||||||
player.role.team
|
player.role.team,
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div class="shroud" @click="toggleStatus()"></div>
|
<div class="shroud" @click="toggleStatus()"></div>
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
@click="changePronouns"
|
@click="changePronouns"
|
||||||
v-if="
|
v-if="
|
||||||
!session.isSpectator ||
|
!session.isSpectator ||
|
||||||
(session.isSpectator && player.id === session.playerId)
|
(session.isSpectator && player.id === session.playerId)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<font-awesome-icon icon="venus-mars" />Change Pronouns
|
<font-awesome-icon icon="venus-mars" />Change Pronouns
|
||||||
|
@ -162,9 +162,7 @@
|
||||||
:class="{ disabled: player.id && player.id !== session.playerId }"
|
:class="{ disabled: player.id && player.id !== session.playerId }"
|
||||||
>
|
>
|
||||||
<font-awesome-icon icon="chair" />
|
<font-awesome-icon icon="chair" />
|
||||||
<template v-if="!player.id">
|
<template v-if="!player.id"> Claim seat </template>
|
||||||
Claim seat
|
|
||||||
</template>
|
|
||||||
<template v-else-if="player.id === session.playerId">
|
<template v-else-if="player.id === session.playerId">
|
||||||
Vacate seat
|
Vacate seat
|
||||||
</template>
|
</template>
|
||||||
|
@ -188,10 +186,12 @@
|
||||||
backgroundImage: `url(${
|
backgroundImage: `url(${
|
||||||
reminder.image && grimoire.isImageOptIn
|
reminder.image && grimoire.isImageOptIn
|
||||||
? reminder.image
|
? reminder.image
|
||||||
: require('../assets/icons/' +
|
: require(
|
||||||
(reminder.imageAlt || reminder.role) +
|
'../assets/icons/' +
|
||||||
'.png')
|
(reminder.imageAlt || reminder.role) +
|
||||||
})`
|
'.png',
|
||||||
|
)
|
||||||
|
})`,
|
||||||
}"
|
}"
|
||||||
></span>
|
></span>
|
||||||
<span class="text">{{ reminder.name }}</span>
|
<span class="text">{{ reminder.name }}</span>
|
||||||
|
@ -210,22 +210,22 @@ import { mapGetters, mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Token
|
Token,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
player: {
|
player: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("players", ["players"]),
|
...mapState("players", ["players"]),
|
||||||
...mapState(["grimoire", "session"]),
|
...mapState(["grimoire", "session"]),
|
||||||
...mapGetters({ nightOrder: "players/nightOrder" }),
|
...mapGetters({ nightOrder: "players/nightOrder" }),
|
||||||
index: function() {
|
index: function () {
|
||||||
return this.players.indexOf(this.player);
|
return this.players.indexOf(this.player);
|
||||||
},
|
},
|
||||||
voteLocked: function() {
|
voteLocked: function () {
|
||||||
const session = this.session;
|
const session = this.session;
|
||||||
const players = this.players.length;
|
const players = this.players.length;
|
||||||
if (!session.nomination) return false;
|
if (!session.nomination) return false;
|
||||||
|
@ -233,7 +233,7 @@ export default {
|
||||||
(this.index - 1 + players - session.nomination[1]) % players;
|
(this.index - 1 + players - session.nomination[1]) % players;
|
||||||
return indexAdjusted < session.lockedVote - 1;
|
return indexAdjusted < session.lockedVote - 1;
|
||||||
},
|
},
|
||||||
zoom: function() {
|
zoom: function () {
|
||||||
const unit = window.innerWidth > window.innerHeight ? "vh" : "vw";
|
const unit = window.innerWidth > window.innerHeight ? "vh" : "vw";
|
||||||
if (this.players.length < 7) {
|
if (this.players.length < 7) {
|
||||||
return { width: 18 + this.grimoire.zoom + unit };
|
return { width: 18 + this.grimoire.zoom + unit };
|
||||||
|
@ -244,12 +244,12 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
return { width: 12 + this.grimoire.zoom + unit };
|
return { width: 12 + this.grimoire.zoom + unit };
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isMenuOpen: false,
|
isMenuOpen: false,
|
||||||
isSwap: false
|
isSwap: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -305,7 +305,7 @@ export default {
|
||||||
this.$store.commit("players/update", {
|
this.$store.commit("players/update", {
|
||||||
player: this.player,
|
player: this.player,
|
||||||
property,
|
property,
|
||||||
value
|
value,
|
||||||
});
|
});
|
||||||
if (closeMenu) {
|
if (closeMenu) {
|
||||||
this.isMenuOpen = false;
|
this.isMenuOpen = false;
|
||||||
|
@ -342,10 +342,10 @@ export default {
|
||||||
if (!this.voteLocked) return;
|
if (!this.voteLocked) return;
|
||||||
this.$store.commit("session/voteSync", [
|
this.$store.commit("session/voteSync", [
|
||||||
this.index,
|
this.index,
|
||||||
!this.session.votes[this.index]
|
!this.session.votes[this.index],
|
||||||
]);
|
]);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -632,11 +632,11 @@ li.move:not(.from) .player .overlay svg.move {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include glow("townsfolk", $townsfolk);
|
@include glow("镇民", $townsfolk);
|
||||||
@include glow("outsider", $outsider);
|
@include glow("外来者", $outsider);
|
||||||
@include glow("demon", $demon);
|
@include glow("恶魔", $demon);
|
||||||
@include glow("minion", $minion);
|
@include glow("爪牙", $minion);
|
||||||
@include glow("traveler", $traveler);
|
@include glow("旅行者", $traveler);
|
||||||
|
|
||||||
.player.you .token {
|
.player.you .token {
|
||||||
animation: townsfolk-glow 5s ease-in-out infinite;
|
animation: townsfolk-glow 5s ease-in-out infinite;
|
||||||
|
@ -869,7 +869,10 @@ li.move:not(.from) .player .overlay svg.move {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15%;
|
top: 15%;
|
||||||
text-shadow: 0 1px 1px #f6dfbd, 0 -1px 1px #f6dfbd, 1px 0 1px #f6dfbd,
|
text-shadow:
|
||||||
|
0 1px 1px #f6dfbd,
|
||||||
|
0 -1px 1px #f6dfbd,
|
||||||
|
1px 0 1px #f6dfbd,
|
||||||
-1px 0 1px #f6dfbd;
|
-1px 0 1px #f6dfbd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
:class="{
|
:class="{
|
||||||
public: grimoire.isPublic,
|
public: grimoire.isPublic,
|
||||||
spectator: session.isSpectator,
|
spectator: session.isSpectator,
|
||||||
vote: session.nomination
|
vote: session.nomination,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ul class="circle" :class="['size-' + players.length]">
|
<ul class="circle" :class="['size-' + players.length]">
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
from: Math.max(swap, move, nominate) === index,
|
from: Math.max(swap, move, nominate) === index,
|
||||||
swap: swap > -1,
|
swap: swap > -1,
|
||||||
move: move > -1,
|
move: move > -1,
|
||||||
nominate: nominate > -1
|
nominate: nominate > -1,
|
||||||
}"
|
}"
|
||||||
></Player>
|
></Player>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -29,12 +29,20 @@
|
||||||
ref="bluffs"
|
ref="bluffs"
|
||||||
:class="{ closed: !isBluffsOpen }"
|
:class="{ closed: !isBluffsOpen }"
|
||||||
>
|
>
|
||||||
<h3>
|
<h5>
|
||||||
<span v-if="session.isSpectator">Other characters</span>
|
<span v-if="session.isSpectator">Other characters</span>
|
||||||
<span v-else>Demon bluffs</span>
|
<span v-else>恶魔的伪装角色</span>
|
||||||
<font-awesome-icon icon="times-circle" @click.stop="toggleBluffs" />
|
<font-awesome-icon
|
||||||
<font-awesome-icon icon="plus-circle" @click.stop="toggleBluffs" />
|
icon="times-circle"
|
||||||
</h3>
|
v-if="isBluffsOpen"
|
||||||
|
@click.stop="toggleBluffs"
|
||||||
|
/>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="plus-circle"
|
||||||
|
v-if="!isBluffsOpen"
|
||||||
|
@click.stop="toggleBluffs"
|
||||||
|
/>
|
||||||
|
</h5>
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="index in bluffSize"
|
v-for="index in bluffSize"
|
||||||
|
@ -47,11 +55,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fabled" :class="{ closed: !isFabledOpen }" v-if="fabled.length">
|
<div class="fabled" :class="{ closed: !isFabledOpen }" v-if="fabled.length">
|
||||||
<h3>
|
<h5>
|
||||||
<span>Fabled</span>
|
<span>传奇角色</span>
|
||||||
<font-awesome-icon icon="times-circle" @click.stop="toggleFabled" />
|
<font-awesome-icon
|
||||||
<font-awesome-icon icon="plus-circle" @click.stop="toggleFabled" />
|
icon="times-circle"
|
||||||
</h3>
|
v-if="isFabledOpen"
|
||||||
|
@click.stop="toggleFabled"
|
||||||
|
/>
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="plus-circle"
|
||||||
|
v-if="!isFabledOpen"
|
||||||
|
@click.stop="toggleFabled"
|
||||||
|
/>
|
||||||
|
</h5>
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="(role, index) in fabled"
|
v-for="(role, index) in fabled"
|
||||||
|
@ -98,12 +114,12 @@ export default {
|
||||||
Player,
|
Player,
|
||||||
Token,
|
Token,
|
||||||
RoleModal,
|
RoleModal,
|
||||||
ReminderModal
|
ReminderModal,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({ nightOrder: "players/nightOrder" }),
|
...mapGetters({ nightOrder: "players/nightOrder" }),
|
||||||
...mapState(["grimoire", "roles", "session"]),
|
...mapState(["grimoire", "roles", "session"]),
|
||||||
...mapState("players", ["players", "bluffs", "fabled"])
|
...mapState("players", ["players", "bluffs", "fabled"]),
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -113,7 +129,7 @@ export default {
|
||||||
move: -1,
|
move: -1,
|
||||||
nominate: -1,
|
nominate: -1,
|
||||||
isBluffsOpen: true,
|
isBluffsOpen: true,
|
||||||
isFabledOpen: true
|
isFabledOpen: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -155,7 +171,7 @@ export default {
|
||||||
if (this.session.isSpectator || this.session.lockedVote) return;
|
if (this.session.isSpectator || this.session.lockedVote) return;
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
`Do you really want to remove ${this.players[playerIndex].name}?`
|
`Do you really want to remove ${this.players[playerIndex].name}?`,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const { nomination } = this.session;
|
const { nomination } = this.session;
|
||||||
|
@ -170,7 +186,7 @@ export default {
|
||||||
// update nomination array if removed player has lower index
|
// update nomination array if removed player has lower index
|
||||||
this.$store.commit("session/setNomination", [
|
this.$store.commit("session/setNomination", [
|
||||||
nomination[0] > playerIndex ? nomination[0] - 1 : nomination[0],
|
nomination[0] > playerIndex ? nomination[0] - 1 : nomination[0],
|
||||||
nomination[1] > playerIndex ? nomination[1] - 1 : nomination[1]
|
nomination[1] > playerIndex ? nomination[1] - 1 : nomination[1],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +202,7 @@ export default {
|
||||||
if (this.session.nomination) {
|
if (this.session.nomination) {
|
||||||
// update nomination if one of the involved players is swapped
|
// update nomination if one of the involved players is swapped
|
||||||
const swapTo = this.players.indexOf(to);
|
const swapTo = this.players.indexOf(to);
|
||||||
const updatedNomination = this.session.nomination.map(nom => {
|
const updatedNomination = this.session.nomination.map((nom) => {
|
||||||
if (nom === this.swap) return swapTo;
|
if (nom === this.swap) return swapTo;
|
||||||
if (nom === swapTo) return this.swap;
|
if (nom === swapTo) return this.swap;
|
||||||
return nom;
|
return nom;
|
||||||
|
@ -200,7 +216,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.$store.commit("players/swap", [
|
this.$store.commit("players/swap", [
|
||||||
this.swap,
|
this.swap,
|
||||||
this.players.indexOf(to)
|
this.players.indexOf(to),
|
||||||
]);
|
]);
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
@ -214,7 +230,7 @@ export default {
|
||||||
if (this.session.nomination) {
|
if (this.session.nomination) {
|
||||||
// update nomination if it is affected by the move
|
// update nomination if it is affected by the move
|
||||||
const moveTo = this.players.indexOf(to);
|
const moveTo = this.players.indexOf(to);
|
||||||
const updatedNomination = this.session.nomination.map(nom => {
|
const updatedNomination = this.session.nomination.map((nom) => {
|
||||||
if (nom === this.move) return moveTo;
|
if (nom === this.move) return moveTo;
|
||||||
if (nom > this.move && nom <= moveTo) return nom - 1;
|
if (nom > this.move && nom <= moveTo) return nom - 1;
|
||||||
if (nom < this.move && nom >= moveTo) return nom + 1;
|
if (nom < this.move && nom >= moveTo) return nom + 1;
|
||||||
|
@ -229,7 +245,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.$store.commit("players/move", [
|
this.$store.commit("players/move", [
|
||||||
this.move,
|
this.move,
|
||||||
this.players.indexOf(to)
|
this.players.indexOf(to),
|
||||||
]);
|
]);
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
@ -251,8 +267,8 @@ export default {
|
||||||
this.move = -1;
|
this.move = -1;
|
||||||
this.swap = -1;
|
this.swap = -1;
|
||||||
this.nominate = -1;
|
this.nominate = -1;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -272,8 +288,8 @@ export default {
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100vw;
|
||||||
height: 100%;
|
height: min(100vw, 100vh);
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
@ -459,8 +475,8 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
li {
|
li {
|
||||||
width: 14vh;
|
width: max(min(8vh, 8vw), 50px);
|
||||||
height: 14vh;
|
height: max(min(8vh, 8vw), 50px);
|
||||||
margin: 0 0.5%;
|
margin: 0 0.5%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
transition: all 250ms;
|
transition: all 250ms;
|
||||||
|
|
|
@ -31,16 +31,16 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data: function() {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
isMaximized: false
|
isMaximized: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
this.$emit("close");
|
this.$emit("close");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -113,25 +113,24 @@ export default {
|
||||||
if (this.players.length > 6) {
|
if (this.players.length > 6) {
|
||||||
rolesFirstNight.push(
|
rolesFirstNight.push(
|
||||||
{
|
{
|
||||||
id: "evil",
|
id: "minion_info",
|
||||||
name: "Minion info",
|
name: "爪牙信息",
|
||||||
firstNight: 5,
|
firstNight: 5,
|
||||||
team: "minion",
|
team: "minion",
|
||||||
players: this.players.filter(p => p.role.team === "minion"),
|
players: this.players.filter(p => p.role.team === "minion"),
|
||||||
firstNightReminder:
|
firstNightReminder:
|
||||||
"• If more than one Minion, they all make eye contact with each other. " +
|
"• 如果有七名或以上玩家:爪牙睁眼相互认识。" +
|
||||||
"• Show the “This is the Demon” card. Point to the Demon."
|
"• 告诉他们恶魔是哪名玩家。"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "evil",
|
id: "demon_info",
|
||||||
name: "Demon info & bluffs",
|
name: "恶魔信息",
|
||||||
firstNight: 8,
|
firstNight: 8,
|
||||||
team: "demon",
|
team: "demon",
|
||||||
players: this.players.filter(p => p.role.team === "demon"),
|
players: this.players.filter(p => p.role.team === "demon"),
|
||||||
firstNightReminder:
|
firstNightReminder:
|
||||||
"• Show the “These are your minions” card. Point to each Minion. " +
|
"• 如果有七名或以上玩家:告诉恶魔,这些玩家是你的爪牙。 " +
|
||||||
"• Show the “These characters are not in play” card. Show 3 character tokens of good " +
|
"• 告诉恶魔3个不在场的伪装角色。"
|
||||||
"characters not in play."
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
backgroundImage: `url(${
|
backgroundImage: `url(${
|
||||||
reminder.image && grimoire.isImageOptIn
|
reminder.image && grimoire.isImageOptIn
|
||||||
? reminder.image
|
? reminder.image
|
||||||
: require('../../assets/icons/' +
|
: require(
|
||||||
(reminder.imageAlt || reminder.role) +
|
'../../assets/icons/' +
|
||||||
'.png')
|
(reminder.imageAlt || reminder.role) +
|
||||||
})`
|
'.png',
|
||||||
|
)
|
||||||
|
})`,
|
||||||
}"
|
}"
|
||||||
></span>
|
></span>
|
||||||
<span class="text">{{ reminder.name }}</span>
|
<span class="text">{{ reminder.name }}</span>
|
||||||
|
@ -39,12 +41,14 @@ import { mapMutations, mapState } from "vuex";
|
||||||
* @param role The role for which the reminder should be generated
|
* @param role The role for which the reminder should be generated
|
||||||
* @return {function(*): {image: string|string[]|string|*, role: *, name: *, imageAlt: string|*}}
|
* @return {function(*): {image: string|string[]|string|*, role: *, name: *, imageAlt: string|*}}
|
||||||
*/
|
*/
|
||||||
const mapReminder = ({ id, image, imageAlt }) => name => ({
|
const mapReminder =
|
||||||
role: id,
|
({ id, image, imageAlt }) =>
|
||||||
image,
|
(name) => ({
|
||||||
imageAlt,
|
role: id,
|
||||||
name
|
image,
|
||||||
});
|
imageAlt,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { Modal },
|
components: { Modal },
|
||||||
|
@ -53,31 +57,31 @@ export default {
|
||||||
availableReminders() {
|
availableReminders() {
|
||||||
let reminders = [];
|
let reminders = [];
|
||||||
const { players, bluffs } = this.$store.state.players;
|
const { players, bluffs } = this.$store.state.players;
|
||||||
this.$store.state.roles.forEach(role => {
|
this.$store.state.roles.forEach((role) => {
|
||||||
// add reminders from player roles
|
// add reminders from player roles
|
||||||
if (players.some(p => p.role.id === role.id)) {
|
if (players.some((p) => p.role.id === role.id)) {
|
||||||
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
||||||
}
|
}
|
||||||
// add reminders from bluff/other roles
|
// add reminders from bluff/other roles
|
||||||
else if (bluffs.some(bluff => bluff.id === role.id)) {
|
else if (bluffs.some((bluff) => bluff.id === role.id)) {
|
||||||
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
||||||
}
|
}
|
||||||
// add global reminders
|
// add global reminders
|
||||||
if (role.remindersGlobal && role.remindersGlobal.length) {
|
if (role.remindersGlobal && role.remindersGlobal.length) {
|
||||||
reminders = [
|
reminders = [
|
||||||
...reminders,
|
...reminders,
|
||||||
...role.remindersGlobal.map(mapReminder(role))
|
...role.remindersGlobal.map(mapReminder(role)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// add fabled reminders
|
// add fabled reminders
|
||||||
this.$store.state.players.fabled.forEach(role => {
|
this.$store.state.players.fabled.forEach((role) => {
|
||||||
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
||||||
});
|
});
|
||||||
|
|
||||||
// add out of script traveler reminders
|
// add out of script traveler reminders
|
||||||
this.$store.state.otherTravelers.forEach(role => {
|
this.$store.state.otherTravelers.forEach((role) => {
|
||||||
if (players.some(p => p.role.id === role.id)) {
|
if (players.some((p) => p.role.id === role.id)) {
|
||||||
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
reminders = [...reminders, ...role.reminders.map(mapReminder(role))];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -88,7 +92,7 @@ export default {
|
||||||
return reminders;
|
return reminders;
|
||||||
},
|
},
|
||||||
...mapState(["modals", "grimoire"]),
|
...mapState(["modals", "grimoire"]),
|
||||||
...mapState("players", ["players"])
|
...mapState("players", ["players"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addReminder(reminder) {
|
addReminder(reminder) {
|
||||||
|
@ -104,12 +108,12 @@ export default {
|
||||||
this.$store.commit("players/update", {
|
this.$store.commit("players/update", {
|
||||||
player,
|
player,
|
||||||
property: "reminders",
|
property: "reminders",
|
||||||
value
|
value,
|
||||||
});
|
});
|
||||||
this.$store.commit("toggleModal", "reminder");
|
this.$store.commit("toggleModal", "reminder");
|
||||||
},
|
},
|
||||||
...mapMutations(["toggleModal"])
|
...mapMutations(["toggleModal"]),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -117,8 +121,8 @@ export default {
|
||||||
ul.reminders .reminder {
|
ul.reminders .reminder {
|
||||||
background: url("../../assets/reminder.png") center center;
|
background: url("../../assets/reminder.png") center center;
|
||||||
background-size: 100%;
|
background-size: 100%;
|
||||||
width: 14vh;
|
width: max(min(14vh, 14vw), 50px);
|
||||||
height: 14vh;
|
height: max(min(14vh, 14vw), 50px);
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -145,12 +149,12 @@ ul.reminders .reminder {
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 65%;
|
font-size: 0.9em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
top: 28%;
|
top: 28%;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
line-height: 1;
|
line-height: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -60,12 +60,12 @@ export default {
|
||||||
availableRoles() {
|
availableRoles() {
|
||||||
const availableRoles = [];
|
const availableRoles = [];
|
||||||
const players = this.$store.state.players.players;
|
const players = this.$store.state.players.players;
|
||||||
this.$store.state.roles.forEach(role => {
|
this.$store.state.roles.forEach((role) => {
|
||||||
// don't show bluff roles that are already assigned to players
|
// don't show bluff roles that are already assigned to players
|
||||||
if (
|
if (
|
||||||
this.playerIndex >= 0 ||
|
this.playerIndex >= 0 ||
|
||||||
(this.playerIndex < 0 &&
|
(this.playerIndex < 0 &&
|
||||||
!players.some(player => player.role.id === role.id))
|
!players.some((player) => player.role.id === role.id))
|
||||||
) {
|
) {
|
||||||
availableRoles.push(role);
|
availableRoles.push(role);
|
||||||
}
|
}
|
||||||
|
@ -75,11 +75,11 @@ export default {
|
||||||
},
|
},
|
||||||
...mapState(["modals", "roles", "session"]),
|
...mapState(["modals", "roles", "session"]),
|
||||||
...mapState("players", ["players"]),
|
...mapState("players", ["players"]),
|
||||||
...mapState(["otherTravelers"])
|
...mapState(["otherTravelers"]),
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tab: "editionRoles"
|
tab: "editionRoles",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -88,7 +88,7 @@ export default {
|
||||||
// assign to bluff slot (index < 0)
|
// assign to bluff slot (index < 0)
|
||||||
this.$store.commit("players/setBluff", {
|
this.$store.commit("players/setBluff", {
|
||||||
index: this.playerIndex * -1 - 1,
|
index: this.playerIndex * -1 - 1,
|
||||||
role
|
role,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (this.session.isSpectator && role.team === "traveler") return;
|
if (this.session.isSpectator && role.team === "traveler") return;
|
||||||
|
@ -97,7 +97,7 @@ export default {
|
||||||
this.$store.commit("players/update", {
|
this.$store.commit("players/update", {
|
||||||
player,
|
player,
|
||||||
property: "role",
|
property: "role",
|
||||||
value: role
|
value: role,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.tab = "editionRoles";
|
this.tab = "editionRoles";
|
||||||
|
@ -107,8 +107,8 @@ export default {
|
||||||
this.tab = "editionRoles";
|
this.tab = "editionRoles";
|
||||||
this.toggleModal("role");
|
this.toggleModal("role");
|
||||||
},
|
},
|
||||||
...mapMutations(["toggleModal"])
|
...mapMutations(["toggleModal"]),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -117,24 +117,34 @@ export default {
|
||||||
|
|
||||||
ul.tokens li {
|
ul.tokens li {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 6vw;
|
width: max(6vw, 60px);
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
transition: transform 500ms ease;
|
transition: transform 500ms ease;
|
||||||
|
|
||||||
&.townsfolk {
|
&.townsfolk {
|
||||||
box-shadow: 0 0 10px $townsfolk, 0 0 10px #004cff;
|
box-shadow:
|
||||||
|
0 0 10px $townsfolk,
|
||||||
|
0 0 10px #004cff;
|
||||||
}
|
}
|
||||||
&.outsider {
|
&.outsider {
|
||||||
box-shadow: 0 0 10px $outsider, 0 0 10px $outsider;
|
box-shadow:
|
||||||
|
0 0 10px $outsider,
|
||||||
|
0 0 10px $outsider;
|
||||||
}
|
}
|
||||||
&.minion {
|
&.minion {
|
||||||
box-shadow: 0 0 10px $minion, 0 0 10px $minion;
|
box-shadow:
|
||||||
|
0 0 10px $minion,
|
||||||
|
0 0 10px $minion;
|
||||||
}
|
}
|
||||||
&.demon {
|
&.demon {
|
||||||
box-shadow: 0 0 10px $demon, 0 0 10px $demon;
|
box-shadow:
|
||||||
|
0 0 10px $demon,
|
||||||
|
0 0 10px $demon;
|
||||||
}
|
}
|
||||||
&.traveler {
|
&.traveler {
|
||||||
box-shadow: 0 0 10px $traveler, 0 0 10px $traveler;
|
box-shadow:
|
||||||
|
0 0 10px $traveler,
|
||||||
|
0 0 10px $traveler;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
v-if="modals.roles && nonTravelers >= 5"
|
v-if="modals.roles && nonTravelers >= 5"
|
||||||
@close="toggleModal('roles')"
|
@close="toggleModal('roles')"
|
||||||
>
|
>
|
||||||
<h3>Select the characters for {{ nonTravelers }} players:</h3>
|
<h3>为 {{ nonTravelers }} 个玩家选择角色:</h3>
|
||||||
<ul class="tokens" v-for="(teamRoles, team) in roleSelection" :key="team">
|
<ul class="tokens" v-for="(teamRoles, team) in roleSelection" :key="team">
|
||||||
<li class="count" :class="[team]">
|
<li class="count" :class="[team]">
|
||||||
{{ teamRoles.reduce((a, { selected }) => a + selected, 0) }} /
|
{{ teamRoles.reduce((a, { selected }) => a + selected, 0) }} /
|
||||||
|
@ -31,14 +31,13 @@
|
||||||
<div class="warning" v-if="hasSelectedSetupRoles">
|
<div class="warning" v-if="hasSelectedSetupRoles">
|
||||||
<font-awesome-icon icon="exclamation-triangle" />
|
<font-awesome-icon icon="exclamation-triangle" />
|
||||||
<span>
|
<span>
|
||||||
Warning: there are characters selected that modify the game setup! The
|
注意:目前选择的角色会影响配板,需要说书人手动调整。
|
||||||
randomizer does not account for these characters.
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<label class="multiple" :class="{ checked: allowMultiple }">
|
<label class="multiple" :class="{ checked: allowMultiple }">
|
||||||
<font-awesome-icon :icon="allowMultiple ? 'check-square' : 'square'" />
|
<font-awesome-icon :icon="allowMultiple ? 'check-square' : 'square'" />
|
||||||
<input type="checkbox" name="allow-multiple" v-model="allowMultiple" />
|
<input type="checkbox" name="allow-multiple" v-model="allowMultiple" />
|
||||||
Allow duplicate characters
|
允许重复角色
|
||||||
</label>
|
</label>
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<div
|
<div
|
||||||
|
@ -49,11 +48,11 @@
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<font-awesome-icon icon="people-arrows" />
|
<font-awesome-icon icon="people-arrows" />
|
||||||
Assign {{ selectedRoles }} characters randomly
|
随机分配 {{ selectedRoles }} 个角色
|
||||||
</div>
|
</div>
|
||||||
<div class="button" @click="selectRandomRoles">
|
<div class="button" @click="selectRandomRoles">
|
||||||
<font-awesome-icon icon="random" />
|
<font-awesome-icon icon="random" />
|
||||||
Shuffle characters
|
随机选取角色
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default new Vuex.Store({
|
||||||
isMenuOpen: false,
|
isMenuOpen: false,
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
isMuted: false,
|
isMuted: false,
|
||||||
isImageOptIn: false,
|
isImageOptIn: true,
|
||||||
zoom: 0,
|
zoom: 0,
|
||||||
background: ""
|
background: ""
|
||||||
},
|
},
|
||||||
|
@ -170,7 +170,7 @@ export default new Vuex.Store({
|
||||||
toggleStatic: toggle("isStatic"),
|
toggleStatic: toggle("isStatic"),
|
||||||
toggleNight: toggle("isNight"),
|
toggleNight: toggle("isNight"),
|
||||||
toggleGrimoire: toggle("isPublic"),
|
toggleGrimoire: toggle("isPublic"),
|
||||||
toggleImageOptIn: toggle("isImageOptIn"),
|
// toggleImageOptIn: toggle("isImageOptIn"),
|
||||||
toggleModal({ modals }, name) {
|
toggleModal({ modals }, name) {
|
||||||
if (name) {
|
if (name) {
|
||||||
modals[name] = !modals[name];
|
modals[name] = !modals[name];
|
||||||
|
|
Loading…
Add table
Reference in a new issue