Tactical Reroll
⋯

Leaders joined to squads (T-145): the plan

Characters joined to squads: how the maths plays them. From design/leaders.md, rendered when the site is built.

Written overnight on 25 Sep for Jordan to read with coffee. Nothing here is built yet: the engine work goes in its own PR that waits for your ok.

Clickable mockup (live numbers from a small copy of the planned engine): https://claude.ai/artifact/QSyqparVA3nHMxGM6gEtGM (private to Jordan; kept out of the repo because it carries statlines).

What we're building

A character can join a squad, on either side of the calculator, and the maths plays it out the way a game would. When your Captain is with the Intercessors, his weapons fire with theirs and his buffs apply to the whole unit. When the enemy's Captain is with their Intercessors, your shots hit the squad first, the Captain goes last, and Precision weapons can pick him out.

The defending side is the part that sets us apart. The calculators we've seen treat the target as one statline, so a Warlord in a bodyguard unit either doesn't exist or soaks shots like a trooper.

How joined units work in 11th edition (our summary)

Checked against the 11e core rules on Wahapedia; the wording below is ours.

What the data gives us

Another 4 describe it loosely; 18 don't say. So the importer can join units automatically most of the time, and the player can always fix or add a join by hand.

Where it shows up

It's not only for uploaded lists. The calculator works from BSData, so it knows every datasheet's eligible leaders.

The engine

All in app.js for the calculator, mirrored in ev.js for the comparator, tested against each other as today.

  1. The target becomes a list of groups instead of one statline: [{ n, w, sv, inv, fnp, character, name }], in allocation order. A plain squad is one group, so today's behaviour is the one-group case and every existing test must still pass unchanged.
  2. Toughness per weapon: the best squad Toughness while any squad model lives, else the leader's. Weapons fire in turn (rollWeapons), so a later weapon can be wounding the leader at his own Toughness.
  3. Saves: roll one die per wound for the whole weapon, sort them lowest first, and resolve each against the group in front at that moment (its Sv, invulnerable save and the weapon's AP). This replaces today's "roll each save against one target number". With one group it gives exactly the same odds.
  4. Damage: onto the wounded model in the front group if there is one, with that group's W and FNP, plus any unit-wide FNP still in play.
  5. Devastating Wounds: mortal wounds after normal damage, at most one model per crit, squad first (or the Precision character).
  6. Precision: puts the chosen character's group in front for that weapon's attacks.
  7. Keywords: Anti-X checks the joined unit's live keywords.
  8. Volley tracks: the existing model field already says which model each hit lands on; it gains a group so the animation can draw the leader.
  9. Army vs Army's exact averages (ev.js killDP): the save dice can still be handled exactly. Walk the die faces 1 to 6 in order: the number of wounds showing each face is a binomial draw from those left. The state is (wounds left to resolve, group in front, models slain in it, wounds left on the model being hit): a few thousand states per weapon, fast enough for a whole army.

Tests: today's one-group numbers unchanged; a Captain in a squad survives until the squad dies; Precision kills the Captain first; toughness switches when the squad dies; lowest-first saves against a 2+/4++ leader in a 3+ squad match a hand-worked case; ev.js averages match the dice engine within noise for joined targets; importer tests for all three list formats.

Leader abilities (the data part)

Leader buffs ("while leading, the unit re-rolls hits of 1", "+1 to wound against the enemy closest") are only in GW's text. We don't host that, so like detachment rules (detfx.json) we write each one as a small dice effect in our own words: docs/data/leaderfx.json, keyed by BSData unit id, reusing detfx.js's effect vocabulary (hit, wound, crit, lethal, sustained, re-rolls, AP, damage, FNP, invulnerable save…). Conditional ones ("after charging") become a chip that's on by default and can be unticked, as detachment rules do now.

Order: the factions in the most winning lists first (Necrons, Custodes, Tyranids, T'au, Emperor's Children, Space Wolves, Mechanicus, Orks, Sisters, CSM), then the rest. A leader with no entry yet still joins and fights. Its buffs just aren't applied, and the card says so.

Build order (all built overnight in PR #58, waiting for Jordan)

  1. ✅ bsdata.js: the leads/supports lists (434 leaders, 55 support characters) and BSData.canJoin().
  2. ✅ Engine: groups, lowest-first saves, Toughness switch, Precision, Devastating Wounds.
  3. ✅ Calculator: + Leader / + Support on both sides, the leader line on the answer card, Precision as a modifier, joins kept in share links.
  4. ✅ Importer: GW app (English and French) and New Recruit text joins. 56 of the 80 winning lists now come joined. New Recruit JSON is still waiting on an example export.
  5. ✅ Army vs Army: joined rows, the Join menu, Split up, 👑 on each row. ev.js simulates joined targets with a fixed seed: there's no closed form once saves go lowest first.
  6. ✅ leaderfx.json: 135 characters across 23 factions (the most-played first), then 225 more in T-147 (361 in all). The 63 Wahapedia doesn't list are T-151.
  7. ✅ The volley draws the leader behind his squad, crowned.

Built differently from the plan:

Simplifications

Questions for Jordan

  1. Precision default: when the attacker has Precision and the target has a leader, aim at the leader automatically? (Recommended: yes, with the chip to switch it off.)
  2. A New Recruit JSON export of any list with a leader attached, so the importer can read joins from it too.
  3. Leader buffs: on by default when their condition is situational (like detachment rules), or off until ticked?