diff --git a/backend/api/functions.js b/backend/api/functions.js new file mode 100644 index 0000000000000000000000000000000000000000..6cf642b16257060fc8c04068b6fde475201c2b01 --- /dev/null +++ b/backend/api/functions.js @@ -0,0 +1,262 @@ +const mongo = require("mongodb"); + +module.exports = { + notifyPlayers: function (client, players, timeout, tournament) { + const objects = []; + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + if (players.length == 0) { + resolve(); + } + for (let i = 0; i < players.length; i++) { + objects.push({ + playerId: mongo.ObjectID(players[i]), + tournamentId: tournament, + timeout: timeout, + }); + } + // Get the collection and bulk api artefacts + var collection = db.collection("alerts"), + bulkUpdateOps = []; + + objects.forEach(function (doc) { + bulkUpdateOps.push({ insertOne: { document: doc } }); + }); + + if (bulkUpdateOps.length > 0) { + collection.bulkWrite(bulkUpdateOps).then(function (r) { + resolve(); + }); + } + }); + }, + + endTournament: function (client, tournament) { + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + const collection = "tournaments"; + db.collection(collection).updateOne( + { _id: tournament }, + { $set: { active: false } }, + (err, result) => { + if (err) { + resolve(500); // Internal server error + return; + } + resolve(result); + return; + } + ); + }); + }, + + timeOut: function (client, tournament, players, end, rounds) { + if (!players) { + players = []; + } + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + db.collection("tournaments").updateOne( + { + _id: tournament, + }, + { + $pull: { players: { $in: players } }, + $inc: { currentPlayers: -players.length }, + $set: { active: !end }, + }, + (err, result) => { + if (err) { + resolve(500); // Internal server error + return; + } + db.collection("rounds").deleteMany( + { + _id: { $in: rounds }, + }, + (err, result) => { + if (err) { + resolve(500); // Internal server error + return; + } + resolve(result); + return; + } + ); + } + ); + }); + }, + + getCurrentRound: function (client, tournamentId) { + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + const collection = "tournaments"; + + db.collection(collection).findOne( + { + _id: tournamentId, + }, + { currentRound: 1, startTime: 1, maxPlayers: 1, currentPlayers: 1 }, + (err, result) => { + if (err) { + resolve(500); // Internal server error + return; + } + resolve(result); + return; + } + ); + }); + }, + + newRound: function ( + client, + tournamentId, + players, + gameId, + roundNr, + deadlineDate + ) { + return new Promise((resolve, reject) => { + // Using the database gameWare and collection rounds + const db = client.db("gameWare"); + const collection = db.collection("rounds"); + let objects = []; + + for (let i = 0; i < players.length; i++) { + objects.push({ + tournamentId: mongo.ObjectID(tournamentId), + playerId: mongo.ObjectID(players[i]), + gameId: mongo.ObjectID(gameId), + roundNr: roundNr, + deadlineDate: deadlineDate, + scoreValue: 0, + hasPlayed: false, + tournamentPoints: 0, + }); + } + + let bulkUpdateOps = []; + + objects.forEach(function (doc) { + bulkUpdateOps.push({ insertOne: { document: doc } }); + }); + + if (bulkUpdateOps.length > 0) { + collection.bulkWrite(bulkUpdateOps).then(function (r) { + resolve(); + }); + } + }); + }, + + updateTournamentRound: function (client, tournament) { + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + const collection = "tournaments"; + + db.collection(collection) + .findOneAndUpdate( + { + _id: tournament, + $expr: { + $lt: ["$currentRound", "$totalGames"], + }, + }, + { + $inc: { currentRound: 1 }, + }, + { + returnOriginal: false, + } + ) + .then((updatedDocument) => { + resolve(updatedDocument); + }); + }); + }, + + checkRounds: function (result, start, max, roundNr, current) { + return new Promise((resolve, reject) => { + let timedOut = []; + let timedOutRounds = []; + let left = []; + let amountComplete = 0; + for (let i = 0; i < result.length; i++) { + if (result[i].hasPlayed === true) { + amountComplete++; + left.push(result[i].playerId); + } else if (new Date(result[i].deadlineDate) <= new Date()) { + timedOut.push(result[i].playerId); + timedOutRounds.push(result[i]._id); + } else { + left.push(result[i].playerId); + } + } + if (amountComplete == max) { + // All players have completed their round + resolve([true, [], left, []]); + } else if (amountComplete == current && roundNr > 1) { + // All players have completed their round + resolve([true, [], left, []]); + } else if (amountComplete > 1 && new Date() >= start && roundNr == 1) { + // more than two have completed first round + // startDelay passed. + resolve([true, timedOut, left, timedOutRounds]); + } else if ( + amountComplete + timedOut.length == current && + amountComplete >= 2 && + roundNr > 1 + ) { + // More than two players have completed round and all players have either completed their round or timed out. + resolve([true, timedOut, left, timedOutRounds]); + } else { + resolve([false, timedOut, left, timedOutRounds]); + } + }); + }, + + fetchRounds: function (client, tournamentId, activeRound) { + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + const collection = "rounds"; + + db.collection("rounds") + .find({ + tournamentId: tournamentId, + roundNr: activeRound, + }) + .sort({ + scoreValue: -1, + }) + .toArray((err, result) => { + if (err) { + return; + } + resolve(result); + }); + }); + }, + + updateScore: function (client, id, placement, playerAmount) { + let tournamentPoints = (playerAmount - placement + 1) * 10; + + return new Promise((resolve, reject) => { + const db = client.db("gameWare"); + const collection = "rounds"; + + db.collection(collection) + .findOneAndUpdate( + { + _id: mongo.ObjectID(id), + }, + { $set: { tournamentPoints: tournamentPoints } }, + { returnNewDocument: true } + ) + .then((updatedDocument) => { + resolve(updatedDocument); + }); + }); + }, +}; diff --git a/backend/api/rounds.js b/backend/api/rounds.js index ef1a00cd99a81d3b098e49ff51b3545678d7cf21..6f6069e0b279c62d34736da67310846b18ff8587 100644 --- a/backend/api/rounds.js +++ b/backend/api/rounds.js @@ -3,6 +3,7 @@ const router = express.Router(); const mongo = require("mongodb"); const MongoClient = mongo.MongoClient; const connectionUrl = process.env.MONGO_CONNECTION_STRING; +const functions = require("./functions"); router.get("/round/:roundId", (req, res) => { // Connect to database @@ -432,17 +433,17 @@ router.put("/:roundid/:tournamentid", (req, res) => { function roundcheck(client, tournament, roundid) { return new Promise((resolve, reject) => { - getCurrentRound(client, tournament).then((roundResult) => { + functions.getCurrentRound(client, tournament).then((roundResult) => { // gets the current round of the tournament if (roundResult == 500) { resolve(500); - return; } const active = roundResult.currentRound; const start = roundResult.startTime; const maxPlayers = roundResult.maxPlayers; + const currentPlayers = roundResult.currentPlayers; - fetchRounds(client, tournament, active).then((rounds) => { + functions.fetchRounds(client, tournament, active).then((rounds) => { // fetched the round objects of the active round let activePlayer; for (let i = 0; i < rounds.length; i++) { @@ -451,132 +452,156 @@ function roundcheck(client, tournament, roundid) { break; } } - checkRounds(rounds, start, maxPlayers, active).then((resultarray) => { - // check to find out if [0] tournament will move on, [1] which players are timed out - // [2] which players are still in the tournament - let result = resultarray[0]; - let timedOut = resultarray[1]; - let left = resultarray[2]; - let timedOutRounds = resultarray[3]; - let end = false; - if ((left.length < 2 && active != 1) || left.length == 0) { - end = true; - //if there are less then two people left in the first round, or zero people left in the first round - //the tournament ends - } + functions + .checkRounds(rounds, start, maxPlayers, active, currentPlayers) + .then((resultarray) => { + // check to find out if [0] tournament will move on, [1] which players are timed out + // [2] which players are still in the tournament + let result = resultarray[0]; + let timedOut = resultarray[1]; + let left = resultarray[2]; + let timedOutRounds = resultarray[3]; + let end = false; + if ((left.length < 2 && active != 1) || left.length == 0) { + end = true; + //if there are less then two people left in the first round, or zero people left in the first round + //the tournament ends + } - timeOut(client, tournament, timedOut, end, timedOutRounds).then( - //updates the state of the tournament and ends it if necessary - (timeoutresult) => { - notifyPlayers(client, timedOut, true, tournament); - const indeks = left.indexOf(activePlayer); - left.splice(indeks, 1); - if (end) { - notifyPlayers(client, left, false, tournament); - endTournament(client, tournament); - getRound(client, roundid).then((round) => { - resolve({ - round: round, - roundCheck: { - active: false, - nextRound: false, - }, - }); - }); - return; - } - if (result) { - //Tournament moves on to next round - let eligibleRounds = []; - for (let i = 0; i < rounds.length; i++) { - let round = rounds[i]; - if (round.hasPlayed === true) { - eligibleRounds.push(round); - } - } - //Here we find the rounds that were actually completed - for (let i = 0; i < eligibleRounds.length; i++) { - let round = eligibleRounds[i]; - updateScore(client, round._id, i + 1, eligibleRounds.length); - //And here we update the tournament score - } - updateTournamentRound(client, tournament).then((result) => { - //updates the tournaments round if there are more rounds left - if (result.value) { - tourny = result.value; - const game = - tourny.games[tourny.currentRound % tourny.games.length]; - const date = new Date(); - date.setTime( - date.getTime() + tourny.timePerRound * 60 * 60 * 1000 - ); - for (let i = 0; i < tourny.players.length; i++) { - newRound( - client, - tournament, - tourny.players[i], - game, - tourny.currentRound, - date - ); - // created new rounds for all the players left - } - getRound(client, roundid).then((round) => { - resolve({ - round: round, - roundCheck: { - active: true, - nextRound: true, - }, - }); + functions + .timeOut(client, tournament, timedOut, end, timedOutRounds) + .then( + //updates the state of the tournament and ends it if necessary + () => { + functions + .notifyPlayers(client, timedOut, true, tournament) + .then(() => { + const indeks = left.indexOf(activePlayer); + left.splice(indeks, 1); + if (end) { + functions + .notifyPlayers(client, left, false, tournament) + .then(() => { + functions + .endTournament(client, tournament) + .then(() => { + getRound(client, roundid).then((round) => { + resolve({ + round: round, + roundCheck: { + active: false, + nextRound: false, + }, + }); + }); + }); + }); + } else if (result) { + //Tournament moves on to next round + let eligibleRounds = []; + for (let i = 0; i < rounds.length; i++) { + let round = rounds[i]; + if (round.hasPlayed === true) { + eligibleRounds.push(round); + } + } + //Here we find the rounds that were actually completed + for (let i = 0; i < eligibleRounds.length; i++) { + let round = eligibleRounds[i]; + functions.updateScore( + client, + round._id, + i + 1, + eligibleRounds.length + ); + //And here we update the tournament score + } + functions + .updateTournamentRound(client, tournament) + .then((result) => { + //updates the tournaments round if there are more rounds left + if (result.value) { + tourny = result.value; + const game = + tourny.games[ + tourny.currentRound % tourny.games.length + ]; + const date = new Date(); + date.setTime( + date.getTime() + + tourny.timePerRound * 24 * 60 * 60 * 1000 + ); + + functions + .newRound( + client, + tournament, + tourny.players, + game, + tourny.currentRound, + date + ) + .then(() => { + getRound(client, roundid).then((round) => { + resolve({ + round: round, + roundCheck: { + active: true, + nextRound: true, + }, + }); + }); + }); + // created new rounds for all the players left + } else { + // if the tournament now is done we simply end it + functions + .endTournament(client, tournament) + .then(() => { + functions + .notifyPlayers( + client, + left, + false, + tournament + ) + .then(() => { + getRound(client, roundid).then( + (round) => { + resolve({ + round: round, + roundCheck: { + active: false, + nextRound: false, + }, + }); + } + ); + }); + }); + } + }); + } else { + getRound(client, roundid).then((round) => { + resolve({ + round: round, + roundCheck: { + // Tournament still waiting for other players + active: true, + nextRound: false, + }, + }); + }); + } }); - } else { - // if the tournament now is done we simply end it - endTournament(client, tournament); - notifyPlayers(client, left, false, tournament); - getRound(client, roundid).then((round) => { - resolve({ - round: round, - roundCheck: { - active: false, - nextRound: false, - }, - }); - }); - return; - } - }); - } else { - getRound(client, roundid).then((round) => { - resolve({ - round: round, - roundCheck: { - // Tournament still waiting for other players - active: true, - nextRound: false, - }, - }); - }); - } - } - ); - }); + } + ); + }); }); }); }); } -function notifyPlayers(client, players, timeout, tournament) { - const db = client.db("gameWare"); - for (let i = 0; i < players.length; i++) { - db.collection("alerts").insertOne({ - playerId: mongo.ObjectID(players[i]), - tournamentId: tournament, - timeout: timeout, - }); - } -} - function getRound(client, id) { return new Promise((resolve, reject) => { const db = client.db("gameWare"); @@ -593,222 +618,6 @@ function getRound(client, id) { }); } -function endTournament(client, tournament) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - db.collection(collection).updateOne( - { _id: tournament }, - { $set: { active: false } }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - }); -} - -function timeOut(client, tournament, players, end, rounds) { - if (!players) { - players = []; - } - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - db.collection("tournaments").updateOne( - { - _id: tournament, - }, - { - $pull: { players: { $in: players } }, - $inc: { currentPlayers: -players.length }, - $set: { active: !end }, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - db.collection("rounds").remove( - { - _id: { $in: rounds }, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - } - ); - }); -} - -function getCurrentRound(client, tournamentId) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - - db.collection(collection).findOne( - { - _id: tournamentId, - }, - { currentRound: 1, startTime: 1, maxPlayers: 1 }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - }); -} - -function newRound( - client, - tournamentId, - playerId, - gameId, - roundNr, - deadlineDate -) { - return new Promise((resolve, reject) => { - // Using the database gameWare and collection rounds - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection(collection).insertOne( - { - tournamentId: mongo.ObjectID(tournamentId), - playerId: mongo.ObjectID(playerId), - gameId: mongo.ObjectID(gameId), - roundNr: roundNr, - deadlineDate: deadlineDate, - scoreValue: 0, - hasPlayed: false, - tournamentPoints: 0, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result.ops[0]); - } - ); - }); -} - -function updateTournamentRound(client, tournament) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - - db.collection(collection) - .findOneAndUpdate( - { - _id: tournament, - $expr: { - $lt: ["$currentRound", "$totalGames"], - }, - }, - { - $inc: { currentRound: 1 }, - }, - { - returnOriginal: false, - } - ) - .then((updatedDocument) => { - resolve(updatedDocument); - }); - }); -} - -function checkRounds(result, start, max, roundNr) { - return new Promise((resolve, reject) => { - let timedOut = []; - let timedOutRounds = []; - let left = []; - let amountComplete = 0; - for (let i = 0; i < result.length; i++) { - if (result[i].hasPlayed === true) { - amountComplete++; - left.push(result[i].playerId); - } else if (new Date(result[i].deadlineDate) <= new Date()) { - timedOut.push(result[i].playerId); - timedOutRounds.push(result[i]._id); - } else { - left.push(result[i].playerId); - } - } - if (amountComplete == max) { - // All players have completed their round - resolve([true, [], left, []]); - } else if (amountComplete > 1 && new Date() >= start && roundNr == 1) { - // more than two have completed first round - // startDelay passed. - resolve([true, timedOut, left, timedOutRounds]); - } else if (amountComplete + timedOut.length == max && amountComplete >= 2) { - // More than two players have completed round and all players have either completed their round or timed out. - resolve([true, timedOut, left, timedOutRounds]); - } else { - resolve([false, timedOut, left, timedOutRounds]); - } - }); -} - -function fetchRounds(client, tournamentId, activeRound) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection("rounds") - .find({ - tournamentId: tournamentId, - roundNr: activeRound, - }) - .sort({ - scoreValue: -1, - }) - .toArray((err, result) => { - if (err) { - return; - } - resolve(result); - }); - }); -} - -function updateScore(client, id, placement, playerAmount) { - let tournamentPoints = (playerAmount - placement + 1) * 10; - - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection(collection) - .findOneAndUpdate( - { - _id: mongo.ObjectID(id), - }, - { $set: { tournamentPoints: tournamentPoints } }, - { returnNewDocument: true } - ) - .then((updatedDocument) => { - resolve(updatedDocument); - }); - }); -} - // Export API routes module.exports = router; diff --git a/backend/api/tournament.js b/backend/api/tournament.js index 1a7f4df6952f8bdcae31f77331bceec65cf2bf88..4f9dfd69066790267a9dab3580dfe25da8166e51 100644 --- a/backend/api/tournament.js +++ b/backend/api/tournament.js @@ -2,6 +2,7 @@ const express = require("express"); const router = express.Router(); const mongo = require("mongodb"); const MongoClient = mongo.MongoClient; +const functions = require("./functions"); const connectionUrl = process.env.MONGO_CONNECTION_STRING; router.post("/leave", (req, res) => { @@ -38,6 +39,9 @@ router.post("/leave", (req, res) => { { $pull: { players: playerid }, $inc: { currentPlayers: -1 }, + }, + { + returnOriginal: false, } ) .then((updatedDocument) => { @@ -47,10 +51,18 @@ router.post("/leave", (req, res) => { playerId: playerid, }) .then((result) => { + if (parseInt(updatedDocument.value.currentPlayers) === 0) { + db.collection("tournaments").deleteOne({ + _id: tournamentid, + }); + } res.json({ deletedRounds: result.result.n }); client.close(); }) - .catch((err) => res.sendStatus(500)); + .catch((err) => { + console.log(err); + res.sendStatus(500); + }); }); } ); @@ -97,7 +109,7 @@ router.post("/new", (req, res) => { } let startTime = new Date( tournamentdate.getTime() + - parseInt(req.body.startDelay) * 60 * 60 * 1000 + parseInt(req.body.startDelay) * 24 * 60 * 60 * 1000 ); values.players = [mongo.ObjectID(req.body.playerId)]; values.games = games; @@ -122,7 +134,7 @@ router.post("/new", (req, res) => { return; } tournamentdate.setTime( - tournamentdate.getTime() + req.body.timePerRound * 60 * 60 * 1000 + tournamentdate.getTime() + req.body.timePerRound * 24 * 60 * 60 * 1000 ); createFirstRound(result.insertedId, result, tournamentdate); }); @@ -196,7 +208,7 @@ router.post("/join", (req, res) => { tournamentdate = updatedDocument.value.dateCreated; tournamentdate.setTime( tournamentdate.getTime() + - updatedDocument.value.timePerRound * 60 * 60 * 1000 + updatedDocument.value.timePerRound * 24 * 60 * 60 * 1000 ); // create the first round for the newly joined player createFirstRound( @@ -333,13 +345,42 @@ router.get("/player/:userid/:active", (req, res) => { //console.log(err); return; } - res.json(result); - client.close(); + if (req.params.active === "true") { + let IDs = result.map((tourny) => tourny._id); + doChecks(client, IDs).then(() => { + db.collection(collection) + .find({ + players: id, + active: req.params.active === "true", + }) + .toArray((err, result) => { + if (err) { + res.sendStatus(500); + //console.log(err); + return; + } + res.json(result); + client.close(); + return; + }); + }); + } else { + res.json(result); + client.close(); + } }); } ); }); +async function doChecks(client, ids) { + for (const tourny of ids) { + let id = mongo.ObjectID(tourny); + const check = await roundcheck(client, id); + } + return; +} + router.put("/roundcheck/:tournamentId", (req, res) => { let tournament = null; try { @@ -362,33 +403,48 @@ router.put("/roundcheck/:tournamentId", (req, res) => { res.sendStatus(500); // Internal server error return; } - - getCurrentRound(client, tournament).then((roundResult) => { - // gets the current round of the tournament - if (roundResult == 500) { + roundcheck(client, tournament).then((result) => { + if (result == 500) { res.sendStatus(500); - client.close(); return; - } else if (roundResult.active === false) { - res.status(400).send("Tournament not active"); - client.close(); + } else if (result == 400) { + res.sendStatus(400); return; } - const active = roundResult.currentRound; - const start = roundResult.startTime; - const maxPlayers = roundResult.maxPlayers; - - fetchRounds(client, tournament, active).then((rounds) => { - // fetched the round objects of the active round - /* - let activePlayer; - for (let i = 0; i < rounds.length; i++) { - if (rounds[i]._id === roundid) { - activePlayer = rounds[i].playerId; - break; - } - }*/ - checkRounds(rounds, start, maxPlayers, active).then((resultarray) => { + res.json(result); + return; + }); + } + ); +}); + +function roundcheck(client, tournament) { + return new Promise((resolve, reject) => { + functions.getCurrentRound(client, tournament).then((roundResult) => { + // gets the current round of the tournament + if (roundResult == 500) { + resolve(500); + } else if (roundResult.active === false) { + resolve(400); + } + const active = roundResult.currentRound; + const start = roundResult.startTime; + const maxPlayers = roundResult.maxPlayers; + const currentPlayers = roundResult.currentPlayers; + + functions.fetchRounds(client, tournament, active).then((rounds) => { + // fetched the round objects of the active round + /* + let activePlayer; + for (let i = 0; i < rounds.length; i++) { + if (rounds[i]._id === roundid) { + activePlayer = rounds[i].playerId; + break; + } + }*/ + functions + .checkRounds(rounds, start, maxPlayers, active, currentPlayers) + .then((resultarray) => { // check to find out if [0] tournament will move on, [1] which players are timed out // [2] which players are still in the tournament let result = resultarray[0]; @@ -396,327 +452,117 @@ router.put("/roundcheck/:tournamentId", (req, res) => { let left = resultarray[2]; let timedOutRounds = resultarray[3]; let end = false; + //console.log(result + " " + left + "; " + timedOut); + //console.log(left.length + " ," + active); if ((left.length < 2 && active != 1) || left.length == 0) { end = true; //if there are less then two people left in the first round, or zero people left in the first round //the tournament ends } - timeOut(client, tournament, timedOut, end, timedOutRounds).then( - //updates the state of the tournament and ends it if necessary - - (timeoutresult) => { - notifyPlayers(client, timedOut, true, tournament); - /*const indeks = left.indexOf(activePlayer); + functions + .timeOut(client, tournament, timedOut, end, timedOutRounds) + .then( + //updates the state of the tournament and ends it if necessary + + () => { + functions + .notifyPlayers(client, timedOut, true, tournament) + .then(() => { + /*const indeks = left.indexOf(activePlayer); left.splice(indeks, 1);*/ - if (end) { - notifyPlayers(client, left, false, tournament); - endTournament(client, tournament); - res.json({ - active: false, - nextRound: false, - }); - client.close(); - return; - } - if (result) { - //Tournament moves on to next round - let eligibleRounds = []; - for (let i = 0; i < rounds.length; i++) { - let round = rounds[i]; - if (round.hasPlayed === true) { - eligibleRounds.push(round); - } - } - //Here we find the rounds that were actually completed - for (let i = 0; i < eligibleRounds.length; i++) { - let round = eligibleRounds[i]; - updateScore( - client, - round._id, - i + 1, - eligibleRounds.length - ); - //And here we update the tournament score - } - updateTournamentRound(client, tournament).then((result) => { - //updates the tournaments round if there are more rounds left - if (result.value) { - tourny = result.value; - const game = - tourny.games[tourny.currentRound % tourny.games.length]; - const date = new Date(); - date.setTime( - date.getTime() + tourny.timePerRound * 60 * 60 * 1000 - ); - for (let i = 0; i < tourny.players.length; i++) { - newRound( - client, - tournament, - tourny.players[i], - game, - tourny.currentRound, - date - ); - // created new rounds for all the players left + if (end) { + functions + .notifyPlayers(client, left, false, tournament) + .then(() => { + functions + .endTournament(client, tournament) + .then(() => { + resolve({ + active: false, + nextRound: false, + }); + }); + }); + } else if (result) { + //Tournament moves on to next round + let eligibleRounds = []; + for (let i = 0; i < rounds.length; i++) { + let round = rounds[i]; + if (round.hasPlayed === true) { + eligibleRounds.push(round); + } + } + //Here we find the rounds that were actually completed + for (let i = 0; i < eligibleRounds.length; i++) { + let round = eligibleRounds[i]; + functions.updateScore( + client, + round._id, + i + 1, + eligibleRounds.length + ); + //And here we update the tournament score + } + functions + .updateTournamentRound(client, tournament) + .then((result) => { + //updates the tournaments round if there are more rounds left + if (result.value) { + tourny = result.value; + const game = + tourny.games[ + tourny.currentRound % tourny.games.length + ]; + const date = new Date(); + date.setTime( + date.getTime() + + tourny.timePerRound * 24 * 60 * 60 * 1000 + ); + + functions + .newRound( + client, + tournament, + tourny.players, + game, + tourny.currentRound, + date + ) + .then(() => { + resolve({ + active: true, + nextRound: true, + }); + }); + // created new rounds for all the players left + } else { + // if the tournament now is done we simply end it + functions + .notifyPlayers(client, left, false, tournament) + .then(() => { + functions + .endTournament(client, tournament) + .then(() => { + resolve({ + active: false, + nextRound: false, + }); + }); + }); + } + }); + } else { + resolve({ + active: true, + nextRound: false, + }); // Tournament still waiting for other players } - res.json({ - active: true, - nextRound: true, - }); - client.close(); - return; - } else { - // if the tournament now is done we simply end it - endTournament(client, tournament); - notifyPlayers(client, left, false, tournament); - res.json({ - active: false, - nextRound: false, - }); - client.close(); - return; - } - }); - } else { - res.json({ - active: true, - nextRound: false, - }); - client.close(); // Tournament still waiting for other players + }); } - } - ); + ); }); - }); }); - } - ); -}); - -function endTournament(client, tournament) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - db.collection(collection).updateOne( - { _id: tournament }, - { $set: { active: false } }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - }); -} - -function notifyPlayers(client, players, timeout, tournament) { - const db = client.db("gameWare"); - for (let i = 0; i < players.length; i++) { - db.collection("alerts").insertOne({ - playerId: mongo.ObjectID(players[i]), - tournamentId: tournament, - timeout: timeout, }); - } -} - -function timeOut(client, tournament, players, end, rounds) { - if (!players) { - players = []; - } - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - db.collection("tournaments").updateOne( - { - _id: tournament, - }, - { - $pull: { players: { $in: players } }, - $inc: { currentPlayers: -players.length }, - $set: { active: !end }, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - db.collection("rounds").remove( - { - _id: { $in: rounds }, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - } - ); - }); -} - -function getCurrentRound(client, tournamentId) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - - db.collection(collection).findOne( - { - _id: tournamentId, - }, - { currentRound: 1, startTime: 1, maxPlayers: 1, active: 1 }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result); - return; - } - ); - }); -} - -function newRound( - client, - tournamentId, - playerId, - gameId, - roundNr, - deadlineDate -) { - return new Promise((resolve, reject) => { - // Using the database gameWare and collection rounds - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection(collection).insertOne( - { - tournamentId: mongo.ObjectID(tournamentId), - playerId: mongo.ObjectID(playerId), - gameId: mongo.ObjectID(gameId), - roundNr: roundNr, - deadlineDate: deadlineDate, - scoreValue: 0, - hasPlayed: false, - tournamentPoints: 0, - }, - (err, result) => { - if (err) { - resolve(500); // Internal server error - return; - } - resolve(result.ops[0]); - } - ); - }); -} - -function updateTournamentRound(client, tournament) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "tournaments"; - - db.collection(collection) - .findOneAndUpdate( - { - _id: tournament, - $expr: { - $lt: ["$currentRound", "$totalGames"], - }, - }, - { - $inc: { currentRound: 1 }, - }, - { - returnOriginal: false, - } - ) - .then((updatedDocument) => { - resolve(updatedDocument); - }); - }); -} - -function checkRounds(result, start, max, roundNr) { - return new Promise((resolve, reject) => { - let timedOut = []; - let timedOutRounds = []; - let left = []; - let amountComplete = 0; - for (let i = 0; i < result.length; i++) { - if (result[i].hasPlayed === true) { - amountComplete++; - left.push(result[i].playerId); - } else if (new Date(result[i].deadlineDate) <= new Date()) { - timedOut.push(result[i].playerId); - timedOutRounds.push(mongo.ObjectID(result[i]._id)); - } else { - left.push(result[i].playerId); - } - } - if (amountComplete == max) { - // All players have completed their round - resolve([true, [], left, []]); - } else if (amountComplete > 1 && new Date() >= start && roundNr == 1) { - // more than two have completed first round - // startDelay passed. - resolve([true, timedOut, left, timedOutRounds]); - } else if (amountComplete + timedOut.length == max && amountComplete >= 2) { - // More than two players have completed round and all players have either completed their round or timed out. - resolve([true, timedOut, left, timedOutRounds]); - } else { - resolve([false, timedOut, left, timedOutRounds]); - } - }); -} - -function fetchRounds(client, tournamentId, activeRound) { - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection("rounds") - .find({ - tournamentId: tournamentId, - roundNr: activeRound, - }) - .sort({ - scoreValue: -1, - }) - .toArray((err, result) => { - if (err) { - return; - } - resolve(result); - }); - }); -} - -function updateScore(client, id, placement, playerAmount) { - let tournamentPoints = (playerAmount - placement + 1) * 10; - - return new Promise((resolve, reject) => { - const db = client.db("gameWare"); - const collection = "rounds"; - - db.collection(collection) - .findOneAndUpdate( - { - _id: mongo.ObjectID(id), - }, - { $set: { tournamentPoints: tournamentPoints } }, - { returnNewDocument: true } - ) - .then((updatedDocument) => { - resolve(updatedDocument); - }); }); } diff --git a/frontend/android/assets/FruitSlicerBackground.png b/frontend/android/assets/FruitSlicerBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..aeb45918edf0eb4ef09fecb80217325aa7afd82c Binary files /dev/null and b/frontend/android/assets/FruitSlicerBackground.png differ diff --git a/frontend/android/assets/FruitSlicerPhotoEdit.png b/frontend/android/assets/FruitSlicerPhotoEdit.png new file mode 100644 index 0000000000000000000000000000000000000000..e2baec9e8f6bb4b5cfa93044aeae5dbe4b663480 Binary files /dev/null and b/frontend/android/assets/FruitSlicerPhotoEdit.png differ diff --git a/frontend/android/assets/FruitTexture1.png b/frontend/android/assets/FruitTexture1.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf6a1c1ae135cf6c3018b72eb05b38b75163f3c Binary files /dev/null and b/frontend/android/assets/FruitTexture1.png differ diff --git a/frontend/android/assets/FruitTexture10.png b/frontend/android/assets/FruitTexture10.png new file mode 100644 index 0000000000000000000000000000000000000000..7dffaa1c39329f5a4fae6df9f10fad0021c816d6 Binary files /dev/null and b/frontend/android/assets/FruitTexture10.png differ diff --git a/frontend/android/assets/FruitTexture11.png b/frontend/android/assets/FruitTexture11.png new file mode 100644 index 0000000000000000000000000000000000000000..d006233a48a6cbf19a7509cb22bf74b03556546f Binary files /dev/null and b/frontend/android/assets/FruitTexture11.png differ diff --git a/frontend/android/assets/FruitTexture12.png b/frontend/android/assets/FruitTexture12.png new file mode 100644 index 0000000000000000000000000000000000000000..78b3ecbd0d671af5182a13a679158d5bce80c67b Binary files /dev/null and b/frontend/android/assets/FruitTexture12.png differ diff --git a/frontend/android/assets/FruitTexture13.png b/frontend/android/assets/FruitTexture13.png new file mode 100644 index 0000000000000000000000000000000000000000..3646e13c25640ac0d756b2b1f6ca00eb07019548 Binary files /dev/null and b/frontend/android/assets/FruitTexture13.png differ diff --git a/frontend/android/assets/FruitTexture14.png b/frontend/android/assets/FruitTexture14.png new file mode 100644 index 0000000000000000000000000000000000000000..f3873a2977a798eba8b4f224d8374e1e0d5bc9fb Binary files /dev/null and b/frontend/android/assets/FruitTexture14.png differ diff --git a/frontend/android/assets/FruitTexture15.png b/frontend/android/assets/FruitTexture15.png new file mode 100644 index 0000000000000000000000000000000000000000..13d1277bd122dea580a8c519d3b140e4bec723a2 Binary files /dev/null and b/frontend/android/assets/FruitTexture15.png differ diff --git a/frontend/android/assets/FruitTexture16.png b/frontend/android/assets/FruitTexture16.png new file mode 100644 index 0000000000000000000000000000000000000000..b7edce403d2eec6121f4b540cb13072536a2d59f Binary files /dev/null and b/frontend/android/assets/FruitTexture16.png differ diff --git a/frontend/android/assets/FruitTexture17.png b/frontend/android/assets/FruitTexture17.png new file mode 100644 index 0000000000000000000000000000000000000000..6e99cf8e4feafe49b8a5bca438489a2bc7d8e5e8 Binary files /dev/null and b/frontend/android/assets/FruitTexture17.png differ diff --git a/frontend/android/assets/FruitTexture18.png b/frontend/android/assets/FruitTexture18.png new file mode 100644 index 0000000000000000000000000000000000000000..8bbc6c18d99ceea5edc31c8d518d277c921f9fc0 Binary files /dev/null and b/frontend/android/assets/FruitTexture18.png differ diff --git a/frontend/android/assets/FruitTexture19.png b/frontend/android/assets/FruitTexture19.png new file mode 100644 index 0000000000000000000000000000000000000000..29d7cbabcd915be4e4bfb68b1055824d80820001 Binary files /dev/null and b/frontend/android/assets/FruitTexture19.png differ diff --git a/frontend/android/assets/FruitTexture2.png b/frontend/android/assets/FruitTexture2.png new file mode 100644 index 0000000000000000000000000000000000000000..81f8fee9bde76bb5354b166c7ba6b83de82ba912 Binary files /dev/null and b/frontend/android/assets/FruitTexture2.png differ diff --git a/frontend/android/assets/FruitTexture20.png b/frontend/android/assets/FruitTexture20.png new file mode 100644 index 0000000000000000000000000000000000000000..ddeb3c07ef388c20b7ce096b14524e694ad45880 Binary files /dev/null and b/frontend/android/assets/FruitTexture20.png differ diff --git a/frontend/android/assets/FruitTexture3.png b/frontend/android/assets/FruitTexture3.png new file mode 100644 index 0000000000000000000000000000000000000000..73c164172ec4e457e290c93d1a209fbefda89532 Binary files /dev/null and b/frontend/android/assets/FruitTexture3.png differ diff --git a/frontend/android/assets/FruitTexture4.png b/frontend/android/assets/FruitTexture4.png new file mode 100644 index 0000000000000000000000000000000000000000..3b05385e113ef2715dc84b9f6957e832723bbc11 Binary files /dev/null and b/frontend/android/assets/FruitTexture4.png differ diff --git a/frontend/android/assets/FruitTexture5.png b/frontend/android/assets/FruitTexture5.png new file mode 100644 index 0000000000000000000000000000000000000000..e254e2f96dee2495ed5a71675c9af9c6aabd1aa6 Binary files /dev/null and b/frontend/android/assets/FruitTexture5.png differ diff --git a/frontend/android/assets/FruitTexture6.png b/frontend/android/assets/FruitTexture6.png new file mode 100644 index 0000000000000000000000000000000000000000..1f69686583226ab6ada554ea9b90fbe2eaf4d377 Binary files /dev/null and b/frontend/android/assets/FruitTexture6.png differ diff --git a/frontend/android/assets/FruitTexture7.png b/frontend/android/assets/FruitTexture7.png new file mode 100644 index 0000000000000000000000000000000000000000..d27047d841cf884933b610d67876cd22fe310a05 Binary files /dev/null and b/frontend/android/assets/FruitTexture7.png differ diff --git a/frontend/android/assets/FruitTexture8.png b/frontend/android/assets/FruitTexture8.png new file mode 100644 index 0000000000000000000000000000000000000000..884c52ff4359379a4cb08f3120d51aa321db05de Binary files /dev/null and b/frontend/android/assets/FruitTexture8.png differ diff --git a/frontend/android/assets/FruitTexture9.png b/frontend/android/assets/FruitTexture9.png new file mode 100644 index 0000000000000000000000000000000000000000..34395c2d34b8e9aaee6c2abe99bbcaf86c96df76 Binary files /dev/null and b/frontend/android/assets/FruitTexture9.png differ diff --git a/frontend/android/assets/sfx/FruitSlicerSquishSound.mp3 b/frontend/android/assets/sfx/FruitSlicerSquishSound.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..50b4128fd80e042af0e6f85265b7068ed3269d5b Binary files /dev/null and b/frontend/android/assets/sfx/FruitSlicerSquishSound.mp3 differ diff --git a/frontend/android/assets/sfx/FruitSlicerWhooshSound.mp3 b/frontend/android/assets/sfx/FruitSlicerWhooshSound.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d57dd2687c1d7614940b655e80a357add37c0107 Binary files /dev/null and b/frontend/android/assets/sfx/FruitSlicerWhooshSound.mp3 differ diff --git a/frontend/android/assets/sfx/small_click.ogg b/frontend/android/assets/sfx/small_click.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d5345267fc690b873c111d96ba4d17ebfcb6c049 Binary files /dev/null and b/frontend/android/assets/sfx/small_click.ogg differ diff --git a/frontend/android/assets/tableBG.png b/frontend/android/assets/tableBG.png new file mode 100644 index 0000000000000000000000000000000000000000..c63788c6cb611357c7f0663c0609b604ebcd3d05 Binary files /dev/null and b/frontend/android/assets/tableBG.png differ diff --git a/frontend/android/assets/tableBGRounded.png b/frontend/android/assets/tableBGRounded.png new file mode 100644 index 0000000000000000000000000000000000000000..f5076b1bb74e656a662e49c83acda133d18808dd Binary files /dev/null and b/frontend/android/assets/tableBGRounded.png differ diff --git a/frontend/core/src/com/gameware/game/GameWare.java b/frontend/core/src/com/gameware/game/GameWare.java index 0c6c0c42ea60b32f96753b88e1159f2907356bb8..6f2691d7925acd48e254a344a2814197e5950b97 100644 --- a/frontend/core/src/com/gameware/game/GameWare.java +++ b/frontend/core/src/com/gameware/game/GameWare.java @@ -13,11 +13,11 @@ import com.gameware.game.models.LocalStorage; import com.gameware.game.states.BubbleWrapState; import com.gameware.game.models.Player; import com.gameware.game.states.ColorRushState; +import com.gameware.game.states.FruitSlicerState; import com.gameware.game.states.GameStateManager; +import com.gameware.game.states.LoginState; import com.gameware.game.states.MenuState; import com.gameware.game.states.PlayStateTemplate; -import com.gameware.game.states.LoginState; - import java.io.IOException; import java.util.ArrayList; @@ -29,6 +29,7 @@ public class GameWare extends ApplicationAdapter { private SpriteBatch batch; private GameStateManager gsm; + private String fruitSlicerId = "5e90541aeba599f7b1bffceb"; private String colorRushId = "5e5d0efaa6e2bc5cb4920b7a"; private String bubbleWrapId = "5e5d0f1ea6e2bc5cb4920b7b"; @@ -67,8 +68,11 @@ public class GameWare extends ApplicationAdapter { } gsm = GameStateManager.getInstance(); + // Playable minigames + gameIdToPlayState.put(fruitSlicerId, new FruitSlicerState(gsm)); gameIdToPlayState.put(colorRushId, new ColorRushState(gsm)); gameIdToPlayState.put(bubbleWrapId, new BubbleWrapState(gsm)); + batch = new SpriteBatch(); music = Gdx.audio.newMusic(Gdx.files.internal(("bensound-goinghigher.mp3"))); @@ -84,7 +88,6 @@ public class GameWare extends ApplicationAdapter { gsm.push(new MenuState(gsm)); } if(musicOn){music.play();} - } @Override diff --git a/frontend/core/src/com/gameware/game/QueryIntermediate.java b/frontend/core/src/com/gameware/game/QueryIntermediate.java index 6e0fea4fd2f25a7c081b86e81779a9330acfce09..19205337c140fd44abd0072682d6020a9e53ed1a 100644 --- a/frontend/core/src/com/gameware/game/QueryIntermediate.java +++ b/frontend/core/src/com/gameware/game/QueryIntermediate.java @@ -341,14 +341,13 @@ public class QueryIntermediate { } // ---------------- Alert methods ---------------- - public static List<Alert> getAlertsForPlayer(String playerId) throws IOException, NoSuchElementException { + public static List<Alert> getAlertsForPlayer(String playerId) throws IOException { String route = "alerts/" + playerId; List<Alert> alerts = new ArrayList<>(); String[] response = sendGetRequest(route); checkStatusCode(response); JsonValue base = jsonReader.parse(response[1]); JsonValue.JsonIterator iterator = base.iterator(); - checkIteratorNotEmpty(iterator); while (iterator.hasNext()) { Alert alert = json.fromJson(Alert.class, iterator.next().toString()); alerts.add(alert); diff --git a/frontend/core/src/com/gameware/game/sprites/Fruit.java b/frontend/core/src/com/gameware/game/sprites/Fruit.java new file mode 100644 index 0000000000000000000000000000000000000000..6f23461d6e6d6c17f336a96b4554dabcaed60aa2 --- /dev/null +++ b/frontend/core/src/com/gameware/game/sprites/Fruit.java @@ -0,0 +1,176 @@ +package com.gameware.game.sprites; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Vector3; + + +public class Fruit extends Sprite { + private Vector3 cutPosition1; + private Vector3 cutPosition2; + + private Vector3 uncutVelocity; + private Vector3 cutVelocity1; + private Vector3 cutVelocity2; + + private int rotationSpeed; + private int cutWidth; + private int cutHeight; + + private float cuttingVelocity; + private float gravity; + + private boolean isCut; + + private com.badlogic.gdx.graphics.g2d.Sprite uncutFruit; + private com.badlogic.gdx.graphics.g2d.Sprite cutFruit1; + private com.badlogic.gdx.graphics.g2d.Sprite cutFruit2; + + public Fruit(int x, int y, int width, int height, Vector3 velocity, Texture uncutFruitTexture){ + this.position = new Vector3(x, y, 0); + this.cutPosition1 = new Vector3(0,0,0); + this.cutPosition2 = new Vector3(0,0,0); + + this.cuttingVelocity = Gdx.graphics.getWidth()/2; + this.gravity = Gdx.graphics.getWidth()/3; + + this.uncutVelocity = velocity; + this.cutVelocity1 = new Vector3(-this.cuttingVelocity,0,0); + this.cutVelocity2 = new Vector3(this.cuttingVelocity,0,0); + + this.rotationSpeed = (int) ((Math.random() - 0.5) * 1000); + this.width = width; + this.height = height; + this.cutWidth = width/2; + this.cutHeight = height; + + this.isCut = false; + + TextureRegion fullTexRegion = new TextureRegion(uncutFruitTexture); + + int regionCutWidth = fullTexRegion.getRegionWidth()/2; + int regionCutHeight = fullTexRegion.getRegionHeight(); + + TextureRegion leftTexRegion = new TextureRegion(fullTexRegion, 0,0, regionCutWidth, regionCutHeight); + TextureRegion rightTexRegion = new TextureRegion(fullTexRegion, regionCutWidth,0, regionCutWidth, regionCutHeight); + + this.uncutFruit = new com.badlogic.gdx.graphics.g2d.Sprite(fullTexRegion); + this.cutFruit1 = new com.badlogic.gdx.graphics.g2d.Sprite(leftTexRegion); + this.cutFruit2 = new com.badlogic.gdx.graphics.g2d.Sprite(rightTexRegion); + } + + + + + @Override + public void reset() { + + } + + @Override + public void draw(SpriteBatch sb) { + sb.begin(); + + if(this.isCut){ + this.cutFruit1.draw(sb); + this.cutFruit2.draw(sb); + } + + else{ + this.uncutFruit.draw(sb); + } + + sb.end(); + } + + @Override + public void update(float dt) { + if(this.isCut){ + // Updates the position of the two fruit pieces based on its velocity + + this.cutVelocity1.scl(dt); + this.cutVelocity2.scl(dt); + + this.cutPosition1.add(this.cutVelocity1.x, this.cutVelocity1.y, 0); + this.cutPosition2.add(this.cutVelocity2.x, this.cutVelocity2.y, 0); + + this.cutVelocity1.scl(1/dt); + this.cutVelocity2.scl(1/dt); + + // Sets the position of the two fruit pieces + this.cutFruit1.setPosition(this.cutPosition1.x, this.cutPosition1.y); + this.cutFruit2.setPosition(this.cutPosition2.x, this.cutPosition2.y); + + // Gravity affects the fruit pieces' velocity + this.cutVelocity1.y -= this.gravity*2*dt; + this.cutVelocity2.y -= this.gravity*2*dt; + + // Oppositely rotates the two pieces by a third of the original rotation speed + this.cutFruit1.rotate(this.rotationSpeed / 3*dt); + this.cutFruit2.rotate(-this.rotationSpeed / 3*dt); + } + + else{ + // Updates the position of the full fruit based on its velocity + this.uncutVelocity.scl(dt); + this.position.add(this.uncutVelocity.x, this.uncutVelocity.y, 0); + this.uncutVelocity.scl(1/dt); + + // Gravity affects the fruit's velocity + this.uncutVelocity.y -= this.gravity*dt; + + // Sets the full fruit's size, position and rotation + this.uncutFruit.setOriginCenter(); + this.uncutFruit.setSize(this.width, this.height); + this.uncutFruit.setPosition(this.position.x, this.position.y); + this.uncutFruit.rotate(this.rotationSpeed * dt); + } + } + + @Override + public void dispose() { + } + + public boolean isDisposable() { + // If the uncut fruit or the two cut fruit pieces have fallen this far in the y-direction, we know we can dispose it + return this.position.y < -this.height*3 || (this.cutPosition1.y < -this.height*3 && this.cutPosition2.y < -this.height*3); + } + + public boolean isPressed(int x, int y) { + // If the user touched the fruit + if(!this.isCut && x > this.position.x && x < (this.position.x + this.width) && (Gdx.graphics.getHeight() - y) > this.position.y && (Gdx.graphics.getHeight() - y) < (this.position.y + this.height)) { + this.isCut = true; + + // Updates the sprite positions + this.cutPosition1.x = this.position.x; + this.cutPosition1.y = this.position.y; + this.cutPosition2.x = this.position.x + this.cutWidth; + this.cutPosition2.y = this.position.y; + + // Rotates the two velocities so the two parts of the fruit are moving away from each other + this.cutVelocity1.rotate(this.uncutFruit.getRotation(), 0, 0, 1); + this.cutVelocity2.rotate(this.uncutFruit.getRotation(), 0, 0, 1); + + // The two pieces keeps 25% of the original full fruits' velocity + this.cutVelocity1.add((float)(this.uncutVelocity.x*0.25), (float)(this.uncutVelocity.y*0.25), 0); + this.cutVelocity2.add((float)(this.uncutVelocity.x*0.25), (float)(this.uncutVelocity.y*0.25), 0); + + // Sets the size + this.cutFruit1.setSize(this.cutWidth, this.cutHeight); + this.cutFruit2.setSize(this.cutWidth, this.cutHeight); + + // Sets the origin of rotation the same as the original full fruit + this.cutFruit1.setOrigin(cutWidth, cutHeight/2); + this.cutFruit2.setOrigin(0, cutHeight/2); + + // Rotates the fruit similar to the full fruit + this.cutFruit1.setRotation(this.uncutFruit.getRotation()); + this.cutFruit2.setRotation(this.uncutFruit.getRotation()); + + return true; + } + return false; + } +} diff --git a/frontend/core/src/com/gameware/game/states/CreateJoinTournamentState.java b/frontend/core/src/com/gameware/game/states/CreateJoinTournamentState.java index 719c2143e2d2cc9d33de4a17a13341fb6b68eba7..eb5650d95e643dd5f7f81aac8b903c96d7e57fae 100644 --- a/frontend/core/src/com/gameware/game/states/CreateJoinTournamentState.java +++ b/frontend/core/src/com/gameware/game/states/CreateJoinTournamentState.java @@ -18,6 +18,7 @@ import com.badlogic.gdx.utils.Scaling; import com.gameware.game.GameWare; import com.gameware.game.QueryIntermediate; import com.gameware.game.models.Round; +import com.gameware.game.models.RoundCheck; import com.gameware.game.models.Tournament; import com.gameware.game.sprites.LoadingText; @@ -54,7 +55,6 @@ public class CreateJoinTournamentState extends State { // Variables - private final int padding = 50; private Tournament tournamentTryingToLeave = null; private boolean includeFinishedTournaments = GameWare.getInstance().getIncludeFin(); private final Color scrollPaneBGColor = Color.SKY; @@ -138,8 +138,8 @@ public class CreateJoinTournamentState extends State { private Table createTournamentList(){ Table innerTable = new Table(); - innerTable.setBackground(makeColorBackground(scrollPaneBGColor)); - innerTable.defaults().space(spacingLittle); + innerTable.setBackground(backgroundTableBlueRounded); + innerTable.defaults().space(spacingLittle).expandY(); innerTable.pad(spacingLittle).padRight(spacingLittle); if(!tournaments.isEmpty()) { @@ -260,6 +260,7 @@ public class CreateJoinTournamentState extends State { this.joinButtonClicked = false; } + this.loadingText.update(dt); } @@ -314,11 +315,24 @@ public class CreateJoinTournamentState extends State { private void handleEnterBtnClick(Tournament t, Round r){ if(GameWare.getInstance().getSoundEffects()){ buttonPressSound.play(); } + if(!t.isActive()){ gsm.set(new FinishedTournamentState(gsm,t)); } else{ - gsm.set(new ViewTournamentState(gsm, t, r)); + RoundCheck rc = null; + try { + rc = QueryIntermediate.doRoundCheck(t.get_id()); + }catch(IOException e){ + e.printStackTrace(); + } + if(rc != null && !rc.isActive()){ + FinishedTournamentState s = new FinishedTournamentState(gsm, t); + s.makeDialogTimeOut(); + gsm.set(s); + } else { + gsm.set(new ViewTournamentState(gsm, t, r)); + } } } @@ -387,7 +401,7 @@ public class CreateJoinTournamentState extends State { void setFeedbackLabelText(String text){ tournamentFeedbackLabel.getColor().a = 1; tournamentFeedbackLabel.addAction(Actions.sequence( - new DelayAction(6), + new DelayAction(8), Actions.fadeOut(2))); tournamentFeedbackLabel.setText(text); } diff --git a/frontend/core/src/com/gameware/game/states/CreateNewTournamentState.java b/frontend/core/src/com/gameware/game/states/CreateNewTournamentState.java index bfdd91ad85614e182ab5954505c6a759b261dbd4..8346c96034b446605a582c59c4cb063ecfa45949 100644 --- a/frontend/core/src/com/gameware/game/states/CreateNewTournamentState.java +++ b/frontend/core/src/com/gameware/game/states/CreateNewTournamentState.java @@ -152,9 +152,13 @@ public class CreateNewTournamentState extends State { Table innerTable = new Table(); innerTable.pad(spacingLittle); innerTable.defaults().space(spacingLittle); - innerTable.setBackground(makeColorBackground(scrollPaneBGColor)); + innerTable.setBackground(backgroundTableBlueRounded); for (final Game g : games){ + if(GameWare.getInstance().getGameIdToPlayState().get(g.getId()) == null){ + continue; + } + innerTable.add(new Image(GameWare.getInstance().getGameIdToPlayState().get(g.getId()).screenshot)); Table innerInnerTable = new Table(); diff --git a/frontend/core/src/com/gameware/game/states/FinishedTournamentState.java b/frontend/core/src/com/gameware/game/states/FinishedTournamentState.java index d451925555c2f56004f5ade7f18069bafc900596..d2e0d322f6e9576da08a5ff933619d7b1870ce6c 100644 --- a/frontend/core/src/com/gameware/game/states/FinishedTournamentState.java +++ b/frontend/core/src/com/gameware/game/states/FinishedTournamentState.java @@ -34,12 +34,13 @@ public class FinishedTournamentState extends State { private final String leaveBtnText = "Leave"; private final String winnerText = "Winner: "; private final String leaveDialogText = "Are you sure want to\nleave "; + private final String dialogTimeOutText = "Tournament finished because\nplayers timed out or left"; // Variables - private final int padding = 50; private final Color scrollPaneBGColor = Color.GOLD; private Dialog dialog; + private Dialog dialogTimeOut; public FinishedTournamentState(GameStateManager gsm, Tournament tournament) { @@ -127,6 +128,13 @@ public class FinishedTournamentState extends State { dialog.button("No", false).pad(padding); //sends "false" as the result } + public void makeDialogTimeOut(){ + dialogTimeOut = new Dialog("", skin, "dialog"); + dialogTimeOut.text(dialogTimeOutText).pad(padding); + dialogTimeOut.button("Okay", false).pad(padding); //sends "false" as the result + dialogTimeOut.show(stage); + } + private TextButton makeBackBtn(){ TextButton backBtn = new TextButton(backBtnText, skin); backBtn.addListener(new ClickListener() { diff --git a/frontend/core/src/com/gameware/game/states/FruitSlicerState.java b/frontend/core/src/com/gameware/game/states/FruitSlicerState.java new file mode 100644 index 0000000000000000000000000000000000000000..9e5e0c4ab5f381b2f1b4acaa69820363888b4ae5 --- /dev/null +++ b/frontend/core/src/com/gameware/game/states/FruitSlicerState.java @@ -0,0 +1,223 @@ +package com.gameware.game.states; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.gameware.game.GameWare; +import com.gameware.game.sprites.Fruit; + +import java.util.ArrayList; +import java.util.List; + +public class FruitSlicerState extends PlayStateTemplate { + private float currentDuration = 0f; + private float totalDuration = 60f; + private float startingEmitFrequency = 1f; + private float endingEmitFrequency = 0.2f; + private float timeSinceLastEmit = 0; + private int totalFruitsCut = 0; + private BitmapFont font; + private Texture background = new Texture(Gdx.files.internal("FruitSlicerBackground.png")); + private List<Texture> fruitTextures; + private List<Fruit> emittedFruits; + private Sound sliceWhooshSound; + private Sound sliceSquishSound; + + private Fruit fruit; + + public FruitSlicerState(GameStateManager gsm) { + super(gsm); + super.setPauseButtonWhite(); + super.screenshot = new Texture(Gdx.files.internal("FruitSlicerPhotoEdit.png")); + + this.sliceWhooshSound = Gdx.audio.newSound(Gdx.files.internal("sfx/FruitSlicerWhooshSound.mp3")); + this.sliceSquishSound = Gdx.audio.newSound(Gdx.files.internal("sfx/FruitSlicerSquishSound.mp3")); + + this.fruitTextures = new ArrayList<>(); + this.emittedFruits = new ArrayList<>(); + + // Creates the bitmapfont + font = new BitmapFont(); + font.setColor(Color.WHITE); + font.getData().setScale(Gdx.graphics.getWidth()/ GameWare.WIDTH*2); + + for(int textureNum = 1; textureNum <= 20; textureNum++){ + String filename = "FruitTexture" + String.valueOf(textureNum) + ".png"; + this.fruitTextures.add(new Texture(Gdx.files.internal(filename))); + } + } + + @Override + public void handleInput(){ + if(Gdx.input.justTouched()) { + int touchX = Gdx.input.getX(); + int touchY = Gdx.input.getY(); + boolean didCut = false; + + for(Fruit fruit : this.emittedFruits){ + if(fruit.isPressed(touchX, touchY)){ + this.totalFruitsCut++; + didCut = true; + } + } + + if(didCut){ + this.sliceWhooshSound.play(); + this.sliceSquishSound.play(0.15f); + } + + super.setScore(this.totalFruitsCut); + } + } + + @Override + public void update(float dt){ + // Effectively updates the pause button and the loading text + super.update(dt); + + this.handleInput(); + + this.currentDuration += dt; + this.timeSinceLastEmit += dt; + + if(this.currentDuration > this.totalDuration){ + super.setGameFinished(); + } + + // Increases the emiting frequency towards the endingEmitFrequency as the game gets closer to the end + float currentFrequency = (float) (this.startingEmitFrequency - (this.startingEmitFrequency - this.endingEmitFrequency) * Math.min(this.currentDuration / (this.totalDuration * 0.6), 1)); + + // Emits a new fruit + if(this.timeSinceLastEmit > currentFrequency){ + this.emitNewFruit(); + this.timeSinceLastEmit = 0; + } + + for(Fruit fruit : this.emittedFruits){ + fruit.update(dt); + } + + // Removes the oldest fruit if it is disposable + if(this.emittedFruits.size() > 0 && this.emittedFruits.get(0).isDisposable()){ + this.emittedFruits.get(0).dispose(); + this.emittedFruits.remove(this.emittedFruits.get(0)); + } + } + + @Override + public void render(SpriteBatch sb){ + sb.begin(); + + // Background + sb.draw(this.background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + + sb.end(); + + // Fruits + for(Fruit fruit : this.emittedFruits){ + fruit.draw(sb); + } + + sb.begin(); + + // Time left + this.font.draw(sb, String.valueOf(Math.max(Math.round((this.totalDuration - this.currentDuration) * 100), 0.00) / 100.0), Gdx.graphics.getWidth()/40,Gdx.graphics.getHeight() - Gdx.graphics.getHeight()/40); + + sb.end(); + + //Effectively renders the pause button and the loading text + super.render(sb); + } + + @Override + public void dispose(){ + super.dispose(); + + this.background.dispose(); + this.font.dispose(); + this.sliceWhooshSound.dispose(); + this.sliceSquishSound.dispose(); + + for(Texture fruit : this.fruitTextures){ + fruit.dispose(); + } + } + + public void emitNewFruit() { + // Four different emit modes: from left, from right, from entire bottom, and from bottom center with different velocity angles + int emitMode = (int) (Math.random() * 4); + Fruit fruit; + Texture fruitTexture = this.fruitTextures.get((int) (Math.random() * 20)); + Vector3 velocity = new Vector3(Gdx.graphics.getWidth() * 3 / 4, 0, 0); + + int x, y, emitAngle, rotationSpeed; + + float fruitAspectRatio = Float.valueOf(fruitTexture.getWidth()) / Float.valueOf(fruitTexture.getHeight()); + int fruitWidth = Gdx.graphics.getWidth() / 5; + int fruitHeight = (int) (fruitWidth / fruitAspectRatio); + + // Emit from left + if (emitMode == 0){ + x = -fruitWidth * 2; + y = (int) (Math.random() * Gdx.graphics.getHeight() / 3); + emitAngle = (int) (15 + Math.random() * 60); + + velocity.rotate(emitAngle, 0, 0, 1); + + fruit = new Fruit(x, y, fruitWidth, fruitHeight, velocity, fruitTexture); + this.emittedFruits.add(fruit); + } + + // Emit from right + else if(emitMode == 1) { + x = Gdx.graphics.getWidth() + fruitWidth * 2; + y = (int) (Math.random() * Gdx.graphics.getHeight() / 3); + emitAngle = (int) (180 - (15 + Math.random() * 60)); + + velocity.rotate(emitAngle, 0, 0, 1); + + fruit = new Fruit(x, y, fruitWidth, fruitHeight, velocity, fruitTexture); + this.emittedFruits.add(fruit); + } + + // Emit from entire bottom part of the screen + else if(emitMode == 2){ + int xWidth = Gdx.graphics.getWidth() + fruitWidth * 2; + x = (int)(xWidth*Math.random()); + y = -fruitHeight*2; + float emitAngleOffset = 30 - 30 * (Float.valueOf(x) / Float.valueOf(xWidth)); + emitAngle = (int) (105 - emitAngleOffset); + + velocity.x = (int) (velocity.x * (1.1 + 0.5 * (15 - Math.abs(90 - Float.valueOf(emitAngle)))/15)); + velocity.rotate(emitAngle, 0, 0, 1); + + fruit = new Fruit(x - fruitWidth, y, fruitWidth, fruitHeight, velocity, fruitTexture); + this.emittedFruits.add(fruit); + } + + // Emit from bottom center, with random emit angles + else if(emitMode == 3){ + x = Gdx.graphics.getWidth()/2 + fruitWidth/2; + y = - fruitHeight*2; + emitAngle = (int) (100 - Math.random()*20); + + velocity.x = (int) (velocity.x * 1.4); + velocity.rotate(emitAngle, 0, 0, 1); + + fruit = new Fruit(x - fruitWidth, y, fruitWidth, fruitHeight, velocity, fruitTexture); + this.emittedFruits.add(fruit); + } + } + + @Override + public void reset(){ + this.currentDuration = 0f; + this.timeSinceLastEmit = 0f; + this.totalFruitsCut = 0; + this.emittedFruits = new ArrayList<>(); + } +} diff --git a/frontend/core/src/com/gameware/game/states/MenuState.java b/frontend/core/src/com/gameware/game/states/MenuState.java index 8927d79ec9397ac217eeac51341db9eb0628f3a1..f4461d4273a8914e3b7bb4e2a3369381c3a343b6 100644 --- a/frontend/core/src/com/gameware/game/states/MenuState.java +++ b/frontend/core/src/com/gameware/game/states/MenuState.java @@ -4,32 +4,57 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Dialog; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.gameware.game.GameWare; +import com.gameware.game.QueryIntermediate; +import com.gameware.game.models.Alert; +import com.gameware.game.models.Tournament; import com.gameware.game.sprites.LoadingText; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + public class MenuState extends State{ +// Data + private List<Alert> alerts = new ArrayList<>(); + // Labels private final Label titleLabel = new Label("GameWare", skin, "big"); private final Label subHeadLabel = new Label("Welcome "+ GameWare.getInstance().getPlayer().getName()+"!", skin, "big"); // Button texts - private final String singlePlayerBtnText = "Single player"; - private final String multiPlayerBtnText = "Multi player"; + private final String singlePlayerBtnText = "Single-Player"; + private final String multiPlayerBtnText = "Multiplayer"; private final String highScoreBtnText = "High Scores"; private final String optionBtnText = "Options"; private final String logOutBtnText = "Log out"; private boolean multiBtnClicked = false; private LoadingText loadingText = new LoadingText(); + private Dialog alertDialog; public MenuState(GameStateManager gsm) { super(gsm); + makeStage(); + + try{ + alerts = QueryIntermediate.getAlertsForPlayer(GameWare.getInstance().getPlayer().getId()); + if(!alerts.isEmpty()){ + QueryIntermediate.deleteAlertsForPlayer(GameWare.getInstance().getPlayer().getId()); + makeAlertDialog(alerts); + } + }catch(NoSuchElementException e){ + }catch (IOException e){ + e.printStackTrace(); + } } @@ -59,6 +84,20 @@ public class MenuState extends State{ } // Make widgets methods + + private void makeAlertDialog(List<Alert> alerts){ + alertDialog = new Dialog("", skin, "dialog") { + public void result(Object obj) { } + }; + String s = "Tournaments that finished:\n"; + for (Alert a : alerts){ + s += a.getTournamentId()+"\n"; + } + alertDialog.text(s).pad(padding); + alertDialog.button("Okay", true).pad(padding); //sends "true" as the result + alertDialog.show(stage); + } + private TextButton makeSinglePlayerBtn(){ TextButton singlePlayerBtn = new TextButton(singlePlayerBtnText, skin); singlePlayerBtn.addListener(new ClickListener() { diff --git a/frontend/core/src/com/gameware/game/states/PauseState.java b/frontend/core/src/com/gameware/game/states/PauseState.java index a1fa1d007b2c9a0a264e57c7b1293689f4b2f3a2..26e83ed633f5dc523899373ce8b405f27a2fcbca 100644 --- a/frontend/core/src/com/gameware/game/states/PauseState.java +++ b/frontend/core/src/com/gameware/game/states/PauseState.java @@ -66,6 +66,7 @@ public class PauseState extends State { if(this.needsConfirmation) { // User doesn't want to exit after all if(this.confirmationBox.noPressed(touchX, touchY)) { + if(GameWare.getInstance().getSoundEffects()){ pauseStateBtnSound.play(); } this.needsConfirmation = false; } @@ -87,6 +88,7 @@ public class PauseState extends State { // First step of exiting; user now needs to confirm the exit via the popup if(this.exitButton.isPressed(touchX, touchY)){ + if(GameWare.getInstance().getSoundEffects()){ pauseStateBtnSound.play(); } this.needsConfirmation = true; } } diff --git a/frontend/core/src/com/gameware/game/states/PlayStateTemplate.java b/frontend/core/src/com/gameware/game/states/PlayStateTemplate.java index 069e060559940f3eb678e8b877d5988d0ca2fc78..6b0056286db271d3ae21a6f2b151bd8ee53c1eb4 100644 --- a/frontend/core/src/com/gameware/game/states/PlayStateTemplate.java +++ b/frontend/core/src/com/gameware/game/states/PlayStateTemplate.java @@ -22,6 +22,7 @@ public abstract class PlayStateTemplate extends State { private Round round = null; private Tournament tournament = null; private Round updatedRound = null; + private RoundCheck roundCheck = null; private PauseButton pauseButton; private LoadingText loadingText = new LoadingText(); protected float totalGameTime = 30f; @@ -79,14 +80,10 @@ public abstract class PlayStateTemplate extends State { break; } } - RoundCheck rc = null; try { this.postScore(id); - //Add new instance of the game into the HashMap in GameWare GameWare.getInstance().updateGameMap(id, this.getClass().getConstructor(GameStateManager.class).newInstance(gsm)); - - rc = QueryIntermediate.doRoundCheck(tournament.get_id()); }catch(Exception e){ e.printStackTrace(); } @@ -94,7 +91,7 @@ public abstract class PlayStateTemplate extends State { if(round == null) { //Singleplayer gsm.set(new ScoreState(gsm, this.score, new SinglePlayerSelectGameState(gsm))); - } else if(!rc.isActive() || (updatedRound.getTournamentPoints() != 0 && updatedRound.getRoundNr() == tournament.getTotalGames())){ + } else if(!roundCheck.isActive() || (updatedRound.getTournamentPoints() != 0 && updatedRound.getRoundNr() == tournament.getTotalGames())){ //Tournament finished gsm.set(new ScoreState(gsm, this.score, new FinishedTournamentState(gsm, tournament))); } else{ @@ -123,6 +120,7 @@ public abstract class PlayStateTemplate extends State { } else{ List<ModelInterface> updatedRoundModels = QueryIntermediate.putRoundScore(round.get_id(),tournament.get_id(), this.score); updatedRound = (Round) updatedRoundModels.get(0); + roundCheck = (RoundCheck) updatedRoundModels.get(1); } } diff --git a/frontend/core/src/com/gameware/game/states/SinglePlayerSelectGameState.java b/frontend/core/src/com/gameware/game/states/SinglePlayerSelectGameState.java index fadaa86c33120880b73e610245996f98149baf2b..3449042b39ea6922ed98e7cf957cac411baa7fe7 100644 --- a/frontend/core/src/com/gameware/game/states/SinglePlayerSelectGameState.java +++ b/frontend/core/src/com/gameware/game/states/SinglePlayerSelectGameState.java @@ -74,7 +74,7 @@ public class SinglePlayerSelectGameState extends State { // Make widgets methods private Table makeInnerTable(){ Table innerTable = new Table(); - innerTable.setBackground(makeColorBackground(scrollPaneBGColor)); + innerTable.setBackground(backgroundTableBlueRounded); innerTable.columnDefaults(0).spaceRight(spacingLittle); if(games.size()==0){ @@ -82,6 +82,9 @@ public class SinglePlayerSelectGameState extends State { innerTable.add(noGamesLabel).pad(padding); }else { for (Game g : games) { + if(GameWare.getInstance().getGameIdToPlayState().get(g.getId()) == null){ + continue; + } innerTable.add(new Image(GameWare.getInstance().getGameIdToPlayState().get(g.getId()).screenshot)).width(imageWidthAndHeigh).height(imageWidthAndHeigh).pad(spacingLittle); Table innerInnerTable = new Table(); diff --git a/frontend/core/src/com/gameware/game/states/State.java b/frontend/core/src/com/gameware/game/states/State.java index 5cdb709838a1dba973aa70e16f1196f1ba7e8f33..1ba092a55dba1a37ac51445e2f3680e5a9a442a5 100644 --- a/frontend/core/src/com/gameware/game/states/State.java +++ b/frontend/core/src/com/gameware/game/states/State.java @@ -47,11 +47,13 @@ public abstract class State { protected TextureRegionDrawable backgroundScore = new TextureRegionDrawable(new TextureRegion(new Texture("bg_score.jpg"))); // protected TextureRegionDrawable buttonDisabledDrawable = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("glassy/raw/button-disabled.png")))); protected TextureRegionDrawable backgroundFinTourn = new TextureRegionDrawable(new TextureRegion(new Texture("bg1_finTourn.jpg"))); + protected TextureRegionDrawable backgroundTableBlueRounded = new TextureRegionDrawable(new TextureRegion(new Texture("tableBGRounded.png"))); // Sound Effects protected Sound buttonPressSound; protected Sound checkBoxSound; protected Sound pauseResumeBtnSound; + protected Sound pauseStateBtnSound; // Variables private boolean firstTimeRunningUpdate = true; @@ -63,7 +65,7 @@ public abstract class State { this.buttonPressSound = Gdx.audio.newSound(Gdx.files.internal("sfx/button_press.ogg")); this.checkBoxSound = Gdx.audio.newSound(Gdx.files.internal("sfx/check_box.ogg")); this.pauseResumeBtnSound = Gdx.audio.newSound(Gdx.files.internal("sfx/pause_button.ogg")); - + this.pauseStateBtnSound = Gdx.audio.newSound(Gdx.files.internal("sfx/small_click.ogg")); Gdx.input.setInputProcessor(stage); } diff --git a/frontend/core/src/com/gameware/game/states/TournamentHighScoreState.java b/frontend/core/src/com/gameware/game/states/TournamentHighScoreState.java index 727904b6cce9b7a58b765aa48fe55f63a086fd96..8e5d2dab7c31423db27769047c7f145bfa1f782b 100644 --- a/frontend/core/src/com/gameware/game/states/TournamentHighScoreState.java +++ b/frontend/core/src/com/gameware/game/states/TournamentHighScoreState.java @@ -76,7 +76,7 @@ public class TournamentHighScoreState extends State{ Table innerTable = new Table(); innerTable.pad(padding); innerTable.defaults().space(spacingLittle); - innerTable.setBackground(makeColorBackground(scrollPaneBGColor)); + innerTable.setBackground(backgroundTableBlueRounded); innerTable.add(colOneLabel).expandX(); innerTable.add(colTwoLabel).expandX(); diff --git a/frontend/core/src/com/gameware/game/states/ViewHighScoreForGameState.java b/frontend/core/src/com/gameware/game/states/ViewHighScoreForGameState.java index d31661ecf3536f915d7f86e7f8b8ce444743bad0..252427ac4c08283ccf51a516128bd45cf386fd7b 100644 --- a/frontend/core/src/com/gameware/game/states/ViewHighScoreForGameState.java +++ b/frontend/core/src/com/gameware/game/states/ViewHighScoreForGameState.java @@ -82,7 +82,7 @@ public class ViewHighScoreForGameState extends State { rootTable.row(); Table secondInnerTable = new Table(); - secondInnerTable.setBackground(makeColorBackground(Color.SKY)); + secondInnerTable.setBackground(backgroundTableBlueRounded); secondInnerTable.add(playerLabel).spaceTop(spacingLittle).pad(padding); secondInnerTable.add(playerScoreLabel).spaceTop(spacingLittle).pad(padding); @@ -109,7 +109,7 @@ public class ViewHighScoreForGameState extends State { private Table createHighScoreList() { Table innerTable = new Table(); - innerTable.setBackground(makeColorBackground(Color.SKY)); + innerTable.setBackground(backgroundTableBlueRounded); innerTable.defaults().spaceRight(spacingLittle); if(isNoHS){ diff --git a/frontend/core/src/com/gameware/game/states/ViewHighScoreState.java b/frontend/core/src/com/gameware/game/states/ViewHighScoreState.java index 9fb7bf698b7ab6f0dcf3f060d14c96c02b765043..2eab3b0b21a3a414a1e2df1d18d84a788a5ba792 100644 --- a/frontend/core/src/com/gameware/game/states/ViewHighScoreState.java +++ b/frontend/core/src/com/gameware/game/states/ViewHighScoreState.java @@ -85,13 +85,16 @@ public class ViewHighScoreState extends State { // Make widgets methods private Table makeInnerTable(){ Table innerTable = new Table(); - innerTable.setBackground(makeColorBackground(scrollPaneBGColor)); + innerTable.setBackground(backgroundTableBlueRounded); if(games.size()==0){ // If the try failed, and no games found innerTable.add(noGamesLabel).pad(padding); }else { for (Game g : games) { + if(GameWare.getInstance().getGameIdToPlayState().get(g.getId()) == null){ + continue; + } innerTable.add(new Image(GameWare.getInstance().getGameIdToPlayState().get(g.getId()).screenshot)).width(imageWidthAndHeigh).height(imageWidthAndHeigh).pad(spacingLittle); Table innerInnerTable = new Table(); diff --git a/frontend/core/src/com/gameware/game/states/ViewTournamentState.java b/frontend/core/src/com/gameware/game/states/ViewTournamentState.java index 3ff31c4b016428345d768316b9f68f6a5a75877f..ff5772ce147d676a860657793176fbaf8626581a 100644 --- a/frontend/core/src/com/gameware/game/states/ViewTournamentState.java +++ b/frontend/core/src/com/gameware/game/states/ViewTournamentState.java @@ -16,9 +16,12 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.gameware.game.GameWare; import com.gameware.game.QueryIntermediate; import com.gameware.game.models.Round; +import com.gameware.game.models.RoundCheck; import com.gameware.game.models.Tournament; import com.gameware.game.sprites.LoadingText; +import java.io.IOException; + public class ViewTournamentState extends State { // Data @@ -28,6 +31,7 @@ public class ViewTournamentState extends State { // Labels private Label disabledPlayBtnFeedback = new Label("Waiting for other players to finish", skin, "big"); private Label titleLabel = new Label("N/A", skin, "big"); + private Label roundDeadline = new Label("N/A", skin, "big"); // Texts private final String backBtnText = "Back"; @@ -39,7 +43,6 @@ public class ViewTournamentState extends State { private final String leaveDialogText = "Are you sure want to\nleave "; // Variables - private final int padding = 50; private final float playBtnWidth = buttonWidth*1.4f; private final float playBtnHeight = buttonHeight*1.2f; @@ -57,6 +60,7 @@ public class ViewTournamentState extends State { this.tournament = tournament; this.round = r; titleLabel.setText(tournament.getName()); + roundDeadline.setText("Round deadline\n"+round.getDeadlineDate().toLocaleString()); makeStage(); } @@ -65,24 +69,24 @@ public class ViewTournamentState extends State { Table rootTable = makeRootTable(); titleLabel.setFontScale(titleFontBigScale); - rootTable.add(titleLabel).expandY().top(); + rootTable.add(titleLabel).expandY().top().colspan(2); rootTable.row(); disabledPlayBtnFeedback.getColor().a = 0; - rootTable.add(disabledPlayBtnFeedback); + rootTable.add(disabledPlayBtnFeedback).colspan(2); rootTable.row(); - rootTable.add(makePlayBtn()).size(playBtnWidth, playBtnHeight); + rootTable.add(makePlayBtn()).size(playBtnWidth, playBtnHeight).colspan(2); rootTable.row(); PlayStateTemplate state = GameWare.getInstance().getGameIdToPlayState().get(round.getGameId()); - rootTable.add(new Image(state.screenshot)).spaceBottom(spacingMedium); + rootTable.add(new Image(state.screenshot)).spaceBottom(spacingMedium).colspan(2); rootTable.row(); - rootTable.add(new Label(nrPlayersText+" "+tournament.getPlayers().size(), skin)); + rootTable.add(new Label(nrPlayersText+" "+tournament.getCurrentPlayers(), skin)).colspan(2); rootTable.row(); - rootTable.add(new Label(roundsLeftText+" "+((tournament.getRoundsPerGame()*tournament.getGames().size())-tournament.getCurrentRound()+1), skin)); + rootTable.add(new Label(roundsLeftText+" "+((tournament.getRoundsPerGame()*tournament.getGames().size())-tournament.getCurrentRound()+1), skin)).colspan(2); rootTable.row(); Table innerTable = new Table(); @@ -90,10 +94,13 @@ public class ViewTournamentState extends State { leaveBtn.addListener(new LeaveClickListener()); innerTable.add(leaveBtn).size(buttonWidth, buttonHeight).spaceRight(spacingLittle); innerTable.add(makeViewPointsBtn()).size(buttonWidth, buttonHeight); - rootTable.add(innerTable); + + rootTable.add(innerTable).colspan(2); rootTable.row(); rootTable.add(makeBackBtn()).expand().bottom().left(); + roundDeadline.setFontScale(0.8f); + rootTable.add(roundDeadline).expand().bottom().right(); stage.addActor(rootTable); makeDialog(); @@ -236,10 +243,23 @@ public class ViewTournamentState extends State { private void handlePlayBtnClick(){ if(GameWare.getInstance().getSoundEffects()){ buttonPressSound.play(); } - PlayStateTemplate state = GameWare.getInstance().getGameIdToPlayState().get(round.getGameId()); - state.setTournament(tournament); - state.setRound(round); - gsm.set(state); + + RoundCheck rc = null; + try { + rc = QueryIntermediate.doRoundCheck(tournament.get_id()); + }catch(IOException e){ + e.printStackTrace(); + } + if(rc != null && !rc.isActive()){ + FinishedTournamentState s = new FinishedTournamentState(gsm, tournament); + s.makeDialogTimeOut(); + gsm.set(s); + } else { + PlayStateTemplate state = GameWare.getInstance().getGameIdToPlayState().get(round.getGameId()); + state.setTournament(tournament); + state.setRound(round); + gsm.set(state); + } } private void handleViewPointsBtnClick(){