Skip to content

Commit

Permalink
Merge pull request #4612 from MegaMek/fix_dropship_nose_idf
Browse files Browse the repository at this point in the history
Allow dropship nose LRM indirect fire
  • Loading branch information
NickAragua authored Jul 10, 2023
2 parents 9ab3a67 + b6eefa1 commit 7d97a9e
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 21 deletions.
1 change: 1 addition & 0 deletions megamek/src/megamek/client/ui/swing/GameOptionsDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ private void addSearchPanel() {
lblSearch.setLabelFor(txtSearch);
lblSearch.setToolTipText(Messages.getString("GameOptionsDialog.SearchToolTip"));
txtSearch.setToolTipText(Messages.getString("GameOptionsDialog.SearchToolTip"));
txtSearch.setColumns(20);
txtSearch.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
Expand Down
30 changes: 21 additions & 9 deletions megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import megamek.common.enums.AimingMode;
import megamek.common.enums.BasementType;
import megamek.common.enums.IlluminationLevel;
import megamek.common.options.Option;
import megamek.common.options.OptionsConstants;
import megamek.common.weapons.InfantryAttack;
import megamek.common.weapons.Weapon;
Expand Down Expand Up @@ -1338,15 +1337,10 @@ public static ToHitData getRangeMods(Game game, Entity ae, int weaponId,
if (isIndirect) {
c3spotter = ae; // no c3 when using indirect fire
}
if (isIndirect
&& game.getOptions().booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)
&& !game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_INDIRECT_ALWAYS_POSSIBLE)
&& LosEffects.calculateLOS(game, ae, target).canSee()
&& (!game.getOptions().booleanOption(OptionsConstants.ADVANCED_DOUBLE_BLIND) || Compute
.canSee(game, ae, target))
&& !(wtype instanceof MekMortarWeapon)) {

if (isIndirect && indirectAttackImpossible(game, ae, target, wtype, weapon)) {
return new ToHitData(TargetRoll.IMPOSSIBLE,
"Indirect fire impossible with direct LOS");
Messages.getString("WeaponAttackAction.NoIndirectWithLOS"));
}

int c3dist = Compute.effectiveDistance(game, c3spotter, target, false);
Expand Down Expand Up @@ -7187,5 +7181,23 @@ public static boolean useSpheroidAtmosphere(Game game, Entity en) {
// are we in atmosphere?
return en.isAirborne();
}

/**
* Worker function that checks if an indirect attack is impossible for the given passed-in arguments
*/
public static boolean indirectAttackImpossible(Game game, Entity ae, Targetable target, WeaponType wtype, Mounted weapon) {
boolean isLandedSpheroid = ae.isAero() && ((IAero) ae).isSpheroid() && (ae.getAltitude() == 0) && game.getBoard().onGround();
int altDif = target.getAltitude() - ae.getAltitude();
boolean noseWeaponAimedAtGroundTarget = (weapon != null) && (weapon.getLocation() == Aero.LOC_NOSE) && (altDif < 1);

return game.getOptions().booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)
&& !game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_INDIRECT_ALWAYS_POSSIBLE)
&& LosEffects.calculateLOS(game, ae, target).canSee()
&& (!game.getOptions().booleanOption(OptionsConstants.ADVANCED_DOUBLE_BLIND)
|| Compute.canSee(game, ae, target))
&& !(wtype instanceof ArtilleryCannonWeapon)
&& !wtype.hasFlag(WeaponType.F_MORTARTYPE_INDIRECT)
&& !(isLandedSpheroid && noseWeaponAimedAtGroundTarget);
}

} // End public class Compute
22 changes: 10 additions & 12 deletions megamek/src/megamek/common/actions/WeaponAttackAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
// Infantry can't clear woods.
if (isAttackerInfantry && (Targetable.TYPE_HEX_CLEAR == target.getTargetType())) {
Hex hexTarget = game.getBoard().getHex(target.getPosition());
if (hexTarget.containsTerrain(Terrains.WOODS)) {
if ((hexTarget != null) && hexTarget.containsTerrain(Terrains.WOODS)) {
return Messages.getString("WeaponAttackAction.NoInfantryWoodsClearing");
}
}
Expand Down Expand Up @@ -1508,21 +1508,25 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
// for spheroid dropships in atmosphere (and on ground), the rules about
// firing arcs are more complicated
// TW errata 2.1

if ((Compute.useSpheroidAtmosphere(game, ae) ||
(ae.isAero() && ((IAero) ae).isSpheroid() && (ae.getAltitude() == 0) && game.getBoard().onGround()))
&& weapon != null) {
int altDif = target.getAltitude() - ae.getAltitude();
&& (weapon != null)) {
int range = Compute.effectiveDistance(game, ae, target, false);
// Only aft-mounted weapons can be fired at range 0 (targets directly underneath)
if (!ae.isAirborne() && (range == 0) && (weapon.getLocation() != Aero.LOC_AFT)) {
return Messages.getString("WeaponAttackAction.OnlyAftAtZero");
}

int altDif = target.getAltitude() - ae.getAltitude();

// Nose-mounted weapons can only be fired at targets at least 1 altitude higher
if ((weapon.getLocation() == Aero.LOC_NOSE) && (altDif < 1)
&& wtype != null
// Unless the weapon is used as artillery
&& (!(wtype instanceof ArtilleryWeapon || wtype.hasFlag(WeaponType.F_ARTILLERY)
|| (ae.getAltitude() == 0 && wtype instanceof CapitalMissileWeapon)))) {
|| (ae.getAltitude() == 0 && wtype instanceof CapitalMissileWeapon)
|| isIndirect))) {
return Messages.getString("WeaponAttackAction.TooLowForNose");
}
// Front-side-mounted weapons can only be fired at targets at the same altitude or higher
Expand Down Expand Up @@ -2196,7 +2200,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
return Messages.getString("WeaponAttackAction.InvalidForFirefighting");
}
Hex hexTarget = game.getBoard().getHex(target.getPosition());
if (!hexTarget.containsTerrain(Terrains.FIRE)) {
if ((hexTarget != null) && !hexTarget.containsTerrain(Terrains.FIRE)) {
return Messages.getString("WeaponAttackAction.TargetNotBurning");
}
} else if (wtype.hasFlag(WeaponType.F_EXTINGUISHER)) {
Expand Down Expand Up @@ -2277,13 +2281,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
// Indirect Fire (LRMs)

// Can't fire Indirect LRM with direct LOS
if (isIndirect && game.getOptions().booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)
&& !game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_INDIRECT_ALWAYS_POSSIBLE)
&& LosEffects.calculateLOS(game, ae, target).canSee()
&& (!game.getOptions().booleanOption(OptionsConstants.ADVANCED_DOUBLE_BLIND)
|| Compute.canSee(game, ae, target))
&& !(wtype instanceof ArtilleryCannonWeapon)
&& !wtype.hasFlag(WeaponType.F_MORTARTYPE_INDIRECT)) {
if (isIndirect && Compute.indirectAttackImpossible(game, ae, target, wtype, weapon)) {
return Messages.getString("WeaponAttackAction.NoIndirectWithLOS");
}

Expand Down

0 comments on commit 7d97a9e

Please sign in to comment.