mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 07:42:54 +01:00
Compare commits
3 Commits
282c713ead
...
7cfbfa1109
Author | SHA1 | Date | |
---|---|---|---|
|
7cfbfa1109 | ||
|
38ae0c7796 | ||
|
acdbad41cd |
72
index.js
72
index.js
@ -16,6 +16,7 @@ import { Lang } from './utils/localisation.js';
|
|||||||
import { rateLimit } from 'express-rate-limit';
|
import { rateLimit } from 'express-rate-limit';
|
||||||
import { RedisStore as LimiterRedisStore } from 'rate-limit-redis';
|
import { RedisStore as LimiterRedisStore } from 'rate-limit-redis';
|
||||||
import SessionRedisStore from 'connect-redis';
|
import SessionRedisStore from 'connect-redis';
|
||||||
|
import mysql from 'mysql';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@ -24,6 +25,8 @@ const app = express();
|
|||||||
|
|
||||||
const flags = process.env.flags ? process.env.flags.split(",") : null;
|
const flags = process.env.flags ? process.env.flags.split(",") : null;
|
||||||
|
|
||||||
|
const langs = [{ id: "en", name: "English" }, { id: "pl", name: "Polish" }];
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
@ -93,6 +96,9 @@ app.get('/', async (req, res) => {
|
|||||||
} else if (req.session.nickname == null) {
|
} else if (req.session.nickname == null) {
|
||||||
auth.getLanguage(req.session.userId).then(language => {
|
auth.getLanguage(req.session.userId).then(language => {
|
||||||
var locale;
|
var locale;
|
||||||
|
|
||||||
|
req.session.autoLang = language == null ? true : false;
|
||||||
|
|
||||||
if (language) {
|
if (language) {
|
||||||
locale = new Lang([language]);
|
locale = new Lang([language]);
|
||||||
req.session.langs = [language];
|
req.session.langs = [language];
|
||||||
@ -230,7 +236,7 @@ app.post('/api/login', (req, res) => {
|
|||||||
helpers: {
|
helpers: {
|
||||||
error: "Niepoprawny adres e-mail",
|
error: "Niepoprawny adres e-mail",
|
||||||
fallback: "/login",
|
fallback: "/login",
|
||||||
|
t: (key) => { return locale.t(key) }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -277,7 +283,13 @@ app.post('/api/nickname', (req, res) => {
|
|||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.sendStatus(400);
|
res.render("error", {
|
||||||
|
helpers: {
|
||||||
|
error: "Nazwa nie spełnia wymogów: Od 3 do 16 znaków, nie może być pusta",
|
||||||
|
fallback: "/nickname",
|
||||||
|
t: (key) => { return locale.t(key) }
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -345,10 +357,47 @@ io.on('connection', async (socket) => {
|
|||||||
|
|
||||||
socket.on('my profile', (callback) => {
|
socket.on('my profile', (callback) => {
|
||||||
auth.getProfile(session.userId).then((profile) => {
|
auth.getProfile(session.userId).then((profile) => {
|
||||||
|
profile.uid = session.userId;
|
||||||
callback(profile);
|
callback(profile);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('locale options', (callback) => {
|
||||||
|
const locale = new Lang(session.langs);
|
||||||
|
|
||||||
|
let userLanguage = langs.find((element) => element.id == locale.lang);
|
||||||
|
let userLangs = langs.filter((element) => element.id != locale.lang);
|
||||||
|
|
||||||
|
if (session.autoLang) {
|
||||||
|
userLangs.unshift(userLanguage);
|
||||||
|
userLangs.unshift({ id: "null", name: "Auto" });
|
||||||
|
} else {
|
||||||
|
userLangs.unshift({ id: "null", name: "Auto" });
|
||||||
|
userLangs.unshift(userLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(userLangs);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('change locale', (locale, callback) => {
|
||||||
|
if (locale === "null" || langs.find((element) => element.id == locale)) {
|
||||||
|
locale = locale === "null" ? null : locale;
|
||||||
|
const conn = mysql.createConnection({ host: process.env.db_host, user: process.env.db_user, password: process.env.db_pass, database: 'statki' });
|
||||||
|
conn.query(`UPDATE accounts SET language = ${conn.escape(locale)} WHERE user_id = ${conn.escape(session.userId)}`, (err) => {
|
||||||
|
if (err) { callback({ status: 'dbErr' }); return; }
|
||||||
|
else callback({ status: 'ok' });
|
||||||
|
|
||||||
|
req.session.reload((err) => {
|
||||||
|
if (err) return socket.disconnect();
|
||||||
|
|
||||||
|
req.session.autoLang = locale ? false : true;
|
||||||
|
req.session.save();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
conn.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('create lobby', (callback) => {
|
socket.on('create lobby', (callback) => {
|
||||||
if (socket.rooms.size === 1) {
|
if (socket.rooms.size === 1) {
|
||||||
let id = genID();
|
let id = genID();
|
||||||
@ -482,12 +531,19 @@ io.on('connection', async (socket) => {
|
|||||||
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
|
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
|
||||||
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
||||||
GInfo.timer(playerGame.id, 90, async () => {
|
GInfo.timer(playerGame.id, 90, async () => {
|
||||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
const members = [...roomMemberIterator(playerGame.id)];
|
||||||
for (let i = 0; i < playerGame.data.boards.length; i++) {
|
for (let i = 0; i < members.length; i++) {
|
||||||
const ships = playerGame.data.boards[i].ships;
|
const sid = members[i][0];
|
||||||
if (!ships.length) {
|
const socket = io.sockets.sockets.get(sid);
|
||||||
AFKEnd(playerGame.id);
|
|
||||||
return;
|
let placedShips = await GInfo.depleteShips(socket);
|
||||||
|
placedShips.forEach(shipData => {
|
||||||
|
socket.emit("placed ship", shipData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (placedShips.length > 0) {
|
||||||
|
const locale = new Lang(session.langs);
|
||||||
|
socket.emit("toast", locale.t("board.Your remaining ships have been randomly placed"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@
|
|||||||
"winrate": "winrate",
|
"winrate": "winrate",
|
||||||
"No matches played": "No matches played"
|
"No matches played": "No matches played"
|
||||||
},
|
},
|
||||||
|
"Settings": {
|
||||||
|
"General": "General"
|
||||||
|
},
|
||||||
"General": {
|
"General": {
|
||||||
"Unknown error occured": "Unknown error occured",
|
"Unknown error occured": "Unknown error occured",
|
||||||
"Status:": "Status:"
|
"Status:": "Status:"
|
||||||
@ -112,6 +115,7 @@
|
|||||||
"You cannot place a ship like this": "You cannot place a ship like this",
|
"You cannot place a ship like this": "You cannot place a ship like this",
|
||||||
"You have ran out of ships of that type": "You have ran out of ships of that type",
|
"You have ran out of ships of that type": "You have ran out of ships of that type",
|
||||||
"You have already shot at this field": "You have already shot at this field",
|
"You have already shot at this field": "You have already shot at this field",
|
||||||
|
"Your remaining ships have been randomly placed": "Your remaining ships have been automatically placed",
|
||||||
|
|
||||||
"Victory": "Victory",
|
"Victory": "Victory",
|
||||||
"Defeat": "Defeat"
|
"Defeat": "Defeat"
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
"PvP/Loading": {
|
"PvP/Loading": {
|
||||||
"PvP / Loading": "PvP / Wczytywanie",
|
"PvP / Loading": "PvP / Wczytywanie",
|
||||||
"Wait": "Czekaj...",
|
"Wait": "Czekaj...",
|
||||||
"You will be redirected soon": "Wkrótce zostaniesz przekierowany(-a)",
|
"You will be redirected soon": "Wkrótce nastąpi przekierowanie",
|
||||||
"Opponent:": "Przeciwnik"
|
"Opponent:": "Przeciwnik"
|
||||||
},
|
},
|
||||||
"Profile": {
|
"Profile": {
|
||||||
@ -56,9 +56,11 @@
|
|||||||
"total matches played": "meczy zagranych łącznie",
|
"total matches played": "meczy zagranych łącznie",
|
||||||
"winrate": "winrate",
|
"winrate": "winrate",
|
||||||
|
|
||||||
"No matches played": "Nie zagrano meczy"
|
"No matches played": "Nie zagrano żadnych meczy"
|
||||||
|
},
|
||||||
|
"Settings": {
|
||||||
|
"General": "Ogólne"
|
||||||
},
|
},
|
||||||
|
|
||||||
"General": {
|
"General": {
|
||||||
"Unknown error occured": "Wystąpił nieznany błąd",
|
"Unknown error occured": "Wystąpił nieznany błąd",
|
||||||
"Status:": "Status:"
|
"Status:": "Status:"
|
||||||
@ -114,6 +116,7 @@
|
|||||||
"You cannot place a ship like this": "Nie możesz tak postawić statku",
|
"You cannot place a ship like this": "Nie możesz tak postawić statku",
|
||||||
"You have ran out of ships of that type": "Skończyły ci się statki tego typu",
|
"You have ran out of ships of that type": "Skończyły ci się statki tego typu",
|
||||||
"You have already shot at this field": "Już strzelałeś w to pole",
|
"You have already shot at this field": "Już strzelałeś w to pole",
|
||||||
|
"Your remaining ships have been randomly placed": "Twoje pozostałe statki zostały automatycznie rozstawione",
|
||||||
|
|
||||||
"Victory": "Zwycięstwo",
|
"Victory": "Zwycięstwo",
|
||||||
"Defeat": "Porażka"
|
"Defeat": "Porażka"
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"ignore": [
|
"ignore": [
|
||||||
"public/*",
|
"public/*",
|
||||||
"views/*",
|
"views/*",
|
||||||
"utils/mail/*"
|
"utils/mail/*",
|
||||||
|
"lang/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -246,8 +246,6 @@ nav span:hover {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
flex: 2;
|
flex: 2;
|
||||||
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#profileView .matchList::-webkit-scrollbar {
|
#profileView .matchList::-webkit-scrollbar {
|
||||||
@ -324,3 +322,19 @@ nav span:hover {
|
|||||||
.tippyTemplate {
|
.tippyTemplate {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#settingsView label {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#settingsView select {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
background-color: black;
|
||||||
|
border: solid 1px white;
|
||||||
|
color: white;
|
||||||
|
border-radius: 15px;
|
||||||
|
outline: none;
|
||||||
|
margin-left: 2rem;
|
||||||
|
}
|
BIN
public/assets/img/statki-logo-crop.png
Normal file
BIN
public/assets/img/statki-logo-crop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
public/assets/img/statki-logo.png
Normal file
BIN
public/assets/img/statki-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -29,7 +29,38 @@ socket.on("gameReady", (gameId) => {
|
|||||||
|
|
||||||
var nickname;
|
var nickname;
|
||||||
|
|
||||||
|
socket.emit('locale options', (langs) => {
|
||||||
|
console.log("Fetching available locale options");
|
||||||
|
let menu = "";
|
||||||
|
langs.forEach(lang => {
|
||||||
|
menu += `<option value="${lang.id}">${lang.name}</option>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#languages").html(menu);
|
||||||
|
console.log("Locale options fetched");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#languages").on("change", function() {
|
||||||
|
lockUI(true);
|
||||||
|
console.log("Switching language to", $(this).val());
|
||||||
|
socket.emit("change locale", $(this).val(), (response) => {
|
||||||
|
switch (response.status) {
|
||||||
|
case "ok":
|
||||||
|
console.log("Switched languages, refreshing");
|
||||||
|
window.location.reload();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
|
||||||
|
lockUI(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
socket.emit("my profile", (profile) => {
|
socket.emit("my profile", (profile) => {
|
||||||
|
console.log("Received user data. UID:", profile.uid);
|
||||||
|
|
||||||
// General profile data
|
// General profile data
|
||||||
let options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
|
let options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
|
||||||
$("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString(undefined, options));
|
$("#playerSince").html(new Date(profile.profile.account_creation).toLocaleDateString(undefined, options));
|
||||||
@ -59,7 +90,7 @@ socket.emit("my profile", (profile) => {
|
|||||||
matchHistoryDOM += `<div class="match" data-matchid="${match.match_id}"><div><h1 class="dynamic${match.won === 1 ? "" : " danger"}">${match.won === 1 ? window.locale["Victory"] : window.locale["Defeat"]}</h1><span> vs. ${match.match_type === "pvp" ? match.opponent : "AI"}</span></div><h2 class="statsButton">${window.locale["Click to view match statistics"]}</h2><span>${date}</span><br><span>${duration}</span></div>`;
|
matchHistoryDOM += `<div class="match" data-matchid="${match.match_id}"><div><h1 class="dynamic${match.won === 1 ? "" : " danger"}">${match.won === 1 ? window.locale["Victory"] : window.locale["Defeat"]}</h1><span> vs. ${match.match_type === "pvp" ? match.opponent : "AI"}</span></div><h2 class="statsButton">${window.locale["Click to view match statistics"]}</h2><span>${date}</span><br><span>${duration}</span></div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchHistoryDOM === "") {
|
if (!matchHistoryDOM) {
|
||||||
matchHistoryDOM = `<h2>${window.locale["No matches played"]}</h2>`;
|
matchHistoryDOM = `<h2>${window.locale["No matches played"]}</h2>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
@ -84,10 +84,10 @@ export class MailAuth {
|
|||||||
const row = response[0];
|
const row = response[0];
|
||||||
|
|
||||||
resolve({ status: 1, uid: row.user_id });
|
resolve({ status: 1, uid: row.user_id });
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLanguage(userId) {
|
getLanguage(userId) {
|
||||||
@ -101,10 +101,10 @@ export class MailAuth {
|
|||||||
} else {
|
} else {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startVerification(email, ip, agent) {
|
startVerification(email, ip, agent) {
|
||||||
@ -191,10 +191,10 @@ export class MailAuth {
|
|||||||
|
|
||||||
|
|
||||||
resolve({ status: 1, uid: row.user_id });
|
resolve({ status: 1, uid: row.user_id });
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
saveMatch(matchId, duration, type, hostId, guestId, boards, winnerIdx) {
|
saveMatch(matchId, duration, type, hostId, guestId, boards, winnerIdx) {
|
||||||
@ -205,11 +205,11 @@ export class MailAuth {
|
|||||||
else conn.query(`INSERT INTO statistics(match_id, user_id, board, won) VALUES (${conn.escape(matchId)}, ${conn.escape(hostId)}, ${conn.escape(JSON.stringify(boards[0]))}, ${conn.escape(!winnerIdx ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx ? 1 : 0)})`, async (error, response) => {
|
else conn.query(`INSERT INTO statistics(match_id, user_id, board, won) VALUES (${conn.escape(matchId)}, ${conn.escape(hostId)}, ${conn.escape(JSON.stringify(boards[0]))}, ${conn.escape(!winnerIdx ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx ? 1 : 0)})`, async (error, response) => {
|
||||||
if (error) reject(error);
|
if (error) reject(error);
|
||||||
else resolve();
|
else resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfile(userId) {
|
getProfile(userId) {
|
||||||
@ -227,10 +227,10 @@ export class MailAuth {
|
|||||||
|
|
||||||
resolve({ profile, stats, matchHistory });
|
resolve({ profile, stats, matchHistory });
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async finishVerification(uid, authCode) {
|
async finishVerification(uid, authCode) {
|
||||||
@ -251,10 +251,10 @@ export class MailAuth {
|
|||||||
conn.query(`UPDATE accounts SET nickname = ${conn.escape(nickname)} WHERE user_id = ${conn.escape(uid)}`, (error) => {
|
conn.query(`UPDATE accounts SET nickname = ${conn.escape(nickname)} WHERE user_id = ${conn.escape(uid)}`, (error) => {
|
||||||
if (error) reject(error);
|
if (error) reject(error);
|
||||||
resolve();
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getNickname(uid) {
|
getNickname(uid) {
|
||||||
@ -263,10 +263,10 @@ export class MailAuth {
|
|||||||
conn.query(`SELECT nickname FROM accounts WHERE user_id = ${conn.escape(uid)}`, (error, response) => {
|
conn.query(`SELECT nickname FROM accounts WHERE user_id = ${conn.escape(uid)}`, (error, response) => {
|
||||||
if (error) reject(error);
|
if (error) reject(error);
|
||||||
resolve(response[0].nickname);
|
resolve(response[0].nickname);
|
||||||
|
});
|
||||||
|
|
||||||
conn.end();
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ export class GameInfo {
|
|||||||
const boards = await this.redis.json.get(`game:${socket.session.activeGame}`, { path: ".boards" });
|
const boards = await this.redis.json.get(`game:${socket.session.activeGame}`, { path: ".boards" });
|
||||||
let stats = [];
|
let stats = [];
|
||||||
|
|
||||||
console.log(boards);
|
|
||||||
boards.forEach(board => {
|
boards.forEach(board => {
|
||||||
stats.push(board.stats);
|
stats.push(board.stats);
|
||||||
});
|
});
|
||||||
@ -100,6 +99,113 @@ export class GameInfo {
|
|||||||
await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, shipData);
|
await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, shipData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async depleteShips(socket) {
|
||||||
|
const gameId = socket.session.activeGame;
|
||||||
|
const key = `game:${gameId}`;
|
||||||
|
const hostId = (await this.redis.json.get(key, { path: '.hostId' }));
|
||||||
|
|
||||||
|
const playerIdx = socket.request.session.id === hostId ? 0 : 1;
|
||||||
|
|
||||||
|
var playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` }));
|
||||||
|
|
||||||
|
const availableShips = getShipsAvailable(playerShips);
|
||||||
|
|
||||||
|
const boardRender = [];
|
||||||
|
const subtrahents = [[0, 0], [0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]];
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
var array = [];
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
array.push(false);
|
||||||
|
}
|
||||||
|
boardRender.push(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
playerShips.forEach(ship => {
|
||||||
|
let multips;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i <= ship.type; i++) {
|
||||||
|
for (let l = 0; l < subtrahents.length; l++) {
|
||||||
|
const idxX = ship.posX - subtrahents[l][0] + multips[0] * i;
|
||||||
|
const idxY = ship.posY - subtrahents[l][1] + multips[1] * i;
|
||||||
|
if (!(idxX < 0 || idxX > 9 || idxY < 0 || idxY > 9)) {
|
||||||
|
boardRender[idxX][idxY] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const placedShips = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < availableShips.length; i++) {
|
||||||
|
let availableShipsOfType = availableShips[i];
|
||||||
|
for (let j = 0; j < availableShipsOfType; j++) {
|
||||||
|
playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` }));
|
||||||
|
for (let y = 0; y < 10; y++) {
|
||||||
|
let row = "";
|
||||||
|
for (let x = 0; x < 10; x++) {
|
||||||
|
row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const search = findEmptyFields(boardRender, i+1);
|
||||||
|
|
||||||
|
const rPos = search[Math.floor(Math.random() * search.length)];
|
||||||
|
|
||||||
|
placedShips.push({ type: i, posX: rPos.posX, posY: rPos.posY, rot: rPos.rot });
|
||||||
|
await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, { type: i, posX: rPos.posX, posY: rPos.posY, rot: rPos.rot, hits: Array.from(new Array(i + 1), () => false) });
|
||||||
|
let multips;
|
||||||
|
|
||||||
|
switch (rPos.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let k = 0; k <= i; k++) {
|
||||||
|
for (let l = 0; l < subtrahents.length; l++) {
|
||||||
|
const idxX = rPos.posX - subtrahents[l][0] + multips[0] * k;
|
||||||
|
const idxY = rPos.posY - subtrahents[l][1] + multips[1] * k;
|
||||||
|
if (!(idxX < 0 || idxX > 9 || idxY < 0 || idxY > 9)) {
|
||||||
|
boardRender[idxX][idxY] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return placedShips;
|
||||||
|
}
|
||||||
|
|
||||||
async removeShip(socket, posX, posY) {
|
async removeShip(socket, posX, posY) {
|
||||||
const gameId = socket.session.activeGame;
|
const gameId = socket.session.activeGame;
|
||||||
const key = `game:${gameId}`;
|
const key = `game:${gameId}`;
|
||||||
@ -175,30 +281,6 @@ export function isPlayerInRoom(socket) {
|
|||||||
return !socket.rooms.size === 1;
|
return !socket.rooms.size === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastTimeChange = new Date().getTime();
|
|
||||||
|
|
||||||
// export function getShipsLeft(data, playerIdx) {
|
|
||||||
// let shipsLeft = [4, 3, 2, 1];
|
|
||||||
|
|
||||||
// const playerShips = shipsLeft.boards[playerIdx].ships;
|
|
||||||
|
|
||||||
// playerShips.forEach(ship => {
|
|
||||||
// var isSunk = true;
|
|
||||||
// ship.hits.every(isHit => {
|
|
||||||
// isSunk = isHit;
|
|
||||||
// return isHit;
|
|
||||||
// });
|
|
||||||
// switch (ship.type) {
|
|
||||||
// case 0:
|
|
||||||
// shipsLeft[0]--;
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
export function getShipsAvailable(ships) {
|
export function getShipsAvailable(ships) {
|
||||||
let shipsLeft = [4, 3, 2, 1];
|
let shipsLeft = [4, 3, 2, 1];
|
||||||
|
|
||||||
@ -340,6 +422,52 @@ export function checkTurn(data, playerId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findEmptyFields(grid, len) {
|
||||||
|
const rowPlacements = [];
|
||||||
|
|
||||||
|
// Helper function to check if a row can be placed horizontally at a given position
|
||||||
|
function canPlaceHorizontally(x, y) {
|
||||||
|
if (x + len >= grid[0].length) {
|
||||||
|
return false; // Ship exceeds board boundaries
|
||||||
|
}
|
||||||
|
for (let i = x; i <= x + len; i++) {
|
||||||
|
if (grid[i][y]) {
|
||||||
|
return false; // One of ship's fields is already occupied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to check if a row can be placed vertically at a given position
|
||||||
|
function canPlaceVertically(x, y) {
|
||||||
|
if (y + len >= grid.length) {
|
||||||
|
return false; // Ship exceeds board boundaries
|
||||||
|
}
|
||||||
|
for (let i = y; i <= y + len; i++) {
|
||||||
|
if (grid[x][i]) {
|
||||||
|
return false; // One of ship's fields is already occupied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < grid.length; i++) {
|
||||||
|
for (let j = 0; j < grid[0].length; j++) {
|
||||||
|
if (grid[j][i] === false) {
|
||||||
|
if (canPlaceHorizontally(j, i)) {
|
||||||
|
rowPlacements.push({ posX: j, posY: i, rot: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canPlaceVertically(j, i)) {
|
||||||
|
rowPlacements.push({ posX: j, posY: i, rot: 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowPlacements;
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(n, min, max) {
|
function clamp(n, min, max) {
|
||||||
return Math.min(Math.max(n, min), max);
|
return Math.min(Math.max(n, min), max);
|
||||||
}
|
}
|
@ -8,18 +8,23 @@ const __dirname = path.dirname(__filename);
|
|||||||
export class Lang {
|
export class Lang {
|
||||||
constructor(langs) {
|
constructor(langs) {
|
||||||
const languagesPath = path.join(__dirname, '../lang');
|
const languagesPath = path.join(__dirname, '../lang');
|
||||||
|
this.allText = null;
|
||||||
for (let i = 0; i < langs.length; i++) {
|
for (let i = 0; i < langs.length; i++) {
|
||||||
const lang = langs[i];
|
const lang = langs[i];
|
||||||
|
|
||||||
if (fs.readdirSync(languagesPath).includes(`${lang}.json`)) {
|
if (fs.readdirSync(languagesPath).includes(`${lang}.json`)) {
|
||||||
try {
|
try {
|
||||||
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, `${lang}.json`), 'utf8'));
|
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, `${lang}.json`), 'utf8'));
|
||||||
|
this.lang = lang;
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, 'en.json'), 'utf8'));
|
||||||
|
this.lang = 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
t(key) {
|
t(key) {
|
||||||
@ -37,5 +42,7 @@ export class Lang {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,9 +93,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container" id="settingsView" data-path="/match">
|
<div class="container" id="settingsView" data-path="/settings">
|
||||||
<div>
|
<div>
|
||||||
|
<h1>{{ t 'menu.Settings.Settings' }}</h1>
|
||||||
|
<h2>{{ t 'menu.Settings.General' }}</h2>
|
||||||
|
<label for="language">Language: </label>
|
||||||
|
<select name="language" id="languages">
|
||||||
|
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -106,6 +111,7 @@
|
|||||||
"Victory": "{{ t 'menu.Profile.Victory' }}",
|
"Victory": "{{ t 'menu.Profile.Victory' }}",
|
||||||
"Defeat": "{{ t 'menu.Profile.Defeat' }}",
|
"Defeat": "{{ t 'menu.Profile.Defeat' }}",
|
||||||
"Click to view match statistics": "{{ t 'menu.Profile.Click to view match statistics' }}",
|
"Click to view match statistics": "{{ t 'menu.Profile.Click to view match statistics' }}",
|
||||||
|
"No matches played": "{{ t 'menu.Profile.No matches played' }}",
|
||||||
|
|
||||||
"Reconnecting": "{{ t 'errors.Reconnecting' }}",
|
"Reconnecting": "{{ t 'errors.Reconnecting' }}",
|
||||||
"Reconnected": "{{ t 'errors.Reconnected' }}",
|
"Reconnected": "{{ t 'errors.Reconnected' }}",
|
||||||
|
Loading…
Reference in New Issue
Block a user