diff --git a/src/assets/icons/demon_info.png b/src/assets/icons/demon_info.png new file mode 100644 index 0000000..f59435e Binary files /dev/null and b/src/assets/icons/demon_info.png differ diff --git a/src/assets/icons/minion_info.png b/src/assets/icons/minion_info.png new file mode 100644 index 0000000..01a2092 Binary files /dev/null and b/src/assets/icons/minion_info.png differ diff --git a/src/components/Menu.vue b/src/components/Menu.vue index 46133ca..09f808d 100644 --- a/src/components/Menu.vue +++ b/src/components/Menu.vue @@ -87,7 +87,7 @@ Background image -
  • +
  • Disable Animations
  • -
  • - Send Characters - -
  • [V]
  • - Leave Session + 退出房间 {{ session.sessionId }}
  • @@ -154,13 +150,13 @@ @@ -169,22 +165,26 @@
  • Characters
  • - Select Edition + 选择剧本 [E]
  • - Choose & Assign + 分配角色 [C]
  • +
  • + 发送角色 + +
  • - Add Fabled + 传奇角色
  • - Remove all + 移除全部角色
  • @@ -193,11 +193,11 @@
  • Help
  • - Reference Sheet + 角色能力表 [R]
  • - Night Order Sheet + 夜晚顺序表 [N]
  • @@ -253,7 +253,7 @@ export default { hostSession() { if (this.session.sessionId) return; const sessionId = prompt( - "Enter a channel number / name for your session", + "输入你想要创建的房间的名称或号码", Math.round(Math.random() * 10000) ); if (sessionId) { @@ -271,7 +271,7 @@ export default { distributeRoles() { if (this.session.isSpectator) return; const popup = - "Do you want to distribute assigned characters to all SEATED players?"; + "你确定要向所有已入座的玩家发送角色吗?"; if (confirm(popup)) { this.$store.commit("session/distributeRoles", true); setTimeout( @@ -292,7 +292,7 @@ export default { joinSession() { if (this.session.sessionId) return this.leaveSession(); let sessionId = prompt( - "Enter the channel number / name of the session you want to join" + "输入你想要加入的房间的名称或号码" ); if (sessionId.match(/^https?:\/\//i)) { sessionId = sessionId.split("#").pop(); @@ -305,7 +305,7 @@ export default { } }, 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/setSessionId", ""); } @@ -320,13 +320,13 @@ export default { }, randomizeSeatings() { if (this.session.isSpectator) return; - if (confirm("Are you sure you want to randomize seatings?")) { + if (confirm("你确定要打乱座位吗?")) { this.$store.dispatch("players/randomize"); } }, clearPlayers() { if (this.session.isSpectator) return; - if (confirm("Are you sure you want to remove all players?")) { + if (confirm("你确定要移除所有座位吗?")) { // abort vote if in progress if (this.session.nomination) { this.$store.commit("session/nomination"); @@ -335,7 +335,7 @@ export default { } }, clearRoles() { - if (confirm("Are you sure you want to remove all player roles?")) { + if (confirm("你确定要移除所有玩家的角色吗?")) { this.$store.dispatch("players/clearRoles"); } }, diff --git a/src/components/Player.vue b/src/components/Player.vue index 65bdf61..7392068 100644 --- a/src/components/Player.vue +++ b/src/components/Player.vue @@ -10,9 +10,9 @@ 'no-vote': player.isVoteless, you: session.sessionId && player.id && player.id === session.playerId, 'vote-yes': session.votes[index], - 'vote-lock': voteLocked + 'vote-lock': voteLocked, }, - player.role.team + player.role.team, ]" >
    @@ -121,7 +121,7 @@ @click="changePronouns" v-if=" !session.isSpectator || - (session.isSpectator && player.id === session.playerId) + (session.isSpectator && player.id === session.playerId) " > Change Pronouns @@ -162,9 +162,7 @@ :class="{ disabled: player.id && player.id !== session.playerId }" > - + @@ -188,10 +186,12 @@ backgroundImage: `url(${ reminder.image && grimoire.isImageOptIn ? reminder.image - : require('../assets/icons/' + - (reminder.imageAlt || reminder.role) + - '.png') - })` + : require( + '../assets/icons/' + + (reminder.imageAlt || reminder.role) + + '.png', + ) + })`, }" > {{ reminder.name }} @@ -210,22 +210,22 @@ import { mapGetters, mapState } from "vuex"; export default { components: { - Token + Token, }, props: { player: { type: Object, - required: true - } + required: true, + }, }, computed: { ...mapState("players", ["players"]), ...mapState(["grimoire", "session"]), ...mapGetters({ nightOrder: "players/nightOrder" }), - index: function() { + index: function () { return this.players.indexOf(this.player); }, - voteLocked: function() { + voteLocked: function () { const session = this.session; const players = this.players.length; if (!session.nomination) return false; @@ -233,7 +233,7 @@ export default { (this.index - 1 + players - session.nomination[1]) % players; return indexAdjusted < session.lockedVote - 1; }, - zoom: function() { + zoom: function () { const unit = window.innerWidth > window.innerHeight ? "vh" : "vw"; if (this.players.length < 7) { return { width: 18 + this.grimoire.zoom + unit }; @@ -244,12 +244,12 @@ export default { } else { return { width: 12 + this.grimoire.zoom + unit }; } - } + }, }, data() { return { isMenuOpen: false, - isSwap: false + isSwap: false, }; }, methods: { @@ -305,7 +305,7 @@ export default { this.$store.commit("players/update", { player: this.player, property, - value + value, }); if (closeMenu) { this.isMenuOpen = false; @@ -342,10 +342,10 @@ export default { if (!this.voteLocked) return; this.$store.commit("session/voteSync", [ this.index, - !this.session.votes[this.index] + !this.session.votes[this.index], ]); - } - } + }, + }, }; @@ -632,11 +632,11 @@ li.move:not(.from) .player .overlay svg.move { } } -@include glow("townsfolk", $townsfolk); -@include glow("outsider", $outsider); -@include glow("demon", $demon); -@include glow("minion", $minion); -@include glow("traveler", $traveler); +@include glow("镇民", $townsfolk); +@include glow("外来者", $outsider); +@include glow("恶魔", $demon); +@include glow("爪牙", $minion); +@include glow("旅行者", $traveler); .player.you .token { animation: townsfolk-glow 5s ease-in-out infinite; @@ -869,7 +869,10 @@ li.move:not(.from) .player .overlay svg.move { width: 100%; position: absolute; 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; } diff --git a/src/components/TownSquare.vue b/src/components/TownSquare.vue index 33a6707..b3c551f 100644 --- a/src/components/TownSquare.vue +++ b/src/components/TownSquare.vue @@ -5,7 +5,7 @@ :class="{ public: grimoire.isPublic, spectator: session.isSpectator, - vote: session.nomination + vote: session.nomination, }" >
      @@ -18,7 +18,7 @@ from: Math.max(swap, move, nominate) === index, swap: swap > -1, move: move > -1, - nominate: nominate > -1 + nominate: nominate > -1, }" >
    @@ -29,12 +29,20 @@ ref="bluffs" :class="{ closed: !isBluffsOpen }" > -

    +

    Other characters - Demon bluffs - - -
    + 恶魔的伪装角色 + + +
    • -

      - Fabled - - -

      +
      + 传奇角色 + + +
      • 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) { // update nomination if one of the involved players is swapped 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 === swapTo) return this.swap; return nom; @@ -200,7 +216,7 @@ export default { } this.$store.commit("players/swap", [ this.swap, - this.players.indexOf(to) + this.players.indexOf(to), ]); this.cancel(); } @@ -214,7 +230,7 @@ export default { if (this.session.nomination) { // update nomination if it is affected by the move 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 && 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.move, - this.players.indexOf(to) + this.players.indexOf(to), ]); this.cancel(); } @@ -251,8 +267,8 @@ export default { this.move = -1; this.swap = -1; this.nominate = -1; - } - } + }, + }, }; @@ -272,8 +288,8 @@ export default { .circle { padding: 0; - width: 100%; - height: 100%; + width: 100vw; + height: min(100vw, 100vh); list-style: none; margin: 0; @@ -459,8 +475,8 @@ export default { align-items: center; justify-content: center; li { - width: 14vh; - height: 14vh; + width: max(min(8vh, 8vw), 50px); + height: max(min(8vh, 8vw), 50px); margin: 0 0.5%; display: inline-block; transition: all 250ms; diff --git a/src/components/modals/Modal.vue b/src/components/modals/Modal.vue index d1bd5e6..301e041 100644 --- a/src/components/modals/Modal.vue +++ b/src/components/modals/Modal.vue @@ -31,16 +31,16 @@ diff --git a/src/components/modals/NightOrderModal.vue b/src/components/modals/NightOrderModal.vue index 97ba4a2..6ab4b22 100644 --- a/src/components/modals/NightOrderModal.vue +++ b/src/components/modals/NightOrderModal.vue @@ -113,25 +113,24 @@ export default { if (this.players.length > 6) { rolesFirstNight.push( { - id: "evil", - name: "Minion info", + id: "minion_info", + name: "爪牙信息", firstNight: 5, team: "minion", players: this.players.filter(p => p.role.team === "minion"), 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", - name: "Demon info & bluffs", + id: "demon_info", + name: "恶魔信息", firstNight: 8, team: "demon", players: this.players.filter(p => p.role.team === "demon"), 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 " + - "characters not in play." + "• 如果有七名或以上玩家:告诉恶魔,这些玩家是你的爪牙。 " + + "• 告诉恶魔3个不在场的伪装角色。" } ); } diff --git a/src/components/modals/ReminderModal.vue b/src/components/modals/ReminderModal.vue index b781b7b..d1802ce 100644 --- a/src/components/modals/ReminderModal.vue +++ b/src/components/modals/ReminderModal.vue @@ -18,10 +18,12 @@ backgroundImage: `url(${ reminder.image && grimoire.isImageOptIn ? reminder.image - : require('../../assets/icons/' + - (reminder.imageAlt || reminder.role) + - '.png') - })` + : require( + '../../assets/icons/' + + (reminder.imageAlt || reminder.role) + + '.png', + ) + })`, }" > {{ reminder.name }} @@ -39,12 +41,14 @@ import { mapMutations, mapState } from "vuex"; * @param role The role for which the reminder should be generated * @return {function(*): {image: string|string[]|string|*, role: *, name: *, imageAlt: string|*}} */ -const mapReminder = ({ id, image, imageAlt }) => name => ({ - role: id, - image, - imageAlt, - name -}); +const mapReminder = + ({ id, image, imageAlt }) => + (name) => ({ + role: id, + image, + imageAlt, + name, + }); export default { components: { Modal }, @@ -53,31 +57,31 @@ export default { availableReminders() { let reminders = []; const { players, bluffs } = this.$store.state.players; - this.$store.state.roles.forEach(role => { + this.$store.state.roles.forEach((role) => { // 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))]; } // 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))]; } // add global reminders if (role.remindersGlobal && role.remindersGlobal.length) { reminders = [ ...reminders, - ...role.remindersGlobal.map(mapReminder(role)) + ...role.remindersGlobal.map(mapReminder(role)), ]; } }); // add fabled reminders - this.$store.state.players.fabled.forEach(role => { + this.$store.state.players.fabled.forEach((role) => { reminders = [...reminders, ...role.reminders.map(mapReminder(role))]; }); // add out of script traveler reminders - this.$store.state.otherTravelers.forEach(role => { - if (players.some(p => p.role.id === role.id)) { + this.$store.state.otherTravelers.forEach((role) => { + if (players.some((p) => p.role.id === role.id)) { reminders = [...reminders, ...role.reminders.map(mapReminder(role))]; } }); @@ -88,7 +92,7 @@ export default { return reminders; }, ...mapState(["modals", "grimoire"]), - ...mapState("players", ["players"]) + ...mapState("players", ["players"]), }, methods: { addReminder(reminder) { @@ -104,12 +108,12 @@ export default { this.$store.commit("players/update", { player, property: "reminders", - value + value, }); this.$store.commit("toggleModal", "reminder"); }, - ...mapMutations(["toggleModal"]) - } + ...mapMutations(["toggleModal"]), + }, }; @@ -117,8 +121,8 @@ export default { ul.reminders .reminder { background: url("../../assets/reminder.png") center center; background-size: 100%; - width: 14vh; - height: 14vh; + width: max(min(14vh, 14vw), 50px); + height: max(min(14vh, 14vw), 50px); max-width: 100px; max-height: 100px; display: flex; @@ -145,12 +149,12 @@ ul.reminders .reminder { .text { color: black; - font-size: 65%; + font-size: 0.9em; font-weight: bold; text-align: center; top: 28%; width: 80%; - line-height: 1; + line-height: 0.9em; } &:hover { diff --git a/src/components/modals/RoleModal.vue b/src/components/modals/RoleModal.vue index eadde8c..6f2c8be 100644 --- a/src/components/modals/RoleModal.vue +++ b/src/components/modals/RoleModal.vue @@ -60,12 +60,12 @@ export default { availableRoles() { const availableRoles = []; 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 if ( 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); } @@ -75,11 +75,11 @@ export default { }, ...mapState(["modals", "roles", "session"]), ...mapState("players", ["players"]), - ...mapState(["otherTravelers"]) + ...mapState(["otherTravelers"]), }, data() { return { - tab: "editionRoles" + tab: "editionRoles", }; }, methods: { @@ -88,7 +88,7 @@ export default { // assign to bluff slot (index < 0) this.$store.commit("players/setBluff", { index: this.playerIndex * -1 - 1, - role + role, }); } else { if (this.session.isSpectator && role.team === "traveler") return; @@ -97,7 +97,7 @@ export default { this.$store.commit("players/update", { player, property: "role", - value: role + value: role, }); } this.tab = "editionRoles"; @@ -107,8 +107,8 @@ export default { this.tab = "editionRoles"; this.toggleModal("role"); }, - ...mapMutations(["toggleModal"]) - } + ...mapMutations(["toggleModal"]), + }, }; @@ -117,24 +117,34 @@ export default { ul.tokens li { border-radius: 50%; - width: 6vw; + width: max(6vw, 60px); margin: 1%; transition: transform 500ms ease; &.townsfolk { - box-shadow: 0 0 10px $townsfolk, 0 0 10px #004cff; + box-shadow: + 0 0 10px $townsfolk, + 0 0 10px #004cff; } &.outsider { - box-shadow: 0 0 10px $outsider, 0 0 10px $outsider; + box-shadow: + 0 0 10px $outsider, + 0 0 10px $outsider; } &.minion { - box-shadow: 0 0 10px $minion, 0 0 10px $minion; + box-shadow: + 0 0 10px $minion, + 0 0 10px $minion; } &.demon { - box-shadow: 0 0 10px $demon, 0 0 10px $demon; + box-shadow: + 0 0 10px $demon, + 0 0 10px $demon; } &.traveler { - box-shadow: 0 0 10px $traveler, 0 0 10px $traveler; + box-shadow: + 0 0 10px $traveler, + 0 0 10px $traveler; } &:hover { transform: scale(1.2); diff --git a/src/components/modals/RolesModal.vue b/src/components/modals/RolesModal.vue index 27833b0..6672654 100644 --- a/src/components/modals/RolesModal.vue +++ b/src/components/modals/RolesModal.vue @@ -4,7 +4,7 @@ v-if="modals.roles && nonTravelers >= 5" @close="toggleModal('roles')" > -

        Select the characters for {{ nonTravelers }} players:

        +

        为 {{ nonTravelers }} 个玩家选择角色:

        • {{ teamRoles.reduce((a, { selected }) => a + selected, 0) }} / @@ -31,14 +31,13 @@
          - Warning: there are characters selected that modify the game setup! The - randomizer does not account for these characters. + 注意:目前选择的角色会影响配板,需要说书人手动调整。
          - Assign {{ selectedRoles }} characters randomly + 随机分配 {{ selectedRoles }} 个角色
          - Shuffle characters + 随机选取角色
          diff --git a/src/store/index.js b/src/store/index.js index feb528d..ef7b0a4 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -104,7 +104,7 @@ export default new Vuex.Store({ isMenuOpen: false, isStatic: false, isMuted: false, - isImageOptIn: false, + isImageOptIn: true, zoom: 0, background: "" }, @@ -170,7 +170,7 @@ export default new Vuex.Store({ toggleStatic: toggle("isStatic"), toggleNight: toggle("isNight"), toggleGrimoire: toggle("isPublic"), - toggleImageOptIn: toggle("isImageOptIn"), + // toggleImageOptIn: toggle("isImageOptIn"), toggleModal({ modals }, name) { if (name) { modals[name] = !modals[name];