Skip to content

Commit

Permalink
Merge pull request #4735 from Sleet01/fix_3546_ltc_fuel_air_damage_wrong
Browse files Browse the repository at this point in the history
Fix various Artillery Cannon and Flak bugs
  • Loading branch information
SJuliez authored Sep 4, 2023
2 parents 140173b + 511e7d1 commit cc78efc
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 118 deletions.
1 change: 1 addition & 0 deletions megamek/i18n/megamek/client/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3923,6 +3923,7 @@ WeaponAttackAction.InvalidAmmoForFighter=cannot use this ammunition in fighter m
WeaponAttackAction.LegBlockedByTerrain=Nearby terrain blocks leg weapons.
WeaponAttackAction.MinimumAlt1=attacker must be at least at elevation 1
WeaponAttackAction.NoAeroDirectArty=Airborne aerospace units cannot make direct-fire artillery attacks.
WeaponAttackAction.FlakOnGroundedAero=Grounded aerospace/vtol units are not valid Flak targets.
WeaponAttackAction.NoAttacker=Invalid Attacker!
WeaponAttackAction.NoBombInMechMode=Cannot launch bomb in mech mode.
WeaponAttackAction.NoFiringSolution=no firing solution to target.
Expand Down
39 changes: 32 additions & 7 deletions megamek/src/megamek/common/AmmoType.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package megamek.common;

import megamek.common.options.OptionsConstants;
import org.apache.commons.lang.ArrayUtils;

import java.math.BigInteger;
import java.util.*;
Expand Down Expand Up @@ -263,7 +264,7 @@ public class AmmoType extends EquipmentType {
public static final long M_FASCAM = 1L << 40;
public static final long M_INFERNO_IV = 1L << 41;
public static final long M_VIBRABOMB_IV = 1L << 42;
// public static final long M_ACTIVE_IV
// public static final long M_ACTIVE_IV
public static final long M_SMOKE = 1L << 43;
public static final long M_LASER_INHIB = 1L << 44;

Expand Down Expand Up @@ -329,6 +330,13 @@ public static Vector<AmmoType> getMunitionsFor(int nAmmoType) {
// Short name of Ammo or RS Printing
protected String shortName = "";


// Collate artillery / artillery cannon types for flak check
// Add ADA here when implemented
private int[] ARTILLERY_TYPES = {T_LONG_TOM, T_SNIPER, T_THUMPER, T_ARROW_IV};
private int[] ARTILLERY_CANNON_TYPES = {T_LONG_TOM_CANNON, T_SNIPER_CANNON, T_THUMPER_CANNON};
private long[] ARTILLERY_FLAK_MUNITIONS = {M_CLUSTER, M_STANDARD};

public AmmoType() {
criticals = 1;
tankslots = 0;
Expand Down Expand Up @@ -436,6 +444,23 @@ public boolean is(int ammoType) {
return getAmmoType() == ammoType;
}

/**
* We need a way to quickly determine if a given ammo type / munition counts as "Flak"
* Note, not _is_ Flak (as in the case of M_FLAK) but can be considered Flak by TW/TO/IO
* rules.
* @return counts true if this ammo can be considered Flak in some situations
*/
public boolean countsAsFlak() {
boolean counts = false;

if(ArrayUtils.contains(ARTILLERY_TYPES, this.getAmmoType())){
counts = ArrayUtils.contains(ARTILLERY_FLAK_MUNITIONS, this.getMunitionType());
} else if(ArrayUtils.contains(ARTILLERY_CANNON_TYPES, this.getAmmoType())){
counts = this.getMunitionType() == AmmoType.M_STANDARD;
}
return counts;
}

public long getMunitionType() {
return munitionType;
}
Expand Down Expand Up @@ -795,7 +820,7 @@ public static void initializeTypes() {
EquipmentType.addType(AmmoType.createISThunderbolt15Ammo());
EquipmentType.addType(AmmoType.createISThunderbolt20Ammo());
EquipmentType.addType(AmmoType.createISMagshotGRAmmo());
//Removed all references to Phoenix/Hawk/Streak MRM. Was ammo only with
//Removed all references to Phoenix/Hawk/Streak MRM. Was ammo only with
//no weapon or code to support them.
EquipmentType.addType(AmmoType.createISHeavyMGAmmo());
EquipmentType.addType(AmmoType.createISHeavyMGAmmoHalf());
Expand Down Expand Up @@ -1810,7 +1835,7 @@ public static void initializeTypes() {
.setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED),
"371, TO"));

//Note of Swarms the intro dates in IntOps are off and it allows Swarm-I to appear before Swarm during the
//Note of Swarms the intro dates in IntOps are off and it allows Swarm-I to appear before Swarm during the
//Clan Invasion. Proposed errata makes 3052 for Swarm-I a hard date, and 3053 for Swarm re-iintroduction a flexible date.
munitions.add(new MunitionMutator("Swarm", 1, M_SWARM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false)
.setUnofficial(false).setTechRating(RATING_E).setAvailability(RATING_E, RATING_X, RATING_D, RATING_D)
Expand Down Expand Up @@ -4878,7 +4903,7 @@ private static AmmoType createCLVGLAmmo() {
.setClanApproximate(false, false, false, true, false);
return ammo;
}

// Machine Gun Ammos
// Standard MGs
private static AmmoType createISMGAmmo() {
Expand Down Expand Up @@ -6172,7 +6197,7 @@ private static AmmoType createISEnhancedLRM5Ammo() {
.setPrototypeFactions(F_FS)
.setProductionFactions(F_FS)
.setStaticTechLevel(SimpleTechLevel.STANDARD);

return ammo;
}

Expand Down Expand Up @@ -12779,7 +12804,7 @@ private static AmmoType createISRailGunAmmo() {
return ammo;
}



private static AmmoType createISAC10iAmmo() {
AmmoType ammo = new AmmoType();
Expand Down Expand Up @@ -13483,7 +13508,7 @@ public AmmoType createMunitionType(AmmoType base) {
|| (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM))
&& ((munition.getMunitionType() == AmmoType.M_DEAD_FIRE))) {
cost *= 0.6;
// TODO - DEAD-FIRE AMMO needs BV which is not a constant but launcher Ammo.
// TODO - DEAD-FIRE AMMO needs BV which is not a constant but launcher Ammo.
}

if (((munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM)
Expand Down
8 changes: 4 additions & 4 deletions megamek/src/megamek/common/ToHitData.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class ToHitData extends TargetRoll {
private int hitTable = HIT_NORMAL;
private int sideTable = SIDE_FRONT;
private int cover = LosEffects.COVER_NONE;
private int margineOfSuccess = 0;
private int marginOfSuccess = 0;

private Coords location;

Expand Down Expand Up @@ -230,14 +230,14 @@ public void setCover(int cover) {
* MoS returns a positive while
* MoF returns a negative
*
* @return <code>int</code>
* @return <code>int</code>
*/
public int getMoS() {
return margineOfSuccess;
return marginOfSuccess;
}

public void setMoS(int moS) {
margineOfSuccess = moS;
marginOfSuccess = moS;
}

public void setLocation(Coords l) {
Expand Down
34 changes: 21 additions & 13 deletions megamek/src/megamek/common/actions/WeaponAttackAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import megamek.common.weapons.lrms.LRTWeapon;
import megamek.common.weapons.mortars.MekMortarWeapon;
import megamek.common.weapons.srms.SRTWeapon;
import org.apache.commons.lang.ArrayUtils;
import org.apache.logging.log4j.LogManager;

import java.io.Serializable;
Expand Down Expand Up @@ -361,10 +362,14 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target,

boolean isFlakAttack = !game.getBoard().inSpace() && (te != null)
&& (te.isAirborne() || te.isAirborneVTOLorWIGE()) && (atype != null)
&& ((((atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_AC_LBX_THB)
|| (atype.getAmmoType() == AmmoType.T_SBGAUSS))
&& (munition == AmmoType.M_CLUSTER))
|| (munition == AmmoType.M_FLAK) || (atype.getAmmoType() == AmmoType.T_HAG));
&& (
(((atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_AC_LBX_THB)
|| (atype.getAmmoType() == AmmoType.T_SBGAUSS))
&& (munition == AmmoType.M_CLUSTER)
)
|| (munition == AmmoType.M_FLAK) || (atype.getAmmoType() == AmmoType.T_HAG)
|| atype.countsAsFlak()
);

boolean isIndirect = (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT));

Expand Down Expand Up @@ -721,7 +726,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target,

// Collect the modifiers for the crew/pilot
toHit = compileCrewToHitMods(game, ae, te, toHit, weapon);

// Collect the modifiers for the attacker's condition/actions
if (ae != null) {
//Conventional fighter, Aerospace and fighter LAM attackers
Expand Down Expand Up @@ -1514,7 +1519,7 @@ 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)) {
Expand All @@ -1523,15 +1528,15 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
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");
}
Expand Down Expand Up @@ -1747,7 +1752,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta
// homing ammo.

if ((ttype != Targetable.TYPE_HEX_ARTILLERY) && (ttype != Targetable.TYPE_MINEFIELD_CLEAR)
&& !isArtilleryFLAK && !isHoming && !target.isOffBoard()) {
&& !(isArtilleryFLAK || (atype != null && atype.countsAsFlak())) && !isHoming && !target.isOffBoard()) {
return Messages.getString("WeaponAttackAction.ArtyAttacksOnly");
}
// Airborne units can't make direct-fire artillery attacks
Expand Down Expand Up @@ -1796,6 +1801,9 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta

// Direct-fire artillery attacks.
if (isArtilleryDirect) {
if ((atype != null && atype.countsAsFlak()) && !(target.isAirborne() || target.isAirborneVTOLorWIGE())){
return Messages.getString("WeaponAttackAction.FlakOnGroundedAero");
}
// Cruise missiles cannot make direct-fire attacks
if (isCruiseMissile) {
return Messages.getString("WeaponAttackAction.NoDirectCruiseMissile");
Expand Down Expand Up @@ -3947,10 +3955,10 @@ else if (wtype.getAtClass() == WeaponType.CLASS_LBX_AC) {
* @param te The target Entity
* @param toHit The running total ToHitData for this WeaponAttackAction
* @param weapon The weapon being used (it's type should be WeaponType!)
*
*
*/
private static ToHitData compileCrewToHitMods(Game game, Entity ae, Entity te, ToHitData toHit, Mounted weapon) {

if (ae == null) {
// These checks won't work without a valid attacker
return toHit;
Expand Down Expand Up @@ -5051,7 +5059,7 @@ private static ToHitData handleArtilleryAttacks(Game game, Entity ae, Targetable
if (isArtilleryDirect) {
//If an airborne unit occupies the target hex, standard artillery ammo makes a flak attack against it
//TN is a flat 3 + the altitude mod + the attacker's weapon skill
if (isArtilleryFLAK && te != null) {
if ((isArtilleryFLAK || (atype != null && atype.countsAsFlak())) && te != null) {
toHit.addModifier(3, Messages.getString("WeaponAttackAction.ArtyFlak"));
if (te.isAirborne()) {
if (te.getAltitude() > 3) {
Expand Down
Loading

0 comments on commit cc78efc

Please sign in to comment.