wildcard and serverside scoring
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,4 +3,4 @@ client/node_modules/
|
|||||||
server/node_modules/
|
server/node_modules/
|
||||||
*.log
|
*.log
|
||||||
*.env
|
*.env
|
||||||
.turns-debug.json
|
turns-debug.json
|
||||||
|
|||||||
@@ -34,12 +34,17 @@ or just use environment variables
|
|||||||
|
|
||||||
### Bugs and Issues
|
### Bugs and Issues
|
||||||
|
|
||||||
|
Prettymuch all of the bugs i'm aware of occur when a user reconnects to a game that's taking place. ESPECIALLY if that user is the host of the game
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
To contribute a translation
|
To contribute a translation there's a few scripts that need to be run
|
||||||
|
|
||||||
|
To see what needs to be completed code-wise, take a look at `TODO`, there you will find tasks that need to be completed as well as known bugs. There's also a lot of TODOs in the code :)
|
||||||
|
|
||||||
### Acknowledgements
|
### Acknowledgements
|
||||||
|
|
||||||
Express.js - HTTP Routing and Management
|
Express.js - HTTP Routing and Management
|
||||||
Socket.io - Socket Routing and Management
|
Socket.io - Socket Routing and Management
|
||||||
|
|
||||||
Inês Filipa Baiõa Antunes - Tranlations (Portuguese, Spanish)
|
Inês Filipa Baiõa Antunes - Tranlations (Portuguese, Spanish)
|
||||||
|
|||||||
24
TODO
24
TODO
@@ -15,8 +15,8 @@
|
|||||||
→ Update with new locales
|
→ Update with new locales
|
||||||
✔ Spanish (Ines) @done(21-04-11 01:03)
|
✔ Spanish (Ines) @done(21-04-11 01:03)
|
||||||
→ Update with new locales
|
→ Update with new locales
|
||||||
→ French (Alexendro)
|
✘ French (Alexendro) @cancelled(21-05-10 18:22)
|
||||||
→ Czech (Mikdore)
|
✘ Czech (Mikdore) @cancelled(21-05-10 18:22)
|
||||||
→ Go through code again once finished and pick out locales
|
→ Go through code again once finished and pick out locales
|
||||||
|
|
||||||
☐ Lobbying logic
|
☐ Lobbying logic
|
||||||
@@ -28,14 +28,14 @@
|
|||||||
→ Find appropriate scrabble dictionary for
|
→ Find appropriate scrabble dictionary for
|
||||||
✔ Portuagese @done(21-04-19 02:10)
|
✔ Portuagese @done(21-04-19 02:10)
|
||||||
✔ Spanish @done(21-04-19 02:10)
|
✔ Spanish @done(21-04-19 02:10)
|
||||||
✔ French @done(21-04-19 02:10)
|
✔ French @done(21-05-10 18:22)
|
||||||
→ Czech
|
✘ Czech @cancelled(21-05-10 18:22)
|
||||||
→ Optimise! n-ary tree
|
→ Optimise! n-ary tree
|
||||||
|
|
||||||
☐ Game networking
|
☐ Game networking
|
||||||
→ Figure out game reconnection procedure
|
✔ Figure out game reconnection procedure @done(21-05-10 18:22)
|
||||||
→ Perhaps players skip a turn if they disconnect on their turn
|
✘ Perhaps players skip a turn if they disconnect on their turn @cancelled(21-05-10 18:22)
|
||||||
→ Game should go on until 1 person remains
|
✘ Game should go on until 1 person remains @cancelled(21-05-10 18:22)
|
||||||
→ Game chat
|
→ Game chat
|
||||||
|
|
||||||
☐ Game logic
|
☐ Game logic
|
||||||
@@ -52,13 +52,13 @@
|
|||||||
✔ Update dynamically @done(21-05-09 22:44)
|
✔ Update dynamically @done(21-05-09 22:44)
|
||||||
|
|
||||||
☐ Code
|
☐ Code
|
||||||
→ Refactor to code portsoc eslint
|
✘ Refactor to code portsoc eslint @cancelled(21-05-10 18:22)
|
||||||
→ Refactor game client
|
✘ Refactor game client @cancelled(21-05-10 18:22)
|
||||||
→ WHY THE HELL ARE THEY CALLED USERS IN SOME PLACES AND PLAYERS IN OTHERS
|
→ WHY THE HELL ARE THEY CALLED USERS IN SOME PLACES AND PLAYERS IN OTHERS
|
||||||
→ Why in some places is it user.name and others user.username
|
→ Why in some places is it user.name and others user.username
|
||||||
|
→ Should lobbies persist once game starts?
|
||||||
|
|
||||||
☐ Bugfixes
|
☐ Bugfixes
|
||||||
→ If a user leaves their current game then makes a new one, it's corrupted
|
✔ If a user leaves their current game then makes a new one, it's corrupted @done(21-05-10 17:56)
|
||||||
→ If a user disconnects during a game, the game is irrevokably corrupted
|
→ If a user disconnects during a game, the game is irrevokably corrupted
|
||||||
|
→ Usually, if a player leaves, it's fine, but if the host leaves. The lobbby is destructed and the logic creates a new game on the spot and they're the only player
|
||||||
|
|
||||||
|
|||||||
@@ -162,10 +162,10 @@ socket.on('lobby-create-error', obj => {
|
|||||||
|
|
||||||
const errorDiv = document.createElement('div');
|
const errorDiv = document.createElement('div');
|
||||||
errorDiv.id = 'lobby-error';
|
errorDiv.id = 'lobby-error';
|
||||||
errorDiv.innerHTML = localeString('error-bold') + ' ' + localeString('error-creating-lobby') + ' ' + JSON.stringify(args);
|
errorDiv.innerHTML = localeString('error-bold') + ' ' + localeString('error-creating-lobby') + ' ' + JSON.stringify(obj);
|
||||||
errorDiv.classList.add('red');
|
errorDiv.classList.add('red');
|
||||||
CreateLobbyBlock.appendChild(errorDiv);
|
CreateLobbyBlock.appendChild(errorDiv);
|
||||||
pageLog(localeString('error-bold') + ' ' + localeString('error-creating-lobby') + ' ' + JSON.stringify(args));
|
pageLog(localeString('error-bold') + ' ' + localeString('error-creating-lobby') + ' ' + JSON.stringify(obj));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ NOTES
|
|||||||
let Users = [];
|
let Users = [];
|
||||||
// just shorthand, so long as i remember to keep it updated lmao
|
// just shorthand, so long as i remember to keep it updated lmao
|
||||||
let MyTurn = false;
|
let MyTurn = false;
|
||||||
|
let TileSet = [];
|
||||||
|
|
||||||
let pastTurns = [];
|
let pastTurns = [];
|
||||||
|
|
||||||
@@ -27,6 +28,8 @@ function initGame(boardstates, tileset, myplayer, players)
|
|||||||
{
|
{
|
||||||
pastTurns.push(...boardstates);
|
pastTurns.push(...boardstates);
|
||||||
|
|
||||||
|
TileSet = tileset;
|
||||||
|
|
||||||
// construct piece array
|
// construct piece array
|
||||||
// structure [{letter: '', score: int}]
|
// structure [{letter: '', score: int}]
|
||||||
let drawerStructure = [];
|
let drawerStructure = [];
|
||||||
|
|||||||
@@ -341,12 +341,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
<script src="network.js"></script>
|
|
||||||
<script src="ui.js"></script>
|
<script src="ui.js"></script>
|
||||||
<script src="dragable.js"></script>
|
<script src="dragable.js"></script>
|
||||||
<script src="board.js"></script>
|
<script src="board.js"></script>
|
||||||
<script src="pieces.js"></script>
|
<script src="pieces.js"></script>
|
||||||
<script src="game.js"></script>
|
<script src="game.js"></script>
|
||||||
<script src="events.js"></script>
|
<script src="events.js"></script>
|
||||||
|
<script src="network.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -129,6 +129,16 @@ function onIdentifyError(socket, args)
|
|||||||
ConnectionState.forEach(e => {
|
ConnectionState.forEach(e => {
|
||||||
e.innerHTML = JSON.stringify(args);
|
e.innerHTML = JSON.stringify(args);
|
||||||
});
|
});
|
||||||
|
removePiecesFromDrawer('*');
|
||||||
|
addPiecesToDrawer([
|
||||||
|
{letter: 'H', score: 1},
|
||||||
|
{letter: 'E', score: 2},
|
||||||
|
{letter: 'L', score: 3},
|
||||||
|
{letter: 'L', score: 4},
|
||||||
|
{letter: 'O', score: 5},
|
||||||
|
{letter: 'O', score: 6},
|
||||||
|
{letter: 'O', score: 7}
|
||||||
|
]);
|
||||||
onDisconnect();
|
onDisconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,6 +309,15 @@ if (isSingleplayer)
|
|||||||
e.innerHTML = localeString('no-connection-singleplayer');
|
e.innerHTML = localeString('no-connection-singleplayer');
|
||||||
});
|
});
|
||||||
alert('Singleplayer is not implemented yet! a practice board will be set up to demonstrate tech and tile stuff');
|
alert('Singleplayer is not implemented yet! a practice board will be set up to demonstrate tech and tile stuff');
|
||||||
|
addPiecesToDrawer([
|
||||||
|
{letter: 'H', score: 1},
|
||||||
|
{letter: 'E', score: 2},
|
||||||
|
{letter: 'L', score: 3},
|
||||||
|
{letter: 'L', score: 4},
|
||||||
|
{letter: 'O', score: 5},
|
||||||
|
{letter: 'O', score: 6},
|
||||||
|
{letter: 'O', score: 7}
|
||||||
|
]);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
initMultiplayer();
|
initMultiplayer();
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ function addPiecesToDrawer(pieces)
|
|||||||
// Removes regardless of vadility
|
// Removes regardless of vadility
|
||||||
function removePiecesFromDrawer(pieces)
|
function removePiecesFromDrawer(pieces)
|
||||||
{
|
{
|
||||||
|
if (pieces === '*')
|
||||||
|
{
|
||||||
|
Drawer.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (const piece of pieces)
|
for (const piece of pieces)
|
||||||
{
|
{
|
||||||
piece.remove();
|
piece.remove();
|
||||||
@@ -221,6 +226,43 @@ function piecePlaced(piece)
|
|||||||
piece.classList.add('staged-piece');
|
piece.classList.add('staged-piece');
|
||||||
piece.dataset.coords = JSON.stringify(coords);
|
piece.dataset.coords = JSON.stringify(coords);
|
||||||
|
|
||||||
|
// Wildcard! (done clientside because of laziness)
|
||||||
|
let letter = piece.dataset.letter;
|
||||||
|
if (letter === '_')
|
||||||
|
{
|
||||||
|
// TODO: this would be a pretty good function for elsewhere..
|
||||||
|
const tilesetincludes = (l) => {
|
||||||
|
for (const range of TileSet)
|
||||||
|
if (range.letters.includes(l)) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
letter = prompt('You placed a wildcard! what would you like the letter to be?').toUpperCase();
|
||||||
|
if (letter === null || !tilesetincludes(letter))
|
||||||
|
{
|
||||||
|
DrawerSounds[Math.floor(Math.random() * 3)].play();
|
||||||
|
|
||||||
|
piece.classList.remove('staged-piece');
|
||||||
|
piece.classList.remove('small-piece');
|
||||||
|
piece.classList.add('unplayed-piece');
|
||||||
|
delete piece.dataset.coords;
|
||||||
|
|
||||||
|
setupPieces();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
piece.dataset.letter = letter;
|
||||||
|
// no way to work this out here
|
||||||
|
|
||||||
|
let score = -1;
|
||||||
|
for (const range in TileSet)
|
||||||
|
if (TileSet[range].letters.includes(letter))
|
||||||
|
score = TileSet[range].points;
|
||||||
|
|
||||||
|
piece.dataset.score = score;
|
||||||
|
piece.innerHTML = `${piece.dataset.letter}<score>${piece.dataset.score}</score>`;
|
||||||
|
}
|
||||||
|
|
||||||
setupPieces();
|
setupPieces();
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -149,6 +149,15 @@ function GetGameByUserUID(useruid)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetGameUserByUserUID(useruid)
|
||||||
|
{
|
||||||
|
for (const game in ActiveGames)
|
||||||
|
for (const player of ActiveGames[game].players)
|
||||||
|
if (player.uid === useruid) return player;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function GetTurnUser(gameuid)
|
function GetTurnUser(gameuid)
|
||||||
{
|
{
|
||||||
if (!ActiveGames[gameuid]) return false;
|
if (!ActiveGames[gameuid]) return false;
|
||||||
@@ -277,14 +286,32 @@ function PlayTurn(gameuid, playeruid, turn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process outcome
|
// process outcome
|
||||||
|
const temptiles = turn.oldboardtiles.concat(turn.boardtiles)
|
||||||
|
|
||||||
// check if user is allowed to make that move
|
// check if user is allowed to make that move
|
||||||
|
const gameplayer = GetGameUserByUserUID(playeruid);
|
||||||
|
console.log(gameplayer);
|
||||||
|
|
||||||
// process turn and allocate scores
|
// process turn and allocate scores
|
||||||
|
|
||||||
// give user new tiles
|
// give user new tiles
|
||||||
|
|
||||||
turn.boardtiles = turn.oldboardtiles.append(turn.boardtiles);
|
// update tiles with scores
|
||||||
|
turn.boardtiles = turn.oldboardtiles.concat(turn.boardtiles);
|
||||||
|
for (const tile in turn.boardtiles)
|
||||||
|
{
|
||||||
|
let score = 0;
|
||||||
|
for (const pointband of Dist.GetDist(game.locale).dist)
|
||||||
|
{
|
||||||
|
if (pointband.letters.includes(turn.boardtiles[tile].letter))
|
||||||
|
{
|
||||||
|
score = pointband.points;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
turn.boardtiles[tile].score = score;
|
||||||
|
}
|
||||||
|
|
||||||
ActiveGames[gameuid].gamestates.push(turn);
|
ActiveGames[gameuid].gamestates.push(turn);
|
||||||
ActiveGames[gameuid].turn = turninfo.newTurn;
|
ActiveGames[gameuid].turn = turninfo.newTurn;
|
||||||
ActiveGames[gameuid].turntotal = turninfo.newTotalTurn;
|
ActiveGames[gameuid].turntotal = turninfo.newTotalTurn;
|
||||||
@@ -327,9 +354,9 @@ function gameNextTurn(gameuid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// same as how the
|
// same as how the
|
||||||
function EndGame()
|
function EndGame(gameuid)
|
||||||
{
|
{
|
||||||
|
delete ActiveGames[gameuid];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -359,6 +386,7 @@ module.exports = {
|
|||||||
|
|
||||||
// Get game exports
|
// Get game exports
|
||||||
GetGameByUserUID: GetGameByUserUID,
|
GetGameByUserUID: GetGameByUserUID,
|
||||||
|
GetGameUserByUserUID: GetGameUserByUserUID,
|
||||||
GetTurnUser: GetTurnUser,
|
GetTurnUser: GetTurnUser,
|
||||||
|
|
||||||
// Change game state exports
|
// Change game state exports
|
||||||
|
|||||||
@@ -458,9 +458,16 @@ function HandleDisconnect(socket, args)
|
|||||||
// if user is in a game, notify the game logic
|
// if user is in a game, notify the game logic
|
||||||
// if the user is the last user in a game - delete it
|
// if the user is the last user in a game - delete it
|
||||||
// if the user is leaving, change their status so reconnect is allowed
|
// if the user is leaving, change their status so reconnect is allowed
|
||||||
|
|
||||||
// TODO: VERY IMPORTANTTTT THAT^^^
|
// TODO: VERY IMPORTANTTTT THAT^^^
|
||||||
|
|
||||||
|
// quick fix, prevents game destruction
|
||||||
|
// if (user.intent === 'GAME')
|
||||||
|
// {
|
||||||
|
// Game.Registrar.UserDisconnect(user.uid);
|
||||||
|
// Logger.info(`SOCKET ${socket.id} DISCONNECTED FROM GAME`);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// if user is in a lobby, leave and if user own's a lobby, destruct
|
// if user is in a lobby, leave and if user own's a lobby, destruct
|
||||||
// leave lobby before user is disconnected
|
// leave lobby before user is disconnected
|
||||||
if (user.intent !== 'GAMETRANSITION')
|
if (user.intent !== 'GAMETRANSITION')
|
||||||
@@ -526,6 +533,8 @@ function EmitGameBegin(game)
|
|||||||
const userturnstartconnection = Game.Registrar.GetConnectionByUser(userturnstart);
|
const userturnstartconnection = Game.Registrar.GetConnectionByUser(userturnstart);
|
||||||
|
|
||||||
io.to(userturnstartconnection).emit('game-your-turn');
|
io.to(userturnstartconnection).emit('game-your-turn');
|
||||||
|
|
||||||
|
Logger.debug(JSON.stringify(game.players, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
function EmitGameReconnect(user, game)
|
function EmitGameReconnect(user, game)
|
||||||
@@ -543,12 +552,17 @@ function EmitGameReconnect(user, game)
|
|||||||
// NOTE it shouldn't ever be their turn on a reconnect
|
// NOTE it shouldn't ever be their turn on a reconnect
|
||||||
// as the game logic should pass control to next player
|
// as the game logic should pass control to next player
|
||||||
// as the game order is changed
|
// as the game order is changed
|
||||||
|
if (!Game.Logic.GetTurnUser(game.uid)) return;
|
||||||
const userturnstart = Game.Logic.GetTurnUser(game.uid).uid;
|
const userturnstart = Game.Logic.GetTurnUser(game.uid).uid;
|
||||||
if (userturnstart === user.uid)
|
if (userturnstart === user.uid)
|
||||||
{
|
{
|
||||||
const userturnstartconnection = Game.Registrar.GetConnectionByUser(userturnstart);
|
io.to(gameuserconnection).emit('game-your-turn');
|
||||||
|
} else
|
||||||
io.to(userturnstartconnection).emit('game-your-turn');
|
{
|
||||||
}
|
// TODO: this needs to send game heuristics
|
||||||
|
io.to(gameuserconnection).emit('game-turn-start');
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.debug(JSON.stringify(game.players, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user