From 48422c1617f4ce2b04b493a81235dbf79a249cc1 Mon Sep 17 00:00:00 2001 From: HikeMap User Date: Fri, 9 Jan 2026 21:27:06 -0600 Subject: [PATCH] Add secondary fog clearing zone for player exploration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 50m explore radius that follows player when outside homebase - Secondary reveal circle only appears when player is outside 800m homebase radius - Update isInRevealedArea() to check both homebase and player position - Update fog of war on GPS position changes and after combat - Geocaches within player's explore radius now become visible 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- index.html | 119 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 35 deletions(-) diff --git a/index.html b/index.html index 8012213..8c9a594 100644 --- a/index.html +++ b/index.html @@ -4185,7 +4185,8 @@ // Fog of War state variables (must be declared before use) let fogCanvas = null; let fogCtx = null; - let playerRevealRadius = 800; + let playerRevealRadius = 800; // Homebase reveal radius (meters) + let playerExploreRadius = 50; // Player's personal reveal radius when exploring (meters) // Initialize fog of war canvas (directly in map container for simple viewport alignment) function initFogOfWar() { @@ -4260,52 +4261,96 @@ fogCtx.fillStyle = 'rgba(0, 0, 0, 0.6)'; fogCtx.fillRect(0, 0, width, height); - // If no homebase set, full fog - if (!playerStats || playerStats.homeBaseLat == null || playerStats.homeBaseLng == null) { - return; + // Homebase reveal (only if homebase exists) + if (playerStats && playerStats.homeBaseLat != null && playerStats.homeBaseLng != null) { + // Calculate reveal circle center using container coordinates (viewport-relative) + const homeLatLng = L.latLng(playerStats.homeBaseLat, playerStats.homeBaseLng); + const centerPoint = map.latLngToContainerPoint(homeLatLng); + + // Calculate radius in pixels using map projection + const edgeLatLng = destinationPoint(homeLatLng, playerRevealRadius, 90); + const edgePoint = map.latLngToContainerPoint(edgeLatLng); + const radiusPixels = Math.abs(edgePoint.x - centerPoint.x); + + // Cut out revealed area using composite operation + fogCtx.save(); + fogCtx.globalCompositeOperation = 'destination-out'; + + // Create gradient for soft edge + const gradient = fogCtx.createRadialGradient( + centerPoint.x, centerPoint.y, radiusPixels * 0.85, + centerPoint.x, centerPoint.y, radiusPixels + ); + gradient.addColorStop(0, 'rgba(0, 0, 0, 1)'); + gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); + + fogCtx.beginPath(); + fogCtx.arc(centerPoint.x, centerPoint.y, radiusPixels, 0, Math.PI * 2); + fogCtx.fillStyle = gradient; + fogCtx.fill(); + + fogCtx.restore(); } - // Calculate reveal circle center using container coordinates (viewport-relative) - const homeLatLng = L.latLng(playerStats.homeBaseLat, playerStats.homeBaseLng); - const centerPoint = map.latLngToContainerPoint(homeLatLng); + // Secondary reveal: Player's explore radius when outside homebase + if (userLocation) { + const playerLatLng = L.latLng(userLocation.lat, userLocation.lng); + + // Check if player is outside homebase radius (or no homebase) + let isOutsideHomebase = true; + if (playerStats && playerStats.homeBaseLat != null && playerStats.homeBaseLng != null) { + const homeLatLng = L.latLng(playerStats.homeBaseLat, playerStats.homeBaseLng); + const distToHome = playerLatLng.distanceTo(homeLatLng); + isOutsideHomebase = distToHome > playerRevealRadius; + } - // Calculate radius in pixels using map projection - const edgeLatLng = destinationPoint(homeLatLng, playerRevealRadius, 90); - const edgePoint = map.latLngToContainerPoint(edgeLatLng); - const radiusPixels = Math.abs(edgePoint.x - centerPoint.x); + if (isOutsideHomebase) { + const playerPoint = map.latLngToContainerPoint(playerLatLng); + const playerEdge = destinationPoint(playerLatLng, playerExploreRadius, 90); + const playerEdgePoint = map.latLngToContainerPoint(playerEdge); + const playerRadiusPixels = Math.abs(playerEdgePoint.x - playerPoint.x); - // Cut out revealed area using composite operation - fogCtx.save(); - fogCtx.globalCompositeOperation = 'destination-out'; + fogCtx.save(); + fogCtx.globalCompositeOperation = 'destination-out'; - // Create gradient for soft edge - const gradient = fogCtx.createRadialGradient( - centerPoint.x, centerPoint.y, radiusPixels * 0.85, - centerPoint.x, centerPoint.y, radiusPixels - ); - gradient.addColorStop(0, 'rgba(0, 0, 0, 1)'); - gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); + const playerGradient = fogCtx.createRadialGradient( + playerPoint.x, playerPoint.y, playerRadiusPixels * 0.85, + playerPoint.x, playerPoint.y, playerRadiusPixels + ); + playerGradient.addColorStop(0, 'rgba(0, 0, 0, 1)'); + playerGradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); - fogCtx.beginPath(); - fogCtx.arc(centerPoint.x, centerPoint.y, radiusPixels, 0, Math.PI * 2); - fogCtx.fillStyle = gradient; - fogCtx.fill(); + fogCtx.beginPath(); + fogCtx.arc(playerPoint.x, playerPoint.y, playerRadiusPixels, 0, Math.PI * 2); + fogCtx.fillStyle = playerGradient; + fogCtx.fill(); - fogCtx.restore(); + fogCtx.restore(); + } + } } - // Check if a location is within the revealed area + // Check if a location is within the revealed area (homebase or player explore radius) function isInRevealedArea(lat, lng) { - // If no homebase, nothing is revealed - if (!playerStats || playerStats.homeBaseLat == null || playerStats.homeBaseLng == null) { - return false; + const checkPoint = L.latLng(lat, lng); + + // Check homebase radius + if (playerStats && playerStats.homeBaseLat != null && playerStats.homeBaseLng != null) { + const homeLatLng = L.latLng(playerStats.homeBaseLat, playerStats.homeBaseLng); + if (homeLatLng.distanceTo(checkPoint) <= playerRevealRadius) { + return true; + } } - // Calculate distance from homebase - const distance = L.latLng(playerStats.homeBaseLat, playerStats.homeBaseLng) - .distanceTo(L.latLng(lat, lng)); + // Check player's explore radius + if (userLocation) { + const playerLatLng = L.latLng(userLocation.lat, userLocation.lng); + if (playerLatLng.distanceTo(checkPoint) <= playerExploreRadius) { + return true; + } + } - return distance <= playerRevealRadius; + return false; } // Hook fog updates to map events (fog will be initialized lazily) @@ -5586,9 +5631,10 @@ // Check for monster clear at home base checkHomeBaseMonsterClear(); - // Update geocache visibility based on new location + // Update geocache visibility and fog of war based on new location if (navMode) { updateGeocacheVisibility(); + updateFogOfWar(); } // Update or create marker @@ -15680,6 +15726,9 @@ statsSyncState.inCombat = false; flushStatsSync(); + // Update fog of war to reflect current position after combat + updateFogOfWar(); + // If victory music isn't playing, switch to appropriate ambient music if (gameMusic.currentTrack !== 'victory' || gameMusic.victory.paused) { const distToHome = getDistanceToHome();