Compare commits
97
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
430b32d0c6 | ||
|
|
11eee64895
|
||
|
|
cc24f96395 | ||
|
|
c3e5a6db1c | ||
|
|
398204c5d5 | ||
|
|
aaa5a1daba | ||
|
|
c112a25409
|
||
|
|
35cab17c21
|
||
|
|
f9c1829a00
|
||
|
|
e03850ce05
|
||
|
|
55ec226407 | ||
|
|
6ef04fcd4e
|
||
|
|
3045d8acbb
|
||
|
|
19a1b79b0a | ||
|
|
d432a5b584 | ||
|
|
8b9345eb36 | ||
|
|
e1eb0077b1 | ||
|
|
745bda11c0 | ||
|
|
0bb31cbe14 | ||
|
|
ef8ad69506 | ||
|
|
f10ad37a74 | ||
|
|
70b60d2fb8
|
||
|
|
7e68580db6
|
||
|
|
8218883faf | ||
|
|
145cb5f637 | ||
|
|
6d3f74f911 | ||
|
|
3d663fb5d6 | ||
|
|
759f654a0d | ||
|
|
c09cce3c97 | ||
|
|
276e331a47
|
||
|
|
62f4fd7b84 | ||
|
|
b22f13887f | ||
|
|
2a3f2212a7 | ||
|
|
98df08e5fa | ||
|
|
8f0cfd4489 | ||
|
|
d42280eb10 | ||
|
|
0739c65961 | ||
|
|
3122696364 | ||
|
|
462f6cde80 | ||
|
|
3f4fa83d87 | ||
|
|
ea599809b8 | ||
|
|
f0b0de405c | ||
|
|
ffc4aaf110 | ||
|
|
58cdc1be8d | ||
|
|
4039202268
|
||
|
|
4677cc5229 | ||
|
|
8800724aa9
|
||
|
|
08c38c6374 | ||
|
|
854775011c | ||
|
|
e33d8c02e9 | ||
|
|
3d52c967b6 | ||
|
|
5c8f3d6fb9 | ||
|
|
b9927f79fc | ||
|
|
56f3a9b380 | ||
|
|
a0d41c388b | ||
|
|
092cc63148 | ||
|
|
95553296bd | ||
|
|
9330227879 | ||
|
|
faaff33841 | ||
|
|
508a6899d8 | ||
|
|
be0f7b64b8 | ||
|
|
15e3248ee1 | ||
|
|
04a897c958 | ||
|
|
845d77ebda | ||
|
|
8bc3fda49b | ||
|
|
d78817180b | ||
|
|
0f810bd2ba | ||
|
|
9d1fc8b60c
|
||
|
|
dd46fb3d32
|
||
|
|
1a40e3a18d | ||
|
|
1aa5d3b43e
|
||
|
|
a418d5cf66 | ||
|
|
5cae286a5b
|
||
|
|
c5d2591371 | ||
|
|
cf59f937c9
|
||
|
|
257f59c96e | ||
|
|
c2f5806394
|
||
|
|
ac0b71fe09 | ||
|
|
19f7b50002
|
||
|
|
6342bb1e79
|
||
|
|
3abdb6910e
|
||
|
|
7d2588f7cd | ||
|
|
be40acdb2d
|
||
|
|
a2f2080959
|
||
|
|
cc49c56075 | ||
|
|
69329b9f81
|
||
|
|
20914b466e
|
||
|
|
3630637ec1
|
||
|
|
42224b074e
|
||
|
|
0e8ed14305
|
||
|
|
d3a12fb6f1 | ||
|
|
3f9d104adc
|
||
|
|
9e5d20796c
|
||
|
|
7433813337 | ||
|
|
42854fe975
|
||
|
|
71681f1e55 | ||
|
|
1cf0ab44fd
|
No files matched your search
@@ -14,7 +14,7 @@ git clone https://gitea.e5tv.hu/esoko/mapguesser.git
|
|||||||
|
|
||||||
All the commands listed here should be executed from the repository root.
|
All the commands listed here should be executed from the repository root.
|
||||||
|
|
||||||
### (Optional) Setup Docker stack
|
### Setup Docker stack (recommended)
|
||||||
|
|
||||||
The easiest way to build up a fully working application with web server and database is to use Docker Compose with the included `docker-compose.yml`.
|
The easiest way to build up a fully working application with web server and database is to use Docker Compose with the included `docker-compose.yml`.
|
||||||
|
|
||||||
@@ -24,9 +24,17 @@ All you have to do is executing the following command:
|
|||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Attach shell to the container of `mapguesser_app`. All of the following commands should be executed there.
|
Attach shell to the container of `mapguesser_app`:
|
||||||
|
|
||||||
**If you don't use the Docker stack you need to install your environment manually. Check `docker-compose.yml` and `docker/Dockerfile` to see the system requirements.**
|
```
|
||||||
|
docker exec -it mapguesser_app_1 bash
|
||||||
|
```
|
||||||
|
|
||||||
|
All of the following commands should be executed there.
|
||||||
|
|
||||||
|
### Manual setup (alternative)
|
||||||
|
|
||||||
|
If you don't use the Docker stack you need to install your environment manually. Check `docker-compose.yml` and `docker/Dockerfile` to see the system requirements.
|
||||||
|
|
||||||
### Initialize project
|
### Initialize project
|
||||||
|
|
||||||
@@ -40,15 +48,28 @@ composer create-project
|
|||||||
|
|
||||||
The `.env` file contains several environment variables that are needed by the application to work properly. These should be configured for your environment.
|
The `.env` file contains several environment variables that are needed by the application to work properly. These should be configured for your environment.
|
||||||
|
|
||||||
**You should set here the API keys that enable playing the game. Without these API keys the application cannot work well. To get Google API keys visit this page: https://console.developers.google.com/**
|
One very important variable is `DEV`. This indicates that the application operates in development (staging) and not in production mode.
|
||||||
|
|
||||||
One very important variable is `DEV`. This indicates that the application operates in development (staging) and not in produciton mode.
|
**Hint:** If you install the application in the Docker stack for development (staging) environment, only the variables for external dependencies (API keys, map attribution, etc.) should be adapted. All other variables (for DB connection, static root, mailing, multiplayer, etc.) are fine with the default value.
|
||||||
|
|
||||||
If you install the application in the Docker stack for development (staging) environment, only the variables for external dependencies (API keys, map attribution, etc.) should be adapted. All other variables (for DB connection, static root, mailing, etc.) are fine with the default value.
|
#### API keys
|
||||||
|
|
||||||
|
**You should set the API keys that enable playing the game. Without these API keys the application cannot work well. To get Google API keys visit this page: https://console.developers.google.com/**
|
||||||
|
|
||||||
|
Required Google APIs:
|
||||||
|
* **Maps JavaScript API**: for the interactive maps and street views
|
||||||
|
* **Maps Static API**: for the static map images
|
||||||
|
* **Street View Static API**: for the backend metadata requests
|
||||||
|
|
||||||
|
Required API keys:
|
||||||
|
* **GOOGLE_MAPS_SERVER_API_KEY**: this it used by the backend and should have access to **Street View Static API**
|
||||||
|
* **GOOGLE_MAPS_JS_API_KEY**: this is used by the frontend and should have access to **Maps JavaScript API** and **Maps Static API**
|
||||||
|
|
||||||
|
Additionally, a tile provider is also needed for map editor. This should be configured by `LEAFLET_TILESERVER_URL` and `LEAFLET_TILESERVER_ATTRIBUTION`. You can find some providers here: https://wiki.openstreetmap.org/wiki/Tile_servers. OpenStreetMap's tile server is fine for testing.
|
||||||
|
|
||||||
### (Production only) Create cron job
|
### (Production only) Create cron job
|
||||||
|
|
||||||
To maintain database (delete inactive users, old sessions etc.), the command `db:maintain` should be regularly executed. It is recommened to create a cron job that runs every hour:
|
To maintain database (delete inactive users, old sessions etc.), the command `db:maintain` should be regularly executed. It is recommended to create a cron job that runs every hour:
|
||||||
|
|
||||||
```
|
```
|
||||||
0 * * * * /path/to/your/installation/mapg db:maintain >>/var/log/cron-mapguesser.log 2>&1
|
0 * * * * /path/to/your/installation/mapg db:maintain >>/var/log/cron-mapguesser.log 2>&1
|
||||||
@@ -56,13 +77,19 @@ To maintain database (delete inactive users, old sessions etc.), the command `db
|
|||||||
|
|
||||||
### Finalize installation
|
### Finalize installation
|
||||||
|
|
||||||
After you set the environment variables in the `.env` file, execute the following command:
|
After you followed the above steps, execute the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/install.sh
|
scripts/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
**And you are done!** The application is ready to use and develop.
|
**Warning: Because of a known issue the image `mapguesser_multi` fails to run without the installation steps. You have to relauch `docker-compose up -d` after you finished the installation process.**
|
||||||
|
|
||||||
|
**And you are done!** The application is ready to use and develop. In development mode an administrative user is also created by the installation script, email is **mapg@mapg.dev**, password is **123456**. In production mode you should create the first administrative user with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
./mapg user:add EMAIL PASSWORD admin
|
||||||
|
```
|
||||||
|
|
||||||
If you installed it in the Docker stack, you can reach it on http://localhost. The mails that are sent by the application can be found on http://localhost:8080/. If needed, the database server can be directly reached on localhost:3306.
|
If you installed it in the Docker stack, you can reach it on http://localhost. The mails that are sent by the application can be found on http://localhost:8080/. If needed, the database server can be directly reached on localhost:3306.
|
||||||
|
|
||||||
|
|||||||
+139
-62
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
process.title = 'mapguesser-multi';
|
process.title = 'mapguesser-multi';
|
||||||
|
|
||||||
class State {
|
|
||||||
static OPEN = 1;
|
|
||||||
static PLACE_RECEIVED = 2;
|
|
||||||
static GUESS_SENT = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MultiGame {
|
class MultiGame {
|
||||||
|
static ROUND_TIMEOUT_DEFAULT = 120000;
|
||||||
|
static ROUND_TIMEOUT_MINIMUM = 15000;
|
||||||
|
static ROUND_TIMEOUT_DIVIDER = 1.5;
|
||||||
|
static ROUND_TIMEOUT_OFFSET = 500;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.rooms = new Map();
|
this.rooms = new Map();
|
||||||
}
|
}
|
||||||
@@ -32,24 +31,25 @@ class MultiGame {
|
|||||||
var member = room.members.get(token);
|
var member = room.members.get(token);
|
||||||
member.connection = connection;
|
member.connection = connection;
|
||||||
|
|
||||||
this._sendInitialData(room, member);
|
this._sendInitialData(room, member, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoom(roomId) {
|
createRoom(roomId) {
|
||||||
this.rooms.set(roomId, { members: new Map(), rounds: [], currentRound: -1, updated: new Date() });
|
this.rooms.set(roomId, { members: new Map(), rounds: [], currentRound: -1, updated: new Date() });
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
joinRoom(roomId, token, userName) {
|
joinRoom(roomId, token, userName) {
|
||||||
if (!this.rooms.has(roomId)) {
|
if (!this.rooms.has(roomId)) {
|
||||||
console.error('Room does not exist!')
|
return { error: 'room_not_found' };
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
var room = this.rooms.get(roomId);
|
||||||
room.updated = new Date();
|
room.updated = new Date();
|
||||||
|
|
||||||
if (room.members.has(token)) {
|
if (room.members.has(token)) {
|
||||||
return;
|
return { error: 'member_already_joined' };
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = { userName: userName };
|
var data = { userName: userName };
|
||||||
@@ -58,14 +58,14 @@ class MultiGame {
|
|||||||
self._sendToMember(member, 'member_joined', data);
|
self._sendToMember(member, 'member_joined', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
room.members.set(token, { userName: userName, state: State.OPEN, connection: null });
|
room.members.set(token, { userName: userName, connection: null });
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
startGame(roomId, places) {
|
startGame(roomId, places) {
|
||||||
if (!this.rooms.has(roomId)) {
|
if (!this.rooms.has(roomId)) {
|
||||||
//TODO: send something back
|
return { error: 'room_not_found' };
|
||||||
console.log('Room does not exist!')
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
var room = this.rooms.get(roomId);
|
||||||
@@ -73,40 +73,50 @@ class MultiGame {
|
|||||||
|
|
||||||
var rounds = [];
|
var rounds = [];
|
||||||
places.forEach(function (place) {
|
places.forEach(function (place) {
|
||||||
rounds.push({ place: place, results: new Map() })
|
rounds.push({
|
||||||
|
place: place,
|
||||||
|
results: new Map(),
|
||||||
|
timeout: MultiGame.ROUND_TIMEOUT_DEFAULT,
|
||||||
|
timeoutStarted: null,
|
||||||
|
timeoutHandler: null
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
room.rounds = rounds;
|
room.rounds = rounds;
|
||||||
|
|
||||||
this.nextRound(roomId, 0);
|
this.nextRound(roomId, 0);
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
guess(roomId, token, guessPosition, distance, score) {
|
guess(roomId, token, guessPosition, distance, score) {
|
||||||
if (!this.rooms.has(roomId)) {
|
if (!this.rooms.has(roomId)) {
|
||||||
//TODO: send something back
|
return { error: 'room_not_found' };
|
||||||
console.log('Room does not exist!')
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
var room = this.rooms.get(roomId);
|
||||||
room.updated = new Date();
|
room.updated = new Date();
|
||||||
|
|
||||||
var round = room.rounds[room.currentRound];
|
var round = room.rounds[room.currentRound];
|
||||||
var member = this.rooms.get(roomId).members.get(token);
|
if (round.results.has(token)) {
|
||||||
|
return { error: 'already_guessed' };
|
||||||
|
}
|
||||||
|
|
||||||
this._sendResultsUntilNow(room, member);
|
var member = room.members.get(token);
|
||||||
|
var allResults = this._collectResultsInRound(room, round);
|
||||||
round.results.set(member.userName, { guessPosition: guessPosition, distance: distance, score: score });
|
|
||||||
member.state = State.GUESS_SENT;
|
|
||||||
|
|
||||||
this._broadcastGuess(room, member.userName, guessPosition, distance, score);
|
this._broadcastGuess(room, member.userName, guessPosition, distance, score);
|
||||||
|
|
||||||
|
round.results.set(token, { guessPosition: guessPosition, distance: distance, score: score });
|
||||||
|
|
||||||
|
this._setNewTimeout(room, round);
|
||||||
|
|
||||||
|
return { allResults: allResults };
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRound(roomId, currentRound) {
|
nextRound(roomId, currentRound) {
|
||||||
if (!this.rooms.has(roomId)) {
|
if (!this.rooms.has(roomId)) {
|
||||||
//TODO: send something back
|
return { error: 'room_not_found' };
|
||||||
console.log('Room does not exist!')
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
var room = this.rooms.get(roomId);
|
||||||
@@ -116,43 +126,100 @@ class MultiGame {
|
|||||||
|
|
||||||
var round = room.rounds[room.currentRound];
|
var round = room.rounds[room.currentRound];
|
||||||
|
|
||||||
|
round.timeoutStarted = new Date();
|
||||||
|
var self = this;
|
||||||
|
round.timeoutHandler = setTimeout(function () {
|
||||||
|
self._endRound(room, round);
|
||||||
|
}, round.timeout + MultiGame.ROUND_TIMEOUT_OFFSET);
|
||||||
|
|
||||||
var data = {};
|
var data = {};
|
||||||
data.place = { panoId: round.place.panoId, pov: round.place.pov };
|
data.place = { panoId: round.place.panoId, pov: round.place.pov };
|
||||||
|
data.timeout = round.timeout;
|
||||||
if (room.currentRound > 0) {
|
|
||||||
data.result = { position: room.rounds[room.currentRound - 1].place.position };
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
room.members.forEach(function (member) {
|
room.members.forEach(function (member) {
|
||||||
self._sendToMember(member, 'new_round', data);
|
self._sendToMember(member, 'new_round', data);
|
||||||
|
});
|
||||||
|
|
||||||
member.state = State.PLACE_RECEIVED;
|
return { ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
_setNewTimeout(room, round) {
|
||||||
|
clearTimeout(round.timeoutHandler);
|
||||||
|
|
||||||
|
if (room.members.size === round.results.size) {
|
||||||
|
round.timeout = 0;
|
||||||
|
round.timeoutStarted = new Date();
|
||||||
|
|
||||||
|
this._endRound(room, round);
|
||||||
|
} else {
|
||||||
|
round.timeout = round.timeout - (new Date() - round.timeoutStarted);
|
||||||
|
if (round.timeout > MultiGame.ROUND_TIMEOUT_DIVIDER * MultiGame.ROUND_TIMEOUT_MINIMUM) {
|
||||||
|
round.timeout = Math.round(round.timeout / MultiGame.ROUND_TIMEOUT_DIVIDER);
|
||||||
|
} else if (round.timeout > MultiGame.ROUND_TIMEOUT_MINIMUM) {
|
||||||
|
round.timeout = MultiGame.ROUND_TIMEOUT_MINIMUM;
|
||||||
|
}
|
||||||
|
round.timeoutStarted = new Date();
|
||||||
|
var self = this;
|
||||||
|
round.timeoutHandler = setTimeout(function () {
|
||||||
|
self._endRound(room, round);
|
||||||
|
}, round.timeout + MultiGame.ROUND_TIMEOUT_OFFSET);
|
||||||
|
|
||||||
|
this._broadcastTimeout(room, round);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_endRound(room, round) {
|
||||||
|
var allResults = this._collectResultsInRound(room, round);
|
||||||
|
var self = this;
|
||||||
|
room.members.forEach(function (member, token) {
|
||||||
|
var result = { guessPosition: null, distance: null, score: 0 };
|
||||||
|
|
||||||
|
if (round.results.has(token)) {
|
||||||
|
result = round.results.get(token);
|
||||||
|
} else {
|
||||||
|
round.results.set(token, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = { position: round.place.position, result: result, allResults: allResults };
|
||||||
|
self._sendToMember(member, 'end_round', data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendInitialData(room, member) {
|
_sendInitialData(room, member, token) {
|
||||||
var data = {};
|
var data = {};
|
||||||
|
|
||||||
if (room.currentRound >= 0) {
|
if (room.currentRound >= 0) {
|
||||||
data.place = room.rounds[room.currentRound].place;
|
var round = room.rounds[room.currentRound];
|
||||||
|
|
||||||
|
data.place = round.place;
|
||||||
|
data.timeout = round.timeout - (new Date() - round.timeoutStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.history = [];
|
data.history = [];
|
||||||
for (var i = 0; i < room.currentRound; ++i) {
|
for (var i = 0; i <= room.currentRound; ++i) {
|
||||||
var round = room.rounds[i];
|
var round = room.rounds[i];
|
||||||
var result;
|
|
||||||
if (round.results.has(member.userName)) {
|
if (i === room.currentRound && !round.results.has(token)) {
|
||||||
result = round.results.get(member.userName);
|
continue;
|
||||||
} else {
|
|
||||||
result = { guessPosition: null, distance: null, score: 0 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result = { guessPosition: null, distance: null, score: 0 };
|
||||||
|
var allResults = [];
|
||||||
|
|
||||||
|
round.results.forEach(function (currentResult, currentToken) {
|
||||||
|
if (token === currentToken) {
|
||||||
|
result = currentResult;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
allResults.push({ userName: room.members.get(currentToken).userName, guessPosition: currentResult.guessPosition, distance: currentResult.distance, score: currentResult.score });
|
||||||
|
});
|
||||||
|
|
||||||
data.history.push({
|
data.history.push({
|
||||||
position: round.place.position,
|
position: round.place.position,
|
||||||
guessPosition: result.guessPosition,
|
result: result,
|
||||||
distance: result.distance,
|
allResults: allResults
|
||||||
score: result.score
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,33 +228,42 @@ class MultiGame {
|
|||||||
data.members.push({ userName: currentMember.userName, me: member === currentMember });
|
data.members.push({ userName: currentMember.userName, me: member === currentMember });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
data.readyToContinue = room.currentRound >= 0 && room.members.size === room.rounds[room.currentRound].results.size
|
||||||
|
|
||||||
this._sendToMember(member, 'initialize', data);
|
this._sendToMember(member, 'initialize', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendResultsUntilNow(room, member) {
|
_collectResultsInRound(room, round) {
|
||||||
if (member.state !== State.GUESS_SENT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var round = room.rounds[room.currentRound];
|
|
||||||
|
|
||||||
var results = [];
|
var results = [];
|
||||||
round.results.forEach(function (result, userName) {
|
round.results.forEach(function (result, token) {
|
||||||
results.push({ userName: userName, guessPosition: result.guessPosition, distance: result.distance, score: result.score });
|
results.push({
|
||||||
|
userName: room.members.get(token).userName,
|
||||||
|
guessPosition: result.guessPosition,
|
||||||
|
distance: result.distance,
|
||||||
|
score: result.score
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this._sendToMember(member, 'results', results);
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
_broadcastTimeout(room, round) {
|
||||||
|
var self = this;
|
||||||
|
room.members.forEach(function (member) {
|
||||||
|
self._sendToMember(member, 'timeout_changed', { timeout: round.timeout });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcastGuess(room, userName, guessPosition, distance, score) {
|
_broadcastGuess(room, userName, guessPosition, distance, score) {
|
||||||
var data = { userName: userName, guessPosition: guessPosition, distance: distance, score: score };
|
var data = { userName: userName, guessPosition: guessPosition, distance: distance, score: score };
|
||||||
|
var round = room.rounds[room.currentRound];
|
||||||
room.members.forEach(function (member) {
|
var self = this;
|
||||||
if (!member.state !== State.GUESS_SENT) {
|
room.members.forEach(function (member, token) {
|
||||||
|
if (!round.results.has(token)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sendToMember(member, 'guess', data);
|
self._sendToMember(member, 'guess', data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,34 +300,35 @@ var tcpServer = net.createServer(function (socket) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var response;
|
||||||
switch (data.func) {
|
switch (data.func) {
|
||||||
case 'create_room':
|
case 'create_room':
|
||||||
multiGame.createRoom(data.args.roomId);
|
response = multiGame.createRoom(data.args.roomId);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'join_room':
|
case 'join_room':
|
||||||
multiGame.joinRoom(data.args.roomId, data.args.token, data.args.userName);
|
response = multiGame.joinRoom(data.args.roomId, data.args.token, data.args.userName);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'start_game':
|
case 'start_game':
|
||||||
multiGame.startGame(data.args.roomId, data.args.places);
|
response = multiGame.startGame(data.args.roomId, data.args.places);
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'guess':
|
case 'guess':
|
||||||
multiGame.guess(data.args.roomId, data.args.token, data.args.guessPosition, data.args.distance, data.args.score);
|
response = multiGame.guess(data.args.roomId, data.args.token, data.args.guessPosition, data.args.distance, data.args.score);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'next_round':
|
case 'next_round':
|
||||||
multiGame.nextRound(data.args.roomId, data.args.currentRound);
|
response = multiGame.nextRound(data.args.roomId, data.args.currentRound);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.write('OK');
|
socket.write(JSON.stringify(response));
|
||||||
socket.end();
|
socket.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -8,6 +8,6 @@
|
|||||||
"ws": "^7.4.4"
|
"ws": "^7.4.4"
|
||||||
},
|
},
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
"author": "Pőcze Bence <bence@pocze.ch>",
|
"author": "Pőcze Bence and The MapGuesser Contributors <bence@pocze.ch>",
|
||||||
"license": "GNU AGPL 3.0"
|
"license": "GNU AGPL 3.0"
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#distanceInfo>p:nth-child(2), #scoreInfo>p:nth-child(2) {
|
#distanceInfo>p:nth-child(2), #distanceInfo>p:nth-child(3), #scoreInfo>p:nth-child(2) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,13 +111,55 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#countdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
padding: 0 8px;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
border: solid 1px #555555;
|
||||||
|
border-radius: 3px;
|
||||||
|
opacity: 0.95;
|
||||||
|
z-index: 5;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#countdown.yellow {
|
||||||
|
background-color: #f7c789;
|
||||||
|
border: solid 1px #e8a349;
|
||||||
|
}
|
||||||
|
|
||||||
|
#countdown.red {
|
||||||
|
background-color: #f7a5a5;
|
||||||
|
border: solid 1px #aa5e5e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#countdown p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#countdown.yellow p {
|
||||||
|
color: #9c4308;
|
||||||
|
}
|
||||||
|
|
||||||
|
#countdown.red p {
|
||||||
|
color: #701919;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navigation {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 599px) {
|
@media screen and (max-width: 599px) {
|
||||||
#mapName {
|
#mapName {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#showGuessButtonContainer {
|
#showGuessButtonContainer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 20px;
|
left: 65px;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@@ -134,6 +176,10 @@
|
|||||||
#scoreBarBase {
|
#scoreBarBase {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
#navigation {
|
||||||
|
bottom: 25px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 600px) {
|
@media screen and (min-width: 600px) {
|
||||||
@@ -177,6 +223,10 @@
|
|||||||
#scoreBarBase {
|
#scoreBarBase {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
#navigation {
|
||||||
|
bottom: 50px;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
@media screen and (max-height: 424px) {
|
@media screen and (max-height: 424px) {
|
||||||
#guess {
|
#guess {
|
||||||
top: 10px;
|
top: 10px;
|
||||||
@@ -191,5 +241,9 @@
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
}
|
}
|
||||||
|
#navigation {
|
||||||
|
bottom: 30px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#map {
|
.map {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -7,6 +7,13 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#mapSelection img {
|
||||||
|
display: inline;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
/* modify the cursor for the Leaflet map */
|
/* modify the cursor for the Leaflet map */
|
||||||
.leaflet-container {
|
.leaflet-container {
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
@@ -48,6 +55,12 @@
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#overlayControl {
|
||||||
|
bottom: 20px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
#deleteButton {
|
#deleteButton {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -65,6 +78,9 @@
|
|||||||
#placeControl {
|
#placeControl {
|
||||||
top: calc(50% + 10px);
|
top: calc(50% + 10px);
|
||||||
}
|
}
|
||||||
|
.hideOnMobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1000px), (max-height: 599px) {
|
@media screen and (min-width: 1000px), (max-height: 599px) {
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ html, body {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
button::-moz-focus-inner, input::-moz-focus-inner {
|
button::-moz-focus-inner, input::-moz-focus-inner {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
@@ -374,6 +378,7 @@ header>p>span:not(:last-child) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
background-color: #ffffff;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,6 +443,43 @@ div.box {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.circleControl {
|
||||||
|
position: absolute;
|
||||||
|
width: 60px;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circleControl .controlItem {
|
||||||
|
height: 60px;
|
||||||
|
margin-top: 10px;
|
||||||
|
opacity: 70%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circleControl .controlItem:hover {
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circleControl .controlItem div {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circleControl .controlBackground {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circleControl .controlIcon {
|
||||||
|
width: 75%;
|
||||||
|
height: 75%;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
-ms-transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 599px) {
|
@media screen and (max-width: 599px) {
|
||||||
header h1 span {
|
header h1 span {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -464,6 +506,12 @@ div.box {
|
|||||||
div.box {
|
div.box {
|
||||||
width: initial;
|
width: initial;
|
||||||
}
|
}
|
||||||
|
.circleControl {
|
||||||
|
width: 45px;
|
||||||
|
}
|
||||||
|
.circleControl .controlItem {
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 600px) {
|
@media screen and (min-width: 600px) {
|
||||||
@@ -493,6 +541,12 @@ div.box {
|
|||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
.circleControl {
|
||||||
|
width: 45px;
|
||||||
|
}
|
||||||
|
.circleControl .controlItem {
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-height: 400px) and (max-height: 499px) {
|
@media screen and (min-height: 400px) and (max-height: 499px) {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 16 16">
|
||||||
|
<circle cx="50%" cy="50%" r="50%" fill="black" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 146 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<polygon id="needleNorth" points="50,0 33,50 66,50" style="fill:red;stroke:black;stroke-width:1" />
|
||||||
|
<polygon id="needleSouth" points="50,100 33,50 66,50" style="fill:white;stroke:black;stroke-width:1" />
|
||||||
|
Sorry, your browser does not support inline SVG.
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 328 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<!-- Original image: Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="#3183ce" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="m8 3.293 6 6V13.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5V9.293l6-6zm5-.793V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
|
||||||
|
<path fill-rule="evenodd" d="M7.293 1.5a1 1 0 0 1 1.414 0l6.647 6.646a.5.5 0 0 1-.708.708L8 2.207 1.354 8.854a.5.5 0 1 1-.708-.708L7.293 1.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 556 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<!-- Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.502.502 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103zM10 1.91l-4-.8v12.98l4 .8V1.91zm1 12.98 4-.8V1.11l-4 .8v12.98zm-6-.8V1.11l-4 .8v12.98l4-.8z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 530 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
<!-- Original image: Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
||||||
|
<svg viewBox="0 0 12 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fill="#3183ce"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
stroke="#19456d"
|
||||||
|
stroke-width="0.3"
|
||||||
|
stroke-linecap="round"
|
||||||
|
d="m 5.9999998,15.849652 c 0,0 5.8511182,-5.579947 5.8511182,-9.8134832 a 5.8511179,5.8880898 0 0 0 -11.7022358,0 c 0,4.2335362 5.8511176,9.8134832 5.8511176,9.8134832" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 529 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<!-- Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" viewBox="0 0 16 16">
|
||||||
|
<path d="m14.12 10.163 1.715.858c.22.11.22.424 0 .534L8.267 15.34a.598.598 0 0 1-.534 0L.165 11.555a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.66zM7.733.063a.598.598 0 0 1 .534 0l7.568 3.784a.3.3 0 0 1 0 .535L8.267 8.165a.598.598 0 0 1-.534 0L.165 4.382a.299.299 0 0 1 0-.535L7.733.063z"/>
|
||||||
|
<path d="m14.12 6.576 1.715.858c.22.11.22.424 0 .534l-7.568 3.784a.598.598 0 0 1-.534 0L.165 7.968a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.659z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 718 B |
+374
-141
@@ -17,6 +17,10 @@
|
|||||||
adaptGuess: false,
|
adaptGuess: false,
|
||||||
googleLink: null,
|
googleLink: null,
|
||||||
|
|
||||||
|
readyToContinue: true,
|
||||||
|
timeoutEnd: null,
|
||||||
|
countdownHandler: null,
|
||||||
|
|
||||||
MultiConnector: {
|
MultiConnector: {
|
||||||
connection: null,
|
connection: null,
|
||||||
reconnectCounter: 0,
|
reconnectCounter: 0,
|
||||||
@@ -30,9 +34,7 @@
|
|||||||
|
|
||||||
Game.MultiConnector.connection.onopen = function () {
|
Game.MultiConnector.connection.onopen = function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
Game.MultiConnector.reconnectCounter = 0;
|
Game.MultiConnector.reconnectCounter = 0;
|
||||||
|
|
||||||
Game.MultiConnector.connection.send(JSON.stringify({ func: 'connect_to_room', args: { roomId: roomId, token: Game.multi.token } }));
|
Game.MultiConnector.connection.send(JSON.stringify({ func: 'connect_to_room', args: { roomId: roomId, token: Game.multi.token } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,12 +68,16 @@
|
|||||||
Game.MultiConnector.newRound(json.data);
|
Game.MultiConnector.newRound(json.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'results':
|
case 'guess':
|
||||||
//TODO
|
Game.MultiConnector.guess(json.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'guess':
|
case 'timeout_changed':
|
||||||
//TODO
|
Game.MultiConnector.timeoutChanged(json.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'end_round':
|
||||||
|
Game.MultiConnector.endRound(json.data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -91,30 +97,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initialize: function (data) {
|
initialize: function (data) {
|
||||||
if (data.history) {
|
Game.readyToContinue = false;
|
||||||
for (var i = 0; i < data.history.length; ++i) {
|
|
||||||
var round = data.history[i];
|
|
||||||
Game.rounds.push({ position: round.position, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null });
|
|
||||||
Game.addRealGuessPair(round.position, round.guessPosition, true);
|
|
||||||
Game.scoreSum += round.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.place) {
|
|
||||||
Game.panoId = data.place.panoId;
|
|
||||||
Game.pov = data.place.pov;
|
|
||||||
|
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
|
||||||
MapGuesser.hideModal();
|
|
||||||
|
|
||||||
Game.startNewRound();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
|
if (data.history.length === 0 && !data.place) {
|
||||||
var div = document.getElementById('players');
|
var div = document.getElementById('players');
|
||||||
|
|
||||||
for (var i = 0; i < data.members.length; ++i) {
|
for (var i = 0; i < data.members.length; ++i) {
|
||||||
@@ -124,6 +109,49 @@
|
|||||||
p.innerHTML = member.userName + (member.me ? ' (me)' : '');
|
p.innerHTML = member.userName + (member.me ? ' (me)' : '');
|
||||||
div.appendChild(p);
|
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) {
|
memberJoined: function (data) {
|
||||||
@@ -135,27 +163,51 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
newRound: function (data) {
|
newRound: function (data) {
|
||||||
//TODO: workaround until results are not sent
|
|
||||||
if (Game.adaptGuess) {
|
|
||||||
document.getElementById('guess').classList.remove('adapt');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
||||||
Game.reset();
|
Game.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if player didn't guess - TODO: show everything on a map
|
Game.readyToContinue = false;
|
||||||
if (data.result && Game.rounds.length > 0 && !Game.rounds[Game.rounds.length - 1].position) {
|
|
||||||
Game.rounds[Game.rounds.length - 1].position = data.result.position;
|
|
||||||
Game.addRealGuessPair(data.result.position, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.panoId = data.place.panoId;
|
Game.panoId = data.place.panoId;
|
||||||
Game.pov = data.place.pov;
|
Game.pov = data.place.pov;
|
||||||
|
|
||||||
MapGuesser.hideModal();
|
document.getElementById('multi').style.visibility = 'hidden';
|
||||||
Game.resetRound();
|
Game.resetRound();
|
||||||
Game.startNewRound();
|
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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -174,11 +226,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
var url = roomId ? '/multiGame/' + roomId + '/prepare.json' : '/game/' + mapId + '/prepare.json';
|
var url = roomId ? '/multiGame/' + roomId + '/prepare.json' : '/game/' + mapId + '/prepare.json';
|
||||||
MapGuesser.httpRequest('POST', url, function () {
|
MapGuesser.httpRequest('POST', url, function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (this.response.error) {
|
||||||
|
Game.handleErrorResponse(this.response.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('mapName').innerHTML = this.response.mapName;
|
document.getElementById('mapName').innerHTML = this.response.mapName;
|
||||||
Game.mapBounds = this.response.bounds;
|
Game.mapBounds = this.response.bounds;
|
||||||
|
|
||||||
@@ -188,13 +244,12 @@
|
|||||||
Game.multi.token = this.response.token;
|
Game.multi.token = this.response.token;
|
||||||
Game.multi.owner = this.response.owner;
|
Game.multi.owner = this.response.owner;
|
||||||
|
|
||||||
MapGuesser.showModal('multi');
|
document.getElementById('multi').style.visibility = 'visible';
|
||||||
if (Game.multi.owner) {
|
if (Game.multi.owner) {
|
||||||
document.getElementById('startMultiGameButton').style.display = 'block';
|
document.getElementById('startMultiGameButton').style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
Game.MultiConnector.connect();
|
Game.MultiConnector.connect();
|
||||||
}
|
}
|
||||||
}, data);
|
}, data);
|
||||||
@@ -202,8 +257,6 @@
|
|||||||
|
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
document.getElementById('panoCover').style.visibility = 'visible';
|
||||||
document.getElementById('currentRound').innerHTML = '1/' + String(Game.NUMBER_OF_ROUNDS);
|
|
||||||
document.getElementById('currentScoreSum').innerHTML = '0/0';
|
|
||||||
|
|
||||||
Game.map.setOptions({
|
Game.map.setOptions({
|
||||||
draggableCursor: 'crosshair'
|
draggableCursor: 'crosshair'
|
||||||
@@ -216,30 +269,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
MapGuesser.httpRequest('POST', '/game/' + mapId + '/initialData.json', function () {
|
MapGuesser.httpRequest('POST', '/game/' + mapId + '/initialData.json', function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||||
|
|
||||||
if (this.response.error) {
|
if (this.response.error) {
|
||||||
//TODO: handle this error
|
Game.handleErrorResponse(this.response.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.panoId = this.response.place.panoId;
|
Game.panoId = this.response.place.panoId;
|
||||||
Game.pov = this.response.place.pov;
|
Game.pov = this.response.place.pov;
|
||||||
|
|
||||||
if (this.response.history) {
|
|
||||||
for (var i = 0; i < this.response.history.length; ++i) {
|
for (var i = 0; i < this.response.history.length; ++i) {
|
||||||
var round = this.response.history[i];
|
var round = this.response.history[i];
|
||||||
Game.rounds.push({ position: round.position, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null });
|
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
|
||||||
Game.addRealGuessPair(round.position, round.guessPosition, true);
|
Game.addPositionToResultMap(true);
|
||||||
Game.scoreSum += round.score;
|
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
|
||||||
|
Game.scoreSum += round.result.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
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);
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
||||||
}
|
|
||||||
|
|
||||||
Game.startNewRound();
|
Game.startNewRound();
|
||||||
});
|
});
|
||||||
@@ -257,9 +308,13 @@
|
|||||||
if (round.realMarker) {
|
if (round.realMarker) {
|
||||||
round.realMarker.setMap(null);
|
round.realMarker.setMap(null);
|
||||||
}
|
}
|
||||||
if (round.guessMarker) {
|
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
||||||
round.guessMarker.setMap(null);
|
var guessMarker = round.guessMarkers[j];
|
||||||
round.line.setMap(null);
|
guessMarker.marker.setMap(null);
|
||||||
|
guessMarker.line.setMap(null);
|
||||||
|
if (guessMarker.info) {
|
||||||
|
guessMarker.info.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,16 +324,21 @@
|
|||||||
var distanceInfo = document.getElementById('distanceInfo');
|
var distanceInfo = document.getElementById('distanceInfo');
|
||||||
distanceInfo.children[0].style.display = null;
|
distanceInfo.children[0].style.display = null;
|
||||||
distanceInfo.children[1].style.display = null;
|
distanceInfo.children[1].style.display = null;
|
||||||
|
distanceInfo.children[2].style.display = null;
|
||||||
var scoreInfo = document.getElementById('scoreInfo');
|
var scoreInfo = document.getElementById('scoreInfo');
|
||||||
scoreInfo.children[0].style.display = null;
|
scoreInfo.children[0].style.display = null;
|
||||||
scoreInfo.children[1].style.display = null;
|
scoreInfo.children[1].style.display = null;
|
||||||
document.getElementById('continueButton').style.display = null;
|
document.getElementById('continueButton').style.display = null;
|
||||||
|
document.getElementById('showSummaryButton').style.display = null;
|
||||||
document.getElementById('startNewGameButton').style.display = null;
|
document.getElementById('startNewGameButton').style.display = null;
|
||||||
|
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
document.getElementById('guess').classList.remove('result');
|
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.initialize();
|
Game.initialize();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -289,16 +349,24 @@
|
|||||||
var lastRound = Game.rounds[Game.rounds.length - 1];
|
var lastRound = Game.rounds[Game.rounds.length - 1];
|
||||||
|
|
||||||
lastRound.realMarker.setVisible(false);
|
lastRound.realMarker.setVisible(false);
|
||||||
if (lastRound.guessMarker) {
|
for (var i = 0; i < lastRound.guessMarkers.length; ++i) {
|
||||||
lastRound.guessMarker.setVisible(false);
|
var guessMarker = lastRound.guessMarkers[i];
|
||||||
lastRound.line.setVisible(false);
|
guessMarker.marker.setVisible(false);
|
||||||
|
guessMarker.line.setVisible(false);
|
||||||
|
if (guessMarker.info) {
|
||||||
|
guessMarker.info.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
document.getElementById('guess').classList.remove('result')
|
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({
|
Game.map.setOptions({
|
||||||
draggableCursor: 'crosshair'
|
draggableCursor: 'crosshair'
|
||||||
@@ -314,27 +382,38 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
startNewRound: function () {
|
startNewRound: function () {
|
||||||
Game.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarker: null, line: null });
|
Game.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarkers: [] });
|
||||||
|
|
||||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
||||||
|
|
||||||
Game.loadPano(Game.panoId, Game.pov);
|
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)";
|
||||||
},
|
},
|
||||||
|
|
||||||
handleErrorResponse: function (error) {
|
handleErrorResponse: function (error) {
|
||||||
// for the time being we only handle the "no_session_found" error and reset the game
|
switch (error) {
|
||||||
|
case 'no_session_found':
|
||||||
if (roomId) {
|
MapGuesser.showModalWithContent('Error', 'Your session is invalid!', [{
|
||||||
//TODO: better error message
|
type: 'button',
|
||||||
alert('Your session is invalid, please start multiplayer again!')
|
classNames: [],
|
||||||
return;
|
text: 'Restart game',
|
||||||
|
onclick: function () {
|
||||||
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
}]);
|
||||||
|
break;
|
||||||
|
|
||||||
MapGuesser.httpRequest('GET', '/game/' + mapId + '/prepare.json', function () {
|
case 'game_already_started':
|
||||||
Game.mapBounds = this.response.bounds;
|
MapGuesser.showModalWithContent('Error', 'This game is already started, you cannot join.');
|
||||||
|
break;
|
||||||
|
|
||||||
Game.reset();
|
default:
|
||||||
});
|
MapGuesser.showModalWithContent('Error', 'Error code: \'' + error + '\'');
|
||||||
|
break
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
loadPano: function (panoId, pov) {
|
loadPano: function (panoId, pov) {
|
||||||
@@ -347,7 +426,106 @@
|
|||||||
Game.panorama.setPano(panoId);
|
Game.panorama.setPano(panoId);
|
||||||
},
|
},
|
||||||
|
|
||||||
evaluateGuess: function () {
|
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);
|
||||||
|
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) {
|
||||||
|
// 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'
|
||||||
|
});
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
||||||
|
document.getElementById('continueButton').style.display = 'none';
|
||||||
|
document.getElementById('showSummaryButton').style.display = 'block';
|
||||||
|
} else if (roomId) {
|
||||||
|
if (Game.multi.owner) {
|
||||||
|
if (!Game.readyToContinue) {
|
||||||
|
document.getElementById('continueButton').disabled = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.getElementById('continueButton').style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
guess: function () {
|
||||||
if (!Game.guessMarker) {
|
if (!Game.guessMarker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -356,73 +534,34 @@
|
|||||||
Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition;
|
Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition;
|
||||||
|
|
||||||
document.getElementById('guessButton').disabled = true;
|
document.getElementById('guessButton').disabled = true;
|
||||||
if (Game.adaptGuess) {
|
|
||||||
document.getElementById('guess').classList.remove('adapt');
|
|
||||||
}
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
document.getElementById('panoCover').style.visibility = 'visible';
|
||||||
|
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
data.append('lat', String(guessPosition.lat));
|
data.append('lat', String(guessPosition.lat));
|
||||||
data.append('lng', String(guessPosition.lng));
|
data.append('lng', String(guessPosition.lng));
|
||||||
|
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
var url = roomId ? '/multiGame/' + roomId + '/guess.json' : '/game/' + mapId + '/guess.json';
|
var url = roomId ? '/multiGame/' + roomId + '/guess.json' : '/game/' + mapId + '/guess.json';
|
||||||
MapGuesser.httpRequest('POST', url, function () {
|
MapGuesser.httpRequest('POST', url, function () {
|
||||||
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
if (this.response.error) {
|
if (this.response.error) {
|
||||||
Game.handleErrorResponse(this.response.error);
|
Game.handleErrorResponse(this.response.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.guessMarker.setMap(null);
|
Game.receiveResult(this.response.position, guessPosition, this.response.result, this.response.allResults);
|
||||||
Game.guessMarker = null;
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
document.getElementById('guess').classList.add('result');
|
|
||||||
|
|
||||||
Game.scoreSum += this.response.result.score;
|
|
||||||
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
||||||
|
|
||||||
Game.rounds[Game.rounds.length - 1].position = this.response.result.position;
|
|
||||||
Game.addRealGuessPair(this.response.result.position, guessPosition);
|
|
||||||
|
|
||||||
var resultBounds = new google.maps.LatLngBounds();
|
|
||||||
resultBounds.extend(this.response.result.position);
|
|
||||||
resultBounds.extend(guessPosition);
|
|
||||||
|
|
||||||
Game.map.setOptions({
|
|
||||||
draggableCursor: 'grab'
|
|
||||||
});
|
|
||||||
Game.map.fitBounds(resultBounds);
|
|
||||||
|
|
||||||
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(this.response.result.distance);
|
|
||||||
document.getElementById('score').innerHTML = this.response.result.score;
|
|
||||||
|
|
||||||
var scoreBarProperties = Game.calculateScoreBarProperties(this.response.result.score, Game.MAX_SCORE);
|
|
||||||
var scoreBar = document.getElementById('scoreBar');
|
|
||||||
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
|
|
||||||
scoreBar.style.width = scoreBarProperties.width;
|
|
||||||
|
|
||||||
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
|
||||||
document.getElementById('continueButton').style.display = 'none';
|
|
||||||
document.getElementById('showSummaryButton').style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.response.place) {
|
if (this.response.place) {
|
||||||
Game.panoId = this.response.place.panoId;
|
Game.panoId = this.response.place.panoId;
|
||||||
Game.pov = this.response.place.pov;
|
Game.pov = this.response.place.pov;
|
||||||
} else {
|
|
||||||
if (!Game.multi.owner) {
|
|
||||||
//TODO: "waiting for" disabled button
|
|
||||||
document.getElementById('continueButton').style.display = 'none';
|
|
||||||
}
|
|
||||||
Game.panoId = null;
|
|
||||||
Game.pov = null;
|
|
||||||
}
|
}
|
||||||
}, data);
|
}, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
addRealGuessPair: function (position, guessPosition, hidden) {
|
addPositionToResultMap: function (hidden) {
|
||||||
var round = Game.rounds[Game.rounds.length - 1];
|
var round = Game.rounds[Game.rounds.length - 1];
|
||||||
|
var position = round.position;
|
||||||
|
|
||||||
round.realMarker = new google.maps.Marker({
|
round.realMarker = new google.maps.Marker({
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
@@ -443,20 +582,25 @@
|
|||||||
round.realMarker.addListener('click', function () {
|
round.realMarker.addListener('click', function () {
|
||||||
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
if (!guessPosition) {
|
addGuessPositionToResultMap: function (guessPosition, result, hidden) {
|
||||||
return;
|
var round = Game.rounds[Game.rounds.length - 1];
|
||||||
}
|
var position = round.position;
|
||||||
|
|
||||||
round.guessMarker = new google.maps.Marker({
|
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() : '?';
|
||||||
|
|
||||||
|
guessMarker.marker = new google.maps.Marker({
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
visible: !hidden,
|
visible: !hidden,
|
||||||
position: guessPosition,
|
position: guessPosition,
|
||||||
zIndex: Game.rounds.length,
|
zIndex: Game.rounds.length,
|
||||||
clickable: false,
|
clickable: !!result,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
icon: {
|
icon: {
|
||||||
url: STATIC_ROOT + '/img/markers/marker-gray-empty.svg?rev=' + REVISION,
|
url: STATIC_ROOT + '/img/markers/' + markerSvg + '?rev=' + REVISION,
|
||||||
size: new google.maps.Size(24, 32),
|
size: new google.maps.Size(24, 32),
|
||||||
scaledSize: new google.maps.Size(24, 32),
|
scaledSize: new google.maps.Size(24, 32),
|
||||||
anchor: new google.maps.Point(12, 32),
|
anchor: new google.maps.Point(12, 32),
|
||||||
@@ -467,11 +611,11 @@
|
|||||||
fontFamily: 'Roboto',
|
fontFamily: 'Roboto',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
text: '?'
|
text: markerLabel
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
round.line = new google.maps.Polyline({
|
guessMarker.line = new google.maps.Polyline({
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
visible: !hidden,
|
visible: !hidden,
|
||||||
path: [
|
path: [
|
||||||
@@ -494,6 +638,19 @@
|
|||||||
draggable: false,
|
draggable: false,
|
||||||
editable: false
|
editable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
guessMarker.info = new google.maps.InfoWindow({
|
||||||
|
content: '<p class="small bold">' + result.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) {
|
calculateScoreBarProperties: function (score, maxScore) {
|
||||||
@@ -514,7 +671,8 @@
|
|||||||
showSummary: function () {
|
showSummary: function () {
|
||||||
var distanceInfo = document.getElementById('distanceInfo');
|
var distanceInfo = document.getElementById('distanceInfo');
|
||||||
distanceInfo.children[0].style.display = 'none';
|
distanceInfo.children[0].style.display = 'none';
|
||||||
distanceInfo.children[1].style.display = 'block';
|
distanceInfo.children[1].style.display = 'none';
|
||||||
|
distanceInfo.children[2].style.display = 'block';
|
||||||
var scoreInfo = document.getElementById('scoreInfo');
|
var scoreInfo = document.getElementById('scoreInfo');
|
||||||
scoreInfo.children[0].style.display = 'none';
|
scoreInfo.children[0].style.display = 'none';
|
||||||
scoreInfo.children[1].style.display = 'block';
|
scoreInfo.children[1].style.display = 'block';
|
||||||
@@ -522,6 +680,9 @@
|
|||||||
|
|
||||||
if (!roomId || Game.multi.owner) {
|
if (!roomId || Game.multi.owner) {
|
||||||
document.getElementById('startNewGameButton').style.display = 'block';
|
document.getElementById('startNewGameButton').style.display = 'block';
|
||||||
|
if (!Game.readyToContinue) {
|
||||||
|
document.getElementById('startNewGameButton').disabled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultBounds = new google.maps.LatLngBounds();
|
var resultBounds = new google.maps.LatLngBounds();
|
||||||
@@ -545,14 +706,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
round.realMarker.setVisible(true);
|
round.realMarker.setVisible(true);
|
||||||
if (round.guessMarker) {
|
|
||||||
round.guessMarker.setVisible(true);
|
|
||||||
round.line.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
resultBounds.extend(round.position);
|
resultBounds.extend(round.position);
|
||||||
if (round.guessMarker) {
|
|
||||||
resultBounds.extend(round.guessPosition);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,6 +745,52 @@
|
|||||||
Game.googleLink.href = 'https://maps.google.com/maps';
|
Game.googleLink.href = 'https://maps.google.com/maps';
|
||||||
}
|
}
|
||||||
}, 1);
|
}, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
startCountdown: function (timeout) {
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -614,7 +821,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
Game.map.addListener('click', function (e) {
|
Game.map.addListener('click', function (e) {
|
||||||
if (Game.rounds[Game.rounds.length - 1].guessPosition) {
|
if (Game.rounds[Game.rounds.length - 1].guessPosition || Game.rounds[Game.rounds.length - 1].position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +836,7 @@
|
|||||||
clickable: false,
|
clickable: false,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
icon: {
|
icon: {
|
||||||
url: STATIC_ROOT + '/img/markers/marker-gray-empty.svg?rev=' + REVISION,
|
url: STATIC_ROOT + '/img/markers/marker-blue-empty.svg?rev=' + REVISION,
|
||||||
size: new google.maps.Size(24, 32),
|
size: new google.maps.Size(24, 32),
|
||||||
scaledSize: new google.maps.Size(24, 32),
|
scaledSize: new google.maps.Size(24, 32),
|
||||||
anchor: new google.maps.Point(12, 32),
|
anchor: new google.maps.Point(12, 32),
|
||||||
@@ -660,6 +867,9 @@
|
|||||||
|
|
||||||
Game.panorama.addListener('pov_changed', function () {
|
Game.panorama.addListener('pov_changed', function () {
|
||||||
Game.rewriteGoogleLink();
|
Game.rewriteGoogleLink();
|
||||||
|
|
||||||
|
const heading = Game.panorama.getPov().heading;
|
||||||
|
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
|
||||||
});
|
});
|
||||||
|
|
||||||
if (COOKIES_CONSENT) {
|
if (COOKIES_CONSENT) {
|
||||||
@@ -669,27 +879,33 @@
|
|||||||
document.getElementById('showGuessButton').onclick = function () {
|
document.getElementById('showGuessButton').onclick = function () {
|
||||||
this.style.visibility = 'hidden';
|
this.style.visibility = 'hidden';
|
||||||
document.getElementById('guess').style.visibility = 'visible';
|
document.getElementById('guess').style.visibility = 'visible';
|
||||||
|
document.getElementById('navigation').style.visibility = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('closeGuessButton').onclick = function () {
|
document.getElementById('closeGuessButton').onclick = function () {
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
|
document.getElementById('navigation').style.visibility = 'visible';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('guessButton').onclick = function () {
|
document.getElementById('guessButton').onclick = function () {
|
||||||
Game.evaluateGuess();
|
Game.guess();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('continueButton').onclick = function () {
|
document.getElementById('continueButton').onclick = function () {
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
if (!Game.multi.owner) {
|
if (!Game.multi.owner || !Game.readyToContinue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/nextRound.json', function () {
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/nextRound.json', function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (this.response.error) {
|
||||||
|
Game.handleErrorResponse(this.response.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Game.resetRound();
|
Game.resetRound();
|
||||||
@@ -707,9 +923,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (this.response.error) {
|
||||||
|
Game.handleErrorResponse(this.response.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Game.reset();
|
Game.reset();
|
||||||
@@ -721,11 +941,24 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapGuesser.hideModal();
|
document.getElementById('multi').style.visibility = 'hidden';
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
|
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
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 });
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
+345
-55
@@ -7,7 +7,6 @@
|
|||||||
description: null
|
description: null
|
||||||
},
|
},
|
||||||
map: null,
|
map: null,
|
||||||
markers: null,
|
|
||||||
panorama: null,
|
panorama: null,
|
||||||
selectedMarker: null,
|
selectedMarker: null,
|
||||||
added: {},
|
added: {},
|
||||||
@@ -81,22 +80,16 @@
|
|||||||
MapEditor.panorama.setPano(panoLocationData.pano);
|
MapEditor.panorama.setPano(panoLocationData.pano);
|
||||||
},
|
},
|
||||||
|
|
||||||
requestPanoData: function (location, canBeIndoor) {
|
requestPanoData: function (location) {
|
||||||
var sv = new google.maps.StreetViewService();
|
var sv = new google.maps.StreetViewService();
|
||||||
|
|
||||||
sv.getPanorama({
|
sv.getPanorama({
|
||||||
location: location,
|
location: location,
|
||||||
preference: google.maps.StreetViewPreference.NEAREST,
|
preference: google.maps.StreetViewPreference.NEAREST,
|
||||||
radius: 100,
|
radius: MapEditor.map.getSearchRadius(location),
|
||||||
source: canBeIndoor ? google.maps.StreetViewSource.DEFAULT : google.maps.StreetViewSource.OUTDOOR
|
|
||||||
}, function (data, status) {
|
}, function (data, status) {
|
||||||
var panoLocationData = status === google.maps.StreetViewStatus.OK ? data.location : null;
|
var panoLocationData = status === google.maps.StreetViewStatus.OK ? data.location : null;
|
||||||
|
|
||||||
if (panoLocationData === null && !canBeIndoor) {
|
|
||||||
MapEditor.requestPanoData(location, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
MapEditor.loadPanoForNewPlace(panoLocationData);
|
MapEditor.loadPanoForNewPlace(panoLocationData);
|
||||||
@@ -118,16 +111,13 @@
|
|||||||
MapEditor.resetSelected();
|
MapEditor.resetSelected();
|
||||||
MapEditor.selectedMarker = marker;
|
MapEditor.selectedMarker = marker;
|
||||||
|
|
||||||
MapEditor.map.invalidateSize(true);
|
MapEditor.map.resize();
|
||||||
MapEditor.map.panTo(marker.getLatLng());
|
MapEditor.map.panTo(marker.getLatLng());
|
||||||
|
|
||||||
MapEditor.panorama.setVisible(false);
|
MapEditor.panorama.setVisible(false);
|
||||||
|
|
||||||
if (marker.placeId) {
|
if (marker.placeId) {
|
||||||
MapEditor.markers.removeLayer(MapEditor.selectedMarker);
|
MapEditor.map.changeMarkerIcon(marker, MapEditor.map.iconCollection.iconBlue);
|
||||||
MapEditor.map.addLayer(MapEditor.selectedMarker);
|
|
||||||
marker.setIcon(IconCollection.iconBlue);
|
|
||||||
marker.setZIndexOffset(2000);
|
|
||||||
|
|
||||||
document.getElementById('deleteButton').style.display = 'block';
|
document.getElementById('deleteButton').style.display = 'block';
|
||||||
|
|
||||||
@@ -165,13 +155,13 @@
|
|||||||
var placeId = MapEditor.selectedMarker.placeId
|
var placeId = MapEditor.selectedMarker.placeId
|
||||||
|
|
||||||
if (places[placeId].id && !del) {
|
if (places[placeId].id && !del) {
|
||||||
MapEditor.map.removeLayer(MapEditor.selectedMarker);
|
MapEditor.map.changeMarkerIcon(
|
||||||
MapEditor.markers.addLayer(MapEditor.selectedMarker);
|
MapEditor.selectedMarker,
|
||||||
MapEditor.selectedMarker.setIcon(places[placeId].noPano ? IconCollection.iconRed : IconCollection.iconGreen);
|
places[placeId].noPano ? MapEditor.map.iconCollection.iconRed : MapEditor.map.iconCollection.iconGreen
|
||||||
MapEditor.selectedMarker.setZIndexOffset(1000);
|
);
|
||||||
} else {
|
} else {
|
||||||
delete places[placeId];
|
delete places[placeId];
|
||||||
MapEditor.map.removeLayer(MapEditor.selectedMarker);
|
MapEditor.map.removeMarker(MapEditor.selectedMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('deleteButton').style.display = 'none';
|
document.getElementById('deleteButton').style.display = 'none';
|
||||||
@@ -223,7 +213,7 @@
|
|||||||
MapEditor.resetSelected(del);
|
MapEditor.resetSelected(del);
|
||||||
MapEditor.selectedMarker = null;
|
MapEditor.selectedMarker = null;
|
||||||
|
|
||||||
MapEditor.map.invalidateSize(true);
|
MapEditor.map.resize();
|
||||||
},
|
},
|
||||||
|
|
||||||
deletePlace: function () {
|
deletePlace: function () {
|
||||||
@@ -239,6 +229,7 @@
|
|||||||
|
|
||||||
delete MapEditor.added[placeId];
|
delete MapEditor.added[placeId];
|
||||||
delete MapEditor.edited[placeId];
|
delete MapEditor.edited[placeId];
|
||||||
|
delete places[placeId];
|
||||||
|
|
||||||
document.getElementById('added').innerHTML = String(Object.keys(MapEditor.added).length);
|
document.getElementById('added').innerHTML = String(Object.keys(MapEditor.added).length);
|
||||||
document.getElementById('edited').innerHTML = String(Object.keys(MapEditor.edited).length);
|
document.getElementById('edited').innerHTML = String(Object.keys(MapEditor.edited).length);
|
||||||
@@ -313,7 +304,49 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var IconCollection = {
|
var Util = {
|
||||||
|
getHighResData: function () {
|
||||||
|
if (window.devicePixelRatio >= 4) {
|
||||||
|
return { ppi: 320, tileSize: 128, zoomOffset: 1, minZoom: 0, maxZoom: 18 };
|
||||||
|
} else if (window.devicePixelRatio >= 2) {
|
||||||
|
return { ppi: 250, tileSize: 256, zoomOffset: 0, minZoom: 1, maxZoom: 19 };
|
||||||
|
} else {
|
||||||
|
return { ppi: 72, tileSize: 512, zoomOffset: -1, minZoom: 2, maxZoom: 20 };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
extractCoordinates: function (coordinatesStr) {
|
||||||
|
var coordinates = { valid: false, latlng: { lat: 0., lng: 0. } };
|
||||||
|
var delimiters = [',', ' ', ';'];
|
||||||
|
|
||||||
|
coordinatesStr = coordinatesStr.trim();
|
||||||
|
if (coordinatesStr.length == 0) {
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var delimiter of delimiters) {
|
||||||
|
if (coordinatesStr.indexOf(delimiter) != -1) {
|
||||||
|
|
||||||
|
var coordinatesArr = coordinatesStr.split(delimiter);
|
||||||
|
coordinates.latlng.lat = parseFloat(coordinatesArr[0]);
|
||||||
|
coordinates.latlng.lng = parseFloat(coordinatesArr[1]);
|
||||||
|
|
||||||
|
if (!isNaN(coordinates.latlng.lat) && !isNaN(coordinates.latlng.lng)) {
|
||||||
|
coordinates.valid = true;
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var LMapWrapper = {
|
||||||
|
map: null,
|
||||||
|
markers: null,
|
||||||
|
divId: null,
|
||||||
|
iconCollection: {
|
||||||
iconGreen: L.icon({
|
iconGreen: L.icon({
|
||||||
iconUrl: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
|
iconUrl: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
|
||||||
iconSize: [24, 32],
|
iconSize: [24, 32],
|
||||||
@@ -328,36 +361,21 @@
|
|||||||
iconUrl: STATIC_ROOT + '/img/markers/marker-blue.svg?rev=' + REVISION,
|
iconUrl: STATIC_ROOT + '/img/markers/marker-blue.svg?rev=' + REVISION,
|
||||||
iconSize: [24, 32],
|
iconSize: [24, 32],
|
||||||
iconAnchor: [12, 32]
|
iconAnchor: [12, 32]
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
var Util = {
|
|
||||||
getHighResData: function () {
|
|
||||||
if (window.devicePixelRatio >= 4) {
|
|
||||||
return { ppi: 320, tileSize: 128, zoomOffset: 1, minZoom: 0, maxZoom: 18 };
|
|
||||||
} else if (window.devicePixelRatio >= 2) {
|
|
||||||
return { ppi: 250, tileSize: 256, zoomOffset: 0, minZoom: 1, maxZoom: 19 };
|
|
||||||
} else {
|
|
||||||
return { ppi: 72, tileSize: 512, zoomOffset: -1, minZoom: 2, maxZoom: 20 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MapEditor.map = L.map('map', {
|
|
||||||
zoomControl: false
|
|
||||||
});
|
|
||||||
|
|
||||||
MapEditor.map.on('click', function (e) {
|
|
||||||
var marker = L.marker(e.latlng, {
|
|
||||||
icon: IconCollection.iconBlue,
|
|
||||||
zIndexOffset: 2000
|
|
||||||
})
|
})
|
||||||
.addTo(MapEditor.map)
|
},
|
||||||
.on('click', function () {
|
|
||||||
MapEditor.select(this);
|
init: function (divId, places) {
|
||||||
|
document.getElementById(divId).style.display = "block";
|
||||||
|
|
||||||
|
if (!LMapWrapper.map) {
|
||||||
|
LMapWrapper.divId = divId;
|
||||||
|
LMapWrapper.map = L.map(LMapWrapper.divId, {
|
||||||
|
center: { lat: 0., lng: 0. },
|
||||||
|
zoom: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
MapEditor.select(marker);
|
LMapWrapper.map.on('click', function (e) {
|
||||||
|
LMapWrapper.placeMarker(e.latlng);
|
||||||
});
|
});
|
||||||
|
|
||||||
var highResData = Util.getHighResData();
|
var highResData = Util.getHighResData();
|
||||||
@@ -370,13 +388,30 @@
|
|||||||
zoomOffset: highResData.zoomOffset,
|
zoomOffset: highResData.zoomOffset,
|
||||||
minZoom: highResData.minZoom,
|
minZoom: highResData.minZoom,
|
||||||
maxZoom: highResData.maxZoom
|
maxZoom: highResData.maxZoom
|
||||||
}).addTo(MapEditor.map);
|
}).addTo(LMapWrapper.map);
|
||||||
|
|
||||||
MapEditor.map.fitBounds(L.latLngBounds({ lat: mapBounds.south, lng: mapBounds.west }, { lat: mapBounds.north, lng: mapBounds.east }));
|
if (mapId) {
|
||||||
|
LMapWrapper.map.fitBounds(L.latLngBounds({ lat: mapBounds.south, lng: mapBounds.west }, { lat: mapBounds.north, lng: mapBounds.east }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MapEditor.markers = L.markerClusterGroup({
|
LMapWrapper.loadMarkers(places);
|
||||||
|
|
||||||
|
document.getElementById('streetViewCoverSelector').style.display = 'none';
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function () {
|
||||||
|
document.getElementById(LMapWrapper.divId).style.display = 'none';
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMarkers: function (places) {
|
||||||
|
if (!LMapWrapper.markers) {
|
||||||
|
LMapWrapper.markers = L.markerClusterGroup({
|
||||||
maxClusterRadius: 50
|
maxClusterRadius: 50
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
LMapWrapper.markers.clearLayers();
|
||||||
|
}
|
||||||
|
|
||||||
for (var placeId in places) {
|
for (var placeId in places) {
|
||||||
if (!places.hasOwnProperty(placeId)) {
|
if (!places.hasOwnProperty(placeId)) {
|
||||||
@@ -386,18 +421,229 @@
|
|||||||
var place = places[placeId];
|
var place = places[placeId];
|
||||||
|
|
||||||
var marker = L.marker({ lat: place.lat, lng: place.lng }, {
|
var marker = L.marker({ lat: place.lat, lng: place.lng }, {
|
||||||
icon: place.noPano ? IconCollection.iconRed : IconCollection.iconGreen,
|
icon: place.noPano ? LMapWrapper.iconCollection.iconRed : LMapWrapper.iconCollection.iconGreen,
|
||||||
zIndexOffset: 1000
|
zIndexOffset: 1000
|
||||||
})
|
})
|
||||||
.addTo(MapEditor.markers)
|
.addTo(LMapWrapper.markers)
|
||||||
.on('click', function () {
|
.on('click', function () {
|
||||||
MapEditor.select(this);
|
MapEditor.select(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
marker.placeId = place.id;
|
marker.placeId = placeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapEditor.map.addLayer(MapEditor.markers);
|
LMapWrapper.map.addLayer(LMapWrapper.markers);
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: check whether marker is already existing on the map for the coordinates
|
||||||
|
// or alternatively block saving for matching coordinates
|
||||||
|
placeMarker: function (latLng) {
|
||||||
|
var marker = L.marker(latLng, {
|
||||||
|
icon: LMapWrapper.iconCollection.iconBlue,
|
||||||
|
zIndexOffset: 2000
|
||||||
|
})
|
||||||
|
.addTo(LMapWrapper.markers)
|
||||||
|
.on('click', function () {
|
||||||
|
MapEditor.select(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
MapEditor.select(marker);
|
||||||
|
},
|
||||||
|
|
||||||
|
panTo: function (latLng) {
|
||||||
|
LMapWrapper.map.panTo(latLng);
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function () {
|
||||||
|
LMapWrapper.map.invalidateSize(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
changeMarkerIcon: function (marker, icon) {
|
||||||
|
marker.setIcon(icon);
|
||||||
|
marker.setZIndexOffset(2000);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMarker: function (marker) {
|
||||||
|
LMapWrapper.markers.removeLayer(marker);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleStreetViewCover: function () { },
|
||||||
|
|
||||||
|
getSearchRadius: function (location) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var GMapWrapper = {
|
||||||
|
map: null,
|
||||||
|
markers: null,
|
||||||
|
divId: null,
|
||||||
|
streetViewCover: null,
|
||||||
|
streetViewCoverOn: false,
|
||||||
|
iconCollection: {
|
||||||
|
iconGreen: {
|
||||||
|
url: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
|
||||||
|
scaledSize: new google.maps.Size(24, 32), // scaled size
|
||||||
|
origin: new google.maps.Point(0, 0), // origin
|
||||||
|
anchor: new google.maps.Point(12, 32) // anchor
|
||||||
|
},
|
||||||
|
iconRed: {
|
||||||
|
url: STATIC_ROOT + '/img/markers/marker-red.svg?rev' + REVISION,
|
||||||
|
scaledSize: new google.maps.Size(24, 32), // scaled size
|
||||||
|
origin: new google.maps.Point(0, 0), // origin
|
||||||
|
anchor: new google.maps.Point(12, 32) // anchor
|
||||||
|
},
|
||||||
|
iconBlue: {
|
||||||
|
url: STATIC_ROOT + '/img/markers/marker-blue.svg?rev' + REVISION,
|
||||||
|
scaledSize: new google.maps.Size(24, 32), // scaled size
|
||||||
|
origin: new google.maps.Point(0, 0), // origin
|
||||||
|
anchor: new google.maps.Point(12, 32) // anchor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
init: function (divId, places) {
|
||||||
|
document.getElementById(divId).style.display = "block";
|
||||||
|
|
||||||
|
if (!GMapWrapper.map) {
|
||||||
|
GMapWrapper.divId = divId;
|
||||||
|
GMapWrapper.map = new google.maps.Map(document.getElementById(GMapWrapper.divId), {
|
||||||
|
center: { lat: 0., lng: 0. },
|
||||||
|
zoom: 2,
|
||||||
|
fullscreenControl: false,
|
||||||
|
zoomControl: true,
|
||||||
|
zoomControlOptions: {
|
||||||
|
position: google.maps.ControlPosition.LEFT_BOTTOM
|
||||||
|
},
|
||||||
|
streetViewControl: false,
|
||||||
|
draggableCursor: 'crosshair'
|
||||||
|
});
|
||||||
|
|
||||||
|
GMapWrapper.streetViewCover = new google.maps.StreetViewCoverageLayer();
|
||||||
|
|
||||||
|
GMapWrapper.map.addListener('click', function (mapsMouseEvent) {
|
||||||
|
GMapWrapper.placeMarker({
|
||||||
|
lat: mapsMouseEvent.latLng.lat(),
|
||||||
|
lng: mapsMouseEvent.latLng.lng()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mapId) {
|
||||||
|
GMapWrapper.map.fitBounds({ south: mapBounds.south, west: mapBounds.west, north: mapBounds.north, east: mapBounds.east });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GMapWrapper.loadMarkers(places);
|
||||||
|
|
||||||
|
document.getElementById('streetViewCoverSelector').style.display = 'block'
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function () {
|
||||||
|
document.getElementById(GMapWrapper.divId).style.display = 'none';
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMarkers: function (places) {
|
||||||
|
if (!GMapWrapper.markers) {
|
||||||
|
GMapWrapper.markers = new MarkerClusterer(GMapWrapper.map, [], {
|
||||||
|
imagePath: STATIC_ROOT + '/img/markers/m',
|
||||||
|
imageExtension: 'png?rev' + REVISION
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
GMapWrapper.markers.clearMarkers();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var placeId in places) {
|
||||||
|
if (!places.hasOwnProperty(placeId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var place = places[placeId];
|
||||||
|
|
||||||
|
var marker = new google.maps.Marker({
|
||||||
|
position: {
|
||||||
|
lat: place.lat,
|
||||||
|
lng: place.lng
|
||||||
|
},
|
||||||
|
icon: place.noPano ? GMapWrapper.iconCollection.iconRed : GMapWrapper.iconCollection.iconGreen
|
||||||
|
});
|
||||||
|
|
||||||
|
marker.getLatLng = function () { return { lat: this.getPosition().lat(), lng: this.getPosition().lng() } };
|
||||||
|
marker.setLatLng = function (coords) { this.setPosition(coords) };
|
||||||
|
|
||||||
|
marker.addListener('click', function () {
|
||||||
|
MapEditor.select(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
marker.placeId = placeId;
|
||||||
|
|
||||||
|
GMapWrapper.markers.addMarker(marker);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: check whether marker is already existing on the map for the coordinates
|
||||||
|
// or alternatively block saving for matching coordinates
|
||||||
|
placeMarker: function (latLng) {
|
||||||
|
var marker = new google.maps.Marker({
|
||||||
|
map: GMapWrapper.map,
|
||||||
|
position: latLng,
|
||||||
|
icon: GMapWrapper.iconCollection.iconBlue,
|
||||||
|
});
|
||||||
|
|
||||||
|
marker.getLatLng = function () { return { lat: this.getPosition().lat(), lng: this.getPosition().lng() } };
|
||||||
|
marker.setLatLng = function (coords) { this.setPosition(coords) };
|
||||||
|
|
||||||
|
marker.addListener('click', function () {
|
||||||
|
MapEditor.select(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
GMapWrapper.markers.addMarker(marker);
|
||||||
|
|
||||||
|
MapEditor.select(marker);
|
||||||
|
},
|
||||||
|
|
||||||
|
panTo: function (latLng) {
|
||||||
|
GMapWrapper.map.panTo(latLng);
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function () {
|
||||||
|
google.maps.event.trigger(GMapWrapper.map, 'resize');
|
||||||
|
},
|
||||||
|
|
||||||
|
changeMarkerIcon: function (marker, icon) {
|
||||||
|
marker.setIcon(icon);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMarker: function (marker) {
|
||||||
|
GMapWrapper.markers.removeMarker(marker);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleStreetViewCover: function () {
|
||||||
|
if (GMapWrapper.streetViewCoverOn) {
|
||||||
|
GMapWrapper.streetViewCover.setMap(null);
|
||||||
|
GMapWrapper.streetViewCoverOn = false;
|
||||||
|
} else {
|
||||||
|
GMapWrapper.streetViewCover.setMap(GMapWrapper.map);
|
||||||
|
GMapWrapper.streetViewCoverOn = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchRadius: function (location) {
|
||||||
|
// source: https://www.yorku.ca/mack/CHI01.htm
|
||||||
|
var movementOffset = 4;
|
||||||
|
|
||||||
|
// source: https://groups.google.com/g/google-maps-js-api-v3/c/hDRO4oHVSeM/m/osOYQYXg2oUJ?pli=1
|
||||||
|
var metersPerPixel = 156543.03392 * Math.cos(location.lat * Math.PI / 180) / Math.pow(2, GMapWrapper.map.getZoom());
|
||||||
|
|
||||||
|
var minSearchRadius = 5;
|
||||||
|
|
||||||
|
var searchRadius = Math.max(minSearchRadius, Math.round(movementOffset * metersPerPixel));
|
||||||
|
|
||||||
|
return searchRadius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialize content of #map with google maps
|
||||||
|
MapEditor.map = GMapWrapper;
|
||||||
|
MapEditor.map.init('gmap', places);
|
||||||
|
|
||||||
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
||||||
// switch off fullscreenControl because positioning doesn't work
|
// switch off fullscreenControl because positioning doesn't work
|
||||||
@@ -440,4 +686,48 @@
|
|||||||
document.getElementById('deleteButton').onclick = function () {
|
document.getElementById('deleteButton').onclick = function () {
|
||||||
MapEditor.deletePlace();
|
MapEditor.deletePlace();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.getElementById('jumpButton').onclick = function (e) {
|
||||||
|
var coordinatesStr = document.getElementById("jumpCoordinates").value;
|
||||||
|
var coordinates = Util.extractCoordinates(coordinatesStr);
|
||||||
|
|
||||||
|
if (coordinates.valid) {
|
||||||
|
MapEditor.map.placeMarker(coordinates.latlng);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('jumpCoordinates').onkeyup = function (e) {
|
||||||
|
var coordinatesStr = document.getElementById("jumpCoordinates").value;
|
||||||
|
var coordinates = Util.extractCoordinates(coordinatesStr);
|
||||||
|
var jumpButton = document.getElementById("jumpButton");
|
||||||
|
|
||||||
|
if (coordinates.valid) {
|
||||||
|
jumpButton.disabled = false;
|
||||||
|
|
||||||
|
if (e.key == 'Enter') {
|
||||||
|
MapEditor.map.placeMarker(coordinates.latlng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jumpButton.disabled = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('mapSelector').onclick = function () {
|
||||||
|
MapEditor.closePlace();
|
||||||
|
MapEditor.map.hide();
|
||||||
|
|
||||||
|
if (MapEditor.map === GMapWrapper) {
|
||||||
|
MapEditor.map = LMapWrapper;
|
||||||
|
MapEditor.map.init('lmap', places);
|
||||||
|
} else {
|
||||||
|
MapEditor.map = GMapWrapper;
|
||||||
|
MapEditor.map.init('gmap', places);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('streetViewCoverSelector').onclick = function () {
|
||||||
|
MapEditor.map.toggleStreetViewCover();
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@@ -59,10 +59,25 @@ def getRevisionForRef(ref):
|
|||||||
return subprocess.check_output(["git", "rev-list", "-1", ref], cwd=REPO).decode().strip()
|
return subprocess.check_output(["git", "rev-list", "-1", ref], cwd=REPO).decode().strip()
|
||||||
|
|
||||||
def getLatestReleaseTag():
|
def getLatestReleaseTag():
|
||||||
return subprocess.check_output(["git", "for-each-ref", "refs/tags/Release*", "--count=1", "--sort=-creatordate", "--format=%(refname:short)"], cwd=REPO).decode().strip()
|
process = subprocess.Popen(["git", "for-each-ref", "refs/tags/Release*", "--sort=-creatordate", "--format=%(refname:short)"], stdout=subprocess.PIPE, cwd=REPO)
|
||||||
|
|
||||||
|
for line in process.stdout:
|
||||||
|
tag = line.decode().rstrip()
|
||||||
|
|
||||||
|
if isTagVerified(tag):
|
||||||
|
return tag
|
||||||
|
|
||||||
|
print(f"[WARNING] Tag '{tag}' is not verified, skipping.")
|
||||||
|
|
||||||
|
raise Exception("No verified 'Release*' tag found!")
|
||||||
|
|
||||||
|
def isTagVerified(tag):
|
||||||
|
process = subprocess.run(["git", "tag", "--verify", tag], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=REPO)
|
||||||
|
|
||||||
|
return process.returncode == 0
|
||||||
|
|
||||||
def updateRepoFromRemote():
|
def updateRepoFromRemote():
|
||||||
subprocess.call(["git", "fetch", "origin", "--prune"], cwd=REPO)
|
subprocess.call(["git", "fetch", "origin", "--prune", "--prune-tags"], cwd=REPO)
|
||||||
|
|
||||||
def checkoutWorktree(worktreePath, ref):
|
def checkoutWorktree(worktreePath, ref):
|
||||||
subprocess.call(["git", "checkout", "-f", ref], cwd=worktreePath)
|
subprocess.call(["git", "checkout", "-f", ref], cwd=worktreePath)
|
||||||
|
|||||||
+4
-1
@@ -16,7 +16,7 @@ echo "Installing Yarn packages..."
|
|||||||
(cd ${ROOT_DIR}/public/static && yarn install)
|
(cd ${ROOT_DIR}/public/static && yarn install)
|
||||||
|
|
||||||
echo "Installing MapGuesser DB..."
|
echo "Installing MapGuesser DB..."
|
||||||
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/db/mapguesser.sql
|
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/database/mapguesser.sql
|
||||||
|
|
||||||
echo "Migrating DB..."
|
echo "Migrating DB..."
|
||||||
(cd ${ROOT_DIR} && ./mapg db:migrate)
|
(cd ${ROOT_DIR} && ./mapg db:migrate)
|
||||||
@@ -27,6 +27,9 @@ if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
|
|||||||
|
|
||||||
echo "Linking view files..."
|
echo "Linking view files..."
|
||||||
(cd ${ROOT_DIR} && ./mapg view:link)
|
(cd ${ROOT_DIR} && ./mapg view:link)
|
||||||
|
else
|
||||||
|
echo "Creating the first user..."
|
||||||
|
(cd ${ROOT_DIR} && ./mapg user:add mapg@mapg.dev 123456 admin)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
touch ${ROOT_DIR}/installed
|
touch ${ROOT_DIR}/installed
|
||||||
@@ -92,6 +92,9 @@ class GameController
|
|||||||
'rounds' => [],
|
'rounds' => [],
|
||||||
'currentRound' => -1
|
'currentRound' => -1
|
||||||
]);
|
]);
|
||||||
|
} else { // update the area of the map in the session in any case
|
||||||
|
$state['area'] = $map->getArea();
|
||||||
|
$session->set('state', $state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonContent([
|
return new JsonContent([
|
||||||
|
|||||||
@@ -61,9 +61,11 @@ class GameFlowController
|
|||||||
$round = $state['rounds'][$i];
|
$round = $state['rounds'][$i];
|
||||||
$response['history'][] = [
|
$response['history'][] = [
|
||||||
'position' => $round['position']->toArray(),
|
'position' => $round['position']->toArray(),
|
||||||
|
'result' => [
|
||||||
'guessPosition' => $round['guessPosition']->toArray(),
|
'guessPosition' => $round['guessPosition']->toArray(),
|
||||||
'distance' => $round['distance'],
|
'distance' => $round['distance'],
|
||||||
'score' => $round['score']
|
'score' => $round['score']
|
||||||
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,11 +128,8 @@ class GameFlowController
|
|||||||
$last['score'] = $result['score'];
|
$last['score'] = $result['score'];
|
||||||
|
|
||||||
$response = [
|
$response = [
|
||||||
'result' => [
|
|
||||||
'position' => $last['position']->toArray(),
|
'position' => $last['position']->toArray(),
|
||||||
'distance' => $result['distance'],
|
'result' => $result
|
||||||
'score' => $result['score']
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$state['rounds'][$state['currentRound']] = $last;
|
$state['rounds'][$state['currentRound']] = $last;
|
||||||
@@ -165,20 +164,22 @@ class GameFlowController
|
|||||||
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
|
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
|
||||||
$result = $this->evalueteGuess($last['position'], $guessPosition, $state['area']);
|
$result = $this->evalueteGuess($last['position'], $guessPosition, $state['area']);
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('guess', [
|
$responseFromMulti = $this->multiConnector->sendMessage('guess', [
|
||||||
'roomId' => $roomId,
|
'roomId' => $roomId,
|
||||||
'token' => $multiState['token'],
|
'token' => $multiState['token'],
|
||||||
'guess' => $guessPosition->toArray(),
|
'guessPosition' => $guessPosition->toArray(),
|
||||||
'distance' => $result['distance'],
|
'distance' => $result['distance'],
|
||||||
'score' => $result['score']
|
'score' => $result['score']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (isset($responseFromMulti['error'])) {
|
||||||
|
return new JsonContent(['error' => $responseFromMulti['error']]);
|
||||||
|
}
|
||||||
|
|
||||||
$response = [
|
$response = [
|
||||||
'result' => [
|
|
||||||
'position' => $last['position']->toArray(),
|
'position' => $last['position']->toArray(),
|
||||||
'distance' => $result['distance'],
|
'result' => $result,
|
||||||
'score' => $result['score']
|
'allResults' => $responseFromMulti['allResults']
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return new JsonContent($response);
|
return new JsonContent($response);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
class MultiConnector
|
class MultiConnector
|
||||||
{
|
{
|
||||||
public function sendMessage(string $func, array $args = []): void
|
public function sendMessage(string $func, array $args = [])
|
||||||
{
|
{
|
||||||
$message = json_encode([
|
$message = json_encode([
|
||||||
'func' => $func,
|
'func' => $func,
|
||||||
@@ -17,8 +17,6 @@ class MultiConnector
|
|||||||
}
|
}
|
||||||
fclose($connection);
|
fclose($connection);
|
||||||
|
|
||||||
if ($response !== 'OK') {
|
return json_decode($response, true);
|
||||||
throw new \Exception('Sending message failed with response: ' . $response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ class Place extends Model
|
|||||||
return $this->pov->getZoom();
|
return $this->pov->getZoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFreshPanoId(bool $canBeIndoor = false): ?string
|
public function getFreshPanoId(): ?string
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
$this->panoIdCachedTimestamp !== null &&
|
$this->panoIdCachedTimestamp !== null &&
|
||||||
@@ -152,19 +152,13 @@ class Place extends Model
|
|||||||
$request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
|
$request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
|
||||||
$request->setQuery([
|
$request->setQuery([
|
||||||
'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
|
'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
|
||||||
'location' => $this->position->getLat() . ',' . $this->position->getLng(),
|
'location' => $this->position->getLat() . ',' . $this->position->getLng()
|
||||||
'source' => $canBeIndoor ? 'default' : 'outdoor'
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $request->send();
|
$response = $request->send();
|
||||||
$panoData = json_decode($response->getBody(), true);
|
$panoData = json_decode($response->getBody(), true);
|
||||||
$panoId = $panoData['status'] === 'OK' ? $panoData['pano_id'] : null;
|
$panoId = $panoData['status'] === 'OK' ? $panoData['pano_id'] : null;
|
||||||
|
|
||||||
// enable indoor panos if no outdoor found
|
|
||||||
if ($panoId === null && !$canBeIndoor) {
|
|
||||||
return $this->getFreshPanoId(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->panoIdCached = $panoId;
|
$this->panoIdCached = $panoId;
|
||||||
$this->panoIdCachedTimestamp = new DateTime();
|
$this->panoIdCachedTimestamp = new DateTime();
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,22 @@
|
|||||||
@js(node_modules/leaflet/dist/leaflet.js)
|
@js(node_modules/leaflet/dist/leaflet.js)
|
||||||
@js(node_modules/leaflet.markercluster/dist/leaflet.markercluster.js)
|
@js(node_modules/leaflet.markercluster/dist/leaflet.markercluster.js)
|
||||||
@js(https://maps.googleapis.com/maps/api/js?key=<?= $_ENV['GOOGLE_MAPS_JS_API_KEY'] ?>)
|
@js(https://maps.googleapis.com/maps/api/js?key=<?= $_ENV['GOOGLE_MAPS_JS_API_KEY'] ?>)
|
||||||
|
@js(https://unpkg.com/@googlemaps/markerclustererplus/dist/index.min.js)
|
||||||
@js(js/map_editor.js)
|
@js(js/map_editor.js)
|
||||||
|
|
||||||
@extends(templates/layout_full)
|
@extends(templates/layout_full)
|
||||||
|
|
||||||
@section(subheader)
|
@section(subheader)
|
||||||
<span><a href="javascript:;" id="mapName" title="Edit map data"><?= $mapName ?></a></span><!--
|
<span><a href="javascript:;" id="mapName" title="Edit map data"><?= $mapName ?></a></span><!--
|
||||||
|
--><span class="inline hideOnMobile" id="mapSelection">
|
||||||
|
<button id="mapSelector">
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/map.svg?rev=<?= REVISION ?>" alt="Map Selector" />
|
||||||
|
</button>
|
||||||
|
</span><!--
|
||||||
|
--><span class="inline hideOnMobile">
|
||||||
|
<input type="text" id="jumpCoordinates" placeholder="Insert coordinates here" />
|
||||||
|
<button id="jumpButton" disabled >Jump</button>
|
||||||
|
</span><!--
|
||||||
--><span><!--
|
--><span><!--
|
||||||
<?php /* Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. */ ?>
|
<?php /* Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. */ ?>
|
||||||
--><svg class="inline" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
--><svg class="inline" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
@@ -53,7 +63,20 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(main)
|
@section(main)
|
||||||
<div id="map"></div>
|
<div id="map" class="map">
|
||||||
|
<div id="lmap" class="map"></div>
|
||||||
|
<div id="gmap" class="map"></div>
|
||||||
|
<div id="overlayControl" class="circleControl">
|
||||||
|
<div id="streetViewCoverSelector" class="controlItem" title="Toggle Street View Cover">
|
||||||
|
<div>
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/street-view-cover.svg?rev=<?= REVISION ?>" alt="Street View Cover" class="controlIcon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="panorama"></div>
|
<div id="panorama"></div>
|
||||||
<div id="noPano">
|
<div id="noPano">
|
||||||
<p class="bold">No panorama is available for this location.</p>
|
<p class="bold">No panorama is available for this location.</p>
|
||||||
|
|||||||
+23
-1
@@ -15,12 +15,15 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(subheader)
|
@section(subheader)
|
||||||
<span id="mapName" class="bold"></span><!--
|
<span id="mapName" class="bold">Loading map...</span><!--
|
||||||
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
||||||
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(main)
|
@section(main)
|
||||||
|
<div id="countdown">
|
||||||
|
<p id="countdownTime" class="mono bold"></p>
|
||||||
|
</div>
|
||||||
<div id="panoCover"></div>
|
<div id="panoCover"></div>
|
||||||
<div id="panorama"></div>
|
<div id="panorama"></div>
|
||||||
<div id="showGuessButtonContainer">
|
<div id="showGuessButtonContainer">
|
||||||
@@ -37,6 +40,7 @@
|
|||||||
<div id="resultInfo">
|
<div id="resultInfo">
|
||||||
<div id="distanceInfo">
|
<div id="distanceInfo">
|
||||||
<p>You were <span id="distance" class="bold"></span> close.</p>
|
<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 class="bold">Game finished.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="scoreInfo">
|
<div id="scoreInfo">
|
||||||
@@ -55,6 +59,24 @@
|
|||||||
<button id="startNewGameButton" class="fullWidth">Play this map again</button>
|
<button id="startNewGameButton" class="fullWidth">Play this map again</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="navigation" class="circleControl">
|
||||||
|
<div id="compassContainer" class="controlItem">
|
||||||
|
<div>
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img id="compass" src="<?= $_ENV['STATIC_ROOT'] ?>/img/compass.svg?rev=<?= REVISION ?>" alt="compass icon" class="controlIcon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="returnToStart" class="controlItem">
|
||||||
|
<div>
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/house-fill.svg?rev=<?= REVISION ?>" alt="Return to Start icon" class="controlIcon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(pageScript)
|
@section(pageScript)
|
||||||
|
|||||||
@@ -29,6 +29,6 @@
|
|||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
||||||
--><p>© Pőcze Bence <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
--><p>© The MapGuesser Contributors <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
||||||
</footer>
|
</footer>
|
||||||
@endsection
|
@endsection
|
||||||
Reference in new issue
Block a user