code
This commit is contained in:
commit
73893b6cb6
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/node_modules/
|
155
client/index.css
Normal file
155
client/index.css
Normal file
@ -0,0 +1,155 @@
|
||||
body {
|
||||
font-family: "Open Sans";
|
||||
margin: 0;
|
||||
color: black;
|
||||
}
|
||||
.wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
background: -moz-radial-gradient(center, ellipse cover, #ffffff 0%, #e5e5e5 100%);
|
||||
background: -webkit-radial-gradient(center, ellipse cover, #ffffff 0%,#e5e5e5 100%);
|
||||
background: radial-gradient(ellipse at center, #ffffff 0%,#e5e5e5 100%);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.screen {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.dialog {
|
||||
position: absolute;
|
||||
width: 260px;
|
||||
padding: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 10px;
|
||||
top: 20%;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
input[type="text"] {
|
||||
background-color: #f9f9f9;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 2px;
|
||||
font-size: 125%;
|
||||
padding: 2px;
|
||||
box-shadow: inset 1px 1px 10px #ddd;
|
||||
color: black;
|
||||
}
|
||||
.dialog input {
|
||||
margin-bottom: 10px;
|
||||
width: 95%;
|
||||
}
|
||||
button {
|
||||
background: #ffffff;
|
||||
background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%);
|
||||
background: -webkit-linear-gradient(top, #ffffff 0%,#e5e5e5 100%);
|
||||
background: linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
|
||||
border: 1px solid #ddd;
|
||||
padding: 5px 15px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
color: black;
|
||||
}
|
||||
button:hover {
|
||||
background: -moz-linear-gradient(top, #ffffff 0%, #e8e8e8 100%);
|
||||
background: -webkit-linear-gradient(top, #ffffff 0%,#e8e8e8 100%);
|
||||
background: linear-gradient(to bottom, #ffffff 0%,#e8e8e8 100%);
|
||||
}
|
||||
canvas {
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
background-color: #03A9F4;
|
||||
margin: 10px;
|
||||
/*border: 5px solid #2196F3;*/
|
||||
}
|
||||
.boxlayout {
|
||||
text-align: center;
|
||||
}
|
||||
.box {
|
||||
text-align: left;
|
||||
width: 25%;
|
||||
display: inline-block;
|
||||
height: 400px;
|
||||
margin: 20px;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
min-width: 280px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #ddd;
|
||||
box-shadow: 4px 4px 10px #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
.stat {
|
||||
display: block;
|
||||
}
|
||||
#waitlist {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
#waitlist .red, #waitlist .green {
|
||||
padding: 10px;
|
||||
}
|
||||
#waitlist .red {
|
||||
background-color: #ffd5d5;
|
||||
border: 1px solid #ff5c5c;
|
||||
}
|
||||
#waitlist .green {
|
||||
background-color: #daffda;
|
||||
border: 1px solid #00f700;
|
||||
}
|
||||
.waitlistInstance {
|
||||
background-color: #f5f5f5;
|
||||
padding: 5px;
|
||||
max-height: 240px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.waitlistInstance:nth-child(odd) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.joinBtn {
|
||||
float: right;
|
||||
color: #03A9F4;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
.joinBtn:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.header {
|
||||
height: 40px;
|
||||
line-height: 2.5;
|
||||
padding: 5px 20px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
button#leave {
|
||||
float: right;
|
||||
line-height: 2;
|
||||
}
|
||||
.sidebar {
|
||||
float: left;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
top: 51px;
|
||||
bottom: 0;
|
||||
}
|
||||
#g_s_stat {
|
||||
margin-top: 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
color: #119286;
|
||||
font-weight: bold;
|
||||
padding-top: 5px;
|
||||
width: 200px;
|
||||
}
|
||||
#game_canvas {
|
||||
margin-left: 265px;
|
||||
}
|
73
client/index.html
Normal file
73
client/index.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script type="text/javascript" src="./index.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="./index.css">
|
||||
<title>HTML5 Battleship (simplified version)</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="screen" id="start">
|
||||
<div class="dialog">
|
||||
<h1>Enter your name</h1>
|
||||
<p id="warning_message"></p>
|
||||
<input type="text" id="player_name">
|
||||
<button id="sock_player_init">Join server</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="screen boxlayout" style="display: none;" id="selection">
|
||||
<div class="box">
|
||||
<h1>Statistics</h1>
|
||||
<span class="stat">Players in game: <span id="stats_players"></span></span>
|
||||
<span class="stat">Total games since server started: <span id="stats_games"></span></span>
|
||||
<span class="stat">You've played in <span id="stats_clientgames"></span> matches this session.</span>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h1>Players waiting</h1>
|
||||
<div id="waitlist">
|
||||
<p><i class="fa fa-spinner fa-spin fa-fw"></i> Loading..</p>
|
||||
</div>
|
||||
<button id="waitlist_quit" style="display: none;">Cancel</button>
|
||||
<div class="idbuttons">
|
||||
<button id="waitlist_join">Join Wait List</button>
|
||||
<button id="waitlist_join_random">Join Random Game</button>
|
||||
<button id="waitlist_join_refresh">Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h1>How to play</h1>
|
||||
<p>This is a puzzle game inspired by <a href="https://en.wikipedia.org/wiki/Battleship_(puzzle)" target="_blank">Battleship</a>, however this one works quite differently.</p>
|
||||
<ul>
|
||||
<li>You start off by placing your ships onto the board.</li>
|
||||
<li>Once you and your opponent finish placing the ships, the game begins.</li>
|
||||
<li>When it's your turn, you click on a square to attempt to bomb an opposing ship.</li>
|
||||
<li>If you miss, it's your opponents turn. If you strike, you can bomb more until you miss again.</li>
|
||||
<li>You must destroy most of the opponents's ship to sink it.</li>
|
||||
<li>You win the game by sinking all of the opponent's ships!</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="screen game gamelayout" style="display: none;" id="game">
|
||||
<div class="header">You're playing against <span id="opponent_name">null</span> <button id="leave">Leave game</button></div>
|
||||
<canvas id="game_canvas" width="513" height="513"></canvas>
|
||||
<div class="sidebar">
|
||||
<span class="stat">You have <span id="g_s_num">0</span> ships left.</span>
|
||||
<span class="stat">Your opponent has <span id="o_s_num">0</span> ships left.</span>
|
||||
<span class="stat" id="g_s_stat">Your turn.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/mustache" id="waitlistInstance">
|
||||
<div class="waitlistInstance">
|
||||
<span class="name">{{name}}</span>
|
||||
<a href="#" class="joinBtn" onclick="joinWaiting('{{gameId}}')">Join</a>
|
||||
</div>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
689
client/index.js
Normal file
689
client/index.js
Normal file
@ -0,0 +1,689 @@
|
||||
(function ($) {
|
||||
let io = window.io.connect()
|
||||
let Battleship = {
|
||||
DOM: {},
|
||||
playerName: '',
|
||||
playerID: '',
|
||||
verified: null,
|
||||
locked: false,
|
||||
waitlist: [],
|
||||
played: 0,
|
||||
Game: {
|
||||
gameId: null,
|
||||
inGame: false,
|
||||
myTurn: true,
|
||||
opponentID: '',
|
||||
opponentName: '',
|
||||
ships: 0,
|
||||
oShips: 0,
|
||||
gridHome: {ships: [], strikes: []},
|
||||
gridOpponent: []
|
||||
}
|
||||
}
|
||||
|
||||
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 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 -= Battleship.DOM.canvas.offsetLeft
|
||||
y -= Battleship.DOM.canvas.offsetTop
|
||||
|
||||
return {x: x, y: y}
|
||||
}
|
||||
|
||||
let GameDrawer = {
|
||||
drawMyBoard: true,
|
||||
boardStaticState: null,
|
||||
|
||||
mX: 0,
|
||||
mY: 0,
|
||||
|
||||
gridX: 0,
|
||||
gridY: 0,
|
||||
|
||||
gridSize: 32,
|
||||
mouseOn: false,
|
||||
|
||||
bw: 512,
|
||||
bh: 512,
|
||||
|
||||
placingShips: true,
|
||||
canPlace: false,
|
||||
shipIndex: 0,
|
||||
shipOrientation: 0,
|
||||
shipTiles: [],
|
||||
|
||||
startGame: () => {
|
||||
GameDrawer.placingShips = true
|
||||
GameDrawer.canPlace = false
|
||||
GameDrawer.shipIndex = 0
|
||||
GameDrawer.shipOrientation = 0
|
||||
GameDrawer.shipTiles = []
|
||||
|
||||
Battleship.ctx.clearRect(0, 0, Battleship.canvasW, Battleship.canvasH)
|
||||
Battleship.Game.myTurn = true
|
||||
|
||||
let p = 0
|
||||
let context = Battleship.ctx
|
||||
|
||||
for (let x = 0; x <= GameDrawer.bw; x += GameDrawer.gridSize) {
|
||||
context.moveTo(0.5 + x + p, p)
|
||||
context.lineTo(0.5 + x + p, GameDrawer.bh + p)
|
||||
}
|
||||
|
||||
for (let x = 0; x <= GameDrawer.bh; x += GameDrawer.gridSize) {
|
||||
context.moveTo(p, 0.5 + x + p)
|
||||
context.lineTo(GameDrawer.bw + p, 0.5 + x + p)
|
||||
}
|
||||
|
||||
context.strokeStyle = "black"
|
||||
context.stroke()
|
||||
|
||||
GameDrawer.boardStaticState = new Image()
|
||||
GameDrawer.boardStaticState.src = Battleship.DOM.canvas.toDataURL()
|
||||
GameDrawer.boardStaticState.onload = () => {
|
||||
GameDrawer.gameLoop()
|
||||
}
|
||||
},
|
||||
|
||||
click: () => {
|
||||
if (GameDrawer.placingShips && GameDrawer.canPlace && GameDrawer.shipIndex != -1) {
|
||||
let shipData = Battleship.ships[GameDrawer.shipIndex]
|
||||
let placed = {
|
||||
name: shipData.name,
|
||||
sunken: false,
|
||||
cells: GameDrawer.shipTiles
|
||||
}
|
||||
|
||||
io.emit('ship_place', {ship: placed, gameId: Battleship.Game.gameId})
|
||||
|
||||
if (GameDrawer.shipIndex + 1 < Battleship.ships.length) {
|
||||
GameDrawer.shipIndex += 1
|
||||
} else {
|
||||
GameDrawer.shipIndex = -1
|
||||
logStatus('Waiting for opponent')
|
||||
}
|
||||
} else if (!GameDrawer.placingShips && Battleship.Game.myTurn) {
|
||||
io.emit('set_bomb', {x: GameDrawer.gridX, y: GameDrawer.gridY, gameId: Battleship.Game.gameId})
|
||||
}
|
||||
},
|
||||
|
||||
intersectsExisting: (cx, cy) => {
|
||||
let is = false
|
||||
for (let i in Battleship.Game.gridHome.ships) {
|
||||
let ship = Battleship.Game.gridHome.ships[i]
|
||||
for (let j in ship.cells) {
|
||||
let cell = ship.cells[j]
|
||||
if (cell.x === cx && cell.y === cy) {
|
||||
is = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return is
|
||||
},
|
||||
|
||||
updater: () => {
|
||||
if (Battleship.Game.myTurn && !GameDrawer.placingShips) {
|
||||
if (GameDrawer.mouseOn) {
|
||||
Battleship.ctx.fillStyle = '#f4b002'
|
||||
Battleship.ctx.fillRect(GameDrawer.gridX * GameDrawer.gridSize, GameDrawer.gridY * GameDrawer.gridSize, GameDrawer.gridSize, GameDrawer.gridSize)
|
||||
}
|
||||
|
||||
for (let i in Battleship.Game.gridHome.strikes) {
|
||||
let strike = Battleship.Game.gridHome.strikes[i]
|
||||
if (strike.destroy) {
|
||||
Battleship.ctx.fillStyle = '#ff0000'
|
||||
} else {
|
||||
Battleship.ctx.fillStyle = '#dddd00'
|
||||
}
|
||||
Battleship.ctx.fillRect(strike.x * GameDrawer.gridSize, strike.y * GameDrawer.gridSize, GameDrawer.gridSize, GameDrawer.gridSize)
|
||||
}
|
||||
} else if ((!Battleship.Game.myTurn && !GameDrawer.placingShips) || (Battleship.Game.myTurn && GameDrawer.placingShips)) {
|
||||
for (let i in Battleship.Game.gridOpponent) {
|
||||
let strike = Battleship.Game.gridOpponent[i]
|
||||
Battleship.ctx.fillStyle = '#dddd00'
|
||||
Battleship.ctx.fillRect(strike.x * GameDrawer.gridSize, strike.y * GameDrawer.gridSize, GameDrawer.gridSize, GameDrawer.gridSize)
|
||||
}
|
||||
|
||||
for (let i in Battleship.Game.gridHome.ships) {
|
||||
let ship = Battleship.Game.gridHome.ships[i]
|
||||
for (let j in ship.cells) {
|
||||
let cell = ship.cells[j]
|
||||
let color = '#dddddd'
|
||||
|
||||
if (cell.destroyed || ship.sunken) {
|
||||
color = '#ff0000'
|
||||
}
|
||||
|
||||
Battleship.ctx.fillStyle = color
|
||||
Battleship.ctx.fillRect(cell.x * GameDrawer.gridSize, cell.y * GameDrawer.gridSize, GameDrawer.gridSize, GameDrawer.gridSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Battleship.Game.myTurn && GameDrawer.placingShips) {
|
||||
let shipData = Battleship.ships[GameDrawer.shipIndex]
|
||||
|
||||
if (!shipData) return
|
||||
|
||||
let shipCenter = Math.floor(shipData.tiles / 2)
|
||||
|
||||
let cellsOff = 0
|
||||
let positions = []
|
||||
let color = '#00dd00'
|
||||
|
||||
for (let i = 0; i < shipData.tiles; i++) {
|
||||
let sx = 0
|
||||
let sy = 0
|
||||
i = parseInt(i)
|
||||
|
||||
let rx = 0
|
||||
let ry = 0
|
||||
|
||||
if (i < shipCenter) {
|
||||
if (GameDrawer.shipOrientation === 0) {
|
||||
sx = GameDrawer.gridX - (shipCenter - i)
|
||||
sy = GameDrawer.gridY
|
||||
} else {
|
||||
sx = GameDrawer.gridX
|
||||
sy = GameDrawer.gridY - (shipCenter - i)
|
||||
}
|
||||
} else if (i === shipCenter) {
|
||||
sx = GameDrawer.gridX
|
||||
sy = GameDrawer.gridY
|
||||
} else {
|
||||
if (GameDrawer.shipOrientation === 0) {
|
||||
sx = GameDrawer.gridX + (i - shipCenter)
|
||||
sy = GameDrawer.gridY
|
||||
} else {
|
||||
sx = GameDrawer.gridX
|
||||
sy = GameDrawer.gridY + (i - shipCenter)
|
||||
}
|
||||
}
|
||||
|
||||
if (sx < 0 || sy < 0 || sx > 15 || sy > 15) {
|
||||
cellsOff += 1
|
||||
}
|
||||
|
||||
if (GameDrawer.intersectsExisting(sx, sy)) {
|
||||
cellsOff += 1
|
||||
}
|
||||
|
||||
positions.push({x: sx, y: sy, destroyed: false})
|
||||
}
|
||||
|
||||
for (let i in positions) {
|
||||
let pos = positions[i]
|
||||
|
||||
if (cellsOff > 0) {
|
||||
color = '#dd0000'
|
||||
GameDrawer.canPlace = false
|
||||
} else {
|
||||
GameDrawer.canPlace = true
|
||||
}
|
||||
|
||||
Battleship.ctx.fillStyle = color
|
||||
Battleship.ctx.fillRect(pos.x * GameDrawer.gridSize, pos.y * GameDrawer.gridSize, GameDrawer.gridSize, GameDrawer.gridSize)
|
||||
}
|
||||
|
||||
GameDrawer.shipTiles = positions
|
||||
}
|
||||
},
|
||||
|
||||
clearCanvas: () => {
|
||||
Battleship.ctx.clearRect(0, 0, Battleship.canvasW, Battleship.canvasH)
|
||||
Battleship.ctx.drawImage(GameDrawer.boardStaticState, 0, 0)
|
||||
},
|
||||
|
||||
gameLoop: () => {
|
||||
GameDrawer.clearCanvas()
|
||||
if (!Battleship.Game.gameId) return
|
||||
|
||||
GameDrawer.updater()
|
||||
|
||||
requestAnimFrame(GameDrawer.gameLoop)
|
||||
},
|
||||
|
||||
initialize: () => {
|
||||
Battleship.DOM.canvas.addEventListener('mousemove', (e) => {
|
||||
let posOnCanvas = pointerOnCanvas(e)
|
||||
GameDrawer.mX = posOnCanvas.x
|
||||
GameDrawer.mY = posOnCanvas.y
|
||||
GameDrawer.mouseOn = true
|
||||
|
||||
let rowCount = GameDrawer.gridSize
|
||||
|
||||
GameDrawer.gridX = Math.floor(GameDrawer.mX / rowCount)
|
||||
GameDrawer.gridY = Math.floor(GameDrawer.mY / rowCount)
|
||||
})
|
||||
|
||||
Battleship.DOM.canvas.addEventListener('mouseleave', (e) => {
|
||||
GameDrawer.mouseOn = false
|
||||
})
|
||||
|
||||
Battleship.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) {
|
||||
Battleship.DOM.joinWarn.innerHTML = msg
|
||||
}
|
||||
|
||||
function logStatus (msg) {
|
||||
Battleship.DOM.statusCurrent.innerHTML = msg
|
||||
}
|
||||
|
||||
function joinGame (game) {
|
||||
Battleship.played += 1
|
||||
|
||||
alert('Game has started!')
|
||||
//io.emit('leave_game', {gameId: Battleship.Game.gameId})
|
||||
Battleship.Game.gameId = game.gameId
|
||||
Battleship.Game.opponentID = game.opponentId
|
||||
Battleship.Game.opponentName = game.opponentName
|
||||
Battleship.DOM.opponentName.innerHTML = game.opponentName
|
||||
|
||||
io.emit('game_poll', {gameId: Battleship.Game.gameId})
|
||||
|
||||
logStatus('Place your ships onto the board.<br>Press `r` to rotate')
|
||||
|
||||
Battleship.DOM.gameScreen.style.display = 'block'
|
||||
Battleship.DOM.selectionScreen.style.display = 'none'
|
||||
Battleship.DOM.waitlistBtns.style.display = 'block'
|
||||
Battleship.DOM.waitlistQuit.style.display = 'none'
|
||||
GameDrawer.startGame()
|
||||
}
|
||||
|
||||
function attemptJoin (name) {
|
||||
if (Battleship.locked) return
|
||||
if (!io.connected) {
|
||||
return logWarning('Disconnected from server socket.')
|
||||
}
|
||||
|
||||
if (playerNameValidation(name) == false) {
|
||||
return logWarning('Username not allowed.')
|
||||
}
|
||||
|
||||
logWarning('Attempting to join..')
|
||||
Battleship.locked = true
|
||||
io.emit('session_create', {name: name})
|
||||
}
|
||||
|
||||
function joinSuccess (data) {
|
||||
Battleship.playerName = data.name
|
||||
Battleship.playerID = data.uid
|
||||
Battleship.DOM.selectionScreen.style.display = 'block'
|
||||
|
||||
storeVar('name', data.name)
|
||||
io.emit('poll_games')
|
||||
Battleship.locked = false
|
||||
}
|
||||
|
||||
function joinResponse (data) {
|
||||
if (data.success !== true) {
|
||||
Battleship.locked = false
|
||||
return logWarning(data.message)
|
||||
}
|
||||
|
||||
Battleship.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 Battleship.waitlist) {
|
||||
let game = Battleship.waitlist[i]
|
||||
finalML += mustacheTempl('waitlistInstance', game)
|
||||
}
|
||||
waitlist.innerHTML = finalML
|
||||
}
|
||||
|
||||
window.joinWaiting = (gameId) => {
|
||||
if (Battleship.Game.gameId) return
|
||||
io.emit('game_attempt_join', {gameId: gameId})
|
||||
}
|
||||
|
||||
function gameEnds (reason, winner) {
|
||||
if (reason === 1) {
|
||||
if (winner === true) {
|
||||
alert('You won!')
|
||||
} else {
|
||||
alert('You lost.')
|
||||
}
|
||||
}
|
||||
|
||||
if (reason === 0 && winner === true) {
|
||||
alert('Your opponent left the game.')
|
||||
}
|
||||
|
||||
Battleship.locked = false
|
||||
Battleship.Game.gameId = null
|
||||
io.emit('poll_games')
|
||||
Battleship.DOM.gameScreen.style.display = 'none'
|
||||
Battleship.DOM.selectionScreen.style.display = 'block'
|
||||
Battleship.DOM.waitlistBtns.style.display = 'block'
|
||||
Battleship.DOM.waitlistQuit.style.display = 'none'
|
||||
|
||||
Battleship.Game.gridHome = {ships: [], strikes: []}
|
||||
Battleship.Game.gridOpponent = []
|
||||
|
||||
Battleship.DOM.dataOpponentDestroyed.innerHTML = '0'
|
||||
Battleship.DOM.dataMineDestroyed.innerHTML = '0'
|
||||
}
|
||||
|
||||
function forceRelogin () {
|
||||
logWarning('Please log in again.')
|
||||
Battleship.DOM.gameScreen.style.display = 'none'
|
||||
Battleship.DOM.selectionScreen.style.display = 'none'
|
||||
Battleship.DOM.startScreen.style.display = 'block'
|
||||
|
||||
Battleship.locked = false
|
||||
Battleship.playerName = ''
|
||||
Battleship.Game.gameId = null
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
const startScreen = Battleship.DOM.startScreen = $.querySelector('#start')
|
||||
const selectionScreen = Battleship.DOM.selectionScreen = $.querySelector('#selection')
|
||||
const gameScreen = Battleship.DOM.gameScreen = $.querySelector('#game')
|
||||
|
||||
const warning = Battleship.DOM.joinWarn = startScreen.querySelector('#warning_message')
|
||||
const playerName = startScreen.querySelector('#player_name')
|
||||
const startButton = startScreen.querySelector('#sock_player_init')
|
||||
|
||||
const waitlist = Battleship.DOM.waitlist = selectionScreen.querySelector('#waitlist')
|
||||
const random = selectionScreen.querySelector('#waitlist_join_random')
|
||||
const newGame = selectionScreen.querySelector('#waitlist_join')
|
||||
const refresh = selectionScreen.querySelector('#waitlist_join_refresh')
|
||||
|
||||
const waitlistQuit = Battleship.DOM.waitlistQuit = selectionScreen.querySelector('#waitlist_quit')
|
||||
const waitlistBtns = Battleship.DOM.waitlistBtns = selectionScreen.querySelector('.idbuttons')
|
||||
|
||||
const stat_ingame = selectionScreen.querySelector('#stats_players')
|
||||
const stat_total = selectionScreen.querySelector('#stats_games')
|
||||
const stat_client = selectionScreen.querySelector('#stats_clientgames')
|
||||
|
||||
const leaveBtn = gameScreen.querySelector('#leave')
|
||||
const opponentName = Battleship.DOM.opponentName = gameScreen.querySelector('#opponent_name')
|
||||
|
||||
let canvas = Battleship.DOM.canvas = gameScreen.querySelector('#game_canvas')
|
||||
let ctx = Battleship.ctx = canvas.getContext('2d')
|
||||
|
||||
Battleship.canvasW = canvas.width
|
||||
Battleship.canvasH = canvas.height
|
||||
|
||||
const dataOpponentDestroyed = Battleship.DOM.dataOpponentDestroyed = gameScreen.querySelector('#o_s_num')
|
||||
const dataMineDestroyed = Battleship.DOM.dataMineDestroyed = gameScreen.querySelector('#g_s_num')
|
||||
Battleship.DOM.statusCurrent = gameScreen.querySelector('#g_s_stat')
|
||||
|
||||
GameDrawer.initialize()
|
||||
|
||||
let uname = getStored('name')
|
||||
if (uname) {
|
||||
playerName.value = uname
|
||||
}
|
||||
|
||||
playerName.addEventListener('keydown', (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
attemptJoin(playerName.value)
|
||||
}
|
||||
}, false)
|
||||
|
||||
startButton.addEventListener('click', (e) => {
|
||||
attemptJoin(playerName.value)
|
||||
}, false)
|
||||
|
||||
newGame.addEventListener('click', (e) => {
|
||||
if (Battleship.locked) return
|
||||
if (Battleship.Game.gameId) return
|
||||
io.emit('new_game')
|
||||
Battleship.locked = true
|
||||
})
|
||||
|
||||
refresh.addEventListener('click', (e) => {
|
||||
if (Battleship.locked) return
|
||||
io.emit('poll_games')
|
||||
})
|
||||
|
||||
waitlistQuit.addEventListener('click', (e) => {
|
||||
io.emit('leave_game', {gameId: Battleship.Game.gameId})
|
||||
})
|
||||
|
||||
leaveBtn.addEventListener('click', (e) => {
|
||||
io.emit('leave_game', {gameId: Battleship.Game.gameId})
|
||||
})
|
||||
|
||||
random.addEventListener('click', (e) => {
|
||||
Battleship.joinRandomWhenDone = true
|
||||
io.emit('poll_games')
|
||||
})
|
||||
|
||||
io.on('destroy_turn', (val) => {
|
||||
GameDrawer.placingShips = false
|
||||
if (val === true) {
|
||||
Battleship.Game.myTurn = true
|
||||
logStatus('It\'s your turn!<br>Click anywhere on the grid to attempt to destroy enemy ships.')
|
||||
} else {
|
||||
Battleship.Game.myTurn = false
|
||||
logStatus('Your opponent\'s turn.')
|
||||
}
|
||||
})
|
||||
|
||||
io.on('update_hits', (data) => {
|
||||
if (data.me) {
|
||||
Battleship.Game.gridHome.strikes = data.strikes
|
||||
} else {
|
||||
Battleship.Game.gridOpponent = data.strikes
|
||||
}
|
||||
})
|
||||
|
||||
io.on('updateShip', (dship) => {
|
||||
for (let i in Battleship.Game.gridHome.ships) {
|
||||
let ship = Battleship.Game.gridHome.ships[i]
|
||||
if (ship.name === dship.name) {
|
||||
for (let j in ship.cells) {
|
||||
let cell = ship.cells[j]
|
||||
cell.destroyed = dship.cells[j].destroyed
|
||||
}
|
||||
ship.sunken = dship.sunken
|
||||
|
||||
if (ship.sunken) {
|
||||
logStatus('Opponent sunk one of your ships!')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
io.on('infmessage', (message) => {
|
||||
logStatus(message)
|
||||
})
|
||||
|
||||
io.on('game_settings', (data) => {
|
||||
Battleship.ships = data.ships
|
||||
})
|
||||
|
||||
io.on('verified_place', (ship) => {
|
||||
Battleship.Game.gridHome.ships.push(ship)
|
||||
})
|
||||
|
||||
io.on('game_start', (data) => {
|
||||
joinGame(data)
|
||||
})
|
||||
|
||||
io.on('left_success', () => {
|
||||
gameEnds(0, null)
|
||||
})
|
||||
|
||||
io.on('game_error', (data) => {
|
||||
alert(data.message)
|
||||
gameEnds(0, null)
|
||||
io.emit('poll_games')
|
||||
})
|
||||
|
||||
io.on('force_relog', () => {
|
||||
forceRelogin()
|
||||
})
|
||||
|
||||
io.on('game_end', (data) => {
|
||||
gameEnds(data.result, data.win)
|
||||
})
|
||||
|
||||
io.on('game_new_done', (data) => {
|
||||
Battleship.locked = true
|
||||
Battleship.DOM.waitlist.innerHTML = '<div class="green">Waiting for an opponent..</div>'
|
||||
Battleship.DOM.waitlistBtns.style.display = 'none'
|
||||
Battleship.DOM.waitlistQuit.style.display = 'block'
|
||||
Battleship.Game.gameId = data.gameId
|
||||
})
|
||||
|
||||
io.on('current_stats', (data) => {
|
||||
dataOpponentDestroyed.innerHTML = data.opponentShipsLeft
|
||||
dataMineDestroyed.innerHTML = data.myShipsLeft
|
||||
})
|
||||
|
||||
io.on('login_status', joinResponse)
|
||||
io.on('poll_games_res', (data) => {
|
||||
Battleship.DOM.waitlistQuit.style.display = 'none'
|
||||
|
||||
let list = data.list
|
||||
|
||||
if (data.sessions != null) {
|
||||
stat_ingame.innerHTML = data.sessions
|
||||
}
|
||||
|
||||
if (data.totalGames != null) {
|
||||
stat_total.innerHTML = data.totalGames
|
||||
}
|
||||
|
||||
stat_client.innerHTML = Battleship.played
|
||||
|
||||
if (!list.length) {
|
||||
waitlist.innerHTML = '<div class="red">No people currently waiting, press <b>Join Wait List</b> to enter.</div>'
|
||||
Battleship.waitlist = []
|
||||
|
||||
if(Battleship.joinRandomWhenDone) {
|
||||
delete Battleship.joinRandomWhenDone
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
Battleship.waitlist = list
|
||||
|
||||
if (Battleship.joinRandomWhenDone && Battleship.waitlist.length) {
|
||||
delete Battleship.joinRandomWhenDone
|
||||
|
||||
let rand = getRandomInt(1, Battleship.waitlist.length)
|
||||
|
||||
io.emit('game_attempt_join', {gameId: Battleship.waitlist[rand - 1].gameId})
|
||||
}
|
||||
|
||||
constructWaitList()
|
||||
})
|
||||
|
||||
io.on('disconnect', () => {
|
||||
gameEnds(0, null)
|
||||
forceRelogin()
|
||||
logWarning('Server disconnected')
|
||||
})
|
||||
}
|
||||
})(document)
|
20
package.json
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "battleship.js",
|
||||
"version": "0.0.0",
|
||||
"description": "Battleship game in the browser",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"battleship",
|
||||
"game",
|
||||
"html5"
|
||||
],
|
||||
"author": "Evert",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "^4.15.2",
|
||||
"socketio": "^1.0.0"
|
||||
}
|
||||
}
|
517
server.js
Normal file
517
server.js
Normal file
@ -0,0 +1,517 @@
|
||||
const express = require('express')
|
||||
const socketio = require('socket.io')
|
||||
const http = require('http')
|
||||
const path = require('path')
|
||||
|
||||
// TODO LIST:
|
||||
// * More ships
|
||||
// * Timer
|
||||
// * Chat box
|
||||
// * Side-by-side board display
|
||||
|
||||
const ships = [
|
||||
{name: 'biggest', tiles: 5, destCount: 4},
|
||||
{name: 'bigger', tiles: 4, destCount: 3},
|
||||
{name: 'medium', tiles: 3, destCount: 2},
|
||||
{name: 'smaller', tiles: 3, destCount: 2},
|
||||
{name: 'smallest', tiles: 2, destCount: 1}
|
||||
]
|
||||
|
||||
let app = express()
|
||||
let server = http.createServer(app)
|
||||
let io = socketio(server)
|
||||
|
||||
app.enable('trust proxy')
|
||||
app.disable('x-powered-by')
|
||||
|
||||
app.use('/', express.static(path.join(__dirname, '/client/')))
|
||||
|
||||
function playerNameValidation (name) {
|
||||
if (/^([A-Z0-9_\-@]{3,20})$/i.test(name)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
let clients = {}
|
||||
let games = {}
|
||||
|
||||
let totalGames = 0
|
||||
|
||||
// Generate a random int betweem two ints
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
// Generate random string of characters
|
||||
function nuid(len) {
|
||||
let buf = [],
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||
charlen = chars.length
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
buf.push(chars[getRandomInt(0, charlen - 1)])
|
||||
}
|
||||
|
||||
return buf.join('')
|
||||
}
|
||||
|
||||
function clientsBySocketID (id) {
|
||||
let result = null
|
||||
|
||||
for (let uid in clients) {
|
||||
let client = clients[uid]
|
||||
if (client.sockID === id) {
|
||||
result = uid
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function killGamesClientIsIn (uid) {
|
||||
for (let gameId in games) {
|
||||
let game = games[gameId]
|
||||
if (game.player1 && game.player1.uid === uid) {
|
||||
if (!game.isWaiting && game.player2) {
|
||||
clients[game.player2.uid].socket.emit('game_end', {win: true, result: 0})
|
||||
}
|
||||
} else if (game.player2 && game.player2.uid === uid) {
|
||||
if (clients[game.player1.uid]) {
|
||||
clients[game.player1.uid].socket.emit('game_end', {win: true, result: 0})
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
delete games[gameId]
|
||||
console.log(gameId + ' was ended abruptly on ' + uid + '\'s demand.')
|
||||
}
|
||||
}
|
||||
|
||||
function createNewGame (uid) {
|
||||
let client = clients[uid]
|
||||
let gameId = nuid(16)
|
||||
|
||||
client.socket.emit('game_new_done', {gameId: gameId})
|
||||
|
||||
console.log(client.name + ' has started a new game. ID: ' + gameId)
|
||||
|
||||
games[gameId] = {
|
||||
player1: {
|
||||
uid: uid,
|
||||
ships: [],
|
||||
strikes: [],
|
||||
placed: false,
|
||||
destructions: 0
|
||||
},
|
||||
player2: null,
|
||||
isWaiting: true,
|
||||
turn: 1,
|
||||
started: new Date()
|
||||
}
|
||||
}
|
||||
|
||||
function joinGame (uid, gameId) {
|
||||
let me = clients[uid]
|
||||
|
||||
if (!games[gameId]) {
|
||||
return socket.emit('game_error', {message: 'That game has ended!'})
|
||||
}
|
||||
|
||||
if (games[gameId].player2 != null) {
|
||||
return socket.emit('game_error', {message: 'That game has already started!'})
|
||||
}
|
||||
|
||||
if (!clients[games[gameId].player1.uid]) {
|
||||
return socket.emit('game_error', {message: 'That game has ended!'})
|
||||
}
|
||||
|
||||
games[gameId].player2 = {
|
||||
uid: uid,
|
||||
ships: [],
|
||||
strikes: [],
|
||||
placed: false,
|
||||
destructions: 0
|
||||
}
|
||||
|
||||
games[gameId].isWaiting = false
|
||||
|
||||
let opponent = clients[games[gameId].player1.uid]
|
||||
|
||||
if (!opponent) {
|
||||
return socket.emit('game_error', {message: 'Your opponent abruptly dissappeared, what?'})
|
||||
}
|
||||
|
||||
opponent.socket.emit('game_start', {gameId: gameId, opponentId: uid, opponentName: me.name})
|
||||
me.socket.emit('game_start', {gameId: gameId, opponentId: opponent.uid, opponentName: opponent.name})
|
||||
|
||||
totalGames += 1
|
||||
}
|
||||
|
||||
function endGame (gameId, victoryId, loserId) {
|
||||
if (clients[victoryId]) {
|
||||
clients[victoryId].socket.emit('game_end', {win: true, result: 1})
|
||||
}
|
||||
|
||||
if (clients[loserId]) {
|
||||
clients[loserId].socket.emit('game_end', {win: false, result: 1})
|
||||
}
|
||||
|
||||
delete games[gameId]
|
||||
console.log(gameId + ' ended with ' + victoryId + '\'s victory.')
|
||||
}
|
||||
|
||||
function waitingGamesList (uid) {
|
||||
let result = []
|
||||
let cap = 0
|
||||
|
||||
let gamesInSession = 0
|
||||
for (let i in games) {
|
||||
let game = games[i]
|
||||
if (!game.isWaiting) {
|
||||
gamesInSession += 1
|
||||
}
|
||||
}
|
||||
|
||||
for (let gameId in games) {
|
||||
if (cap >= 20) break
|
||||
|
||||
let game = games[gameId]
|
||||
|
||||
if (game.isWaiting) {
|
||||
let userName = clients[game.player1.uid].name
|
||||
if (uid && game.player1.uid === uid) continue
|
||||
|
||||
result.push({
|
||||
gameId: gameId,
|
||||
name: userName,
|
||||
started: game.started
|
||||
})
|
||||
|
||||
cap += 1
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
sessions: gamesInSession,
|
||||
totalGames: totalGames,
|
||||
list: result
|
||||
}
|
||||
}
|
||||
|
||||
function bombTile (playerIndex, gameId, xTile, yTile) {
|
||||
|
||||
}
|
||||
|
||||
function determinePlayerById (gameId, uid) {
|
||||
let game = games[gameId]
|
||||
|
||||
if (game.player1 && game.player1.uid === uid) {
|
||||
return 'player1'
|
||||
} else if (game.player2 && game.player2.uid === uid) {
|
||||
return 'player2'
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function getShipByName (name) {
|
||||
let ship = null
|
||||
for (let i in ships) {
|
||||
if (ships[i].name === name) {
|
||||
ship = ships[i]
|
||||
}
|
||||
}
|
||||
return ship
|
||||
}
|
||||
|
||||
function integrityCheck (shipDataProvided) {
|
||||
if (!shipDataProvided.name || shipDataProvided.sunken == null || !shipDataProvided.cells) {
|
||||
return false
|
||||
}
|
||||
|
||||
let shipActual = getShipByName(shipDataProvided.name)
|
||||
|
||||
if (shipActual === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (shipDataProvided.cells.length !== shipActual.tiles) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function getDestroyedTiles (ship) {
|
||||
let count = 0
|
||||
for (let i in ship.cells) {
|
||||
let cell = ship.cells[i]
|
||||
if (cell.destroyed === true) {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
function markAllTilesDestroyed (ship, myStrikes) {
|
||||
for (let i in ship.cells) {
|
||||
let cell = ship.cells[i]
|
||||
cell.destroyed = true
|
||||
myStrikes.push({x: cell.x, y: cell.y, destroy: true})
|
||||
}
|
||||
ship.sunken = true
|
||||
}
|
||||
|
||||
function attemptToBombTile (playerIndex, opponent, game, x, y) {
|
||||
let me = game[playerIndex]
|
||||
let opponentObj = game[opponent]
|
||||
|
||||
let tileMatch = null
|
||||
let shipMatch = null
|
||||
|
||||
for (let i in opponentObj.ships) {
|
||||
let ship = opponentObj.ships[i]
|
||||
for (let j in ship.cells) {
|
||||
let cell = ship.cells[j]
|
||||
if (cell.x === x && cell.y === y) {
|
||||
tileMatch = cell
|
||||
shipMatch = ship
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tileMatch) {
|
||||
me.strikes.push({x: x, y: y, destroy: false})
|
||||
//opponentObj.strikes.push({x: x, y: y, destroy: false})
|
||||
return {event: 2, ship: null}
|
||||
}
|
||||
|
||||
if (tileMatch.destroyed === true) {
|
||||
return {event: 5, ship: shipMatch}
|
||||
}
|
||||
|
||||
tileMatch.destroyed = true
|
||||
me.strikes.push({x: x, y: y, destroy: true})
|
||||
|
||||
let shipActual = getShipByName(shipMatch.name)
|
||||
let destroyedTileCount = getDestroyedTiles(shipMatch)
|
||||
|
||||
if (destroyedTileCount >= shipActual.destCount) {
|
||||
markAllTilesDestroyed(shipMatch, me.strikes)
|
||||
opponentObj.destructions += 1
|
||||
|
||||
if (opponentObj.destructions === ships.length) {
|
||||
console.log('winner: ' + me.uid)
|
||||
return {event: 6, ship: shipMatch}
|
||||
}
|
||||
|
||||
return {event: 1, ship: shipMatch}
|
||||
}
|
||||
|
||||
return {event: 0, ship: shipMatch}
|
||||
}
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
socket.on('session_create', (data) => {
|
||||
if (!data.name) {
|
||||
return socket.emit('login_status', {success: false, message: 'Invalid name.'})
|
||||
}
|
||||
|
||||
if (!playerNameValidation(data.name)) {
|
||||
return socket.emit('login_status', {success: false, message: 'Invalid name.'})
|
||||
}
|
||||
|
||||
let playerUid = nuid(32)
|
||||
|
||||
socket.emit('login_status', {success: true, uid: playerUid, name: data.name})
|
||||
socket.emit('game_settings', {ships: ships})
|
||||
clients[playerUid] = {
|
||||
socket: socket,
|
||||
name: data.name,
|
||||
sockID: socket.conn.id
|
||||
}
|
||||
|
||||
console.log('New player: "' + data.name + '" with uid ' + playerUid)
|
||||
})
|
||||
|
||||
socket.on('poll_games', () => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
socket.emit('poll_games_res', waitingGamesList(client))
|
||||
})
|
||||
|
||||
socket.on('game_attempt_join', (data) => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
|
||||
if (!client) {
|
||||
socket.emit('game_error', {message: 'You are not logged in properly!'})
|
||||
socket.emit('force_relog')
|
||||
return
|
||||
}
|
||||
|
||||
if (!data.gameId) return
|
||||
|
||||
joinGame(client, data.gameId)
|
||||
})
|
||||
|
||||
socket.on('leave_game', (data) => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
|
||||
if (!client) return
|
||||
killGamesClientIsIn(client)
|
||||
|
||||
socket.emit('left_success')
|
||||
})
|
||||
|
||||
socket.on('new_game', () => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
|
||||
if (!client) {
|
||||
socket.emit('game_error', {message: 'You are not logged in properly!'})
|
||||
socket.emit('force_relog')
|
||||
return
|
||||
}
|
||||
|
||||
createNewGame(client)
|
||||
})
|
||||
|
||||
socket.on('ship_place', (data) => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
|
||||
if (!client) {
|
||||
socket.emit('game_error', {message: 'You are not logged in properly!'})
|
||||
socket.emit('force_relog')
|
||||
return
|
||||
}
|
||||
|
||||
if (!data.gameId || !data.ship) return
|
||||
|
||||
let game = games[data.gameId]
|
||||
let playerInGame = determinePlayerById(data.gameId, client)
|
||||
|
||||
if (!playerInGame) {
|
||||
socket.emit('game_error', {message: 'unexpected error. code: 763'})
|
||||
return
|
||||
}
|
||||
|
||||
let meObj = game[playerInGame]
|
||||
if (meObj.placed === true) {
|
||||
socket.emit('game_error', {message: 'Please don\'t cheat.'})
|
||||
return
|
||||
}
|
||||
|
||||
if (!integrityCheck(data.ship)) {
|
||||
socket.emit('game_error', {message: 'Something went wrong when you tried placing a ship.'})
|
||||
return
|
||||
}
|
||||
|
||||
meObj.ships.push({
|
||||
name: data.ship.name,
|
||||
sunken: false,
|
||||
cells: data.ship.cells
|
||||
})
|
||||
|
||||
socket.emit('verified_place', data.ship)
|
||||
|
||||
if (meObj.ships.length === ships.length) {
|
||||
meObj.placed = true
|
||||
let opponent = 'player2'
|
||||
|
||||
if (playerInGame === 'player2') {
|
||||
opponent = 'player1'
|
||||
}
|
||||
|
||||
if (game[opponent].placed) {
|
||||
game.turn = 'player1'
|
||||
clients[game.player1.uid].socket.emit('destroy_turn', true)
|
||||
clients[game.player2.uid].socket.emit('destroy_turn', false)
|
||||
}
|
||||
|
||||
clients[meObj.uid].socket.emit('current_stats', {
|
||||
opponentShipsLeft: ships.length - game[opponent].destructions,
|
||||
myShipsLeft: ships.length - meObj.destructions
|
||||
})
|
||||
clients[game[opponent].uid].socket.emit('current_stats', {
|
||||
opponentShipsLeft: ships.length - meObj.destructions,
|
||||
myShipsLeft: ships.length - game[opponent].destructions
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('set_bomb', (data) => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
|
||||
if (!client) {
|
||||
socket.emit('game_error', {message: 'You are not logged in properly!'})
|
||||
socket.emit('force_relog')
|
||||
return
|
||||
}
|
||||
|
||||
let game = games[data.gameId]
|
||||
let playerInGame = determinePlayerById(data.gameId, client)
|
||||
|
||||
if (!playerInGame) {
|
||||
socket.emit('game_error', {message: 'unexpected error. code: 763'})
|
||||
return
|
||||
}
|
||||
|
||||
let opponent = 'player2'
|
||||
|
||||
if (playerInGame === 'player2') {
|
||||
opponent = 'player1'
|
||||
}
|
||||
|
||||
let result = attemptToBombTile(playerInGame, opponent, game, data.x, data.y)
|
||||
|
||||
let opponentObj = game[opponent]
|
||||
let me = game[playerInGame]
|
||||
|
||||
if (result.ship) {
|
||||
clients[opponentObj.uid].socket.emit('updateShip', result.ship)
|
||||
}
|
||||
|
||||
clients[me.uid].socket.emit('update_hits', {me: true, strikes: me.strikes})
|
||||
clients[me.uid].socket.emit('update_hits', {me: false, strikes: opponentObj.strikes})
|
||||
|
||||
switch (result.event) {
|
||||
case 5:
|
||||
case 1:
|
||||
clients[me.uid].socket.emit('infmessage', 'You sunk a ship!')
|
||||
break
|
||||
case 0:
|
||||
clients[me.uid].socket.emit('infmessage', 'You destroyed some of the opponents ship!')
|
||||
break
|
||||
case 2:
|
||||
game.turn = opponent
|
||||
clients[me.uid].socket.emit('destroy_turn', false)
|
||||
clients[opponentObj.uid].socket.emit('destroy_turn', true)
|
||||
clients[me.uid].socket.emit('infmessage', 'You missed!')
|
||||
break
|
||||
case 6:
|
||||
endGame(data.gameId, client, opponentObj.uid)
|
||||
break
|
||||
}
|
||||
|
||||
clients[me.uid].socket.emit('current_stats', {
|
||||
opponentShipsLeft: ships.length - opponentObj.destructions,
|
||||
myShipsLeft: ships.length - me.destructions
|
||||
})
|
||||
clients[opponentObj.uid].socket.emit('current_stats', {
|
||||
opponentShipsLeft: ships.length - me.destructions,
|
||||
myShipsLeft: ships.length - opponentObj.destructions
|
||||
})
|
||||
})
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
let client = clientsBySocketID(socket.conn.id)
|
||||
if (!client) return
|
||||
|
||||
killGamesClientIsIn(client)
|
||||
|
||||
console.log('Player uid ' + client + ' left.')
|
||||
|
||||
delete clients[client]
|
||||
})
|
||||
})
|
||||
|
||||
server.listen(8000)
|
Loading…
Reference in New Issue
Block a user