From 87d978fb34426a63c005b855f45e6c9b2b947420 Mon Sep 17 00:00:00 2001 From: Gregory Goijaerts Date: Sat, 29 Aug 2026 19:19:49 +0200 Subject: [PATCH 1/2] Remember artillery and target positions across reloads --- js/core/core.js | 3 + js/features/saved-targets.js | 116 +++++++++++++++++++++++++++++++++++ js/main.js | 6 ++ js/ui/inputs.js | 13 ++++ 4 files changed, 138 insertions(+) diff --git a/js/core/core.js b/js/core/core.js index 42a622c80..2e3756c7e 100644 --- a/js/core/core.js +++ b/js/core/core.js @@ -47,6 +47,9 @@ const SAVED_TARGETS_KEY = const SAVE_ARTILLERY_KEY = 'wardogs-save-artillery-position'; +const MAP_POINTS_KEY = + 'wardogs-map-points'; + /* ========================= ZOOM diff --git a/js/features/saved-targets.js b/js/features/saved-targets.js index 83b764f64..526080a66 100644 --- a/js/features/saved-targets.js +++ b/js/features/saved-targets.js @@ -85,6 +85,122 @@ function persistSavedTargets() { ); } +/* ========================= + ARTILLERY / TARGET POSITIONS + ========================= */ + +/* + * Where the two points sit is worth keeping across a reload: coming back + * to a gun laid on the wrong side of the map means placing it again every + * single time. + * + * The map id rides along because the coordinates are meaningless on a + * different map, and a mismatch drops them rather than dropping the gun + * somewhere arbitrary. + */ +const MAP_POINTS_WRITE_DELAY_MS = 300; + +let mapPointsWriteTimer = null; + +function persistMapPoints() { + + /* + * inputs() runs on every frame of a drag, so the write trails the + * gesture instead of hitting localStorage a hundred times across it. + */ + if (mapPointsWriteTimer) { + return; + } + + mapPointsWriteTimer = setTimeout( + () => { + mapPointsWriteTimer = null; + writeMapPoints(); + }, + MAP_POINTS_WRITE_DELAY_MS + ); +} + +function writeMapPoints() { + + try { + localStorage.setItem( + MAP_POINTS_KEY, + JSON.stringify({ + map: S.map, + origin: { + x: S.origin.x, + y: S.origin.y + }, + target: { + x: S.target.x, + y: S.target.y + } + }) + ); + } catch (error) { + console.warn( + 'Failed to save map points:', + error + ); + } +} + +function readStoredPoint(value) { + + return ( + value && + Number.isFinite(Number(value.x)) && + Number.isFinite(Number(value.y)) + ) + ? { + x: Number(value.x), + y: Number(value.y) + } + : null; +} + +function loadMapPoints() { + + try { + const raw = + localStorage.getItem( + MAP_POINTS_KEY + ); + + if (!raw) { + return; + } + + const parsed = + JSON.parse(raw); + + if (parsed?.map !== S.map) { + return; + } + + const origin = + readStoredPoint(parsed.origin); + + const target = + readStoredPoint(parsed.target); + + if (origin) { + S.origin = origin; + } + + if (target) { + S.target = target; + } + + } catch (error) { + console.warn( + 'Failed to load map points:', + error + ); + } +} + function getSaveArtilleryPreference() { return ( diff --git a/js/main.js b/js/main.js index 39c3c26f7..73f12ad43 100644 --- a/js/main.js +++ b/js/main.js @@ -142,6 +142,12 @@ async function init() { initLayout(); + /* + * Before the clamp below, so points restored from a previous + * visit are pulled inside the map's bounds like any other. + */ + loadMapPoints(); + /* * Sync initial state with the * selected preset map after the diff --git a/js/ui/inputs.js b/js/ui/inputs.js index c17785c7b..d52dbcc52 100644 --- a/js/ui/inputs.js +++ b/js/ui/inputs.js @@ -24,6 +24,19 @@ function inputs() { $('h').value = S.h; + /* + * Origin and target are written from six different places (map drags, + * the coordinate inputs, saved-target restore, undo, coordinate + * search). They all land here, so one throttled write covers them all + * instead of a hook at each site. + */ + if ( + typeof persistMapPoints === + 'function' + ) { + persistMapPoints(); + } + result(); draw(); } From 463d30088fe753dacb0cc0a9d6d630c0a1b11dfe Mon Sep 17 00:00:00 2001 From: Gregory Goijaerts Date: Sun, 30 Aug 2026 11:26:02 +0200 Subject: [PATCH 2/2] Key remembered artillery and target positions by map id --- js/events.js | 7 +++ js/features/saved-targets.js | 97 +++++++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 28 deletions(-) diff --git a/js/events.js b/js/events.js index 3e4c6d624..0ce626d75 100644 --- a/js/events.js +++ b/js/events.js @@ -46,6 +46,13 @@ function bindEvents() { 'custom'; } + if ( + typeof loadMapPoints === + 'function' + ) { + loadMapPoints(); + } + clamp( S.origin ); diff --git a/js/features/saved-targets.js b/js/features/saved-targets.js index 526080a66..0511a1079 100644 --- a/js/features/saved-targets.js +++ b/js/features/saved-targets.js @@ -94,9 +94,9 @@ function persistSavedTargets() { * to a gun laid on the wrong side of the map means placing it again every * single time. * - * The map id rides along because the coordinates are meaningless on a - * different map, and a mismatch drops them rather than dropping the gun - * somewhere arbitrary. + * Every map keeps its own entry, keyed by map id, because the coordinates + * are meaningless on a different map. Switching maps restores that map's + * pair and leaves the others untouched. */ const MAP_POINTS_WRITE_DELAY_MS = 300; @@ -121,22 +121,72 @@ function persistMapPoints() { ); } +function readMapPointsStore() { + + const raw = + localStorage.getItem( + MAP_POINTS_KEY + ); + + if (!raw) { + return {}; + } + + let parsed = null; + + try { + parsed = + JSON.parse(raw); + } catch (error) { + return {}; + } + + if ( + !parsed || + typeof parsed !== 'object' + ) { + return {}; + } + + /* + * The first release stored a single { map, origin, target } object; + * fold that lone map into the keyed shape instead of dropping it. + */ + if ( + typeof parsed.map === 'string' + ) { + + return { + [parsed.map]: { + origin: parsed.origin, + target: parsed.target + } + }; + } + + return parsed; +} + function writeMapPoints() { try { + const store = + readMapPointsStore(); + + store[S.map] = { + origin: { + x: S.origin.x, + y: S.origin.y + }, + target: { + x: S.target.x, + y: S.target.y + } + }; + localStorage.setItem( MAP_POINTS_KEY, - JSON.stringify({ - map: S.map, - origin: { - x: S.origin.x, - y: S.origin.y - }, - target: { - x: S.target.x, - y: S.target.y - } - }) + JSON.stringify(store) ); } catch (error) { console.warn( @@ -163,27 +213,18 @@ function readStoredPoint(value) { function loadMapPoints() { try { - const raw = - localStorage.getItem( - MAP_POINTS_KEY - ); - - if (!raw) { - return; - } - - const parsed = - JSON.parse(raw); + const stored = + readMapPointsStore()[S.map]; - if (parsed?.map !== S.map) { + if (!stored) { return; } const origin = - readStoredPoint(parsed.origin); + readStoredPoint(stored.origin); const target = - readStoredPoint(parsed.target); + readStoredPoint(stored.target); if (origin) { S.origin = origin;