Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
784037de6f | ||
|
|
6f27450423 | ||
|
|
bbaa2fe1eb | ||
|
|
28165d76d3 | ||
|
|
1c1e5f051d | ||
|
|
283c214c50 | ||
|
|
7970927654 | ||
|
|
567602c749 | ||
|
|
a5238234d2 | ||
|
|
c965713c9c | ||
|
|
b00fe4ebe3 | ||
|
|
599d8bf153 | ||
|
|
636c47366a | ||
|
|
4520d11559 | ||
|
|
5f0b639fe7 | ||
|
|
d4a279d2f4 | ||
|
|
aadeda05af | ||
|
|
b78d564f6f | ||
|
|
c02f595606 | ||
|
|
54bc9c31db
|
No files matched your search
@@ -20,3 +20,4 @@ MULTI_INTERNAL_HOST=multi
|
||||
MULTI_INTERNAL_PORT=5000
|
||||
MULTI_WS_URL=mapguesser-dev.ch:8090
|
||||
MULTI_WS_PORT=8090
|
||||
ENABLE_GAME_FOR_GUESTS=0
|
||||
@@ -168,6 +168,43 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#highscoresTable {
|
||||
margin: 1em;
|
||||
border-collapse: collapse;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#highscoresTable td, #highscoresTable th {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#highscoresTable tr:nth-child(even) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
#highscoresTable tr:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
#highscoresTable th {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
text-align: left;
|
||||
background-color: #e8a349;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#highscoresTable tr.ownPlayer {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 899px) {
|
||||
.hideOnNarrowScreen {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 599px) {
|
||||
#mapName {
|
||||
display: none;
|
||||
|
||||
@@ -31,11 +31,11 @@ main {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
p, h1, h2, input, textarea, select, button, a {
|
||||
p, h1, h2, h3, input, textarea, select, button, a, table, label {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
h1, h2, h3 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,11 @@ h2, header.small h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
p, h2 {
|
||||
h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
p, h2, h3 {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,16 +75,6 @@ div.mapItem>div.buttonContainer {
|
||||
grid-auto-flow: column;
|
||||
}
|
||||
|
||||
#restrictions {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
#restrictions h3 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#restrictions input {
|
||||
height: auto;
|
||||
margin: 0.5em;
|
||||
@@ -93,6 +83,7 @@ div.mapItem>div.buttonContainer {
|
||||
#restrictions input[type=range] {
|
||||
height: 1.5em;
|
||||
margin-left: 2em;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#timeLimitType {
|
||||
|
||||
+156
-15
@@ -296,7 +296,10 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
Game.loadHistory(this.response.history);
|
||||
Game.loadHistory(this.response);
|
||||
|
||||
Game.restrictions = this.response.restrictions;
|
||||
Game.displayRestrictions();
|
||||
|
||||
if (this.response.finished) {
|
||||
|
||||
@@ -305,8 +308,6 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
|
||||
} else {
|
||||
|
||||
Game.restrictions = this.response.restrictions;
|
||||
|
||||
Game.panoId = this.response.place.panoId;
|
||||
Game.pov = this.response.place.pov;
|
||||
|
||||
@@ -334,13 +335,57 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
}
|
||||
|
||||
if (Game.restrictions.timeLimit) {
|
||||
Game.startCountdown(Game.restrictions.timeLimit, function() {
|
||||
Game.startCountdown(Game.restrictions.timeLimit, function () {
|
||||
Game.guess();
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
displayRestrictions: function () {
|
||||
if (!Game.restrictions) {
|
||||
return;
|
||||
}
|
||||
|
||||
var restrictionsForDisplay = [];
|
||||
if (Game.restrictions.timeLimit) {
|
||||
restrictionsForDisplay.push('time limit per ' + Game.restrictions.timeLimitType);
|
||||
}
|
||||
if (Game.restrictions.noPan) {
|
||||
restrictionsForDisplay.push('no camera change');
|
||||
}
|
||||
else {
|
||||
if (Game.restrictions.noMove) {
|
||||
restrictionsForDisplay.push('no move');
|
||||
}
|
||||
if (Game.restrictions.noZoom) {
|
||||
restrictionsForDisplay.push('no zoom');
|
||||
}
|
||||
}
|
||||
|
||||
if (restrictionsForDisplay.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create restrictions span for header
|
||||
var restrictions = document.createElement('span');
|
||||
restrictions.setAttribute('id', 'restrictions');
|
||||
restrictions.setAttribute('class', 'hideOnNarrowScreen');
|
||||
var restrictionsTitle = document.createElement('span');
|
||||
restrictionsTitle.setAttribute('class', 'bold');
|
||||
restrictionsTitle.innerText = 'Restrictions: ';
|
||||
var restrictionsList = document.createElement('span');
|
||||
restrictionsList.innerText = restrictionsForDisplay.join(', ');
|
||||
restrictions.appendChild(restrictionsTitle);
|
||||
restrictions.appendChild(restrictionsList);
|
||||
|
||||
var roundContainer = document.getElementById('roundContainer');
|
||||
var header = roundContainer.parentNode;
|
||||
header.insertBefore(restrictions, roundContainer);
|
||||
},
|
||||
|
||||
disableRestrictions: function () {
|
||||
|
||||
Game.panorama.setOptions({
|
||||
clickToGo: true,
|
||||
linksControl: true,
|
||||
@@ -350,6 +395,15 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
document.getElementById('panningBlockerCover').style.display = null;
|
||||
|
||||
Game.startCountdown(0);
|
||||
Game.timeoutEnd = null;
|
||||
},
|
||||
|
||||
hideRestrictions: function () {
|
||||
var restrictions = document.getElementById('restrictions');
|
||||
if (restrictions) {
|
||||
var header = restrictions.parentNode;
|
||||
header.removeChild(restrictions);
|
||||
}
|
||||
},
|
||||
|
||||
transitToResultMap: function () {
|
||||
@@ -387,11 +441,11 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
}
|
||||
},
|
||||
|
||||
loadHistory: function (history) {
|
||||
if (!history)
|
||||
loadHistory: function (response) {
|
||||
if (!response.history)
|
||||
return;
|
||||
|
||||
Game.history = history;
|
||||
Game.history = response.history;
|
||||
|
||||
for (var i = 0; i < Game.rounds.length; ++i) {
|
||||
var round = Game.rounds[i];
|
||||
@@ -410,6 +464,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
}
|
||||
Game.rounds = [];
|
||||
|
||||
Game.scoreSum = 0;
|
||||
for (var i = 0; i < Game.history.length; ++i) {
|
||||
var round = Game.history[i];
|
||||
|
||||
@@ -417,7 +472,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
|
||||
Game.addPositionToResultMap(true);
|
||||
if (round.result.guessPosition) {
|
||||
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
|
||||
Game.addGuessPositionToResultMap(round.result.guessPosition, round.result, true);
|
||||
}
|
||||
Game.scoreSum += round.result.score;
|
||||
|
||||
@@ -463,6 +518,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
distanceInfo.children[0].style.display = null;
|
||||
distanceInfo.children[1].style.display = null;
|
||||
distanceInfo.children[2].style.display = null;
|
||||
document.getElementById('summaryInfo').innerHTML = "Game finished."
|
||||
var scoreInfo = document.getElementById('scoreInfo');
|
||||
scoreInfo.children[0].style.display = null;
|
||||
scoreInfo.children[1].style.display = null;
|
||||
@@ -478,9 +534,12 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
document.getElementById("navigation").style.visibility = 'visible';
|
||||
|
||||
Game.disableRestrictions();
|
||||
Game.hideRestrictions();
|
||||
|
||||
document.getElementById('panningBlockerCover').style.display = null;
|
||||
|
||||
Game.history = [];
|
||||
|
||||
Game.initialize();
|
||||
},
|
||||
|
||||
@@ -589,7 +648,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
resultBounds.extend(position);
|
||||
|
||||
if (guessPosition) {
|
||||
Game.addGuessPositionToResultMap(guessPosition);
|
||||
Game.addGuessPositionToResultMap(guessPosition, result);
|
||||
resultBounds.extend(guessPosition);
|
||||
}
|
||||
|
||||
@@ -649,11 +708,16 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
},
|
||||
|
||||
guess: function () {
|
||||
|
||||
Game.disableRestrictions();
|
||||
|
||||
var data = new FormData();
|
||||
|
||||
if (Game.timeoutEnd) {
|
||||
var timeLeft = Math.ceil((Game.timeoutEnd - new Date()) / 1000);
|
||||
data.append('timeLeft', timeLeft);
|
||||
}
|
||||
|
||||
Game.disableRestrictions();
|
||||
|
||||
if (Game.guessMarker) {
|
||||
var guessPosition = Game.guessMarker.getPosition().toJSON();
|
||||
Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition;
|
||||
@@ -675,7 +739,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
Game.history = this.response.history;
|
||||
Game.loadHistory(this.response);
|
||||
Game.restrictions = this.response.restrictions;
|
||||
|
||||
Game.receiveResult(this.response.position, guessPosition, this.response.result, this.response.allResults);
|
||||
@@ -718,8 +782,8 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
var position = round.position;
|
||||
|
||||
var guessMarker = { marker: null, line: null, info: null };
|
||||
var markerSvg = result ? 'marker-gray-empty.svg' : 'marker-blue-empty.svg';
|
||||
var markerLabel = result ? result.userName.charAt(0).toUpperCase() : '?';
|
||||
var markerSvg = result && result.userName ? 'marker-gray-empty.svg' : 'marker-blue-empty.svg';
|
||||
var markerLabel = result && result.userName ? result.userName.charAt(0).toUpperCase() : '?';
|
||||
|
||||
guessMarker.marker = new google.maps.Marker({
|
||||
map: Game.map,
|
||||
@@ -769,8 +833,9 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const userName = result.userName ? result.userName : 'me';
|
||||
guessMarker.info = new google.maps.InfoWindow({
|
||||
content: '<p class="small bold">' + result.userName + '</p>' +
|
||||
content: '<p class="small bold">' + userName + '</p>' +
|
||||
'<p class="small">' + Util.printDistanceForHuman(result.distance) + ' | ' + result.score + ' points</p>',
|
||||
});
|
||||
|
||||
@@ -797,6 +862,36 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
return { width: percent + '%', backgroundColor: color };
|
||||
},
|
||||
|
||||
calculateHighScores: function () {
|
||||
|
||||
var highscores = new Map();
|
||||
highscores.set('me', Game.scoreSum);
|
||||
|
||||
// collect the results of users who are through the last round
|
||||
const round = Game.history[Game.history.length - 1];
|
||||
if (round.allResults) {
|
||||
for (const result of round.allResults) {
|
||||
highscores.set(result.userName, result.score);
|
||||
}
|
||||
}
|
||||
|
||||
// add up scores only for the finishers
|
||||
for (var i = Game.history.length - 2; i >= 0; --i) {
|
||||
const round = Game.history[i];
|
||||
if (round.allResults) {
|
||||
for (const result of round.allResults) {
|
||||
if (highscores.has(result.userName)) {
|
||||
highscores.set(result.userName, highscores.get(result.userName) + result.score);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sortedHighscores = Array.from(highscores, ([userName, score]) => ({ 'userName': userName, 'score': score }))
|
||||
.sort(function (resultA, resultB) { return resultB.score - resultA.score });
|
||||
return sortedHighscores;
|
||||
},
|
||||
|
||||
showSummary: function () {
|
||||
var distanceInfo = document.getElementById('distanceInfo');
|
||||
distanceInfo.children[0].style.display = 'none';
|
||||
@@ -856,6 +951,48 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
var scoreBar = document.getElementById('scoreBar');
|
||||
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
|
||||
scoreBar.style.width = scoreBarProperties.width;
|
||||
|
||||
Game.showHighscores();
|
||||
|
||||
},
|
||||
|
||||
showHighscores: function () {
|
||||
|
||||
if (Game.type == GameType.CHALLENGE) {
|
||||
var highscores = this.calculateHighScores();
|
||||
var summaryInfo = document.getElementById('summaryInfo');
|
||||
|
||||
if (highscores.length > 2) {
|
||||
var table = document.getElementById('highscoresTable');
|
||||
for (const result of highscores) {
|
||||
var userName = document.createElement('td');
|
||||
userName.innerHTML = result.userName;
|
||||
var score = document.createElement('td');
|
||||
score.innerHTML = result.score;
|
||||
var line = document.createElement('tr');
|
||||
line.appendChild(userName);
|
||||
line.appendChild(score);
|
||||
table.appendChild(line);
|
||||
|
||||
if (result.userName === 'me') {
|
||||
line.setAttribute('class', 'ownPlayer');
|
||||
}
|
||||
}
|
||||
|
||||
MapGuesser.showModal('highscores');
|
||||
} else if (highscores.length == 2) {
|
||||
|
||||
if (highscores[0].userName === 'me') {
|
||||
summaryInfo.innerHTML = 'You won! <span class="hideOnNarrowScreen">' + highscores[1].userName + ' got only ' + highscores[1].score + ' points.</span>';
|
||||
} else {
|
||||
summaryInfo.innerHTML = 'You lost! <span class="hideOnNarrowScreen">' + highscores[0].userName + ' won with ' + highscores[0].score + ' points.</span>';
|
||||
}
|
||||
|
||||
} else if (highscores.length == 1) {
|
||||
summaryInfo.innerHTML = 'You are the first to finish. <span class="hideOnNarrowScreen">Invite your friends by sending them the link.</span>'
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
rewriteGoogleLink: function () {
|
||||
@@ -1103,4 +1240,8 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
||||
document.getElementById('compassContainer').onclick = function () {
|
||||
Game.panorama.setPov({ heading: 0, pitch: Game.panorama.getPov().pitch });
|
||||
}
|
||||
|
||||
document.getElementById('closeHighscoresButton').onclick = function () {
|
||||
MapGuesser.hideModal();
|
||||
};
|
||||
})();
|
||||
@@ -65,6 +65,32 @@
|
||||
}
|
||||
};
|
||||
|
||||
var Util = {
|
||||
printTimeForHuman: function (time) {
|
||||
const minutes = Math.floor(time / 60);
|
||||
const seconds = time % 60;
|
||||
var time_str = '';
|
||||
|
||||
if (minutes == 1) {
|
||||
time_str += '1 minute';
|
||||
} else if (minutes > 1) {
|
||||
time_str += minutes + ' minutes';
|
||||
}
|
||||
|
||||
if (minutes > 0 && seconds > 0) {
|
||||
time_str += ' and ';
|
||||
}
|
||||
|
||||
if (seconds == 1) {
|
||||
time_str += '1 second';
|
||||
} else if (seconds > 1) {
|
||||
time_str += seconds + ' seconds';
|
||||
}
|
||||
|
||||
return time_str;
|
||||
}
|
||||
};
|
||||
|
||||
Maps.addStaticMaps();
|
||||
|
||||
Maps.initializeDescriptionDivs();
|
||||
@@ -119,7 +145,7 @@
|
||||
document.getElementById('playMode').style.visibility = 'hidden';
|
||||
|
||||
var timeLimit = document.getElementById('timeLimit').value;
|
||||
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + timeLimit + ' seconds per round';
|
||||
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + Util.printTimeForHuman(timeLimit);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,7 +175,7 @@
|
||||
|
||||
document.getElementById('timeLimit').oninput = function () {
|
||||
var timeLimit = document.getElementById('timeLimit').value;
|
||||
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + timeLimit + ' seconds per round';
|
||||
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + Util.printTimeForHuman(timeLimit);
|
||||
document.getElementById('timerEnabled').checked = true;
|
||||
}
|
||||
})();
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use DateTime;
|
||||
use Faker\Factory;
|
||||
use MapGuesser\Interfaces\Authorization\ISecured;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
@@ -20,7 +21,7 @@ use MapGuesser\Repository\PlaceRepository;
|
||||
use MapGuesser\Repository\UserInChallengeRepository;
|
||||
use MapGuesser\Response\Redirect;
|
||||
|
||||
class GameController
|
||||
class GameController implements ISecured
|
||||
{
|
||||
const NUMBER_OF_ROUNDS = 5;
|
||||
|
||||
@@ -52,6 +53,11 @@ class GameController
|
||||
$this->userInChallengeRepository = new UserInChallengeRepository();
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return !empty($_ENV['ENABLE_GAME_FOR_GUESTS']) || $this->request->user() !== null;
|
||||
}
|
||||
|
||||
public function getGame(): IContent
|
||||
{
|
||||
$mapId = (int) $this->request->query('mapId');
|
||||
@@ -106,11 +112,10 @@ class GameController
|
||||
public function createNewChallenge(): IContent
|
||||
{
|
||||
// create Challenge
|
||||
$challengeToken = rand();
|
||||
while ($this->challengeRepository->getByToken($challengeToken)) {
|
||||
// if a challenge with the same token already exists
|
||||
$challengeToken = rand();
|
||||
}
|
||||
do {
|
||||
// initiliaze or if a challenge with the same token already exists
|
||||
$challengeToken = mt_rand();
|
||||
} while ($this->challengeRepository->getByToken($challengeToken));
|
||||
|
||||
$challenge = new Challenge();
|
||||
$challenge->setToken($challengeToken);
|
||||
@@ -202,7 +207,7 @@ class GameController
|
||||
|
||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
||||
|
||||
if(!isset($room)) {
|
||||
if (!isset($room)) {
|
||||
return new JsonContent(['error' => 'game_not_found']);
|
||||
}
|
||||
|
||||
@@ -259,7 +264,7 @@ class GameController
|
||||
return new JsonContent(['error' => 'game_not_found']);
|
||||
}
|
||||
|
||||
if(!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) {
|
||||
if (!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) {
|
||||
// new player is joining
|
||||
$userInChallenge = new UserInChallenge();
|
||||
$userInChallenge->setUserId($userId);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use DateTime;
|
||||
use MapGuesser\Interfaces\Authorization\ISecured;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Util\Geo\Position;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
@@ -24,7 +25,7 @@ use MapGuesser\Repository\UserInChallengeRepository;
|
||||
use MapGuesser\Repository\UserPlayedPlaceRepository;
|
||||
use MapGuesser\Repository\UserRepository;
|
||||
|
||||
class GameFlowController
|
||||
class GameFlowController implements ISecured
|
||||
{
|
||||
const NUMBER_OF_ROUNDS = 5;
|
||||
const MAX_SCORE = 1000;
|
||||
@@ -69,6 +70,11 @@ class GameFlowController
|
||||
$this->guessRepository = new GuessRepository();
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return !empty($_ENV['ENABLE_GAME_FOR_GUESTS']) || $this->request->user() !== null;
|
||||
}
|
||||
|
||||
public function initialData(): IContent
|
||||
{
|
||||
$mapId = (int) $this->request->query('mapId');
|
||||
@@ -149,6 +155,7 @@ class GameFlowController
|
||||
{
|
||||
$currentPlace = $this->placeRepository->getByRoundInChallenge($challenge, $currentRound);
|
||||
|
||||
// if the last round was played ($currentPlace == null) or history is explicitly requested (for initializing)
|
||||
if (!isset($currentPlace) || $withHistory) {
|
||||
|
||||
$withRelations = [User::class, PlaceInChallenge::class, Place::class];
|
||||
@@ -211,15 +218,16 @@ class GameFlowController
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response['restrictions'] = [
|
||||
'timeLimit' => $challenge->getTimeLimit() * 1000,
|
||||
'noMove' => $challenge->getNoMove(),
|
||||
'noPan' => $challenge->getNoPan(),
|
||||
'noZoom' => $challenge->getNoZoom()
|
||||
];
|
||||
}
|
||||
|
||||
$response['restrictions'] = [
|
||||
'timeLimit' => $challenge->getTimeLimit() * 1000,
|
||||
'timeLimitType' => $challenge->getTimeLimitType(),
|
||||
'noMove' => $challenge->getNoMove(),
|
||||
'noPan' => $challenge->getNoPan(),
|
||||
'noZoom' => $challenge->getNoZoom()
|
||||
];
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -239,6 +247,11 @@ class GameFlowController
|
||||
|
||||
$response = $this->prepareChallengeResponse($userId, $challenge, $currentRound, true);
|
||||
|
||||
if ($challenge->getTimeLimitType() === 'game' && $challenge->getTimeLimit() !== null && $userInChallenge->getCurrentRound() > 0) {
|
||||
$timeLimit = max(10, $userInChallenge->getTimeLeft());
|
||||
$response['restrictions']['timeLimit'] = $timeLimit * 1000;
|
||||
}
|
||||
|
||||
return new JsonContent($response);
|
||||
}
|
||||
|
||||
@@ -288,9 +301,9 @@ class GameFlowController
|
||||
$session = $this->request->session();
|
||||
$userId = $session->get('userId');
|
||||
|
||||
if(isset($userId)) {
|
||||
if (isset($userId)) {
|
||||
$userPlayedPlace = $this->userPlayedPlaceRepository->getByUserIdAndPlaceId($userId, $placeId);
|
||||
if(!$userPlayedPlace) {
|
||||
if (!$userPlayedPlace) {
|
||||
$userPlayedPlace = new UserPlayedPlace();
|
||||
$userPlayedPlace->setUserId($userId);
|
||||
$userPlayedPlace->setPlaceId($placeId);
|
||||
@@ -381,10 +394,20 @@ class GameFlowController
|
||||
$response['result'] = ['distance' => null, 'score' => 0];
|
||||
}
|
||||
|
||||
// save user relevant state of challenge
|
||||
$userInChallenge->setCurrentRound($nextRound);
|
||||
$timeLeft = $this->request->post('timeLeft');
|
||||
if (isset($timeLeft)) {
|
||||
$userInChallenge->setTimeLeft(intval($timeLeft));
|
||||
}
|
||||
$this->pdm->saveToDb($userInChallenge);
|
||||
|
||||
if(isset($response['history'][$currentRound]['allResults'])) {
|
||||
if ($challenge->getTimeLimitType() === 'game' && isset($timeLeft)) {
|
||||
$timeLimit = max(10, intval($timeLeft));
|
||||
$response['restrictions']['timeLimit'] = $timeLimit * 1000;
|
||||
}
|
||||
|
||||
if (isset($response['history'][$currentRound]['allResults'])) {
|
||||
$response['allResults'] = $response['history'][$currentRound]['allResults'];
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ class Select
|
||||
$queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0];
|
||||
}
|
||||
|
||||
if($this->isDerivedTable()) {
|
||||
if ($this->isDerivedTable()) {
|
||||
$queryString = '(' . $queryString . ') AS ' . $this->tableAliases[Select::DERIVED_TABLE_KEY];
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ class Select
|
||||
return [(string) $table, $params];
|
||||
}
|
||||
|
||||
if($table instanceof Select)
|
||||
if ($table instanceof Select)
|
||||
{
|
||||
return $table->generateQuery();
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class Select
|
||||
$joinQueries = [];
|
||||
$params = [];
|
||||
|
||||
foreach($this->joins as $join) {
|
||||
foreach ($this->joins as $join) {
|
||||
list($joinQueryFragment, $paramsFragment) = $this->generateTable($join[1], true);
|
||||
$joinQueries[] = $join[0] . ' JOIN ' . $joinQueryFragment . ' ON ' . $this->generateColumn($join[2]) . ' ' . $join[3] . ' ' . $this->generateColumn($join[4]);
|
||||
$params = array_merge($params, $paramsFragment);
|
||||
|
||||
@@ -33,7 +33,7 @@ class Challenge extends Model
|
||||
|
||||
public function setTimeLimit(?int $timeLimit): void
|
||||
{
|
||||
if(isset($timeLimit)) {
|
||||
if (isset($timeLimit)) {
|
||||
$this->timeLimit = $timeLimit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ class UserInChallenge extends Model
|
||||
|
||||
public function setTimeLeft(?int $timeLeft): void
|
||||
{
|
||||
if(isset($timeLeft)) {
|
||||
$this->timeLeft = $timeLeft;
|
||||
if (isset($timeLeft)) {
|
||||
$this->timeLeft = max(0, $timeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,14 @@ class UserInChallengeRepository
|
||||
yield from $this->pdm->selectMultipleFromDb($select, UserInChallenge::class);
|
||||
}
|
||||
|
||||
public function getAllByChallengeWithUsers(Challenge $challenge) : Generator
|
||||
{
|
||||
$select = new Select(\Container::$dbConnection);
|
||||
$select->where('challenge_id', '=', $challenge->getId());
|
||||
|
||||
yield from $this->pdm->selectMultipleFromDb($select, UserInChallenge::class, true, [User::class]);
|
||||
}
|
||||
|
||||
public function getByUserIdAndChallenge(int $userId, Challenge $challenge): ?UserInChallenge
|
||||
{
|
||||
$select = new Select(\Container::$dbConnection);
|
||||
@@ -49,10 +57,8 @@ class UserInChallengeRepository
|
||||
}
|
||||
|
||||
// validate token string
|
||||
foreach (str_split($token_str) as $char) {
|
||||
if (!(('0' <= $char && $char <= '9') || ('a' <= $char && $char <= 'f'))) {
|
||||
return null;
|
||||
}
|
||||
if (!ctype_xdigit($token_str)) {
|
||||
return null;
|
||||
}
|
||||
// convert token to int
|
||||
$token = hexdec($token_str);
|
||||
|
||||
+16
-2
@@ -12,11 +12,25 @@
|
||||
<div id="players" class="marginTop"></div>
|
||||
<button id="startMultiGameButton" class="button fullWidth marginTop green">Start game</button>
|
||||
</div>
|
||||
<div id="highscores" class="modal">
|
||||
<h2>Highscores</h2>
|
||||
<div>
|
||||
<table id="highscoresTable">
|
||||
<tr>
|
||||
<th>Player</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button id="closeHighscoresButton" class="gray marginTop" type="button">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section(subheader)
|
||||
<span id="mapName" class="bold">Loading map...</span><!--
|
||||
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
||||
--><span id="roundContainer">Round <span id="currentRound" class="bold"></span></span><!--
|
||||
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
||||
@endsection
|
||||
|
||||
@@ -42,7 +56,7 @@
|
||||
<div id="distanceInfo">
|
||||
<p>You were <span id="distance" class="bold"></span> close.</p>
|
||||
<p>You didn't guess in this round.</p>
|
||||
<p class="bold">Game finished.</p>
|
||||
<p id="summaryInfo" class="bold">Game finished.</p>
|
||||
</div>
|
||||
<div id="scoreInfo">
|
||||
<p>You earned <span id="score" class="bold"></span> points.</p>
|
||||
|
||||
+13
-9
@@ -43,7 +43,7 @@ TODO: condition!
|
||||
<p class="bold center marginTop marginBottom">OR</p>
|
||||
-->
|
||||
|
||||
<div id="restrictions">
|
||||
<div id="restrictions" class="marginTop marginBottom">
|
||||
<h3>Optional restrictions</h3>
|
||||
<div>
|
||||
<div>
|
||||
@@ -51,10 +51,10 @@ TODO: condition!
|
||||
<label id="timeLimitLabel" for="timerEnabled">Time limit measured in seconds</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="range" id="timeLimit" name="timeLimit" min="10" max="600" value="120" />
|
||||
<input type="range" id="timeLimit" name="timeLimit" min="10" max="1800" step="10" value="300" />
|
||||
</div>
|
||||
<div id="timeLimitType">
|
||||
Time limit
|
||||
<label>Time limit</label>
|
||||
<input type="radio" id="timeLimitTypeGame" name="timeLimitType" value="game" checked />
|
||||
<label for="timeLimitTypeGame">for the whole game</label>
|
||||
<input type="radio" id="timeLimitTypeRound" name="timeLimitType" value="round" />
|
||||
@@ -67,7 +67,7 @@ TODO: condition!
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="noZoom" name="noZoom" value="noZoom" />
|
||||
<label for="noMove">No zoom allowed</label>
|
||||
<label for="noZoom">No zoom allowed</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="noPan" name="noPan" value="noPan" />
|
||||
@@ -114,12 +114,16 @@ TODO: condition!
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttonContainer">
|
||||
<?php if ($isAdmin): ?>
|
||||
<button class="button fullWidth noRightRadius playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
||||
<a class="button yellow fullWidth noLeftRadius noRightRadius" href="/admin/mapEditor/<?= $map['id']; ?>" title="Edit map '<?= $map['name'] ?>'">Edit</a>
|
||||
<button class="button red fullWidth noLeftRadius deleteButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Delete map '<?= $map['name'] ?>'">Delete</button>
|
||||
<?php if (!empty($_ENV['ENABLE_GAME_FOR_GUESTS']) || Container::$request->user()): ?>
|
||||
<?php if ($isAdmin): ?>
|
||||
<button class="button fullWidth noRightRadius playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
||||
<a class="button yellow fullWidth noLeftRadius noRightRadius" href="/admin/mapEditor/<?= $map['id']; ?>" title="Edit map '<?= $map['name'] ?>'">Edit</a>
|
||||
<button class="button red fullWidth noLeftRadius deleteButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Delete map '<?= $map['name'] ?>'">Delete</button>
|
||||
<?php else: ?>
|
||||
<button class="button fullWidth playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<button class="button fullWidth playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
||||
<a href="/login" class="button fullWidth" title="Play map '<?= $map['name'] ?>'">Play this map</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user