diff --git a/index.js b/index.js
index 082382a..c2380b4 100644
--- a/index.js
+++ b/index.js
@@ -29,7 +29,7 @@ const io = new Server(server);
const redis = createClient();
redis.on('error', err => console.log('Redis Client Error', err));
await redis.connect();
-redis.flushDb();
+// redis.flushDb();
const GInfo = new bships.GameInfo(redis, io);
@@ -224,7 +224,16 @@ io.on('connection', async (socket) => {
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
- bships.timer(90, () => {
+ bships.timer(20, async () => {
+ const playerGame = await GInfo.getPlayerGameData(socket);
+ for (let i = 0; i < playerGame.data.boards.length; i++) {
+ const ships = playerGame.data.boards[i].ships;
+ if (!ships.length) {
+ AFKEnd(playerGame.id);
+ return;
+ }
+ }
+
GInfo.endPrepPhase(socket);
bships.timer(30, () => {
AFKEnd(playerGame.id);
@@ -250,7 +259,7 @@ io.on('connection', async (socket) => {
} else if (!shipAvailable) {
socket.emit("toast", "Nie masz już statków tego typu");
} else {
- await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot });
+ await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot, hits: Array.from(new Array(type+1), () => false) });
socket.emit("placed ship", { type: type, posX: posX, posY: posY, rot: rot });
}
}
@@ -265,12 +274,24 @@ io.on('connection', async (socket) => {
}
});
- socket.on('shoot', async () => {
+ socket.on('shoot', async (posX, posY) => {
const playerGame = await GInfo.getPlayerGameData(socket);
if (playerGame.data.state === 'action') {
- if (bships.checkTurn(playerGame, socket.request.session.id)) {
-
+ if (bships.checkTurn(playerGame.data, socket.request.session.id)) {
+ const enemyIdx = socket.request.session.id === playerGame.data.hostId ? 1 : 0;
+
+ if (await GInfo.shootShip(socket, posX, posY)) {
+ io.to(playerGame.id).emit("shot hit", enemyIdx, posX, posY);
+ } else {
+ io.to(playerGame.id).emit("shot missed", enemyIdx, posX, posY);
+ }
+
+ await GInfo.passTurn(socket);
+ bships.resetTimers();
+ bships.timer(30, () => {
+ AFKEnd(playerGame.id);
+ });
}
}
});
diff --git a/public/assets/css/board.css b/public/assets/css/board.css
index ca1ef32..535027a 100644
--- a/public/assets/css/board.css
+++ b/public/assets/css/board.css
@@ -1,18 +1,23 @@
:root {
font-size: 20px;
-
--field: rgb(36, 36, 36);
--mark-line: rgb(59, 59, 59);
--mark-spot: rgb(90, 90, 90);
+
--mark-ship-valid: hsl(120, 100%, 80%);
--mark-ship-invalid: hsl(0, 100%, 80%);
+
+ --mark-hit: #ffffff;
+
--ship-valid: hsl(120, 70%, 55%);
--ship-invalid: hsl(0, 70%, 55%);
+ --ship-miss: hsl(0, 0%, 18%);
--dynamic: rgb(83, 83, 245);
--danger: rgb(243, 56, 56);
--important: rgb(203, 50, 241);
+
color: rgb(136, 136, 136)
}
@@ -21,7 +26,7 @@
}
body {
- background: black;
+ background-color: black;
color: white;
font-family: 'Lato', sans-serif;
transition: opacity 0.3s ease;
@@ -67,14 +72,14 @@ h1,h2,h3,h4,h5,h6 {
aspect-ratio: 1;
border-radius: 20%;
cursor: pointer;
- transition: background 0.1s;
+ transition: background-color 0.1s;
}
.field .shipField {
width: 100%;
aspect-ratio: 1;
border-radius: 20%;
- background: var(--ship-valid);
+ background-color: var(--ship-valid);
pointer-events: none;
opacity: 0;
transform: scale(0);
@@ -82,7 +87,7 @@ h1,h2,h3,h4,h5,h6 {
}
#secondaryBoard .field .shipField {
- background: var(--ship-invalid);
+ background-color: var(--ship-invalid);
}
.field.active .shipField {
@@ -208,9 +213,9 @@ h1,h2,h3,h4,h5,h6 {
justify-content: center;
align-items: center;
text-align: center;
- background: rgb(0, 0, 0, 0.6);
+ background-color: rgb(0, 0, 0, 0.6);
backdrop-filter: blur(20px);
- transition: opacity 0.5s;
+ transition: opacity 0.5s, transform 0.5s;
z-index: 999;
}
@@ -219,9 +224,9 @@ h1,h2,h3,h4,h5,h6 {
}
@keyframes timerDanger {
- 0% { color: var(--important) }
- 50% { color: var(--danger) }
- 100% { color: var(--important) }
+ 0% { color: var(--important); transform: scale(1); }
+ 50% { color: var(--danger); transform: scale(1.1); }
+ 100% { color: var(--important); transform: scale(1); }
}
#timer.active {
diff --git a/public/assets/js/battleships-lib.js b/public/assets/js/battleships-lib.js
index 84e5b00..3c6ead3 100644
--- a/public/assets/js/battleships-lib.js
+++ b/public/assets/js/battleships-lib.js
@@ -12,7 +12,7 @@ class Battleships {
for (var i = 0; i < size; i++) {
let row = "
";
for (var n = 0; n < size; n++) {
- row += `
`;
+ row += `
`;
}
row += "
";
board += row;
@@ -31,6 +31,16 @@ class Battleships {
}
}
+ getFieldSecondary(x, y) {
+ if (0 <= x && x < this.boardSize && 0 <= y && y < this.boardSize) {
+ x++;
+ y++;
+ return $(`#secondaryBoard .row:nth-child(${y}) .field:nth-child(${x})`);
+ } else {
+ throw new RangeError("getField position out of range.");
+ }
+ }
+
getRow(row) {
row++;
if (row<=this.boardSize) {
@@ -49,6 +59,32 @@ class Battleships {
}
}
+ setField(x, y, state, primary = false) {
+ if (state==="hit") {
+ this.getField(x, y).children().children("svg").html("");
+ this.getField(x, y).addClass("hit");
+ } else if (state==="miss") {
+ this.getField(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
+ this.getField(x, y).addClass("active hit");
+ this.getField(x, y).children().children("svg").html("");
+ }
+
+ this.getFieldSecondary(x, y).addClass("hit");
+ }
+
+ setFieldEnemy(x, y, state, primary = false) {
+ if (state === "hit") {
+ this.getFieldSecondary(x, y).children().children("svg").html("");
+ this.getFieldSecondary(x, y).addClass("active hit");
+ } else if (state === "miss") {
+ this.getFieldSecondary(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
+ this.getFieldSecondary(x, y).addClass("active hit");
+ this.getFieldSecondary(x, y).children().children("svg").html("");
+ }
+
+ this.getFieldSecondary(x, y).addClass("hit");
+ }
+
placeShip(data) {
let fields = [];
switch (data.rot) {
diff --git a/public/assets/js/main.js b/public/assets/js/main.js
index ee883cc..5733f1d 100644
--- a/public/assets/js/main.js
+++ b/public/assets/js/main.js
@@ -30,20 +30,20 @@ $(".board .field").hover(function () {
changedFields.push(row, column, $(this));
- row.css("background", "var(--mark-line)");
- column.css("background", "var(--mark-line)");
+ row.css("background-color", "var(--mark-line)");
+ column.css("background-color", "var(--mark-line)");
previousRow = row;
previousColumn = column;
if (postPrep) {
if (myTurn) {
- $(this).css("background", "var(--mark-ship-invalid)");
+ $(this).css("background-color", "var(--mark-ship-invalid)");
} else {
- (this).css("background", "var(--mark-spot)");
+ $(this).css("background-color", "var(--mark-spot)");
}
} else {
- $(this).css("background", "var(--mark-spot)");
+ $(this).css("background-color", "var(--mark-spot)");
// Pokaż podgląd statku
@@ -87,9 +87,9 @@ $(".board .field").hover(function () {
}
if (failed) {
- fieldElem.css("background", "var(--mark-ship-invalid)");
+ fieldElem.css("background-color", "var(--mark-ship-invalid)");
} else {
- fieldElem.css("background", "var(--mark-ship-valid)");
+ fieldElem.css("background-color", "var(--mark-ship-valid)");
}
changedFields.push(fieldElem);
}
@@ -98,7 +98,7 @@ $(".board .field").hover(function () {
hoveredField = null;
// Wyłącz "miarki" po wyjściu kursora z pola (aby się nie duplikowały w przyszłości)
changedFields.forEach(field => {
- field.css("background", "var(--field)");
+ field.css("background-color", "var(--field)");
});
changedFields.length = 0;
});
@@ -185,7 +185,7 @@ function refreshBoardView() {
if (hoveredField) {
changedFields.forEach(field => {
- field.css("background", "var(--field)");
+ field.css("background-color", "var(--field)");
});
changedFields.length = 0;
@@ -196,10 +196,10 @@ function refreshBoardView() {
changedFields.push(row, column, $(hoveredField));
- row.css("background", "var(--mark-line)");
- column.css("background", "var(--mark-line)");
+ row.css("background-color", "var(--mark-line)");
+ column.css("background-color", "var(--mark-line)");
- $(hoveredField).css("background", "var(--mark-field)");
+ $(hoveredField).css("background-color", "var(--mark-field)");
previousRow = row;
previousColumn = column;
@@ -243,9 +243,9 @@ function refreshBoardView() {
}
if (failed) {
- fieldElem.css("background", "var(--mark-ship-invalid)");
+ fieldElem.css("background-color", "var(--mark-ship-invalid)");
} else {
- fieldElem.css("background", "var(--mark-ship-valid)");
+ fieldElem.css("background-color", "var(--mark-ship-valid)");
}
changedFields.push(fieldElem);
}
diff --git a/public/assets/js/socket-game.js b/public/assets/js/socket-game.js
index 68c98b0..3b56b6f 100644
--- a/public/assets/js/socket-game.js
+++ b/public/assets/js/socket-game.js
@@ -5,10 +5,15 @@ var timerDestination = null;
var gamePhase = 'pregame';
var occupiedFields = [];
-$('.field').on('click', function () {
+$('#board .field').on('click', function () {
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
});
+$('#secondaryBoard .field').on('click', function () {
+ socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
+});
+
+
$('.field').on('contextmenu', function () {
if ($(this).hasClass('active')) {
let originPos = occupiedFields.find((elem) => elem.pos[0] == $(this).data('pos-x') && elem.pos[1] == $(this).data('pos-y')).origin;
@@ -54,6 +59,24 @@ socket.on("removed ship", (data) => {
refreshBoardView();
});
+socket.on("shot hit", (victimIdx, posX, posY) => {
+ console.log("hit");
+ if (victimIdx === playerIdx) {
+ bsc.setField(posX, posY, "hit");
+ } else {
+ bsc.setFieldEnemy(posX, posY, "hit");
+ }
+});
+
+socket.on("shot missed", (victimIdx, posX, posY) => {
+ console.log("missed");
+ if (victimIdx === playerIdx) {
+ bsc.setField(posX, posY, "miss");
+ } else {
+ bsc.setFieldEnemy(posX, posY, "miss");
+ }
+});
+
socket.on('connect', () => {
$(".cover h1").html("Oczekiwanie na serwer...");
});
diff --git a/utils/battleships.js b/utils/battleships.js
index cb8203b..a295b77 100644
--- a/utils/battleships.js
+++ b/utils/battleships.js
@@ -36,12 +36,12 @@ export class GameInfo {
const key = `game:${gameId}`;
await this.redis.json.set(key, '.state', 'action');
- let nextPlayer = await this.redis.json.get(key, '.nextPlayer');
+ let nextPlayer = await this.redis.json.get(key, { path:'.nextPlayer' });
nextPlayer = nextPlayer === 0 ? 1 : 0;
await this.redis.json.set(key, '.nextPlayer', nextPlayer);
const UTCTs = Math.floor((new Date()).getTime() / 1000 + 30);
- this.io.to(gameId).emit('turn update', { turn: 0, phase: "action", timerToUTC: UTCTs });
+ this.io.to(gameId).emit('turn update', { turn: nextPlayer, phase: "action", timerToUTC: UTCTs });
}
async placeShip(socket, shipData) {
@@ -73,6 +73,37 @@ export class GameInfo {
await this.redis.json.set(key, `.boards[${playerIdx}].ships`, playerShips);
return deletedShip;
}
+
+ async shootShip(socket, posX, posY) {
+ const gameId = socket.session.activeGame;
+ const key = `game:${gameId}`;
+ const hostId = (await this.redis.json.get(key, { path: '.hostId' }));
+
+ const enemyIdx = socket.request.session.id === hostId ? 1 : 0;
+ const playerIdx = enemyIdx ? 0 : 1;
+
+ let playerShips = await this.redis.json.get(key, { path: `.boards[${enemyIdx}].ships` });
+
+ var check = checkHit(playerShips, posX, posY);
+
+ if (!check) {
+ return false;
+ }
+
+ var shotShip;
+ for (let i = 0; i < playerShips.length; i++) {
+ const ship = playerShips[i];
+
+ if (ship.posX === check.originPosX & ship.posY === check.originPosY) {
+ shotShip = ship;
+ playerShips[i].hits[check.fieldIdx] = true;
+ }
+ }
+
+ await this.redis.json.set(key, `.boards[${enemyIdx}].ships`, playerShips);
+
+ return true;
+ }
}
export function isPlayerInRoom(socket) {
@@ -135,11 +166,7 @@ export function getShipsAvailable(ships) {
return shipsLeft;
}
-export function checkHit(data, playerIdx, posX, posY) {
- playerIdx = playerIdx === 0 ? 1 : 0;
-
- let enemyBoard = data.boards[playerIdx];
-
+export function checkHit(ships, posX, posY) {
let boardRender = [];
for (let i = 0; i < 10; i++) {
@@ -150,7 +177,7 @@ export function checkHit(data, playerIdx, posX, posY) {
boardRender.push(array);
}
- enemyBoard.ships.forEach(ship => {
+ ships.forEach(ship => {
let multips;
switch (ship.rot) {
@@ -172,7 +199,8 @@ export function checkHit(data, playerIdx, posX, posY) {
}
for (let i = 0; i < ship.type + 2; i++) {
- boardRender[ship.posX + multips[1] * i][ship.posY + multips[0] * i] = true;
+ console.log(`boardRender[${ship.posX + multips[1] * i}][${ship.posY + multips[0] * i}]`)
+ boardRender[ship.posX + multips[1] * i][ship.posY + multips[0] * i] = {fieldIdx: i, originPosX: ship.posX, originPosY: ship.posY};
}
});
@@ -180,6 +208,10 @@ export function checkHit(data, playerIdx, posX, posY) {
}
export function validateShipPosition(ships, type, posX, posY, rot) {
+ if (type < 0 || type > 3 || rot < 0 || rot > 3) {
+ return false;
+ }
+
let boardRender = [];
for (let i = 0; i < 10; i++) {