Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix machine gun array burst damage against conventional infantry #4841

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions megamek/i18n/megamek/common/report-messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

# 0 through 999 -- System messages? (reserved at the moment)

950=<newline>
# Email subject lines
990=MegaMek Deployment Report
991=MegaMek Round #<data> Report
Expand Down
54 changes: 40 additions & 14 deletions megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -6400,10 +6400,11 @@ public static int directBlowBADamage(double damage, int damageType,
* Used to get a human-readable string that represents the passed damage
* type.
*
* @param damageType
* @return
* @param damageType The dmaageType constant
* @param burstMultiplier The multiplier for burst damage, used by machine gun arrays against conventional infantry
* @return A string representation of the damage type
*/
public static String getDamageTypeString(int damageType) {
public static String getDamageTypeString(int damageType, int burstMultiplier) {
switch (damageType) {
case WeaponType.WEAPON_DIRECT_FIRE:
return Messages.getString("WeaponType.DirectFire");
Expand All @@ -6417,6 +6418,7 @@ public static String getDamageTypeString(int damageType) {
case WeaponType.WEAPON_CLUSTER_MISSILE_3D6:
return Messages.getString("WeaponType.Missile");
case WeaponType.WEAPON_BURST_HALFD6:
return Messages.getString("WeaponType.BurstHalf");
case WeaponType.WEAPON_BURST_1D6:
case WeaponType.WEAPON_BURST_2D6:
case WeaponType.WEAPON_BURST_3D6:
Expand All @@ -6425,7 +6427,8 @@ public static String getDamageTypeString(int damageType) {
case WeaponType.WEAPON_BURST_6D6:
case WeaponType.WEAPON_BURST_7D6:
default:
return Messages.getString("WeaponType.Burst");
return String.format("%s (%dD6)", Messages.getString("WeaponType.Burst"),
burstMultiplier * (damageType - WeaponType.WEAPON_BURST_HALFD6));
}
}

Expand All @@ -6447,9 +6450,32 @@ public static int directBlowInfantryDamage(double damage, int mos,
* @param damageType
* @return
*/
public static int directBlowInfantryDamage(double damage, int mos,
int damageType, boolean isNonInfantryAgainstMechanized,
boolean isAttackThruBuilding, int attackerId, Vector<Report> vReport) {
return directBlowInfantryDamage(damage, mos, damageType, isNonInfantryAgainstMechanized,
isAttackThruBuilding, attackerId, vReport, 1);
}

/**
* Method replicates the Non-Conventional Damage against Infantry damage
* table as well as shifting for direct blows. also adjust for non-infantry
* damaging mechanized infantry
*
* @param damage The base amount of damage
* @param mos The margin of success
* @param damageType The damage class of the weapon, used to adjust damage against infantry
* @param isNonInfantryAgainstMechanized Whether this is a non-infantry attack against mechanized infantry
* @param isAttackThruBuilding Whether the attack is coming through a building hex
* @param attackerId The entity id of the attacking unit
* @param vReport The report messages vector
* @param mgaSize For machine gun array attacks, the number of linked weapons. For other weapons this should be 1.
* @return The adjusted damage
*/
public static int directBlowInfantryDamage(double damage, int mos,
int damageType, boolean isNonInfantryAgainstMechanized,
boolean isAttackThruBuilding, int attackerId, Vector<Report> vReport) {
boolean isAttackThruBuilding, int attackerId, Vector<Report> vReport,
int mgaSize) {

int origDamageType = damageType;
damageType += mos;
Expand Down Expand Up @@ -6488,43 +6514,43 @@ public static int directBlowInfantryDamage(double damage, int mos,
}
break;
case WeaponType.WEAPON_BURST_1D6:
damage = Compute.d6();
damage = Compute.d6(mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_2D6:
damage = Compute.d6(2);
damage = Compute.d6(2 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_3D6:
damage = Compute.d6(3);
damage = Compute.d6(3 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_4D6:
damage = Compute.d6(4);
damage = Compute.d6(4 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_5D6:
damage = Compute.d6(5);
damage = Compute.d6(5 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_6D6:
damage = Compute.d6(6);
damage = Compute.d6(6 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
break;
case WeaponType.WEAPON_BURST_7D6:
damage = Compute.d6(7);
damage = Compute.d6(7 * mgaSize);
if (isAttackThruBuilding) {
damage *= 0.5;
}
Expand All @@ -6549,14 +6575,14 @@ public static int directBlowInfantryDamage(double damage, int mos,
r.subject = attackerId;
r.indent(2);

r.add(getDamageTypeString(origDamageType));
r.add(getDamageTypeString(origDamageType, mgaSize));
if (origDamageType != damageType) {
if (isAttackThruBuilding) {
r.messageId = 9973;
} else {
r.messageId = 9972;
}
r.add(getDamageTypeString(damageType));
r.add(getDamageTypeString(damageType, mgaSize));
} else if (isAttackThruBuilding) {
r.messageId = 9971;
} else {
Expand Down
14 changes: 7 additions & 7 deletions megamek/src/megamek/common/MoveStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -3903,7 +3903,6 @@ public boolean canAeroTurn(Game game) {
return true;
}


if (en instanceof ConvFighter) {
// conventional fighters can only turn on free turns or maneuvers
return false;
Expand Down Expand Up @@ -4015,18 +4014,19 @@ public boolean isManeuver() {
return maneuver;
}

public Minefield getMinefield() {
return mf;
}


/**
* @return Whether this step is a maneuver that allows a free facing change.
*/
public boolean isFacingChangeManeuver() {
return maneuver && (
maneuverType == ManeuverType.MAN_IMMELMAN
|| maneuverType == ManeuverType.MAN_SPLIT_S
);
}

public Minefield getMinefield() {
return mf;
|| maneuverType == ManeuverType.MAN_SPLIT_S
);
}

/**
Expand Down
69 changes: 41 additions & 28 deletions megamek/src/megamek/common/weapons/MGAWeaponHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,10 @@

import java.util.Vector;

import megamek.common.Building;
import megamek.common.Compute;
import megamek.common.Entity;
import megamek.common.HitData;
import megamek.common.Game;
import megamek.common.Hex;
import megamek.common.Report;
import megamek.common.ToHitData;
import megamek.common.*;
import megamek.common.actions.WeaponAttackAction;
import megamek.common.options.OptionsConstants;
import megamek.server.GameManager;
import megamek.server.Server;

/**
* @author Sebastian Brocks
Expand All @@ -45,6 +38,29 @@
super(t, w, g, m);
}

@Override
protected int calcDamagePerHit() {
if (target.isConventionalInfantry()) {
calcDmgPerHitReport.add(new Report(950));
int damage = Compute.directBlowInfantryDamage(
wtype.getDamage(), bDirect ? toHit.getMoS() / 3 : 0,
wtype.getInfantryDamageClass(),
((Infantry) target).isMechanized(),
toHit.getThruBldg() != null, ae.getId(), calcDmgPerHitReport, howManyShots);
damage = applyGlancingBlowModifier(damage, true);
if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_RANGE)) {
if (nRange > wtype.getRanges(weapon)[RangeType.RANGE_LONG]) {
damage *= 0.75;

Check failure

Code scanning / CodeQL

Implicit narrowing conversion in compound assignment High

Implicit cast of source type double to narrower destination type int.
} else if (nRange > wtype.getRanges(weapon)[RangeType.RANGE_EXTREME]) {
damage *= 0.5;

Check failure

Code scanning / CodeQL

Implicit narrowing conversion in compound assignment High

Implicit cast of source type double to narrower destination type int.
}
}
return damage;
} else {
return super.calcDamagePerHit();
}
}

/*
* (non-Javadoc)
*
Expand Down Expand Up @@ -86,24 +102,21 @@
int shotsHit;
int nMod = getClusterModifiers(true);

switch (howManyShots) {
case 1:
shotsHit = 1;
break;
default:
shotsHit = allShotsHit() ? howManyShots : Compute.missilesHit(
howManyShots, nMod);
Report r = new Report(3325);
r.subject = subjectId;
r.add(shotsHit);
r.add(" shot(s) ");
r.add(toHit.getTableDesc());
r.newlines = 0;
vPhaseReport.addElement(r);
r = new Report(3345);
r.subject = subjectId;
vPhaseReport.addElement(r);
break;
if ((howManyShots == 1) || target.isConventionalInfantry()) {
shotsHit = 1;
} else {
shotsHit = allShotsHit() ? howManyShots : Compute.missilesHit(
howManyShots, nMod);
Report r = new Report(3325);
r.subject = subjectId;
r.add(shotsHit);
r.add(" shot(s) ");
r.add(toHit.getTableDesc());
r.newlines = 0;
vPhaseReport.addElement(r);
r = new Report(3345);
r.subject = subjectId;
vPhaseReport.addElement(r);
}
bSalvo = true;
return shotsHit;
Expand Down Expand Up @@ -151,7 +164,7 @@

hit.setGeneralDamageType(generalDamageType);
if (!bSalvo) {
// Each hit in the salvo get's its own hit location.
// Each hit in the salvo gets its own hit location.
Report r = new Report(3405);
r.subject = subjectId;
r.add(toHit.getTableDesc());
Expand Down
7 changes: 2 additions & 5 deletions megamek/src/megamek/common/weapons/mgs/CLMGA.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,12 @@
*/
package megamek.common.weapons.mgs;

import megamek.common.AmmoType;
import megamek.common.Game;
import megamek.common.Mounted;
import megamek.common.ToHitData;
import megamek.common.*;
import megamek.common.actions.WeaponAttackAction;
import megamek.common.weapons.AmmoWeapon;
import megamek.common.weapons.AttackHandler;
import megamek.common.weapons.MGAWeaponHandler;
import megamek.server.GameManager;
import megamek.server.Server;

/**
* @author Sebastian Brocks
Expand All @@ -38,6 +34,7 @@ public CLMGA() {
sortingName = "MGA C";
heat = 0;
damage = 2;
infDamageClass = WeaponType.WEAPON_BURST_2D6;
rackSize = 2;
ammoType = AmmoType.T_MG;
minimumRange = WEAPON_NA;
Expand Down