mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 02:22:54 +01:00
Major changes
- Partially added removing ships on mobile (still doesn't work at all though) - Added client-side logging - Fixed a crash caused by the MySQL connector - Multiple bug fixes
This commit is contained in:
parent
c0ae701507
commit
b1a822f39e
6
index.js
6
index.js
@ -510,7 +510,7 @@ io.on('connection', async (socket) => {
|
|||||||
socket.on('place ship', async (type, posX, posY, rot) => {
|
socket.on('place ship', async (type, posX, posY, rot) => {
|
||||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
|
||||||
if (playerGame.data.state === 'preparation') {
|
if (playerGame && playerGame.data.state === 'preparation') {
|
||||||
const playerShips = await GInfo.getPlayerShips(socket);
|
const playerShips = await GInfo.getPlayerShips(socket);
|
||||||
let canPlace = bships.validateShipPosition(playerShips, type, posX, posY, rot);
|
let canPlace = bships.validateShipPosition(playerShips, type, posX, posY, rot);
|
||||||
let shipAvailable = bships.getShipsAvailable(playerShips)[type] > 0;
|
let shipAvailable = bships.getShipsAvailable(playerShips)[type] > 0;
|
||||||
@ -534,7 +534,7 @@ io.on('connection', async (socket) => {
|
|||||||
socket.on('remove ship', async (posX, posY) => {
|
socket.on('remove ship', async (posX, posY) => {
|
||||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
|
||||||
if (playerGame.data.state === 'preparation') {
|
if (playerGame && playerGame.data.state === 'preparation') {
|
||||||
const deletedShip = await GInfo.removeShip(socket, posX, posY);
|
const deletedShip = await GInfo.removeShip(socket, posX, posY);
|
||||||
socket.emit("removed ship", { posX: posX, posY: posY, type: deletedShip.type });
|
socket.emit("removed ship", { posX: posX, posY: posY, type: deletedShip.type });
|
||||||
await GInfo.incrStat(socket, 'placedShips', -1);
|
await GInfo.incrStat(socket, 'placedShips', -1);
|
||||||
@ -544,7 +544,7 @@ io.on('connection', async (socket) => {
|
|||||||
socket.on('shoot', async (posX, posY) => {
|
socket.on('shoot', async (posX, posY) => {
|
||||||
let playerGame = await GInfo.getPlayerGameData(socket);
|
let playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
|
||||||
if (playerGame.data.state === 'action') {
|
if (playerGame && playerGame.data.state === 'action') {
|
||||||
if (bships.checkTurn(playerGame.data, socket.session.id)) {
|
if (bships.checkTurn(playerGame.data, socket.session.id)) {
|
||||||
const enemyIdx = socket.session.id === playerGame.data.hostId ? 1 : 0;
|
const enemyIdx = socket.session.id === playerGame.data.hostId ? 1 : 0;
|
||||||
|
|
||||||
|
@ -111,6 +111,9 @@
|
|||||||
|
|
||||||
"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",
|
||||||
|
|
||||||
|
"Victory": "Victory",
|
||||||
|
"Defeat": "Defeat"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -113,6 +113,9 @@
|
|||||||
|
|
||||||
"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",
|
||||||
|
|
||||||
|
"Victory": "Zwycięstwo",
|
||||||
|
"Defeat": "Porażka"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,8 +15,17 @@ if ($(window).width() <= 820) {
|
|||||||
animation: "shift-toward-subtle",
|
animation: "shift-toward-subtle",
|
||||||
interactive: true,
|
interactive: true,
|
||||||
content: (reference) => {
|
content: (reference) => {
|
||||||
|
// Need to fix this
|
||||||
|
|
||||||
|
console.log("a");
|
||||||
let fieldData = `${$(reference).data('pos-x')}, ${$(reference).data('pos-y')}`;
|
let fieldData = `${$(reference).data('pos-x')}, ${$(reference).data('pos-y')}`;
|
||||||
|
|
||||||
|
let pos = occupiedFields.find((elem) => elem.pos[0] == $(reference).data('pos-x') && elem.pos[1] == $(reference).data('pos-y'));
|
||||||
|
|
||||||
|
if (pos) {
|
||||||
|
return $('#removeTippyTemplate').html().replaceAll("[[FIELDPOS]]", fieldData);
|
||||||
|
}
|
||||||
|
|
||||||
return $('#mainTippyTemplate').html().replaceAll("[[FIELDPOS]]", fieldData);
|
return $('#mainTippyTemplate').html().replaceAll("[[FIELDPOS]]", fieldData);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -39,6 +48,8 @@ $('#board .field').on('click', function () {
|
|||||||
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
if ($(window).width() > 820) {
|
if ($(window).width() > 820) {
|
||||||
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
||||||
|
|
||||||
|
navigator.vibrate(200);
|
||||||
lastTimeClick = new Date().getTime() / 1000;
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,12 +59,15 @@ function manualPlace(posX, posY) {
|
|||||||
hoveredShip = null;
|
hoveredShip = null;
|
||||||
refreshBoardView();
|
refreshBoardView();
|
||||||
socket.emit("place ship", selectedShip, posX, posY, shipRotation);
|
socket.emit("place ship", selectedShip, posX, posY, shipRotation);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#secondaryBoard .field').on('click', function () {
|
$('#secondaryBoard .field').on('click', function () {
|
||||||
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
if ($(window).width() > 820) {
|
if ($(window).width() > 820) {
|
||||||
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
||||||
|
|
||||||
|
navigator.vibrate(200);
|
||||||
lastTimeClick = new Date().getTime() / 1000;
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,17 +75,29 @@ $('#secondaryBoard .field').on('click', function () {
|
|||||||
|
|
||||||
function manualShoot(posX, posY) {
|
function manualShoot(posX, posY) {
|
||||||
socket.emit("shoot", posX, posY);
|
socket.emit("shoot", posX, posY);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.field').on('contextmenu', function () {
|
$('.field').on('contextmenu', function () {
|
||||||
if ($(this).hasClass('active') && new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
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 pos = occupiedFields.find((elem) => elem.pos[0] == $(this).data('pos-x') && elem.pos[1] == $(this).data('pos-y'));
|
||||||
|
|
||||||
socket.emit("remove ship", originPos[0], originPos[1]);
|
if (pos) {
|
||||||
lastTimeClick = new Date().getTime() / 1000;
|
socket.emit("remove ship", pos.origin[0], pos.origin[1]);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function manualRemove(posX, posY) {
|
||||||
|
let pos = occupiedFields.find((elem) => elem.pos[0] == posX && elem.pos[1] == posY);
|
||||||
|
|
||||||
|
if (pos) {
|
||||||
|
socket.emit("remove ship", pos.origin[0], pos.origin[1]);
|
||||||
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
socket.on('toast', (msg) => {
|
socket.on('toast', (msg) => {
|
||||||
Toastify({
|
Toastify({
|
||||||
text: msg,
|
text: msg,
|
||||||
@ -170,7 +196,7 @@ var updateTimer = setInterval(() => {
|
|||||||
} else {
|
} else {
|
||||||
const UTCNow = Math.floor((new Date()).getTime() / 1000);
|
const UTCNow = Math.floor((new Date()).getTime() / 1000);
|
||||||
|
|
||||||
const time = Math.abs(UTCNow - timerDestination);
|
const time = Math.max(timerDestination - UTCNow, 0);
|
||||||
|
|
||||||
if (time < 10) {
|
if (time < 10) {
|
||||||
$("#timer").addClass("active");
|
$("#timer").addClass("active");
|
||||||
@ -190,10 +216,10 @@ socket.on("game finished", (winnerIdx, oppName) => {
|
|||||||
$("#opponent").html(`Vs. <span class="important">${oppName}</span>`);
|
$("#opponent").html(`Vs. <span class="important">${oppName}</span>`);
|
||||||
|
|
||||||
if (winnerIdx === playerIdx) {
|
if (winnerIdx === playerIdx) {
|
||||||
$("#state").html("Zwycięstwo");
|
$("#state").html(locale["Victory"]);
|
||||||
$("#state").addClass("dynamic");
|
$("#state").addClass("dynamic");
|
||||||
} else {
|
} else {
|
||||||
$("#state").html("Porażka");
|
$("#state").html(locale["Defeat"]);
|
||||||
$("#state").addClass("danger");
|
$("#state").addClass("danger");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +254,6 @@ socket.on('turn update', (turnData) => {
|
|||||||
|
|
||||||
timerDestination = turnData.timerToUTC;
|
timerDestination = turnData.timerToUTC;
|
||||||
gamePhase = turnData.phase;
|
gamePhase = turnData.phase;
|
||||||
refreshBoardView();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('player left', () => {
|
socket.on('player left', () => {
|
||||||
|
@ -7,16 +7,22 @@ socket.on("joined", (nick) => {
|
|||||||
$("#oppNameField").html(nick);
|
$("#oppNameField").html(nick);
|
||||||
switchView("preparingGame");
|
switchView("preparingGame");
|
||||||
lockUI(false);
|
lockUI(false);
|
||||||
|
|
||||||
|
console.log("Player joined the game:", nick);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("player left", () => {
|
socket.on("player left", () => {
|
||||||
lockUI(true);
|
lockUI(true);
|
||||||
switchView("mainMenuView");
|
switchView("mainMenuView");
|
||||||
lockUI(false);
|
lockUI(false);
|
||||||
|
|
||||||
|
console.log("Player left the game");
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("gameReady", (gameId) => {
|
socket.on("gameReady", (gameId) => {
|
||||||
|
console.log("Game is ready, redirecting in 2 seconds. Game ID:", gameId);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
console.log("Redirecting...");
|
||||||
window.location.replace("/game?id=" + gameId);
|
window.location.replace("/game?id=" + gameId);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
@ -58,19 +64,22 @@ socket.emit("my profile", (profile) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(".matchList").html(matchHistoryDOM);
|
$(".matchList").html(matchHistoryDOM);
|
||||||
|
console.log("Profile data fetched successfully");
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit("whats my nick", (myNickname) => {
|
socket.emit("whats my nick", (myNickname) => {
|
||||||
nickname = myNickname;
|
nickname = myNickname;
|
||||||
$("#profileButton").html(nickname);
|
$("#profileButton").html(nickname);
|
||||||
console.log(nickname);
|
console.log("Received player nickname:", myNickname);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#createGameButton").on("click", function () {
|
$("#createGameButton").on("click", function () {
|
||||||
lockUI(true);
|
lockUI(true);
|
||||||
|
console.log("Creating a lobby...");
|
||||||
socket.emit("create lobby", (response) => {
|
socket.emit("create lobby", (response) => {
|
||||||
switch (response.status) {
|
switch (response.status) {
|
||||||
case "ok":
|
case "ok":
|
||||||
|
console.log("Lobby created");
|
||||||
$("#createGameCode").val(response.gameCode);
|
$("#createGameCode").val(response.gameCode);
|
||||||
switchView("pvpCreateView");
|
switchView("pvpCreateView");
|
||||||
returnLock = true;
|
returnLock = true;
|
||||||
@ -78,12 +87,14 @@ $("#createGameButton").on("click", function () {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "alreadyInLobby":
|
case "alreadyInLobby":
|
||||||
|
console.log("Lobby creation failed (player is already in a lobby)");
|
||||||
$("#createGameCode").val(response.gameCode);
|
$("#createGameCode").val(response.gameCode);
|
||||||
switchView("pvpCreateView");
|
switchView("pvpCreateView");
|
||||||
lockUI(false);
|
lockUI(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
console.log("Lobby creation failed (unknown)");
|
||||||
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
|
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
|
||||||
lockUI(false);
|
lockUI(false);
|
||||||
break;
|
break;
|
||||||
@ -107,9 +118,11 @@ form.addEventListener('submit', (e) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (input.value && input.value.length === 6) {
|
if (input.value && input.value.length === 6) {
|
||||||
lockUI(true);
|
lockUI(true);
|
||||||
|
console.log("Joining a lobby with code:", input.value);
|
||||||
socket.emit("join lobby", input.value, (response) => {
|
socket.emit("join lobby", input.value, (response) => {
|
||||||
switch (response.status) {
|
switch (response.status) {
|
||||||
case "ok":
|
case "ok":
|
||||||
|
console.log("Joined a lobby by:", response.oppNickname);
|
||||||
$("#oppNameField").html(response.oppNickname);
|
$("#oppNameField").html(response.oppNickname);
|
||||||
switchView("preparingGame");
|
switchView("preparingGame");
|
||||||
lockUI(false);
|
lockUI(false);
|
||||||
|
@ -84,6 +84,8 @@ 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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -99,6 +101,8 @@ export class MailAuth {
|
|||||||
} else {
|
} else {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -187,6 +191,8 @@ export class MailAuth {
|
|||||||
|
|
||||||
|
|
||||||
resolve({ status: 1, uid: row.user_id });
|
resolve({ status: 1, uid: row.user_id });
|
||||||
|
|
||||||
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -199,6 +205,8 @@ 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 == 0 ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx == 1 ? 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 == 0 ? 1 : 0)}), (${conn.escape(matchId)}, ${conn.escape(guestId)}, ${conn.escape(JSON.stringify(boards[1]))}, ${conn.escape(winnerIdx == 1 ? 1 : 0)})`, async (error, response) => {
|
||||||
if (error) reject(error);
|
if (error) reject(error);
|
||||||
else resolve();
|
else resolve();
|
||||||
|
|
||||||
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -207,7 +215,7 @@ export class MailAuth {
|
|||||||
getProfile(userId) {
|
getProfile(userId) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const conn = mysql.createConnection(this.mysqlOptions);
|
const conn = mysql.createConnection(this.mysqlOptions);
|
||||||
conn.query(`SELECT nickname, account_creation FROM accounts WHERE user_id = ${conn.escape(userId)}; SELECT ROUND((AVG(statistics.won)) * 100) AS winrate, COUNT(statistics.match_id) AS alltime_matches, COUNT(CASE WHEN (YEAR(matches.date) = YEAR(NOW()) AND MONTH(matches.date) = MONTH(NOW())) THEN matches.match_id END) AS monthly_matches FROM accounts NATURAL JOIN statistics NATURAL JOIN matches WHERE accounts.user_id = ${conn.escape(userId)}; SELECT statistics.match_id, accounts.nickname AS opponent, matches.match_type, statistics.won, matches.duration, matches.date FROM statistics JOIN matches ON matches.match_id = statistics.match_id JOIN accounts ON accounts.user_id = (CASE WHEN matches.host_id != statistics.user_id THEN matches.host_id ELSE matches.guest_id END) WHERE statistics.user_id = ${conn.escape(userId)} LIMIT 10;`, async (error, response) => {
|
conn.query(`SELECT nickname, account_creation FROM accounts WHERE user_id = ${conn.escape(userId)}; SELECT ROUND((AVG(statistics.won)) * 100) AS winrate, COUNT(statistics.match_id) AS alltime_matches, COUNT(CASE WHEN (YEAR(matches.date) = YEAR(NOW()) AND MONTH(matches.date) = MONTH(NOW())) THEN matches.match_id END) AS monthly_matches FROM accounts NATURAL JOIN statistics NATURAL JOIN matches WHERE accounts.user_id = ${conn.escape(userId)}; SELECT statistics.match_id, accounts.nickname AS opponent, matches.match_type, statistics.won, matches.duration, matches.date FROM statistics JOIN matches ON matches.match_id = statistics.match_id JOIN accounts ON accounts.user_id = (CASE WHEN matches.host_id != statistics.user_id THEN matches.host_id ELSE matches.guest_id END) WHERE statistics.user_id = ${conn.escape(userId)} ORDER BY matches.date DESC LIMIT 10;`, async (error, response) => {
|
||||||
if (error) reject(error);
|
if (error) reject(error);
|
||||||
else {
|
else {
|
||||||
if (response[0].length === 0 || response[1].length === 0) {
|
if (response[0].length === 0 || response[1].length === 0) {
|
||||||
@ -219,6 +227,8 @@ export class MailAuth {
|
|||||||
|
|
||||||
resolve({ profile, stats, matchHistory });
|
resolve({ profile, stats, matchHistory });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -241,6 +251,8 @@ 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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -251,6 +263,8 @@ 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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,10 @@
|
|||||||
<button class="tippyBtn" style="background-color: var(--important)" onclick="switchRotation()"><span class="material-symbols-outlined">refresh</span></button>
|
<button class="tippyBtn" style="background-color: var(--important)" onclick="switchRotation()"><span class="material-symbols-outlined">refresh</span></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="removeTippyTemplate" class="tippyTemplate">
|
||||||
|
<button class="tippyBtn" style="background-color: var(--danger)" onclick="manualRemove([[FIELDPOS]])"><span class="material-symbols-outlined">delete</span></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="secondaryTippyTemplate" class="tippyTemplate">
|
<div id="secondaryTippyTemplate" class="tippyTemplate">
|
||||||
<button class="tippyBtn" style="background-color: var(--danger)" onclick="manualShoot([[FIELDPOS]])"><span class="material-symbols-outlined">ads_click</span></button>
|
<button class="tippyBtn" style="background-color: var(--danger)" onclick="manualShoot([[FIELDPOS]])"><span class="material-symbols-outlined">ads_click</span></button>
|
||||||
</div>
|
</div>
|
||||||
@ -67,6 +71,9 @@
|
|||||||
"Three-masted": "{{ t 'board.Three-masted' }}",
|
"Three-masted": "{{ t 'board.Three-masted' }}",
|
||||||
"Four-masted": "{{ t 'board.Four-masted' }}",
|
"Four-masted": "{{ t 'board.Four-masted' }}",
|
||||||
|
|
||||||
|
"Victory": "{{ t 'board.Victory' }}",
|
||||||
|
"Defeat": "{{ t 'board.Defeat' }}",
|
||||||
|
|
||||||
"Preparation phase": "{{ t 'board.Preparation phase' }}",
|
"Preparation phase": "{{ t 'board.Preparation phase' }}",
|
||||||
"Your turn": "{{ t 'board.Your turn' }}",
|
"Your turn": "{{ t 'board.Your turn' }}",
|
||||||
"Opponents turn": "{{ t 'board.Opponents turn' }}",
|
"Opponents turn": "{{ t 'board.Opponents turn' }}",
|
||||||
|
Loading…
Reference in New Issue
Block a user