id: ev
title: Damage as a distribution, not a mean
status: open
dependsOn: [protocol]
exitCriterion: >
Fire allocation is chosen on P(threshold), and the calculator is tested against
hand-computed cases. #
ev #
At a to-hit of 11 a PPC has an expected 0.83 damage and an actual outcome of
"nothing, 92% of the time". Overkill decisions need the distribution; the mean
says a Locust needs two PPCs when it needs many more. (The figure was written
here against a to-hit of 10, which 2d6 reaches one time in six, not one in
twelve.)
The calculator lives in crates/sds-core/src/ev.rs. Nothing calls it yet.
Per-shot PMF over integer damage: 1 - P(hit) at zero, the rest across the
cluster table for the rack size, times per-missile damage
Convolve shots for an allocation; memoise on
(rack, per-missile damage, to-hit, cluster modifier)
Query it for mean, p50, p90, P(>=20) (the piloting-roll cliff)
Carry expected packet count alongside, for punch-versus-sandblast
P(kill) and P(breach), against the location the damage reaches rather
than the target's total. at_least(threshold) is still the whole of the
arithmetic; what was missing was not the threshold but the distribution to
apply it to. EvCache::location_allocation carries the per-location
compound distribution, and hitloc supplies the shares. See
plan/features.md for the size of the error this removed
Feed AMS into the cluster modifier. The key has the field and the roll
applies it; nothing on the wire says a target mounts AMS
Force-level greedy allocation against the concave value curve. Waits on
force-level assignment machinery, which does not exist yet. Greedy on a
submodular objective is within 1-1/e; any search over subsets is exponential
Declare high-concentration weapons first. Declaration order is
resolution order - TWGameManager.handleAttacks walks
getAttacksVector() calling handle, with no sort or comparator in it -
and the ladder already orders a declaration by descending damage per
packet, which is "most concentrated first". That sort exists to choose
which subsets to offer , so the property was incidental; it is now
pinned by a test that fails if the ladder is reordered. The guarantee is
over one declaration: the attacks vector interleaves both sides in
arrival order, so a friendly gun opening a location for a friendly
cluster weapon is reliable and an enemy's position in that vector is not.
Ordering by p_breach rather than by packet size is a possible
refinement and is not measured.