(function ($) { let io = window.io.connect() let Connect4 = { DOM: {}, playerName: '', playerID: '', verified: null, locked: false, waitlist: [], played: 0, renderTick: false, Game: { gameId: null, myTurn: false, myColor: '', opponentID: '', opponentName: '', places: [[],[],[],[],[],[],[],[],[]] }, color: { blue: '#102aed', red: '#ed1010' } } window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60) } })() function mustacheTempl (tmlTag, data) { let html = '' const tag = document.querySelector('#' + tmlTag) if (!tag) return '' html = tag.innerHTML html = window.Mustache.to_html(html, data) return html } function modalAlert (msg) { Connect4.DOM.modalMsg.innerHTML = msg Connect4.DOM.alertModal.showModal() } function pointerOnCanvas (e) { let x let y if (e.changedTouches) { let touch = e.changedTouches[0] if (touch) { e.pageX = touch.pageX e.pageY = touch.pageY } } if (e.pageX || e.pageY) { x = e.pageX y = e.pageY } else { x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop } x -= Connect4.DOM.canvas.offsetLeft y -= Connect4.DOM.canvas.offsetTop return {x: x, y: y} } let GameDrawer = { drawMyBoard: true, boardStaticState: null, mX: 0, mY: 0, padding: 32, gridX: 0, gridY: 0, gridSize: 64, mouseOn: false, bw: 576, bh: 576, startGame: () => { Connect4.Game.places = [[],[],[],[],[],[],[],[],[]] Connect4.ctx.clearRect(0, 0, Connect4.canvasW, Connect4.canvasH) let p = GameDrawer.padding Connect4.ctx.beginPath() for (let x = 0; x <= GameDrawer.bw; x += GameDrawer.gridSize) { Connect4.ctx.moveTo(0.5 + x + p, p) Connect4.ctx.lineTo(0.5 + x + p, GameDrawer.bh + p) } for (let x = 0; x <= GameDrawer.bh; x += GameDrawer.gridSize) { Connect4.ctx.moveTo(p, 0.5 + x + p) Connect4.ctx.lineTo(GameDrawer.bw + p, 0.5 + x + p) } Connect4.ctx.closePath() Connect4.ctx.lineWidth = 1 Connect4.ctx.strokeStyle = "black" Connect4.ctx.stroke() GameDrawer.boardStaticState = new Image() GameDrawer.boardStaticState.src = Connect4.DOM.canvas.toDataURL() GameDrawer.boardStaticState.onload = () => { Connect4.renderTick = true GameDrawer.gameLoop() } }, possible: (column) => { let inTable = Connect4.Game.places[column] if (inTable.length === 9) { return false } return true }, click: () => { if (!Connect4.Game.gameId) return if (Connect4.Game.myTurn && GameDrawer.mouseOn) { let column = GameDrawer.gridX - 1 if (GameDrawer.possible(column)) { Connect4.Game.myTurn = false io.emit('place_at', {column: column, gameId: Connect4.Game.gameId}) } } }, updater: () => { for (let i in Connect4.Game.places) { let col = Connect4.Game.places[i] for (let p in col) { let piece = col[p] if (piece.dy < piece.y) { piece.dy += 0.5 } else { piece.dy = piece.y } Connect4.ctx.fillStyle = Connect4.color[piece.color] Connect4.ctx.fillRect((parseInt(i) * GameDrawer.gridSize) + GameDrawer.padding, (piece.dy * GameDrawer.gridSize) + GameDrawer.padding, GameDrawer.gridSize, GameDrawer.gridSize) } } if (!Connect4.renderTick || !Connect4.Game.gameId) return if (Connect4.Game.myTurn) { if (GameDrawer.mouseOn) { let pos = (GameDrawer.gridX * GameDrawer.gridSize) Connect4.ctx.beginPath() Connect4.ctx.moveTo(pos - 8, (GameDrawer.padding / 2) - 4) Connect4.ctx.lineTo(pos, (GameDrawer.padding / 2) + 4) Connect4.ctx.lineTo(pos + 8, (GameDrawer.padding / 2) - 4) Connect4.ctx.closePath() Connect4.ctx.lineWidth = 10 Connect4.ctx.strokeStyle = Connect4.color[Connect4.Game.myColor] Connect4.ctx.stroke() } } }, gameLoop: () => { Connect4.ctx.clearRect(0, 0, Connect4.canvasW, Connect4.canvasH) if (!Connect4.renderTick) return GameDrawer.updater() Connect4.ctx.drawImage(GameDrawer.boardStaticState, 0, 0) requestAnimFrame(GameDrawer.gameLoop) }, initialize: () => { Connect4.DOM.canvas.addEventListener('mousemove', (e) => { let p = pointerOnCanvas(e) if (p.x > GameDrawer.padding && p.y > GameDrawer.padding) { let gridX = Math.floor((p.x + GameDrawer.padding) / GameDrawer.gridSize) let gridY = Math.floor((p.y + GameDrawer.padding) / GameDrawer.gridSize) if (gridX <= 9 && gridY <= 9) { GameDrawer.mouseOn = true GameDrawer.gridX = gridX GameDrawer.gridY = gridY } else { GameDrawer.mouseOn = false } } else { GameDrawer.mouseOn = false } }) Connect4.DOM.canvas.addEventListener('mouseleave', (e) => { GameDrawer.mouseOn = false }) Connect4.DOM.canvas.addEventListener('click', (e) => { GameDrawer.click() }) document.addEventListener('keydown', (e) => { if (GameDrawer.placingShips && e.keyCode === 82) { if (GameDrawer.shipOrientation === 0) { GameDrawer.shipOrientation = 1 } else { GameDrawer.shipOrientation = 0 } } }) } } function getStored (variable) { let result = null if (!window.localStorage) { return null } if (window.localStorage.game_store) { try { let obj = JSON.parse(window.localStorage.game_store) if (obj[variable] != null) { result = obj[variable] } } catch (e) { result = null } } return result } function storeVar (variable, value) { if (!window.localStorage) { return null } if (window.localStorage.game_store) { try { let obj = JSON.parse(window.localStorage.game_store) obj[variable] = value window.localStorage.game_store = JSON.stringify(obj) } catch (e) { return null } } else { let obj = {} obj[variable] = value window.localStorage.game_store = JSON.stringify(obj) } } function playerNameValidation (name) { if (/^([A-Z0-9_\-@]{3,20})$/i.test(name)) { return true } return false } function logWarning (msg) { Connect4.DOM.joinWarn.innerHTML = msg } function logStatus (msg) { Connect4.DOM.statusCurrent.innerHTML = msg } function joinGame (game) { Connect4.played += 1 modalAlert('Game has started!') //io.emit('leave_game', {gameId: Connect4.Game.gameId}) Connect4.Game.gameId = game.gameId Connect4.Game.opponentID = game.opponentId Connect4.Game.opponentName = game.opponentName Connect4.Game.myColor = game.color Connect4.DOM.opponentName.innerHTML = game.opponentName Connect4.DOM.chatbox.innerHTML = '' io.emit('game_poll', {gameId: Connect4.Game.gameId}) Connect4.DOM.gameScreen.style.display = 'block' Connect4.DOM.selectionScreen.style.display = 'none' Connect4.DOM.waitlistBtns.style.display = 'block' Connect4.DOM.waitlistQuit.style.display = 'none' GameDrawer.startGame() addChatMessage('event', null, 'Game started!') } function attemptJoin (name) { if (Connect4.locked) return if (!io.connected) { return logWarning('Disconnected from server socket.') } if (playerNameValidation(name) == false) { return logWarning('Username not allowed.') } logWarning('Attempting to join..') Connect4.locked = true io.emit('session_create', {name: name}) } function joinSuccess (data) { Connect4.playerName = data.name Connect4.playerID = data.uid Connect4.DOM.selectionScreen.style.display = 'block' storeVar('name', data.name) io.emit('poll_games') Connect4.locked = false } function joinResponse (data) { if (data.success !== true) { Connect4.locked = false return logWarning(data.message) } Connect4.DOM.startScreen.style.display = 'none' joinSuccess(data) } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min } function constructWaitList() { let finalML = '' for (let i in Connect4.waitlist) { let game = Connect4.waitlist[i] finalML += mustacheTempl('waitlistInstance', game) } waitlist.innerHTML = finalML } window.joinWaiting = (gameId) => { if (Connect4.Game.gameId) return io.emit('game_attempt_join', {gameId: gameId}) } function gameEnds (reason, winner) { if (reason === 1) { if (winner === true) { modalAlert('You won!') logStatus('You won!') } else { modalAlert('You lost.') logStatus('You lost.') } } if (reason === 0 && winner === true) { modalAlert('Your opponent left the game.') Connect4.DOM.gameScreen.style.display = 'none' Connect4.DOM.selectionScreen.style.display = 'block' Connect4.renderTick = false } if (reason === 2) { modalAlert('You tied!') logStatus('It\'s a tie!.') } Connect4.locked = false Connect4.Game.gameId = null Connect4.Game.myTurn = false io.emit('poll_games') //Connect4.DOM.gameScreen.style.display = 'none' //Connect4.DOM.selectionScreen.style.display = 'block' Connect4.DOM.waitlistBtns.style.display = 'block' Connect4.DOM.waitlistQuit.style.display = 'none' addChatMessage('event', null, 'Disconnected') } function forceRelogin () { logWarning('Please log in again.') Connect4.DOM.gameScreen.style.display = 'none' Connect4.DOM.selectionScreen.style.display = 'none' Connect4.DOM.startScreen.style.display = 'block' Connect4.DOM.resultScreen.style.display = 'none' Connect4.locked = false Connect4.playerName = '' Connect4.Game.gameId = null } function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'") } function addChatMessage (type, senderName, message) { let msgElem = '