diff --git a/public/index.html b/public/index.html index a7a699a..ab05535 100755 --- a/public/index.html +++ b/public/index.html @@ -52,6 +52,7 @@ + diff --git a/public/scripts/make-sounds.js b/public/scripts/make-sounds.js new file mode 100755 index 0000000..dc2ae37 --- /dev/null +++ b/public/scripts/make-sounds.js @@ -0,0 +1,22 @@ +const sounds = {}; +sounds['victory'] = new Audio('/sounds/victory.ogg'); +sounds['defeat'] = new Audio('/sounds/defeat.ogg'); +sounds['draw'] = new Audio('/sounds/draw.ogg'); +sounds['move'] = new Audio('/sounds/move.ogg'); + +Object.values(sounds).forEach((sound) => { + sound.volume = 0.12; +}); + +document.addEventListener('htmx:wsAfterMessage', function (e) { + let msg; + try { + msg = JSON.parse(e.detail.message); + } catch (_) { + return; + } + if (msg.type !== 'sound') { + return; + } + sounds[msg.sound].play(); +}); diff --git a/public/sounds/defeat.ogg b/public/sounds/defeat.ogg new file mode 100755 index 0000000..5db6d6b Binary files /dev/null and b/public/sounds/defeat.ogg differ diff --git a/public/sounds/draw.ogg b/public/sounds/draw.ogg new file mode 100755 index 0000000..101735f Binary files /dev/null and b/public/sounds/draw.ogg differ diff --git a/public/sounds/move.ogg b/public/sounds/move.ogg new file mode 100755 index 0000000..de81b9e Binary files /dev/null and b/public/sounds/move.ogg differ diff --git a/public/sounds/victory.ogg b/public/sounds/victory.ogg new file mode 100755 index 0000000..537115f Binary files /dev/null and b/public/sounds/victory.ogg differ diff --git a/src/index.ts b/src/index.ts index b3239f7..0f02d2d 100755 --- a/src/index.ts +++ b/src/index.ts @@ -3,9 +3,10 @@ import { html } from '@elysiajs/html'; import { staticPlugin } from '@elysiajs/static'; import { cookie } from '@elysiajs/cookie'; import { WebSocketHandler } from './web-socket-handler'; -import { GomokuGame } from './game/game-instance'; +import { ElysiaWS } from 'elysia/dist/ws'; const wsHandler = new WebSocketHandler(); +export type WS = ElysiaWS<{ query: { playerId: string; gameId: string } }>; const app = new Elysia() .use( diff --git a/src/web-socket-handler.tsx b/src/web-socket-handler.tsx index 4b7f4ab..74fb277 100755 --- a/src/web-socket-handler.tsx +++ b/src/web-socket-handler.tsx @@ -13,8 +13,7 @@ import { UpdateDisplayNameMessage, } from './messages'; import { v4 as uuidv4 } from 'uuid'; - -type WS = ElysiaWS<{ query: { playerId: string; gameId: string } }>; +import { WS } from '.'; class PlayerConnection { id: string; @@ -107,6 +106,19 @@ class GameServer { ); } + public broadcastSound(sound: string) { + this.connections.forEach((conn: PlayerConnection) => + this.broadcastSoundToPlayer(conn, sound), + ); + } + + public broadcastSoundToPlayer(conn: PlayerConnection, sound: string) { + conn.ws.send({ + type: 'sound', + sound: sound, + }); + } + public broadcastBoardToPlayer(conn: PlayerConnection) { const isToPlay = this.gomoku.currentPlayerColor == this.getPlayerColor(conn); @@ -430,6 +442,39 @@ class GameServer { if (stateBeforeMove != this.gomoku.status) { this.broadcastButtons(); } + + // Broadcast sounds + if (this.gomoku.status === 'playing') { + this.broadcastSound('move'); + } else { + const whiteConn = this.whitePlayerId + ? this.connections.get(this.whitePlayerId) + : null; + const blackConn = this.blackPlayerId + ? this.connections.get(this.blackPlayerId) + : null; + switch (this.gomoku.winnerColor) { + case 'draw': + this.broadcastSound('draw'); + case 'white': + if (whiteConn) { + this.broadcastSoundToPlayer(whiteConn, 'victory'); + } + if (blackConn) { + this.broadcastSoundToPlayer(blackConn, 'defeat'); + } + break; + case 'black': + if (whiteConn) { + this.broadcastSoundToPlayer(whiteConn, 'defeat'); + } + if (blackConn) { + this.broadcastSoundToPlayer(blackConn, 'victory'); + } + break; + } + } + console.log( `Move made in game ${this.id} by ${conn.id}: (${row}, ${col})`, ); @@ -461,6 +506,17 @@ class GameServer { this.broadcastBoard(); this.broadcastTitle(); this.broadcastButtons(); + this.broadcastSoundToPlayer(conn, 'defeat'); + const otherPlayerId = + resigningPlayerColor === 'white' + ? this.blackPlayerId + : this.whitePlayerId; + if (otherPlayerId) { + const otherPlayer = this.connections.get(otherPlayerId); + if (otherPlayer) { + this.broadcastSoundToPlayer(otherPlayer, 'victory'); + } + } console.log(`Player ${conn.id} resigned from game ${this.id}`); } @@ -634,6 +690,7 @@ class GameServer { this.broadcastBoard(); this.broadcastButtons(); this.broadcastTitle(); + this.broadcastSound('draw'); } private handleDeclineDraw(): void {