Skip to content

Swarm missiles: stop at conventional infantry, and consider every unit in an adjacent hex - #8958

Open
HammerGS wants to merge 4 commits into
mainfrom
Fix-8911-swarm-secondary-target-in-building
Open

Swarm missiles: stop at conventional infantry, and consider every unit in an adjacent hex#8958
HammerGS wants to merge 4 commits into
mainfrom
Fix-8911-swarm-secondary-target-in-building

Conversation

@HammerGS

@HammerGS HammerGS commented Sep 12, 2026

Copy link
Copy Markdown
Member

What this changes

Two corrections to how leftover Swarm and Swarm-I missiles pick and finish with a secondary target (TO:AUE p.183).

A swarm flight now stops when it hits conventional infantry. Cluster weapons do not roll on the cluster table against infantry (TW p.215), so the platoon absorbs every remaining missile and the attack is over. calcHits returns early for infantry and never updated the remaining count, so handle still saw missiles left and chained on to a further target. Asked and answered officially:

Q: whenever a primary or secondary Swarm LRM attack hits a conventional infantry unit that unit simply absorbs all the (remaining) missiles for standard anti-infantry damage and the attack ends there?

A: That's a strange side-effect of the infantry rules, but yes.

https://www.battletech.com/forums/index.php/topic,46840.msg1080115.html#msg1080115

Every unit in an adjacent hex is a candidate again. The rule makes every unit at the same distance eligible, chosen at random among them. The adjacent-hex scan looked at one unit per hex, so anything standing behind the first could never be picked.

Related to #8911

What was removed, and why

An earlier version of this PR skipped infantry sheltering in a building unless the attacker's line of sight ran through it. That was wrong. The rule is explicit:

No form of line of sight from the attacker to the secondary target is required.

A platoon inside a building is a legal secondary target. The earlier change applied TW p.172, that you cannot fire on infantry inside a building from outside, which the swarm rules override for secondary targets. It removed a target the rules allow, and it has been taken out along with its tests.

The building still absorbs the damage. That is ordinary building protection and nothing in the swarm rules or the official clarifications overrides it, so a platoon taking nothing from a volley fired from outside is correct behaviour, not the bug it looked like.

No rules-level gate is involved: Swarm LRMs are Advanced, not Core.

Testing

Tested in game, and the same report shows both outcomes, so the change discriminates on hit versus miss rather than just suppressing a line.

A miss lets the flight carry on, which is correct: the rules say if the attack missed, the missiles go to another secondary.

8 missiles continue.
LRM 20 (LRM 20 Swarm) at Foot Platoon (Rifle); needs 4, rolls 3 : misses
8 missiles continue.
LRM 20 (LRM 20 Swarm) at Agrotera AGT-1A; needs 4, rolls 7 : 7 swarm missile(s) hit.
The remaining 1 missile(s) find no new target.

A hit ends it. Four volleys across two runs, every one stopping at the platoon with nothing after it:

8 missiles continue.
LRM 20 (LRM 20 Swarm) at Foot Platoon (Rifle); needs 3, rolls 9 : hits
8 dmg Missile weapon against infantry, damage changed to 2 (1/5)
Medium Building #6012 absorbs 2 points of damage at level 0.
Foot Platoon (Rifle) suffers no damage.

Nothing follows, and a Mek sitting one hex away is left alone. Before this change the flight went on to it.

Three things those runs also confirm. The platoon is chosen while inside the building, which the removed line-of-sight change would have prevented, and it is a friendly unit, which the rules allow. The building absorbs the damage, so the platoon takes none from the swarm. And the flight stops even though the platoon is unhurt, which is right: it absorbs the missiles whether or not they get through the wall.

Selection order was right too: the target's own hex first, then the hex north of it.

compileJava, checkstyleMain, checkstyleTest, spotlessApply and javadoc pass. SwarmMissileTargetTest is 24 tests, 0 failures, written from the rule text: a platoon in a building is still a valid target, a unit already hit by this flight is not picked again, the target's own hex outranks an adjacent one, every unit in an adjacent hex is reachable, and nothing nearby means the missiles are lost.

The adjacent-hex case is a repeated test, since selection among equals is random. It fails on every repetition with that change reverted.

What is not proven yet

  • The adjacent-hex fix was not reached in game. It only bites when an adjacent hex holds two or more units and the first is already marked as hit by this flight. In the runs above the platoon sat in the target's own hex, so nearest-first always picked it and the flight ended there. Covered by the repeated test instead.
  • A swarm whose primary target is conventional infantry was not tried. It should stop immediately rather than spawn any secondary at all.
  • The infantry stop has no direct unit test. It sits inside calcHits, which needs a full weapon handler and a resolved attack; a test for it wants the handler harness rather than the Compute one. It is evidenced by the four in-game volleys above.

In-game test

  1. Ground map. Put a conventional infantry platoon in a building at level 0, and a second unit in the same hex or an adjacent one.
  2. From a Mek outside, fire an LRM 20 loaded with Swarm at the building hex.
  3. Read the report where the missiles say they continue.

Expect the platoon to be a legal target, the building to absorb the damage, and the flight to stop rather than move on to the second unit. Before this change it carried on.


  • This PR is focused on one issue or RFE
  • Every file in the diff has a deliberate change
  • Tests added or updated, if this implements a rule or changes game state
  • Javadoc literals use {@code true} / {@code null} rather than bare or quoted text
  • Dev team only: AI tools used -> AI Assisted Development label applied

…ding

Fixes #8911

Leftover swarm missiles choose a secondary target from the units in the
same or an adjacent hex (TO:AUE p.183). The search accepted any unit,
including conventional infantry inside a building, which units outside
cannot fire on directly (TW p.172). The leftover missiles then resolved
against the platoon and the building soaked the damage, so a volley aimed
at a building hit the infantry sheltering in it.

Compute.getSwarmMissileTarget now skips a candidate that is infantry in a
building unless the attacker's line of sight runs through that building,
which is how a unit already inside legally shoots the platoon it shares
the building with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 12, 2026 14:31
@HammerGS HammerGS added the AI Assisted Development This project/code contains AI use under the supervision of a human developer. With Human testing. label Sep 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Adjacent-hex target collection still only considers the first entity in each hex (missing valid targets), and the new targeting behavior needs a regression test to prevent reintroductions.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes swarm LRM secondary-target selection so leftover swarm missiles no longer directly attack infantry that are inside a building when the attacker cannot legally target them (per TW p.172 / TO:AUE p.183), preventing “wasted” follow-on attacks against protected infantry.

Changes:

  • Adds an eligibility check (canBeSwarmedFrom) to exclude infantry inside buildings unless LOS indicates fire is “through” the building (i.e., same-building targeting).
  • Applies the new eligibility filter when collecting possible swarm secondary targets from the original and adjacent hexes.
File summaries
File Description
megamek/src/megamek/common/compute/Compute.java Filters swarm-missile secondary targets to skip infantry sheltered in buildings unless LOS/building rules allow direct targeting.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +6478 to +6482
entities = game.getEntities(tempcoords);
if (entities.hasNext()) {
tempEntity = entities.next();
if (!tempEntity.getTargetedBySwarm(aeId, weaponId)) {
if (!tempEntity.getTargetedBySwarm(aeId, weaponId)
&& canBeSwarmedFrom(game, attacker, tempEntity)) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, and it matters more because of this PR. The single-unit scan was already there and was mostly harmless, but this branch adds a reason to reject a unit, so a hex whose first unit is sheltering infantry now contributes nothing and hides whatever else is standing in it. Changed to walk the hex in dd00dd9, matching the original-target scan a few lines above.

Comment on lines +6513 to +6514
private static boolean canBeSwarmedFrom(Game game, @Nullable Entity attacker, Entity target) {
boolean isShelteringInfantry = (target instanceof Infantry) && isInBuilding(game, target);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in dd00dd9 as SwarmMissileTargetTest. Four cases: infantry in a building skipped from outside, infantry in the open still picked, a non-infantry unit in the same building still picked, and a legal target standing behind a shelterer still found.

The last one fails with the loop change reverted. The shelter case failed while the building terrain was absent, so it is genuinely reading the rule rather than passing by accident.

Worth noting for anyone reusing this: the board is built in code rather than from a board string, because the test board loader fills hexes in file order rather than at the coordinates written, which put the building in the wrong hex.

HammerGS and others added 3 commits September 12, 2026 11:54
The adjacent-hex scan looked at one unit per hex. That was harmless
before, but this branch adds a reason to reject a unit, so a hex whose
first unit is infantry sheltering in a building contributed nothing and
hid whatever else stood there. Now walks the hex, as the original-target
scan already did.

Adds SwarmMissileTargetTest: infantry in a building skipped from
outside, infantry in the open still picked, a non-infantry unit in the
building still picked, and a legal target behind a shelterer still
found. The last one fails with the loop change reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1Lb2sbXg7jYcZoGDgyhWB
The line-of-sight exclusion was wrong. TO:AUE p.183 says plainly that
"no form of line of sight from the attacker to the secondary target is
required", so a platoon sheltering in a building is a legal secondary
target. The earlier change applied the general rule that you cannot
shoot infantry inside a building from outside (TW p.172), which the
swarm rules explicitly override. Removed.

The building still absorbs the damage. That is ordinary building
protection and nothing in the swarm rules overrides it, so a platoon
taking nothing from a volley fired from outside is correct.

Stops the flight when conventional infantry is hit. Cluster weapons do
not roll on the cluster table against infantry (TW p.215), so the
platoon absorbs every remaining missile and the attack is over. Asked
and answered officially:
https://www.battletech.com/forums/index.php/topic,46840.msg1080115.html#msg1080115
calcHits returns early for infantry and never updated the remainder, so
the missiles chained on to a further target instead of stopping.

Keeps the adjacent-hex scan fix. Every unit at the same distance is a
candidate chosen at random, so looking at one unit per hex silently
narrowed the field. Confirmed load-bearing: the repeated test fails on
every repetition with it reverted.

No rules-level gate: Swarm LRMs are Advanced, not Core.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1Lb2sbXg7jYcZoGDgyhWB
@HammerGS HammerGS changed the title Fix #8911: Swarm missiles hit infantry sheltering in a building Swarm missiles: stop at conventional infantry, and consider every unit in an adjacent hex Sep 13, 2026
@HammerGS
HammerGS marked this pull request as ready for review September 13, 2026 03:21
@HammerGS
HammerGS requested a review from a team as a code owner September 13, 2026 03:21
@HammerGS HammerGS added the AI ready for Review Indicates that is has been in game tested and is ready for review as it can be label Sep 13, 2026
@HammerGS

Copy link
Copy Markdown
Member Author

Tested in game and working. Out of draft.

The same report shows both outcomes, which is better evidence than either alone: a miss lets the flight carry on to the next secondary, a hit on conventional infantry ends it. Four volleys across two runs, all stopping at the platoon, with a Mek one hex away left untouched where it would previously have been attacked.

Scope changed substantially during review. An earlier version skipped infantry sheltering in a building, on the basis that you cannot shoot infantry inside a building from outside (TW p.172). The swarm rules override that for secondary targets: "no form of line of sight from the attacker to the secondary target is required". That change removed a target the rules allow and has been taken out with its tests. The building absorbing the damage is normal building protection and is correct, which is why the original report looked like a bug and was not.

The real defect was the one the official clarification names: the flight must end when it hits conventional infantry, and calcHits returned early for infantry without updating the missiles remaining.

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

Labels

AI Assisted Development This project/code contains AI use under the supervision of a human developer. With Human testing. AI ready for Review Indicates that is has been in game tested and is ready for review as it can be

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants