1. Race condition: session_end now waits for an in-flight
session_start promise before sending, so quick restarts
don't drop the end call.
2. beforeunload: replaced sendBeacon (which can't set headers)
with fetch(..., keepalive: true) so the X-API-Key header
is included and the backend doesn't 401.
3. Stats double-counting: removed stats_record_damage_dealt
and stats_record_kill from damage_entity (which was called
for all damage including player deaths). Now only recorded
at player-sourced call sites (projectile hits, stomps).
4. Removed const-cast: analytics_session_end now takes
GameStats* (non-const) since stats_update_score mutates it.
5. beforeunload now uses stashed stats from the last C-side
session_end call instead of hardcoded zeroes. Session ID is
cleared synchronously before async fetch to prevent races.
6. Removed unused stdint.h include from stats.h.
Implements session-based analytics tracking that sends gameplay
stats to the Horchposten API. Adds stats.{c,h} for accumulating
per-session metrics (kills, deaths, shots, dashes, jumps, pickups,
damage, time) and analytics.{c,h} with EM_JS bridge for fetch()
calls to the backend. Client ID is persisted in localStorage.
Session start/end hooks are wired into all game lifecycle events
(level transitions, restart, quit, tab close via sendBeacon).
Analytics URL/key are configured via data attributes on the canvas
container. Non-WASM builds compile with no-op stubs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Space is now the alternate jump key (was shoot). Web shell shows
game controls by default and hides editor UI unless
localStorage.show_editor is set to 'true'. The E key and ?edit URL
are blocked when the editor is not enabled.
Also fix Makefile to track web/shell.html as a WASM link dependency
so shell changes trigger a rebuild.
Introduce moon01.lvl as the starting level — a pure jump-and-run intro
with no gun and no enemies, just platforming over gaps and dodging falling
asteroids. The player picks up their gun upon transitioning to level01.
New features:
- Moon tileset and PARALLAX_STYLE_MOON with crater terrain backgrounds
- Asteroid entity (ENT_ASTEROID): falls from sky, damages on contact,
explodes on ground with particles, respawns after delay
- PLAYER_UNARMED directive disables gun for the level
- Pit rescue mechanic: falling costs 1 HP and auto-dashes upward
- Gun powerup entity type for future armed-pickup levels
- Segment-based procedural level generator with themed rooms
- Extended editor with entity palette and improved tile cycling
- Web shell improvements for Emscripten builds