1237 lines
46 KiB
JavaScript
1237 lines
46 KiB
JavaScript
'use strict';
|
|
|
|
const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
|
|
|
|
(function () {
|
|
var Game = {
|
|
NUMBER_OF_ROUNDS: 5,
|
|
MAX_SCORE: 1000,
|
|
|
|
type: GameType.SINGLE,
|
|
mapBounds: null,
|
|
multi: { token: null, owner: false },
|
|
rounds: [],
|
|
scoreSum: 0,
|
|
panoId: null,
|
|
pov: null,
|
|
panorama: null,
|
|
map: null,
|
|
guessMarker: null,
|
|
adaptGuess: false,
|
|
googleLink: null,
|
|
history: [],
|
|
restrictions: null,
|
|
|
|
readyToContinue: true,
|
|
timeoutEnd: null,
|
|
countdownHandler: null,
|
|
|
|
MultiConnector: {
|
|
connection: null,
|
|
reconnectCounter: 0,
|
|
|
|
connect: function () {
|
|
if (Game.MultiConnector.connection && Game.MultiConnector.connection.readyState !== WebSocket.CLOSED) {
|
|
return;
|
|
}
|
|
|
|
Game.MultiConnector.connection = new WebSocket((MapGuesser.isSecure ? 'wss' : 'ws') + '://' + multiUrl);
|
|
|
|
Game.MultiConnector.connection.onopen = function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
Game.MultiConnector.reconnectCounter = 0;
|
|
Game.MultiConnector.connection.send(JSON.stringify({ func: 'connect_to_room', args: { roomId: roomId, token: Game.multi.token } }));
|
|
};
|
|
|
|
Game.MultiConnector.connection.onclose = Game.MultiConnector.noConnection;
|
|
|
|
Game.MultiConnector.connection.onerror = function (event) {
|
|
console.error('WebSocket error in Game.MultiConnector:', event);
|
|
};
|
|
|
|
Game.MultiConnector.connection.onmessage = function (message) {
|
|
var json;
|
|
|
|
try {
|
|
json = JSON.parse(message.data);
|
|
} catch (e) {
|
|
console.error('Cannot parse message!');
|
|
console.error(message.data);
|
|
return;
|
|
}
|
|
|
|
switch (json.type) {
|
|
case 'initialize':
|
|
Game.MultiConnector.initialize(json.data);
|
|
break;
|
|
|
|
case 'member_joined':
|
|
Game.MultiConnector.memberJoined(json.data);
|
|
break;
|
|
|
|
case 'new_round':
|
|
Game.MultiConnector.newRound(json.data);
|
|
break;
|
|
|
|
case 'guess':
|
|
Game.MultiConnector.guess(json.data);
|
|
break;
|
|
|
|
case 'timeout_changed':
|
|
Game.MultiConnector.timeoutChanged(json.data);
|
|
break;
|
|
|
|
case 'end_round':
|
|
Game.MultiConnector.endRound(json.data);
|
|
break;
|
|
}
|
|
};
|
|
},
|
|
|
|
noConnection: function () {
|
|
if (Game.MultiConnector.reconnectCounter === 2) {
|
|
console.error('Could not reconnect WebSocket for Game.MultiConnector...')
|
|
}
|
|
|
|
setTimeout(function () {
|
|
Game.MultiConnector.reconnectCounter++;
|
|
|
|
console.log('Reconnecting WebSocket for Game.MultiConnector... ' + Game.MultiConnector.reconnectCounter);
|
|
Game.MultiConnector.connect();
|
|
}, 1000 + Math.min(Game.MultiConnector.reconnectCounter * 500, 9000));
|
|
},
|
|
|
|
initialize: function (data) {
|
|
Game.readyToContinue = false;
|
|
|
|
if (data.history.length === 0 && !data.place) {
|
|
var div = document.getElementById('players');
|
|
|
|
for (var i = 0; i < data.members.length; ++i) {
|
|
var member = data.members[i];
|
|
|
|
var p = document.createElement('p');
|
|
p.innerHTML = member.userName + (member.me ? ' (me)' : '');
|
|
div.appendChild(p);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < data.history.length; ++i) {
|
|
var round = data.history[i];
|
|
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.scoreSum += round.result.score;
|
|
|
|
for (var j = 0; j < round.allResults.length; ++j) {
|
|
var result = round.allResults[j];
|
|
if (result.guessPosition) {
|
|
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
|
|
if (data.timeout) {
|
|
Game.startCountdown(data.timeout);
|
|
}
|
|
|
|
if (data.place) {
|
|
Game.readyToContinue = data.readyToContinue;
|
|
Game.panoId = data.place.panoId;
|
|
Game.pov = data.place.pov;
|
|
|
|
document.getElementById('multi').style.visibility = 'hidden';
|
|
|
|
if (Game.rounds.length === 0 || !Game.rounds[Game.rounds.length - 1].position) {
|
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
|
Game.startNewRound();
|
|
} else {
|
|
Game.loadPano(Game.panoId, Game.pov);
|
|
Game.showResultFromHistory(data.history[data.history.length - 1].result);
|
|
}
|
|
}
|
|
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
},
|
|
|
|
memberJoined: function (data) {
|
|
var div = document.getElementById('players');
|
|
|
|
var p = document.createElement('p');
|
|
p.innerHTML = data.userName;
|
|
div.appendChild(p);
|
|
},
|
|
|
|
newRound: function (data) {
|
|
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
|
Game.reset();
|
|
}
|
|
|
|
Game.readyToContinue = false;
|
|
Game.panoId = data.place.panoId;
|
|
Game.pov = data.place.pov;
|
|
|
|
document.getElementById('multi').style.visibility = 'hidden';
|
|
Game.resetRound();
|
|
Game.startNewRound();
|
|
|
|
Game.startCountdown(data.timeout);
|
|
},
|
|
|
|
guess: function (data) {
|
|
var resultBounds = Game.map.getBounds();
|
|
|
|
Game.addGuessPositionToResultMap(data.guessPosition, data);
|
|
resultBounds.extend(data.guessPosition);
|
|
|
|
Game.map.fitBounds(resultBounds);
|
|
},
|
|
|
|
timeoutChanged: function (data) {
|
|
Game.startCountdown(data.timeout);
|
|
},
|
|
|
|
endRound: function (data) {
|
|
Game.readyToContinue = true;
|
|
Game.startCountdown(0);
|
|
|
|
if (Game.rounds[Game.rounds.length - 1].guessPosition || Game.rounds[Game.rounds.length - 1].position) {
|
|
if (Game.multi.owner) {
|
|
document.getElementById('continueButton').disabled = false;
|
|
document.getElementById('startNewGameButton').disabled = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
document.getElementById('guessButton').disabled = true;
|
|
document.getElementById('panoCover').style.visibility = 'visible';
|
|
|
|
Game.receiveResult(data.position, data.result.guessPosition, { distance: data.result.distance, score: data.result.score }, data.allResults);
|
|
}
|
|
},
|
|
|
|
getGameIdentifier: function () {
|
|
switch (Game.type) {
|
|
case GameType.SINGLE:
|
|
return '/game/' + mapId;
|
|
case GameType.MULTI:
|
|
return '/multiGame/' + roomId;
|
|
case GameType.CHALLENGE:
|
|
return '/challenge/' + challengeToken;
|
|
default:
|
|
return '/game/' + mapId;
|
|
}
|
|
},
|
|
|
|
prepare: function () {
|
|
var data = new FormData();
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
var url = Game.getGameIdentifier() + '/prepare.json';
|
|
MapGuesser.httpRequest('POST', url, function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
|
|
document.getElementById('mapName').innerHTML = this.response.mapName;
|
|
Game.mapBounds = this.response.bounds;
|
|
|
|
Game.initialize();
|
|
|
|
if (roomId) {
|
|
Game.multi.token = this.response.token;
|
|
Game.multi.owner = this.response.owner;
|
|
|
|
document.getElementById('multi').style.visibility = 'visible';
|
|
if (Game.multi.owner) {
|
|
document.getElementById('startMultiGameButton').style.display = 'block';
|
|
}
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
Game.MultiConnector.connect();
|
|
}
|
|
}, data);
|
|
},
|
|
|
|
initialize: function () {
|
|
document.getElementById('panoCover').style.visibility = 'visible';
|
|
|
|
Game.map.setOptions({
|
|
draggableCursor: 'crosshair'
|
|
});
|
|
Game.map.fitBounds(Game.mapBounds);
|
|
|
|
if (roomId) {
|
|
// if it is multiplayer mode, data is sent via WS
|
|
return;
|
|
}
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
MapGuesser.httpRequest('POST', Game.getGameIdentifier() + '/initialData.json', function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
|
|
Game.loadHistory(this.response);
|
|
|
|
Game.restrictions = this.response.restrictions;
|
|
Game.displayRestrictions();
|
|
|
|
if (this.response.finished) {
|
|
|
|
Game.transitToResultMap();
|
|
Game.showSummary();
|
|
|
|
} else {
|
|
|
|
Game.panoId = this.response.place.panoId;
|
|
Game.pov = this.response.place.pov;
|
|
|
|
Game.startNewRound();
|
|
}
|
|
|
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
});
|
|
},
|
|
|
|
enableRestrictions: function () {
|
|
if (!Game.restrictions) {
|
|
return;
|
|
}
|
|
|
|
Game.panorama.setOptions({
|
|
clickToGo: !Game.restrictions.noMove,
|
|
linksControl: !(Game.restrictions.noMove || Game.restrictions.noPan),
|
|
scrollwheel: !Game.restrictions.noZoom
|
|
});
|
|
|
|
if (Game.restrictions.noPan) {
|
|
document.getElementById('panningBlockerCover').style.display = 'block';
|
|
}
|
|
|
|
if (Game.restrictions.timeLimit) {
|
|
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,
|
|
scrollwheel: true
|
|
});
|
|
|
|
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 () {
|
|
// TODO: refactor - it is necessary for mobile
|
|
if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') {
|
|
document.getElementById('showGuessButton').click();
|
|
}
|
|
|
|
if (Game.adaptGuess) {
|
|
document.getElementById('guess').classList.remove('adapt');
|
|
}
|
|
|
|
if (Game.guessMarker) {
|
|
Game.guessMarker.setMap(null);
|
|
Game.guessMarker = null;
|
|
}
|
|
|
|
document.getElementById('guess').classList.add('result');
|
|
|
|
Game.map.setOptions({
|
|
draggableCursor: 'grab'
|
|
});
|
|
|
|
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
|
document.getElementById('continueButton').style.display = 'none';
|
|
document.getElementById('showSummaryButton').style.display = 'block';
|
|
} else if (Game.type == GameType.MULTI) {
|
|
if (Game.multi.owner) {
|
|
if (!Game.readyToContinue) {
|
|
document.getElementById('continueButton').disabled = true;
|
|
}
|
|
} else {
|
|
document.getElementById('continueButton').style.display = 'none';
|
|
}
|
|
}
|
|
},
|
|
|
|
loadHistory: function (response) {
|
|
if (!response.history)
|
|
return;
|
|
|
|
Game.history = response.history;
|
|
|
|
for (var i = 0; i < Game.rounds.length; ++i) {
|
|
var round = Game.rounds[i];
|
|
|
|
if (round.realMarker) {
|
|
round.realMarker.setMap(null);
|
|
}
|
|
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
var guessMarker = round.guessMarkers[j];
|
|
guessMarker.marker.setMap(null);
|
|
guessMarker.line.setMap(null);
|
|
if (guessMarker.info) {
|
|
guessMarker.info.close();
|
|
}
|
|
}
|
|
}
|
|
Game.rounds = [];
|
|
|
|
Game.scoreSum = 0;
|
|
for (var i = 0; i < Game.history.length; ++i) {
|
|
var round = Game.history[i];
|
|
|
|
if (round.result) {
|
|
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, round.result, true);
|
|
}
|
|
Game.scoreSum += round.result.score;
|
|
|
|
|
|
if (round.allResults !== undefined) {
|
|
for (var j = 0; j < round.allResults.length; ++j) {
|
|
var result = round.allResults[j];
|
|
if (result.guessPosition) {
|
|
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
reset: function () {
|
|
if (Game.guessMarker) {
|
|
Game.guessMarker.setMap(null);
|
|
Game.guessMarker = null;
|
|
}
|
|
|
|
for (var i = 0; i < Game.rounds.length; ++i) {
|
|
var round = Game.rounds[i];
|
|
|
|
if (round.realMarker) {
|
|
round.realMarker.setMap(null);
|
|
}
|
|
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
var guessMarker = round.guessMarkers[j];
|
|
guessMarker.marker.setMap(null);
|
|
guessMarker.line.setMap(null);
|
|
if (guessMarker.info) {
|
|
guessMarker.info.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
Game.rounds = [];
|
|
Game.scoreSum = 0;
|
|
|
|
var distanceInfo = document.getElementById('distanceInfo');
|
|
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;
|
|
document.getElementById('continueButton').style.display = null;
|
|
document.getElementById('showSummaryButton').style.display = null;
|
|
document.getElementById('startNewGameButton').style.display = null;
|
|
|
|
document.getElementById('showGuessButton').style.visibility = null;
|
|
document.getElementById('guess').style.visibility = null;
|
|
document.getElementById('guess').classList.remove('result');
|
|
|
|
// needs to be set visible after the show guess map hid it in mobile view
|
|
document.getElementById("navigation").style.visibility = 'visible';
|
|
|
|
Game.disableRestrictions();
|
|
Game.hideRestrictions();
|
|
|
|
document.getElementById('panningBlockerCover').style.display = null;
|
|
|
|
Game.history = [];
|
|
|
|
Game.initialize();
|
|
},
|
|
|
|
resetRound: function () {
|
|
document.getElementById('scoreBar').style.width = null;
|
|
|
|
if (Game.rounds.length > 0) {
|
|
var lastRound = Game.rounds[Game.rounds.length - 1];
|
|
|
|
lastRound.realMarker.setVisible(false);
|
|
for (var i = 0; i < lastRound.guessMarkers.length; ++i) {
|
|
var guessMarker = lastRound.guessMarkers[i];
|
|
guessMarker.marker.setVisible(false);
|
|
guessMarker.line.setVisible(false);
|
|
if (guessMarker.info) {
|
|
guessMarker.info.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
|
document.getElementById('showGuessButton').style.visibility = null;
|
|
document.getElementById('guess').style.visibility = null;
|
|
document.getElementById('guess').classList.remove('result');
|
|
|
|
// needs to be set visible after the show guess map hid it in mobile view
|
|
document.getElementById("navigation").style.visibility = 'visible';
|
|
|
|
Game.map.setOptions({
|
|
draggableCursor: 'crosshair'
|
|
});
|
|
Game.map.fitBounds(Game.mapBounds);
|
|
|
|
if (roomId) {
|
|
// if it is multiplayer mode, data is sent via WS
|
|
return;
|
|
}
|
|
|
|
Game.startNewRound();
|
|
},
|
|
|
|
startNewRound: function () {
|
|
Game.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarkers: [] });
|
|
|
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
|
|
|
Game.loadPano(Game.panoId, Game.pov);
|
|
|
|
// update the compass
|
|
const heading = Game.panorama.getPov().heading;
|
|
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
|
|
|
|
Game.enableRestrictions();
|
|
},
|
|
|
|
handleErrorResponse: function (error) {
|
|
switch (error) {
|
|
case 'no_session_found':
|
|
MapGuesser.showModalWithContent('Error', 'Your session is invalid!', [{
|
|
type: 'button',
|
|
classNames: [],
|
|
text: 'Restart game',
|
|
onclick: function () {
|
|
window.location.reload();
|
|
}
|
|
}]);
|
|
break;
|
|
|
|
case 'game_already_started':
|
|
MapGuesser.showModalWithContent('Error', 'This game is already started, you cannot join.');
|
|
break;
|
|
|
|
case 'game_not_found':
|
|
MapGuesser.showModalWithContent('Error', 'The game was not found by this ID. Please check the link.');
|
|
break;
|
|
|
|
case 'anonymous_user':
|
|
MapGuesser.showModalWithContent('Error', 'You have to login to join this game!');
|
|
break;
|
|
|
|
default:
|
|
MapGuesser.showModalWithContent('Error', 'Error code: \'' + error + '\'');
|
|
break
|
|
}
|
|
},
|
|
|
|
loadPano: function (panoId, pov) {
|
|
if (Game.adaptGuess) {
|
|
document.getElementById('guess').classList.add('adapt');
|
|
}
|
|
|
|
Game.panorama.setPov({ heading: pov.heading, pitch: pov.pitch });
|
|
Game.panorama.setZoom(pov.zoom);
|
|
Game.panorama.setPano(panoId);
|
|
},
|
|
|
|
receiveResult: function (position, guessPosition, result, allResults) {
|
|
Game.scoreSum += result.score;
|
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
|
|
var resultBounds = new google.maps.LatLngBounds();
|
|
|
|
Game.rounds[Game.rounds.length - 1].position = position;
|
|
Game.addPositionToResultMap();
|
|
resultBounds.extend(position);
|
|
|
|
if (guessPosition) {
|
|
Game.addGuessPositionToResultMap(guessPosition, result);
|
|
resultBounds.extend(guessPosition);
|
|
}
|
|
|
|
if (allResults) {
|
|
for (var i = 0; i < allResults.length; ++i) {
|
|
var currentResult = allResults[i];
|
|
if (currentResult.guessPosition) {
|
|
Game.addGuessPositionToResultMap(currentResult.guessPosition, currentResult);
|
|
resultBounds.extend(currentResult.guessPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
Game.showResultMap(result, resultBounds);
|
|
},
|
|
|
|
showResultFromHistory: function (result) {
|
|
var round = Game.rounds[Game.rounds.length - 1];
|
|
var resultBounds = new google.maps.LatLngBounds();
|
|
|
|
round.realMarker.setVisible(true);
|
|
resultBounds.extend(round.position);
|
|
|
|
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
var guessMarker = round.guessMarkers[j];
|
|
guessMarker.marker.setVisible(true);
|
|
guessMarker.line.setVisible(true);
|
|
|
|
resultBounds.extend(guessMarker.marker.getPosition());
|
|
}
|
|
|
|
Game.showResultMap(result, resultBounds);
|
|
},
|
|
|
|
showResultMap: function (result, resultBounds) {
|
|
|
|
Game.transitToResultMap();
|
|
|
|
Game.map.fitBounds(resultBounds);
|
|
|
|
var distanceInfo = document.getElementById('distanceInfo');
|
|
if (result.distance === null) {
|
|
distanceInfo.children[0].style.display = 'none';
|
|
distanceInfo.children[1].style.display = 'block';
|
|
} else {
|
|
distanceInfo.children[0].style.display = 'block';
|
|
distanceInfo.children[1].style.display = 'none';
|
|
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(result.distance);
|
|
}
|
|
|
|
document.getElementById('score').innerHTML = result.score;
|
|
|
|
var scoreBarProperties = Game.calculateScoreBarProperties(result.score, Game.MAX_SCORE);
|
|
var scoreBar = document.getElementById('scoreBar');
|
|
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
|
|
scoreBar.style.width = scoreBarProperties.width;
|
|
},
|
|
|
|
guess: function () {
|
|
|
|
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;
|
|
|
|
data.append('lat', String(guessPosition.lat));
|
|
data.append('lng', String(guessPosition.lng));
|
|
}
|
|
|
|
document.getElementById('guessButton').disabled = true;
|
|
document.getElementById('panoCover').style.visibility = 'visible';
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
var url = Game.getGameIdentifier() + '/guess.json';
|
|
|
|
MapGuesser.httpRequest('POST', url, function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
|
|
Game.loadHistory(this.response);
|
|
Game.restrictions = this.response.restrictions;
|
|
|
|
Game.receiveResult(this.response.position, guessPosition, this.response.result, this.response.allResults);
|
|
|
|
if (this.response.place) {
|
|
Game.panoId = this.response.place.panoId;
|
|
Game.pov = this.response.place.pov;
|
|
}
|
|
|
|
}, data);
|
|
},
|
|
|
|
addPositionToResultMap: function (hidden) {
|
|
var round = Game.rounds[Game.rounds.length - 1];
|
|
var position = round.position;
|
|
|
|
round.realMarker = new google.maps.Marker({
|
|
map: Game.map,
|
|
visible: !hidden,
|
|
position: position,
|
|
title: 'Open in Google Maps',
|
|
zIndex: Game.rounds.length * 2,
|
|
clickable: true,
|
|
draggable: false,
|
|
icon: {
|
|
url: STATIC_ROOT + '/img/markers/marker-green.svg?rev=' + REVISION,
|
|
size: new google.maps.Size(24, 32),
|
|
scaledSize: new google.maps.Size(24, 32),
|
|
anchor: new google.maps.Point(12, 32)
|
|
},
|
|
});
|
|
|
|
round.realMarker.addListener('click', function () {
|
|
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
|
});
|
|
},
|
|
|
|
addGuessPositionToResultMap: function (guessPosition, result, hidden) {
|
|
var round = Game.rounds[Game.rounds.length - 1];
|
|
var position = round.position;
|
|
|
|
var guessMarker = { marker: null, line: null, info: null };
|
|
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,
|
|
visible: !hidden,
|
|
position: guessPosition,
|
|
zIndex: Game.rounds.length,
|
|
clickable: !!result,
|
|
draggable: false,
|
|
icon: {
|
|
url: STATIC_ROOT + '/img/markers/' + markerSvg + '?rev=' + REVISION,
|
|
size: new google.maps.Size(24, 32),
|
|
scaledSize: new google.maps.Size(24, 32),
|
|
anchor: new google.maps.Point(12, 32),
|
|
labelOrigin: new google.maps.Point(12, 14)
|
|
},
|
|
label: {
|
|
color: '#ffffff',
|
|
fontFamily: 'Roboto',
|
|
fontSize: '16px',
|
|
fontWeight: '500',
|
|
text: markerLabel
|
|
}
|
|
});
|
|
|
|
guessMarker.line = new google.maps.Polyline({
|
|
map: Game.map,
|
|
visible: !hidden,
|
|
path: [
|
|
position,
|
|
guessPosition
|
|
],
|
|
geodesic: true,
|
|
strokeOpacity: 0,
|
|
icons: [{
|
|
icon: {
|
|
path: 'M 0,-1 0,1',
|
|
strokeOpacity: 1,
|
|
strokeWeight: 2,
|
|
scale: 2
|
|
},
|
|
offset: '0',
|
|
repeat: '10px'
|
|
}],
|
|
clickable: false,
|
|
draggable: false,
|
|
editable: false
|
|
});
|
|
|
|
if (result) {
|
|
const userName = result.userName ? result.userName : 'me';
|
|
guessMarker.info = new google.maps.InfoWindow({
|
|
content: '<p class="small bold">' + userName + '</p>' +
|
|
'<p class="small">' + Util.printDistanceForHuman(result.distance) + ' | ' + result.score + ' points</p>',
|
|
});
|
|
|
|
guessMarker.marker.addListener('click', function () {
|
|
guessMarker.info.open(Game.map, this);
|
|
});
|
|
}
|
|
|
|
round.guessMarkers.push(guessMarker);
|
|
},
|
|
|
|
calculateScoreBarProperties: function (score, maxScore) {
|
|
var percent = Math.floor((score / maxScore) * 100);
|
|
|
|
var color;
|
|
if (percent >= 90) {
|
|
color = '#11ca00';
|
|
} else if (percent >= 10) {
|
|
color = '#ea9000';
|
|
} else {
|
|
color = '#ca1100';
|
|
}
|
|
|
|
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';
|
|
distanceInfo.children[1].style.display = 'none';
|
|
distanceInfo.children[2].style.display = 'block';
|
|
var scoreInfo = document.getElementById('scoreInfo');
|
|
scoreInfo.children[0].style.display = 'none';
|
|
scoreInfo.children[1].style.display = 'block';
|
|
document.getElementById('showSummaryButton').style.display = null;
|
|
|
|
if (Game.type == GameType.SINGLE || Game.multi.owner) {
|
|
document.getElementById('startNewGameButton').style.display = 'block';
|
|
if (!Game.readyToContinue) {
|
|
document.getElementById('startNewGameButton').disabled = true;
|
|
}
|
|
} else if (Game.type == GameType.CHALLENGE) {
|
|
document.getElementById('goToStart').style.display = 'block';
|
|
}
|
|
|
|
var resultBounds = new google.maps.LatLngBounds();
|
|
|
|
for (var i = 0; i < Game.rounds.length; ++i) {
|
|
var round = Game.rounds[i];
|
|
|
|
round.realMarker.setIcon({
|
|
url: STATIC_ROOT + '/img/markers/marker-green-empty.svg?rev=' + REVISION,
|
|
size: new google.maps.Size(24, 32),
|
|
scaledSize: new google.maps.Size(24, 32),
|
|
anchor: new google.maps.Point(12, 32),
|
|
labelOrigin: new google.maps.Point(12, 14)
|
|
});
|
|
round.realMarker.setLabel({
|
|
color: '#285624',
|
|
fontFamily: 'Roboto',
|
|
fontSize: '16px',
|
|
fontWeight: '500',
|
|
text: String(i + 1)
|
|
});
|
|
|
|
round.realMarker.setVisible(true);
|
|
resultBounds.extend(round.position);
|
|
|
|
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
var guessMarker = round.guessMarkers[j];
|
|
guessMarker.marker.setVisible(true);
|
|
guessMarker.line.setVisible(true);
|
|
|
|
resultBounds.extend(guessMarker.marker.getPosition());
|
|
}
|
|
}
|
|
|
|
Game.map.fitBounds(resultBounds);
|
|
|
|
document.getElementById('scoreSum').innerHTML = String(Game.scoreSum);
|
|
|
|
var scoreBarProperties = Game.calculateScoreBarProperties(Game.scoreSum, Game.NUMBER_OF_ROUNDS * Game.MAX_SCORE);
|
|
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 () {
|
|
if (!Game.googleLink) {
|
|
var anchors = document.getElementById('panorama').getElementsByTagName('a');
|
|
for (var i = 0; i < anchors.length; i++) {
|
|
var a = anchors[i];
|
|
if (a.href.indexOf('maps.google.com/maps') !== -1) {
|
|
Game.googleLink = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setTimeout(function () {
|
|
if (Game.googleLink) {
|
|
Game.googleLink.title = 'Google Maps';
|
|
Game.googleLink.href = 'https://maps.google.com/maps';
|
|
}
|
|
}, 1);
|
|
},
|
|
|
|
startCountdown: function (timeout, timedOutHandler) {
|
|
if (Game.countdownHandler) {
|
|
clearInterval(Game.countdownHandler);
|
|
}
|
|
|
|
Game.countdownElement = document.getElementById('countdown');
|
|
Game.countdownTimeElement = document.getElementById('countdownTime');
|
|
|
|
Game.setCountdownTime(Math.round(timeout / 1000));
|
|
|
|
if (timeout <= 0) {
|
|
return;
|
|
}
|
|
|
|
Game.timeoutEnd = new Date(new Date().getTime() + timeout);
|
|
|
|
Game.countdownHandler = setInterval(function () {
|
|
var timeLeft = Math.round((Game.timeoutEnd - new Date()) / 1000);
|
|
|
|
Game.setCountdownTime(timeLeft);
|
|
|
|
if (timeLeft <= 0) {
|
|
if (typeof timedOutHandler === 'function') {
|
|
timedOutHandler();
|
|
} else {
|
|
document.getElementById('panoCover').style.visibility = 'visible';
|
|
}
|
|
|
|
clearInterval(Game.countdownHandler);
|
|
}
|
|
}, 1000);
|
|
},
|
|
|
|
setCountdownTime: function (time) {
|
|
if (time <= 0) {
|
|
Game.countdownElement.style.visibility = 'hidden';
|
|
return;
|
|
}
|
|
|
|
if (time <= 15) {
|
|
Game.countdownElement.className = 'red';
|
|
} else if (time <= 30) {
|
|
Game.countdownElement.className = 'yellow';
|
|
} else {
|
|
Game.countdownElement.className = '';
|
|
}
|
|
|
|
Game.countdownElement.style.visibility = 'visible';
|
|
Game.countdownTimeElement.innerHTML = time;
|
|
}
|
|
};
|
|
|
|
var Util = {
|
|
printDistanceForHuman: function (distance) {
|
|
if (distance < 1000) {
|
|
return Number.parseFloat(distance).toFixed(0) + ' m';
|
|
} else if (distance < 10000) {
|
|
return Number.parseFloat(distance / 1000).toFixed(2) + ' km';
|
|
} else if (distance < 100000) {
|
|
return Number.parseFloat(distance / 1000).toFixed(1) + ' km';
|
|
} else {
|
|
return Number.parseFloat(distance / 1000).toFixed(0) + ' km';
|
|
}
|
|
}
|
|
};
|
|
|
|
MapGuesser.sessionAvailableHooks.reinitializeGame = Game.prepare;
|
|
|
|
if (!('ontouchstart' in document.documentElement)) {
|
|
Game.adaptGuess = true;
|
|
}
|
|
|
|
Game.map = new google.maps.Map(document.getElementById('map'), {
|
|
disableDefaultUI: true,
|
|
clickableIcons: false,
|
|
draggingCursor: 'grabbing'
|
|
});
|
|
|
|
Game.map.addListener('click', function (e) {
|
|
if (Game.rounds[Game.rounds.length - 1].guessPosition || Game.rounds[Game.rounds.length - 1].position) {
|
|
return;
|
|
}
|
|
|
|
if (Game.guessMarker) {
|
|
Game.guessMarker.setPosition(e.latLng);
|
|
return;
|
|
}
|
|
|
|
Game.guessMarker = new google.maps.Marker({
|
|
map: Game.map,
|
|
position: e.latLng,
|
|
clickable: false,
|
|
draggable: true,
|
|
icon: {
|
|
url: STATIC_ROOT + '/img/markers/marker-blue-empty.svg?rev=' + REVISION,
|
|
size: new google.maps.Size(24, 32),
|
|
scaledSize: new google.maps.Size(24, 32),
|
|
anchor: new google.maps.Point(12, 32),
|
|
labelOrigin: new google.maps.Point(12, 14)
|
|
},
|
|
label: {
|
|
color: '#ffffff',
|
|
fontFamily: 'Roboto',
|
|
fontSize: '16px',
|
|
fontWeight: '500',
|
|
text: '?'
|
|
}
|
|
});
|
|
|
|
document.getElementById('guessButton').disabled = false;
|
|
});
|
|
|
|
Game.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
|
disableDefaultUI: true,
|
|
linksControl: true,
|
|
showRoadLabels: false,
|
|
motionTracking: false
|
|
});
|
|
|
|
Game.panorama.addListener('position_changed', function () {
|
|
Game.rewriteGoogleLink();
|
|
});
|
|
|
|
Game.panorama.addListener('pov_changed', function () {
|
|
Game.rewriteGoogleLink();
|
|
|
|
const heading = Game.panorama.getPov().heading;
|
|
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
|
|
});
|
|
|
|
if (roomId !== null) {
|
|
Game.type = GameType.MULTI;
|
|
} else if (challengeToken !== null) {
|
|
Game.type = GameType.CHALLENGE;
|
|
}
|
|
|
|
if (COOKIES_CONSENT) {
|
|
Game.prepare();
|
|
}
|
|
|
|
document.getElementById('showGuessButton').onclick = function () {
|
|
this.style.visibility = 'hidden';
|
|
document.getElementById('guess').style.visibility = 'visible';
|
|
document.getElementById('navigation').style.visibility = 'hidden';
|
|
}
|
|
|
|
document.getElementById('closeGuessButton').onclick = function () {
|
|
document.getElementById('showGuessButton').style.visibility = null;
|
|
document.getElementById('guess').style.visibility = null;
|
|
document.getElementById('navigation').style.visibility = 'visible';
|
|
}
|
|
|
|
document.getElementById('guessButton').onclick = function () {
|
|
Game.guess();
|
|
}
|
|
|
|
document.getElementById('continueButton').onclick = function () {
|
|
if (roomId) {
|
|
if (!Game.multi.owner || !Game.readyToContinue) {
|
|
return;
|
|
}
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/nextRound.json', function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
});
|
|
} else {
|
|
Game.resetRound();
|
|
}
|
|
}
|
|
|
|
document.getElementById('showSummaryButton').onclick = function () {
|
|
Game.showSummary();
|
|
}
|
|
|
|
document.getElementById('startNewGameButton').onclick = function () {
|
|
if (roomId) {
|
|
if (!Game.multi.owner) {
|
|
return;
|
|
}
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
});
|
|
} else {
|
|
Game.reset();
|
|
}
|
|
}
|
|
|
|
document.getElementById('startMultiGameButton').onclick = function () {
|
|
if (!roomId || !Game.multi.owner) {
|
|
return;
|
|
}
|
|
|
|
document.getElementById('multi').style.visibility = 'hidden';
|
|
|
|
document.getElementById('loading').style.visibility = 'visible';
|
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
|
document.getElementById('loading').style.visibility = 'hidden';
|
|
|
|
if (this.response.error) {
|
|
Game.handleErrorResponse(this.response.error);
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
|
|
document.getElementById('returnToStart').onclick = function () {
|
|
Game.loadPano(Game.panoId, Game.pov);
|
|
}
|
|
|
|
document.getElementById('compassContainer').onclick = function () {
|
|
Game.panorama.setPov({ heading: 0, pitch: Game.panorama.getPov().pitch });
|
|
}
|
|
|
|
document.getElementById('closeHighscoresButton').onclick = function () {
|
|
MapGuesser.hideModal();
|
|
};
|
|
})();
|