diff --git a/apps/gg/app.js b/apps/gg/app.js index 10835555..d8ae30db 100644 --- a/apps/gg/app.js +++ b/apps/gg/app.js @@ -8,6 +8,7 @@ tfrpc.register(async function createIdentity() { return ssb.createIdentity(); }); tfrpc.register(async function appendMessage(id, message) { + print('APPEND', JSON.stringify(message)); return ssb.appendMessageWithIdentity(id, message); }); tfrpc.register(function url() { diff --git a/apps/gg/index.html b/apps/gg/index.html index d0f9dcf1..57d98809 100644 --- a/apps/gg/index.html +++ b/apps/gg/index.html @@ -9,6 +9,6 @@ - + \ No newline at end of file diff --git a/apps/gg/script.js b/apps/gg/script.js index 25851ca8..62e82fb0 100644 --- a/apps/gg/script.js +++ b/apps/gg/script.js @@ -14,6 +14,12 @@ const k_color_pavement = [32, 32, 32, 255]; const k_color_grass = [0, 255, 0, 255]; const k_color_default = [128, 128, 128, 255]; +const k_store = { + '🦞': 15, + '🛶': 10, + '🏠': 10, +}; + class GgAppElement extends LitElement { static get properties() { return { @@ -22,11 +28,12 @@ class GgAppElement extends LitElement { activities: {type: Array}, activity: {type: Object}, world: {type: Object}, - id: {type: String}, + whoami: {type: String}, status: {type: Object}, tab: {type: String}, url: {type: String}, currency: {type: Number}, + to_build: {type: String}, }; } @@ -35,6 +42,7 @@ class GgAppElement extends LitElement { this.activities = []; this.activity = {}; this.loaded_activities = []; + this.placed_emojis = []; this.strava = {}; this.min_lat = Number.MAX_VALUE; this.min_lon = Number.MAX_VALUE; @@ -63,7 +71,7 @@ class GgAppElement extends LitElement { console.log('update_activities failed', e); } await this.acquire_ssb_identity(); - if (this.id && this.activities?.length) { + if (this.whoami && this.activities?.length) { await this.sync_activities(); } await this.get_activities_from_ssb(); @@ -118,8 +126,30 @@ class GgAppElement extends LitElement { this.status = {text: 'calculating balance'}; rows = await tfrpc.rpc.query(` SELECT count(*) AS currency FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-activity' - `, [this.id]); - this.currency = rows[0].currency; + `, [this.whoami]); + let currency = rows[0].currency; + rows = await tfrpc.rpc.query(` + SELECT SUM(json_extract(content, '$.cost')) AS cost FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-place' + `, [this.whoami]); + let spent = rows[0].cost; + this.currency = currency - spent; + this.status = {text: 'getting placed emojis'}; + rows = await tfrpc.rpc.query(` + SELECT messages.content + FROM messages_fts('"gg-place"') + JOIN messages ON messages.rowid = messages_fts.rowid + WHERE json_extract(messages.content, '$.type') = 'gg-place' + ORDER BY messages.timestamp + `); + for (let row of rows) { + console.log(row.content); + let content = JSON.parse(row.content); + this.placed_emojis.push({ + position: content.position, + emoji: content.emoji, + }); + } + console.log(this.placed_emojis); this.status = undefined; this.update_map(); } @@ -137,7 +167,7 @@ class GgAppElement extends LitElement { SELECT from_strava.value FROM json_each(?) AS from_strava LEFT OUTER JOIN my_activities ON from_strava.value = my_activities.url WHERE my_activities.url IS NULL - `, [this.id, JSON.stringify(ids)]); + `, [this.whoami, JSON.stringify(ids)]); console.log('missing = ', missing); for (let [index, row] of missing.entries()) { this.status = {text: 'syncing from strava', value: index, max: missing.length}; @@ -163,7 +193,7 @@ class GgAppElement extends LitElement { } ], }; - await tfrpc.rpc.appendMessage(this.id, message); + await tfrpc.rpc.appendMessage(this.whoami, message); } this.status = undefined; } @@ -182,16 +212,16 @@ class GgAppElement extends LitElement { ORDER BY timestamp DESC limit 1 `, [JSON.stringify(ids)])).map(row => row.author) : []; if (!players.length) { - this.id = await tfrpc.rpc.createIdentity(); - if (this.id) { - await tfrpc.rpc.appendMessage(this.id, { + this.whoami = await tfrpc.rpc.createIdentity(); + if (this.whoami) { + await tfrpc.rpc.appendMessage(this.whoami, { type: 'gg-player', active: true, }); } } else { players.sort(); - this.id = players[0]; + this.whoami = players[0]; } } @@ -294,6 +324,57 @@ class GgAppElement extends LitElement { .openOn(this.leaflet); } + async build() { + if (this.popup) { + this.popup.remove(); + } + if (!this.marker) { + return; + } + let latlng = this.marker.getLatLng(); + + let cost = k_store[this.to_build]; + if (cost > this.currency) { + alert('Insufficient funds.'); + return; + } + let message = { + type: 'gg-place', + position: {lat: latlng.lat, lng: latlng.lng}, + emoji: this.to_build, + cost: cost, + }; + let id = await tfrpc.rpc.appendMessage(this.whoami, message); + this.marker.remove(); + this.placed_emojis.push({ + position: {lat: latlng.lat, lng: latlng.lng}, + emoji: this.to_build, + }); + this.currency -= cost; + return this.update_map(); + } + + on_marker_click(event) { + this.popup = L.popup() + .setLatLng(event.latlng) + .setContent(` + ${this.to_build} (-${k_store[this.to_build]}) + `) + .openOn(this.leaflet); + } + + on_mouse_down(event) { + if (this.marker) { + this.marker.remove(); + this.marker = undefined; + } + + if (this.to_build) { + this.marker = L.marker(event.latlng, {icon: L.divIcon({className: 'build-icon'}), draggable: true}).addTo(this.leaflet); + this.marker.on({click: this.on_marker_click.bind(this)}); + } + } + async update_map() { let map = this.shadowRoot.getElementById('map'); if (!map || !this.loaded_activities.length) { @@ -304,6 +385,7 @@ class GgAppElement extends LitElement { if (!this.leaflet) { this.leaflet = L.map(map, {attributionControl: false, maxZoom: 16, bounceAtZoomLimits: false}); this.leaflet.on({contextmenu: this.on_click.bind(this)}); + this.leaflet.on({click: this.on_mouse_down.bind(this)}); } let self = this; let grid_layer = L.GridLayer.extend({ @@ -336,6 +418,16 @@ class GgAppElement extends LitElement { } } } + for (let placed of self.placed_emojis) { + let position = self.leaflet.options.crs.latLngToPoint(placed.position, coords.z); + let tile_x = Math.floor(position.x / size.x); + let tile_y = Math.floor(position.y / size.y); + position.x = position.x - tile_x * size.x; + position.y = position.y - tile_y * size.y; + if (tile_x == coords.x && tile_y == coords.y) { + context.fillText(placed.emoji, position.x, position.y + 10); + } + } return tile; } }); @@ -539,8 +631,8 @@ class GgAppElement extends LitElement { } ], }; - console.log('id =', this.id, 'message = ', message); - let id = await tfrpc.rpc.appendMessage(this.id, message); + console.log('id =', this.whoami, 'message = ', message); + let id = await tfrpc.rpc.appendMessage(this.whoami, message); console.log('appended message', id); alert('Activity uploaded.'); await this.get_activities_from_ssb(); @@ -579,10 +671,20 @@ class GgAppElement extends LitElement { `; } + render_store_item(item) { + let [emoji, cost] = item; + return html` +
+ this.to_build = emoji}> ${cost} ${emoji == this.to_build ? '<-- Will be built next' : undefined} +
+ `; + } + render_store() { return html`

Store

Your balance: ${this.currency}
+ ${Object.entries(k_store).map(this.render_store_item.bind(this))} `; } @@ -595,7 +697,7 @@ class GgAppElement extends LitElement { header = html`
Please login to Strava.
- ${this.id} + ${this.whoami}
`; @@ -604,7 +706,7 @@ class GgAppElement extends LitElement {

Welcome, ${this.user.credentials.session.name}

- ${this.id} + ${this.whoami}

${this.status?.text} ${this.status?.value}

@@ -646,6 +748,12 @@ class GgAppElement extends LitElement { } return html` +
${header}