Swarm missiles: stop at conventional infantry, and consider every unit in an adjacent hex - #8958
Swarm missiles: stop at conventional infantry, and consider every unit in an adjacent hex#8958HammerGS wants to merge 4 commits into
Conversation
…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>
There was a problem hiding this comment.
🟡 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.
| entities = game.getEntities(tempcoords); | ||
| if (entities.hasNext()) { | ||
| tempEntity = entities.next(); | ||
| if (!tempEntity.getTargetedBySwarm(aeId, weaponId)) { | ||
| if (!tempEntity.getTargetedBySwarm(aeId, weaponId) | ||
| && canBeSwarmedFrom(game, attacker, tempEntity)) { |
There was a problem hiding this comment.
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.
| private static boolean canBeSwarmedFrom(Game game, @Nullable Entity attacker, Entity target) { | ||
| boolean isShelteringInfantry = (target instanceof Infantry) && isInBuilding(game, target); |
There was a problem hiding this comment.
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.
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
…ary-target-in-building
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
|
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 |
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.
calcHitsreturns early for infantry and never updated the remaining count, sohandlestill saw missiles left and chained on to a further target. Asked and answered officially: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:
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.
A hit ends it. Four volleys across two runs, every one stopping at the platoon with nothing after it:
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,spotlessApplyandjavadocpass.SwarmMissileTargetTestis 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
calcHits, which needs a full weapon handler and a resolved attack; a test for it wants the handler harness rather than theComputeone. It is evidenced by the four in-game volleys above.In-game test
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.