wildcard and serverside scoring

This commit is contained in:
Ben
2021-05-10 18:52:49 +01:00
parent 4cc96b201e
commit 3e4dd69105
10 changed files with 137 additions and 26 deletions

2
.gitignore vendored
View File

@@ -3,4 +3,4 @@ client/node_modules/
server/node_modules/
*.log
*.env
.turns-debug.json
turns-debug.json

View File

@@ -34,12 +34,17 @@ or just use environment variables
### 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
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
Express.js - HTTP Routing and Management
Socket.io - Socket Routing and Management
Inês Filipa Baiõa Antunes - Tranlations (Portuguese, Spanish)

24
TODO
View File

@@ -15,8 +15,8 @@
→ Update with new locales
✔ Spanish (Ines) @done(21-04-11 01:03)
→ Update with new locales
French (Alexendro)
Czech (Mikdore)
French (Alexendro) @cancelled(21-05-10 18:22)
Czech (Mikdore) @cancelled(21-05-10 18:22)
→ Go through code again once finished and pick out locales
☐ Lobbying logic
@@ -28,14 +28,14 @@
→ Find appropriate scrabble dictionary for
✔ Portuagese @done(21-04-19 02:10)
✔ Spanish @done(21-04-19 02:10)
✔ French @done(21-04-19 02:10)
Czech
✔ French @done(21-05-10 18:22)
Czech @cancelled(21-05-10 18:22)
→ Optimise! n-ary tree
☐ Game networking
Figure out game reconnection procedure
Perhaps players skip a turn if they disconnect on their turn
Game should go on until 1 person remains
Figure out game reconnection procedure @done(21-05-10 18:22)
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 @cancelled(21-05-10 18:22)
→ Game chat
☐ Game logic
@@ -52,13 +52,13 @@
✔ Update dynamically @done(21-05-09 22:44)
☐ Code
Refactor to code portsoc eslint
Refactor game client
Refactor to code portsoc eslint @cancelled(21-05-10 18:22)
Refactor game client @cancelled(21-05-10 18:22)
→ 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
→ Should lobbies persist once game starts?
☐ 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
→ 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

View File

@@ -162,10 +162,10 @@ socket.on('lobby-create-error', obj => {
const errorDiv = document.createElement('div');
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');
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));
});

View File

@@ -20,6 +20,7 @@ NOTES
let Users = [];
// just shorthand, so long as i remember to keep it updated lmao
let MyTurn = false;
let TileSet = [];
let pastTurns = [];
@@ -27,6 +28,8 @@ function initGame(boardstates, tileset, myplayer, players)
{
pastTurns.push(...boardstates);
TileSet = tileset;
// construct piece array
// structure [{letter: '', score: int}]
let drawerStructure = [];

View File

@@ -341,12 +341,12 @@
<script src="index.js"></script>
<script src="network.js"></script>
<script src="ui.js"></script>
<script src="dragable.js"></script>
<script src="board.js"></script>
<script src="pieces.js"></script>
<script src="game.js"></script>
<script src="events.js"></script>
<script src="network.js"></script>
</body>
</html>

View File

@@ -129,6 +129,16 @@ function onIdentifyError(socket, args)
ConnectionState.forEach(e => {
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();
}
@@ -299,6 +309,15 @@ if (isSingleplayer)
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');
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
{
initMultiplayer();

View File

@@ -52,6 +52,11 @@ function addPiecesToDrawer(pieces)
// Removes regardless of vadility
function removePiecesFromDrawer(pieces)
{
if (pieces === '*')
{
Drawer.innerHTML = '';
return;
}
for (const piece of pieces)
{
piece.remove();
@@ -216,11 +221,48 @@ function piecePlaced(piece)
BoardSounds[0].play();
placePieceOnBoard(piece, coords.x, coords.y);
piece.classList.remove('unplayed-piece');
piece.classList.add('staged-piece');
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();
} else
{

View File

@@ -149,6 +149,15 @@ function GetGameByUserUID(useruid)
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)
{
if (!ActiveGames[gameuid]) return false;
@@ -277,14 +286,32 @@ function PlayTurn(gameuid, playeruid, turn)
}
// process outcome
const temptiles = turn.oldboardtiles.concat(turn.boardtiles)
// check if user is allowed to make that move
const gameplayer = GetGameUserByUserUID(playeruid);
console.log(gameplayer);
// process turn and allocate scores
// 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].turn = turninfo.newTurn;
ActiveGames[gameuid].turntotal = turninfo.newTotalTurn;
@@ -327,9 +354,9 @@ function gameNextTurn(gameuid)
}
// same as how the
function EndGame()
function EndGame(gameuid)
{
delete ActiveGames[gameuid];
}
@@ -359,6 +386,7 @@ module.exports = {
// Get game exports
GetGameByUserUID: GetGameByUserUID,
GetGameUserByUserUID: GetGameUserByUserUID,
GetTurnUser: GetTurnUser,
// Change game state exports

View File

@@ -458,9 +458,16 @@ function HandleDisconnect(socket, args)
// 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 leaving, change their status so reconnect is allowed
// 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
// leave lobby before user is disconnected
if (user.intent !== 'GAMETRANSITION')
@@ -526,6 +533,8 @@ function EmitGameBegin(game)
const userturnstartconnection = Game.Registrar.GetConnectionByUser(userturnstart);
io.to(userturnstartconnection).emit('game-your-turn');
Logger.debug(JSON.stringify(game.players, null, 2));
}
function EmitGameReconnect(user, game)
@@ -543,12 +552,17 @@ function EmitGameReconnect(user, game)
// NOTE it shouldn't ever be their turn on a reconnect
// as the game logic should pass control to next player
// as the game order is changed
if (!Game.Logic.GetTurnUser(game.uid)) return;
const userturnstart = Game.Logic.GetTurnUser(game.uid).uid;
if (userturnstart === user.uid)
{
io.to(gameuserconnection).emit('game-your-turn');
} else
{
const userturnstartconnection = Game.Registrar.GetConnectionByUser(userturnstart);
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));
}