Skip to content

Drawing max range rings based on map elevation - #11

Open
Crecket wants to merge 12 commits into
apollyon-sys:mainfrom
Crecket:upstream-pr/terrain-range-ring
Open

Drawing max range rings based on map elevation#11
Crecket wants to merge 12 commits into
apollyon-sys:mainfrom
Crecket:upstream-pr/terrain-range-ring

Conversation

@Crecket

@Crecket Crecket commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

The max range ring currently assumes flat ground. Shooting downhill reaches further than the circle shows, uphill less. This solves the ring against a baked heightfield instead.

What is in here

  • scripts/lib/ballistics.mjs + scripts/fit-ballistics.mjs: a vacuum trajectory model fitted from the shipped firing tables, giving max range as a function of height difference.
  • data/ballistics/projectile-model.json: the fitted model.
  • scripts/lib/heightfield.mjs + scripts/build-heightfield.mjs: bakes a coarse height grid per map.
  • data/terrain/{bakurani,ozeti}/heightfield.{bin,json}: 370 KB total.
  • scripts/lib/terrain-source.mjs: shared reader for the raw terrain chunks.
  • js/map/heightfield.js: runtime loader and sampling.
  • js/map/range-ring.js: the solve and the drawing.

Both generators reproduce the committed artifacts byte-identically (except a generatedAt timestamp) from data already tracked here.

Rendering change

This is the one part that modifies existing code. draw() in js/map/renderer.js had the max-range circle inline under /* Layer 5: artillery range. */. That block is replaced with a call to drawMaxRangeRing(a, rangePx, v.scale); a, rangePx and v.scale were already computed on the line above.

The ring is drawn as two outlines: the flat-ground range, and the extra reach where the terrain gives it. When there is no heightfield, no fitted model, or the map is unsupported, drawMaxRangeRing draws exactly the circle it draws today, with the same canvas calls.

The min range circle is untouched and stays inline. It is deliberately not height-corrected.

Safety property

With the heightfield forced flat, every bearing returns the declared max range to within 9e-5 m, so the terrain solve cannot quietly shrink the ring relative to what the tables say.

Review notes

  • No new user-facing strings. The gain band is unlabelled.
  • No CSS. Canvas only.
  • loadProjectileModel() and PROJECTILE_MODEL are exported from range-ring.js and load in init().
  • The last commit adds unit tests and a browser test plus a test:scripts entry. The project has no test setup today, so that commit is last and separable.

With the contour lines from #10 on to show its on a elevated spot:

image

@apollyon-sys

Copy link
Copy Markdown
Owner

I'm going to hold this one for now.

The implementation is interesting, but the projectile model here is based on the older vacuum-fit approximation. The private ballistic research has moved significantly beyond that model, and automatic terrain ballistic behaviour is deliberately still disabled until the current held-out gameplay validation is complete

I don't want to introduce a public feature based on a model that we already know is superseded, even if it is only being used for the range-ring delta

The idea is good though, and I'd definitely like to revisit it once the validated ballistic model is ready

Crecket added a commit to Crecket/wardogs-calculator that referenced this pull request Aug 30, 2026
@Crecket

Crecket commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

I did end up doing some ballistics tests last night in the test range and it seems pretty confident about our range and time of flight estimates now with a newer model, dunno if you plan on doing more research on this but otherwise I can see about refactoring those changes into this PR aswell

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants