Class AerospaceGeometry
Every method here takes a pose - a position and an altitude the unit might occupy - rather than
an Entity whose state it reads. That is deliberate. Path ranking evaluates hundreds of positions
the unit is not in, and the engine's own Compute.inDeadZone reads attacker.getAltitude(),
so calling it during ranking answers a question about the present rather than the hypothesis. The same
mistake produced the Entity.height() bug found in the #8659 review.
The dead zone
TW p.241: two airborne units add one hex of range per level of altitude between them, and "units cannot aim into the area immediately above or below their own hexes". Quantified by the same paragraph: one altitude apart needs two hexes of horizontal separation, two altitudes needs three, and so on - a widening cone above and below every fighter, not a fixed bubble.
What makes this the decisive rule in atmospheric combat is that it is measured in low-altitude hexes on
both venues. Over a ground mapsheet one altitude of separation therefore blocks fire within seventeen
ground hexes and two altitudes within thirty-three - most of a normal playing area. See
AerospaceVenue.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordAn inclusive range of altitudes. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intHighest altitude in atmosphere; a unit reaching it may leave vertically under the climb-out option.static final intLowest altitude an airborne aerospace unit can hold; below this it is landing or crashing.static final intAltitude levels a unit will willingly shed in one turn.static final intThrust points to climb one altitude level. -
Method Summary
Modifier and TypeMethodDescriptionstatic intclampAltitude(int altitude) Holds an altitude to the range an airborne aerospace unit can legally occupy.static booleandeadZoneBlocksAttack(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, boolean attackerFliesAsSpheroid, Coords targetPosition, int targetAltitude) Whether the dead zone actually bars this attacker from shooting.static inteffectiveRange(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, Coords targetPosition, int targetAltitude) The range an air-to-air shot is resolved at, in the low-altitude hexes that weapon brackets use.static inthexesToNearestEdge(Coords position, Board board) How far this hex sits from the nearest board edge, in hexes.static inthexesUntilOffBoard(Coords start, int facing, Board board, int maximum) How many hexes a unit can fly straight ahead from this pose before leaving the board.static booleaninDeadZone(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, Coords targetPosition, int targetAltitude) Whether a shot between two poses is inside the attacker's dead zone.reachableAltitudeBand(Entity entity) The altitudes a unit could still be at when its turn ends.
-
Field Details
-
MINIMUM_ALTITUDE
public static final int MINIMUM_ALTITUDELowest altitude an airborne aerospace unit can hold; below this it is landing or crashing.- See Also:
-
MAXIMUM_ALTITUDE
public static final int MAXIMUM_ALTITUDEHighest altitude in atmosphere; a unit reaching it may leave vertically under the climb-out option.- See Also:
-
THRUST_PER_ALTITUDE_GAIN
public static final int THRUST_PER_ALTITUDE_GAINThrust points to climb one altitude level. Descending is free, which is what makes diving cheap.- See Also:
-
SAFE_DESCENT_PER_TURN
public static final int SAFE_DESCENT_PER_TURNAltitude levels a unit will willingly shed in one turn.Descent costs no thrust, but dropping more than two levels forces a severe control roll, so no sane pilot - and neither does
AeroPathUtil.generateValidAltitudeChanges(megamek.common.moves.MovePath)- plans past it.- See Also:
-
-
Method Details
-
inDeadZone
public static boolean inDeadZone(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, Coords targetPosition, int targetAltitude) Whether a shot between two poses is inside the attacker's dead zone.Pure geometry, so it answers the same question for either side of an engagement and for a position nobody occupies yet. It does not know about spheroids, which are exempt - use
deadZoneBlocksAttack(megamek.client.bot.princess.AerospaceVenue, megamek.common.board.Coords, int, boolean, megamek.common.board.Coords, int)to ask whether a particular attacker is actually barred.The predicate is the engine's, rearranged.
Compute.inDeadZonecompares the altitude difference againsteffectiveDistance - altitudeDifference, and sinceeffectiveDistanceis the converted horizontal range plus that same difference, the two cancel and what remains is a comparison against horizontal range alone.- Parameters:
venue- which set of atmospheric rules is in forceattackerPosition- the hex the attacker would be firing fromattackerAltitude- the altitude the attacker would be firing fromtargetPosition- the target's hextargetAltitude- the target's altitude- Returns:
trueif the target sits in the cone above or below the attacker and cannot be aimed at
-
deadZoneBlocksAttack
public static boolean deadZoneBlocksAttack(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, boolean attackerFliesAsSpheroid, Coords targetPosition, int targetAltitude) Whether the dead zone actually bars this attacker from shooting.Spheroids are the exception the rules carve out (TW p.241): they may fire nose weapons at a target above them and aft weapons at one below, so the geometry never blocks them outright. The engine gates its own block the same way, in
Compute.getRangeMods.- Parameters:
venue- which set of atmospheric rules is in forceattackerPosition- the hex the attacker would be firing fromattackerAltitude- the altitude the attacker would be firing fromattackerFliesAsSpheroid-trueif the attacker is behaving as a spheroid in atmospheretargetPosition- the target's hextargetAltitude- the target's altitude- Returns:
trueif the attacker has no legal shot from this pose
-
effectiveRange
public static int effectiveRange(AerospaceVenue venue, Coords attackerPosition, int attackerAltitude, Coords targetPosition, int targetAltitude) The range an air-to-air shot is resolved at, in the low-altitude hexes that weapon brackets use.Two parts, both from TW p.241: the horizontal distance converted to low-altitude hexes, plus one hex for every level of altitude between the two units. The book's own example - two fighters ten hexes apart at altitudes 3 and 5 are at an effective twelve - is the low-altitude case.
- Parameters:
venue- which set of atmospheric rules is in forceattackerPosition- the hex the attacker would be firing fromattackerAltitude- the altitude the attacker would be firing fromtargetPosition- the target's hextargetAltitude- the target's altitude- Returns:
- the effective range in low-altitude hexes
-
hexesUntilOffBoard
How many hexes a unit can fly straight ahead from this pose before leaving the board.Aerospace movement is mostly committed displacement: the velocity a path ends with must be flown next turn, largely along the facing it ends on. A pose a few hexes from the edge, pointing out, is a departure already in progress whatever the pilot intends - so the ranker needs this distance to price edge headings before they become exits.
- Parameters:
start- the hex the pose ends infacing- the facing the pose ends onboard- the board being flown overmaximum- cap on the walk, so the cost stays bounded by what the caller cares about- Returns:
- hexes travelled before the first off-board hex, capped at
maximum
-
hexesToNearestEdge
How far this hex sits from the nearest board edge, in hexes.The directional walk in
hexesUntilOffBoard(megamek.common.board.Coords, int, megamek.common.board.Board, int)prices the exit a pose is pointing at; this prices the edges it is merely standing beside. A fighter parked on the westernmost column facing north reads as safe to the directional walk while one hexside of leftward drift is an instant exit - observed live as a damaged bot hugging the map edge with the directional charge barely registering.- Parameters:
position- the hex to measureboard- the board being flown over- Returns:
- hexes to the nearest edge; 0 means standing on an edge row or column
-
reachableAltitudeBand
The altitudes a unit could still be at when its turn ends.Asymmetric, because the rules are: climbing costs 2 thrust per level and is limited by the thrust budget, while descending is free and limited only by how much control risk a pilot will accept. A fighter with six thrust can therefore reach three levels up but only two down, and it is much likelier to take the free option.
Used to model an enemy that has not moved yet. Reading such a unit's current altitude as though it were settled is what leaves the bot committing to geometry its opponent is about to leave.
- Parameters:
entity- the unit to bound, which need not have moved- Returns:
- the inclusive band of altitudes it can reach, clamped to legal airborne altitudes
-
clampAltitude
public static int clampAltitude(int altitude) Holds an altitude to the range an airborne aerospace unit can legally occupy.
-