mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 00:32:55 +01:00
Major changes
- Multiple visual improvements to animation - Added ship color dimming when they sunk - Added game ending (looks and works primitvely for now) - Added socket.io client error handling and alerts - Finished and improved hit registration and client hit display To-do: - Fix timers (currently resetting the timer is global, which by mistake affects other independent lobbies, critical bug) - Post-match stats - Improve many mechanics - Improve overall quality of the game
This commit is contained in:
parent
6021305f4a
commit
a027313139
14
index.js
14
index.js
@ -281,10 +281,18 @@ io.on('connection', async (socket) => {
|
|||||||
if (bships.checkTurn(playerGame.data, socket.request.session.id)) {
|
if (bships.checkTurn(playerGame.data, socket.request.session.id)) {
|
||||||
const enemyIdx = socket.request.session.id === playerGame.data.hostId ? 1 : 0;
|
const enemyIdx = socket.request.session.id === playerGame.data.hostId ? 1 : 0;
|
||||||
|
|
||||||
if (await GInfo.shootShip(socket, posX, posY)) {
|
let hit = await GInfo.shootShip(socket, posX, posY);
|
||||||
io.to(playerGame.id).emit("shot hit", enemyIdx, posX, posY);
|
if (!hit.status) {
|
||||||
} else {
|
|
||||||
io.to(playerGame.id).emit("shot missed", enemyIdx, posX, posY);
|
io.to(playerGame.id).emit("shot missed", enemyIdx, posX, posY);
|
||||||
|
} else if (hit.status === 1) {
|
||||||
|
io.to(playerGame.id).emit("shot hit", enemyIdx, posX, posY);
|
||||||
|
} else if (hit.status === 2) {
|
||||||
|
io.to(playerGame.id).emit("shot hit", enemyIdx, posX, posY);
|
||||||
|
io.to(playerGame.id).emit("ship sunk", enemyIdx, hit.ship);
|
||||||
|
|
||||||
|
if (hit.gameFinished) {
|
||||||
|
io.to(playerGame.id).emit("game finished", !enemyIdx ? 1 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await GInfo.passTurn(socket);
|
await GInfo.passTurn(socket);
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
--ship-invalid: hsl(0, 70%, 55%);
|
--ship-invalid: hsl(0, 70%, 55%);
|
||||||
--ship-miss: hsl(0, 0%, 18%);
|
--ship-miss: hsl(0, 0%, 18%);
|
||||||
|
|
||||||
|
--ship-ally-sunken: hsl(120, 30%, 40%);
|
||||||
|
--ship-enemy-sunken: hsl(0, 30%, 40%);
|
||||||
|
|
||||||
--dynamic: rgb(83, 83, 245);
|
--dynamic: rgb(83, 83, 245);
|
||||||
--danger: rgb(243, 56, 56);
|
--danger: rgb(243, 56, 56);
|
||||||
--important: rgb(203, 50, 241);
|
--important: rgb(203, 50, 241);
|
||||||
@ -83,7 +86,7 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
transition: opacity 0.25s, transform 0.25s 0.05s;
|
transition: opacity 0.25s, transform 0.25s 0.05s, background-color 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#secondaryBoard .field .shipField {
|
#secondaryBoard .field .shipField {
|
||||||
@ -110,6 +113,14 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#board .field.sunken .shipField {
|
||||||
|
background-color: var(--ship-ally-sunken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#secondaryBoard .field.sunken .shipField {
|
||||||
|
background-color: var(--ship-enemy-sunken);
|
||||||
|
}
|
||||||
|
|
||||||
.dynamic {
|
.dynamic {
|
||||||
color: var(--dynamic);
|
color: var(--dynamic);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class Battleships {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setField(x, y, state, primary = false) {
|
setField(x, y, state) {
|
||||||
if (state==="hit") {
|
if (state==="hit") {
|
||||||
this.getField(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
this.getField(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
||||||
this.getField(x, y).addClass("hit");
|
this.getField(x, y).addClass("hit");
|
||||||
@ -67,12 +67,12 @@ class Battleships {
|
|||||||
this.getField(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
this.getField(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
||||||
this.getField(x, y).addClass("active hit");
|
this.getField(x, y).addClass("active hit");
|
||||||
this.getField(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
this.getField(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
||||||
|
} else if (state === "sunken") {
|
||||||
|
this.getField(x, y).addClass("sunken");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getFieldSecondary(x, y).addClass("hit");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFieldEnemy(x, y, state, primary = false) {
|
setFieldEnemy(x, y, state) {
|
||||||
if (state === "hit") {
|
if (state === "hit") {
|
||||||
this.getFieldSecondary(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
this.getFieldSecondary(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
||||||
this.getFieldSecondary(x, y).addClass("active hit");
|
this.getFieldSecondary(x, y).addClass("active hit");
|
||||||
@ -80,9 +80,9 @@ class Battleships {
|
|||||||
this.getFieldSecondary(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
this.getFieldSecondary(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
||||||
this.getFieldSecondary(x, y).addClass("active hit");
|
this.getFieldSecondary(x, y).addClass("active hit");
|
||||||
this.getFieldSecondary(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
this.getFieldSecondary(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
||||||
|
} else if (state === "sunken") {
|
||||||
|
this.getFieldSecondary(x, y).addClass("sunken");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getFieldSecondary(x, y).addClass("hit");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
placeShip(data) {
|
placeShip(data) {
|
||||||
|
72
public/assets/js/socket-err-handler.js
Normal file
72
public/assets/js/socket-err-handler.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Handling connection errors
|
||||||
|
socket.on("reconnecting", (number) => {
|
||||||
|
Toastify({
|
||||||
|
text: `Ponowne łączenie... ${number}`,
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("reconnect", () => {
|
||||||
|
Toastify({
|
||||||
|
text: "Połączono ponownie",
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("reconnect_error", () => {
|
||||||
|
Toastify({
|
||||||
|
text: "Wystąpił problem w trakcie ponownego łączenia",
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("reconnect_failed", () => {
|
||||||
|
Toastify({
|
||||||
|
text: "Nie udało się połączyć ponownie",
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disconnect", () => {
|
||||||
|
Toastify({
|
||||||
|
text: "Rozłączono z serwerem\nSpróbuj odświeżyć stronę jeżeli błąd będzie się powtarzał",
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("error", () => {
|
||||||
|
Toastify({
|
||||||
|
text: "Błąd połączenia",
|
||||||
|
duration: 5000,
|
||||||
|
newWindow: true,
|
||||||
|
gravity: "bottom",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: "bshipstoast",
|
||||||
|
}).showToast();
|
||||||
|
});
|
@ -5,20 +5,29 @@ var timerDestination = null;
|
|||||||
var gamePhase = 'pregame';
|
var gamePhase = 'pregame';
|
||||||
var occupiedFields = [];
|
var occupiedFields = [];
|
||||||
|
|
||||||
|
var lastTimeClick = 0;
|
||||||
|
|
||||||
$('#board .field').on('click', function () {
|
$('#board .field').on('click', function () {
|
||||||
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
console.log(new Date().getTime() / 1000 - lastTimeClick);
|
||||||
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
|
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#secondaryBoard .field').on('click', function () {
|
$('#secondaryBoard .field').on('click', function () {
|
||||||
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
|
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$('.field').on('contextmenu', function () {
|
$('.field').on('contextmenu', function () {
|
||||||
if ($(this).hasClass('active')) {
|
if ($(this).hasClass('active') && new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
let originPos = occupiedFields.find((elem) => elem.pos[0] == $(this).data('pos-x') && elem.pos[1] == $(this).data('pos-y')).origin;
|
let originPos = occupiedFields.find((elem) => elem.pos[0] == $(this).data('pos-x') && elem.pos[1] == $(this).data('pos-y')).origin;
|
||||||
|
|
||||||
socket.emit("remove ship", originPos[0], originPos[1]);
|
socket.emit("remove ship", originPos[0], originPos[1]);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,19 +57,20 @@ socket.on("removed ship", (data) => {
|
|||||||
return elem.origin[0] == data.posX && elem.origin[1] == data.posY;
|
return elem.origin[0] == data.posX && elem.origin[1] == data.posY;
|
||||||
});
|
});
|
||||||
|
|
||||||
shipFields.forEach(field => {
|
for (let i = 0; i < shipFields.length; i++) {
|
||||||
bsc.getField(field.pos[0], field.pos[1]).removeClass("active");
|
const field = shipFields[i];
|
||||||
});
|
setTimeout(() => {
|
||||||
|
bsc.getField(field.pos[0], field.pos[1]).removeClass("active");
|
||||||
|
}, i * 150);
|
||||||
|
}
|
||||||
|
|
||||||
occupiedFields = occupiedFields.filter(n => !shipFields.includes(n));
|
occupiedFields = occupiedFields.filter(n => !shipFields.includes(n));
|
||||||
|
|
||||||
console.log(`shipsLeft[${data.type}] = ${shipsLeft[data.type]}`)
|
|
||||||
shipsLeft[data.type]++;
|
shipsLeft[data.type]++;
|
||||||
refreshBoardView();
|
refreshBoardView();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("shot hit", (victimIdx, posX, posY) => {
|
socket.on("shot hit", (victimIdx, posX, posY) => {
|
||||||
console.log("hit");
|
|
||||||
if (victimIdx === playerIdx) {
|
if (victimIdx === playerIdx) {
|
||||||
bsc.setField(posX, posY, "hit");
|
bsc.setField(posX, posY, "hit");
|
||||||
} else {
|
} else {
|
||||||
@ -69,7 +79,6 @@ socket.on("shot hit", (victimIdx, posX, posY) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("shot missed", (victimIdx, posX, posY) => {
|
socket.on("shot missed", (victimIdx, posX, posY) => {
|
||||||
console.log("missed");
|
|
||||||
if (victimIdx === playerIdx) {
|
if (victimIdx === playerIdx) {
|
||||||
bsc.setField(posX, posY, "miss");
|
bsc.setField(posX, posY, "miss");
|
||||||
} else {
|
} else {
|
||||||
@ -77,6 +86,51 @@ socket.on("shot missed", (victimIdx, posX, posY) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("ship sunk", (victimIdx, ship) => {
|
||||||
|
switch (ship.rot) {
|
||||||
|
case 0:
|
||||||
|
multips = [1, 0];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
multips = [0, 1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
multips = [-1, 0];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
multips = [0, -1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let l = !ship.type ? ship.type + 1 : ship.type + 2;
|
||||||
|
if (victimIdx === playerIdx) {
|
||||||
|
for (let i = 0; i < l; i++) {
|
||||||
|
console.log("ourship");
|
||||||
|
setTimeout(() => {
|
||||||
|
bsc.setField(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
||||||
|
}, i * 150);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < l; i++) {
|
||||||
|
console.log("theirship");
|
||||||
|
setTimeout(() => {
|
||||||
|
bsc.setFieldEnemy(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
||||||
|
}, i * 150);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("game finished", (winnerIdx) => {
|
||||||
|
if (winnerIdx === playerIdx) {
|
||||||
|
alert("Wygrałeś!");
|
||||||
|
} else {
|
||||||
|
alert("Przegrałeś!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
$(".cover h1").html("Oczekiwanie na serwer...");
|
$(".cover h1").html("Oczekiwanie na serwer...");
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const socket = io();
|
const socket = io();
|
||||||
|
|
||||||
|
// Handling server-sent events
|
||||||
socket.on("joined", (nick) => {
|
socket.on("joined", (nick) => {
|
||||||
lockUI(true);
|
lockUI(true);
|
||||||
$("#oppNameField").html(nick);
|
$("#oppNameField").html(nick);
|
||||||
|
@ -37,7 +37,7 @@ export class GameInfo {
|
|||||||
|
|
||||||
await this.redis.json.set(key, '.state', 'action');
|
await this.redis.json.set(key, '.state', 'action');
|
||||||
let nextPlayer = await this.redis.json.get(key, { path:'.nextPlayer' });
|
let nextPlayer = await this.redis.json.get(key, { path:'.nextPlayer' });
|
||||||
nextPlayer = nextPlayer === 0 ? 1 : 0;
|
nextPlayer = !nextPlayer ? 1 : 0;
|
||||||
await this.redis.json.set(key, '.nextPlayer', nextPlayer);
|
await this.redis.json.set(key, '.nextPlayer', nextPlayer);
|
||||||
|
|
||||||
const UTCTs = Math.floor((new Date()).getTime() / 1000 + 30);
|
const UTCTs = Math.floor((new Date()).getTime() / 1000 + 30);
|
||||||
@ -80,14 +80,14 @@ export class GameInfo {
|
|||||||
const hostId = (await this.redis.json.get(key, { path: '.hostId' }));
|
const hostId = (await this.redis.json.get(key, { path: '.hostId' }));
|
||||||
|
|
||||||
const enemyIdx = socket.request.session.id === hostId ? 1 : 0;
|
const enemyIdx = socket.request.session.id === hostId ? 1 : 0;
|
||||||
const playerIdx = enemyIdx ? 0 : 1;
|
// const playerIdx = enemyIdx ? 0 : 1;
|
||||||
|
|
||||||
let playerShips = await this.redis.json.get(key, { path: `.boards[${enemyIdx}].ships` });
|
let playerShips = await this.redis.json.get(key, { path: `.boards[${enemyIdx}].ships` });
|
||||||
|
|
||||||
var check = checkHit(playerShips, posX, posY);
|
var check = checkHit(playerShips, posX, posY);
|
||||||
|
|
||||||
if (!check) {
|
if (!check) {
|
||||||
return false;
|
return { status: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
var shotShip;
|
var shotShip;
|
||||||
@ -97,12 +97,26 @@ export class GameInfo {
|
|||||||
if (ship.posX === check.originPosX & ship.posY === check.originPosY) {
|
if (ship.posX === check.originPosX & ship.posY === check.originPosY) {
|
||||||
shotShip = ship;
|
shotShip = ship;
|
||||||
playerShips[i].hits[check.fieldIdx] = true;
|
playerShips[i].hits[check.fieldIdx] = true;
|
||||||
|
if (!playerShips[i].hits.includes(false)) {
|
||||||
|
console.log(playerShips);
|
||||||
|
let gameFinished = true;
|
||||||
|
await this.redis.json.set(key, `.boards[${enemyIdx}].ships`, playerShips);
|
||||||
|
playerShips.every(ship => {
|
||||||
|
if (ship.hits.includes(false)) {
|
||||||
|
gameFinished = false;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { status: 2, ship: ship, gameFinished: gameFinished };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.redis.json.set(key, `.boards[${enemyIdx}].ships`, playerShips);
|
await this.redis.json.set(key, `.boards[${enemyIdx}].ships`, playerShips);
|
||||||
|
return { status: 1, ship: shotShip };
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,9 +212,13 @@ export function checkHit(ships, posX, posY) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < ship.type + 2; i++) {
|
let l = !ship.type ? ship.type + 1 : ship.type + 2;
|
||||||
console.log(`boardRender[${ship.posX + multips[1] * i}][${ship.posY + multips[0] * i}]`)
|
for (let i = 0; i < l; i++) {
|
||||||
boardRender[ship.posX + multips[1] * i][ship.posY + multips[0] * i] = {fieldIdx: i, originPosX: ship.posX, originPosY: ship.posY};
|
// console.log("a");
|
||||||
|
let x = clamp(ship.posX + multips[0] * i, 0, 9);
|
||||||
|
let y = clamp(ship.posY + multips[1] * i, 0, 9);
|
||||||
|
|
||||||
|
boardRender[x][y] = {fieldIdx: i, originPosX: ship.posX, originPosY: ship.posY};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -295,29 +313,6 @@ export function checkTurn(data, playerId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let type = 3;
|
function clamp(n, min, max) {
|
||||||
// let posX = 3;
|
return Math.min(Math.max(n, min), max);
|
||||||
// let posY = 0;
|
}
|
||||||
// let rot = 2;
|
|
||||||
|
|
||||||
// let data = {
|
|
||||||
// hostId: "123456",
|
|
||||||
// state: "action",
|
|
||||||
// boards: [
|
|
||||||
// {
|
|
||||||
// ships: [
|
|
||||||
// { type: type, posX: posX, posY: posY, rot: rot, hits: [false, false, false] },
|
|
||||||
// ],
|
|
||||||
// shots: [],
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// ships: [],
|
|
||||||
// shots: [],
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// nextPlayer: 0,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// checkHit(data, 1, 0, 0);
|
|
||||||
|
|
||||||
// console.log(validateShipPosition(type, posX, posY, rot));
|
|
@ -33,4 +33,5 @@
|
|||||||
<script src="/assets/js/battleships-lib.js"></script>
|
<script src="/assets/js/battleships-lib.js"></script>
|
||||||
<script src="/assets/js/main.js"></script>
|
<script src="/assets/js/main.js"></script>
|
||||||
<script src="/assets/js/key-handling.js"></script>
|
<script src="/assets/js/key-handling.js"></script>
|
||||||
<script src="/assets/js/socket-game.js"></script>
|
<script src="/assets/js/socket-game.js"></script>
|
||||||
|
<script src="/assets/js/socket-err-handler.js"></script>
|
@ -75,4 +75,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/socket.js"></script>
|
<script src="/assets/js/socket.js"></script>
|
||||||
|
<script src="/assets/js/socket-err-handler.js"></script>
|
||||||
<script src="/assets/js/spa_lib.js"></script>
|
<script src="/assets/js/spa_lib.js"></script>
|
Loading…
Reference in New Issue
Block a user