diff --git a/client/package.json b/client/package.json index 7020f6c..1086335 100644 --- a/client/package.json +++ b/client/package.json @@ -48,7 +48,7 @@ }, "dependencies": { "uikit": "^3.0.0-beta.40", - "vue": "^2.4.2", + "vue": "^2.5.16", "vue-router": "^2.7.0" } } diff --git a/client/src/components/game-log.js b/client/src/components/game-log.js new file mode 100644 index 0000000..63d4309 --- /dev/null +++ b/client/src/components/game-log.js @@ -0,0 +1,8 @@ +require('./game-log.scss') + +module.exports = require('vue').component('game-log', { + props: { + log: Array + }, + template: require('./game-log.pug')() +}) diff --git a/client/src/components/game-log.pug b/client/src/components/game-log.pug new file mode 100644 index 0000000..0cf7924 --- /dev/null +++ b/client/src/components/game-log.pug @@ -0,0 +1,2 @@ +.game-log + p(v-for="message in log") • {{ message }} diff --git a/client/src/components/game-log.scss b/client/src/components/game-log.scss new file mode 100644 index 0000000..4b2f14a --- /dev/null +++ b/client/src/components/game-log.scss @@ -0,0 +1,5 @@ +.game-log { + height: 40em; + line-height: 0.2em; + position: absolute; +} diff --git a/client/src/components/game.js b/client/src/components/game.js index a943e1c..94a81c0 100644 --- a/client/src/components/game.js +++ b/client/src/components/game.js @@ -6,23 +6,21 @@ let ws = null module.exports = require('vue').component('game', { data, methods: { - addBot: function addBot() { - console.log('(local) adding bot!') - ws.send(JSON.stringify(['player:bot'])) - }, - start: function start() { - console.log('(local) starting game!') - ws.send(JSON.stringify(['game:start'])) - }, - stop: function stop() { - console.log('(local) stopping game!') - ws.send(JSON.stringify(['game:stop'])) - } + addBot, + pass, + play, + start, + stop }, mounted, template: require('./game.pug')() }) +function addBot() { + console.log('(local) adding bot!') + ws.send(JSON.stringify(['player:bot'])) +} + function data() { return { activityLog: [], @@ -49,24 +47,7 @@ function data() { } ], player: { - hand: [ - { - id: 'gut-punch', - name: 'Gut Punch', - type: 'attack' - }, - { - disabled: true, - id: 'block', - name: 'Block', - type: 'counter' - }, - { - id: 'a-gun', - name: 'A Gun', - type: 'unstoppable' - } - ], + hand: [], hp: 8, maxHp: 10 }, @@ -101,7 +82,15 @@ function onMessage({ data: msg }) { } if (payload.player) { - vm.player.hand = payload.player.hand + vm.player.hand = payload.player.hand.map((card) => { + return Object.assign(card, { + selected: false + }) + }) + } + + if (payload.message) { + vm.activityLog.unshift(payload.message) } if (codes[code]) { @@ -110,3 +99,24 @@ function onMessage({ data: msg }) { console.log(code, payload) } + +function pass() { + ws.send(JSON.stringify(['player:pass'])) +} + +function play() { + ws.send(JSON.stringify([ + 'player:play', + this.player.hand.filter(card => card.selected) + ])) +} + +function start() { + console.log('(local) starting game!') + ws.send(JSON.stringify(['game:start'])) +} + +function stop() { + console.log('(local) stopping game!') + ws.send(JSON.stringify(['game:stop'])) +} diff --git a/client/src/components/game.pug b/client/src/components/game.pug index c316e54..768d725 100644 --- a/client/src/components/game.pug +++ b/client/src/components/game.pug @@ -8,3 +8,7 @@ div button(@click="start", type="button", v-if="!started") Start button(@click="stop", type="button", v-if="started && !stopped") Stop button(@click="addBot", type="button") Add bot + button(@click="play", type="button") Play + button(@click="pass", type="button") Pass + hr + game-log(:log="activityLog") diff --git a/client/src/components/player-card.js b/client/src/components/player-card.js index 9e2a88d..05febe9 100644 --- a/client/src/components/player-card.js +++ b/client/src/components/player-card.js @@ -1,9 +1,19 @@ require('./player-card.scss') module.exports = require('vue').component('player-card', { + methods: { + toggleSelect + }, props: { disabled: Boolean, card: Object }, template: require('./player-card.pug')() }) + +function toggleSelect(card) { + if (!card.disabled) { + card.selected = !card.selected + console.log(this.card.selected) + } +} diff --git a/client/src/components/player-card.pug b/client/src/components/player-card.pug index 8d68aef..935f795 100644 --- a/client/src/components/player-card.pug +++ b/client/src/components/player-card.pug @@ -1,4 +1,6 @@ -.player-card(:class="{ disabled: card.disabled }") +.player-card( + @click="toggleSelect(card)", + v-bind:class="{ disabled: card.disabled, selected: card.selected }") .front p {{ card.name }} p {{ card.type.toUpperCase() }} diff --git a/client/src/components/player-card.scss b/client/src/components/player-card.scss index fdf7452..ab03c25 100644 --- a/client/src/components/player-card.scss +++ b/client/src/components/player-card.scss @@ -32,4 +32,10 @@ &.disabled { opacity: 0.3; } + + &.selected { + border-color: red; + border-style: solid; + border-width: 2px; + } } diff --git a/client/src/components/player-hand.pug b/client/src/components/player-hand.pug index 3e7b4ee..9587430 100644 --- a/client/src/components/player-hand.pug +++ b/client/src/components/player-hand.pug @@ -3,4 +3,5 @@ div player-card( :card="card", :disabled="false", + :key="card.uid", v-for="card in hand") diff --git a/server/index.js b/server/index.js index a3c5e0e..193a05b 100644 --- a/server/index.js +++ b/server/index.js @@ -44,6 +44,8 @@ function connection(ws, req) { 'game:start': require('./responses/game-start'), 'player:bot': require('./responses/player-bot'), 'player:join': require('./responses/player-join'), + 'player:pass': require('./responses/player-pass'), + 'player:play': require('./responses/player-play'), 'player:language': require('./responses/player-language') } if (codes[code]) { diff --git a/server/responses/player-join.js b/server/responses/player-join.js index 2a6b12f..64ea9d7 100644 --- a/server/responses/player-join.js +++ b/server/responses/player-join.js @@ -2,6 +2,7 @@ const JunkyardBrawl = require('junkyard-brawl') const { getPhrase } = require('junkyard-brawl/src/language') const { getGame, getSocket, setGame, setSocket } = require('../state') const { scrubGameData, scrubPlayerData } = require('../util') +const uuid = require('uuid/v4') module.exports = (socket, { player }) => { let game = getGame(socket.gameId) @@ -15,6 +16,8 @@ module.exports = (socket, { player }) => { generateAnnounceCallback(socket), generateWhisperCallback(socket) ) + // Patch in some unique IDs to appease Vue + game.deck.forEach(card => (card.uid = uuid())) game.id = socket.gameId setGame(socket.gameId, game) game.announce('game:created') @@ -40,7 +43,7 @@ function generateAnnounceCallback(socket) { } catch (err) {} playerSocket.send(JSON.stringify([code, { - game: scrubGameData(game), + game: scrubGameData(game, playerSocket), message: newMessage || message, // Send updated personal info player: scrubPlayerData(player) @@ -73,7 +76,7 @@ function generateWhisperCallback(socket) { const playerSocket = getSocket(playerId) if (playerSocket) { playerSocket.send(JSON.stringify(code, { - game: scrubGameData(game), + game: scrubGameData(game, playerSocket), message: getPhrase(code, (playerSocket.language || game.language))(messageProps), player: scrubPlayerData(messageProps.player) })) diff --git a/server/responses/player-language.js b/server/responses/player-language.js index f3ee9d4..678d2ce 100644 --- a/server/responses/player-language.js +++ b/server/responses/player-language.js @@ -5,8 +5,8 @@ module.exports = (socket, { language }) => { socket.language = language } -module.exports.validator = (value) => { - return getSupportedLanguages().find(lang => lang === value) +module.exports.validator = (payload) => { + return getSupportedLanguages().find(lang => lang === payload) } const languages = getSupportedLanguages().join(', ') diff --git a/server/responses/player-pass.js b/server/responses/player-pass.js new file mode 100644 index 0000000..b3aa47a --- /dev/null +++ b/server/responses/player-pass.js @@ -0,0 +1,8 @@ +const { getGame } = require('../state') + +module.exports = (socket, payload) => { + const game = getGame(socket.gameId) + if (game) { + game.pass(socket.id) + } +} diff --git a/server/responses/player-play.js b/server/responses/player-play.js new file mode 100644 index 0000000..5b96838 --- /dev/null +++ b/server/responses/player-play.js @@ -0,0 +1,26 @@ +const { getGame } = require('../state') + +module.exports = (socket, payload) => { + const game = getGame(socket.gameId) + if (game) { + const player = game.getPlayer(socket.id) + game.play(socket.id, payload.map((card) => { + return player.hand.find(_card => _card.uid === card.uid) + }).filter(card => card)) + } +} + +module.exports.validator = (payload) => { + if (!Array.isArray(payload)) return false + payload.forEach((card) => { + if (typeof card.id !== 'string') { + return false + } + if (typeof card.uid !== 'string') { + return false + } + }) + return true +} + +module.exports.validatorMessage = 'Expected array of card objects.' diff --git a/server/util.js b/server/util.js index 20d7a05..34dfc63 100644 --- a/server/util.js +++ b/server/util.js @@ -3,23 +3,23 @@ const { getGame, getSocket } = require('./state') module.exports = { scrubGameData, - scrubOpponentData, scrubPlayerData } // We need to remove circular references and return // only the data needing to be sent over the socket. -function scrubGameData(game) { +function scrubGameData(game, playerSocket) { if (!game) { return game } + const language = playerSocket.language || game.language return { manager: { id: game.manager.id, name: game.manager.name }, - dropouts: game.dropouts.map(scrubOpponentData), - players: game.players.map(scrubOpponentData), + dropouts: game.dropouts.map(player => scrubOpponentData(player, language)), + players: game.players.map(player => scrubOpponentData(player, language)), started: game.started ? game.started.valueOf() : false, stopped: game.stopped ? game.stopped.valueOf() : false, turns: game.turns @@ -27,14 +27,14 @@ function scrubGameData(game) { } // We can know everything about the player but what is in their hand -function scrubOpponentData(player) { +function scrubOpponentData(player, language) { if (!player) { return player } return { id: player.id, - conditionCards: scrubCards(player.conditionCards), - discard: scrubCards(player.discard), + conditionCards: scrubCards(player.conditionCards, language), + discard: scrubCards(player.discard, language), extraTurns: player.extraTurns, name: player.name, hand: player.hand.map(card => ({ type: 'unknown' })), @@ -55,7 +55,7 @@ function scrubPlayerData(player) { const playerSocket = getSocket(player.id) const game = getGame(playerSocket.gameId) const language = playerSocket.language || game.language - return Object.assign(scrubOpponentData(player), { + return Object.assign(scrubOpponentData(player, language), { hand: scrubCards(player.hand, language) }) } @@ -65,7 +65,8 @@ function scrubCards(cards, language) { return { id: card.id, name: getPhrase(`card:${card.id}`, language)(), - type: card.type + type: card.type, + uid: card.uid } }) }