Skip to content

Commit

Permalink
Merge pull request #5416 from MegaMek/weapon_mounted_bays
Browse files Browse the repository at this point in the history
Weapon bay rework
  • Loading branch information
neoancient authored Apr 25, 2024
2 parents ddf3b38 + a846587 commit 2db2dca
Show file tree
Hide file tree
Showing 45 changed files with 553 additions and 547 deletions.
12 changes: 6 additions & 6 deletions megamek/src/megamek/client/bot/BotClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import megamek.common.actions.WeaponAttackAction;
import megamek.common.annotations.Nullable;
import megamek.common.enums.GamePhase;
import megamek.common.equipment.WeaponMounted;
import megamek.common.event.*;
import megamek.common.net.packets.Packet;
import megamek.common.options.OptionsConstants;
Expand Down Expand Up @@ -1006,13 +1007,12 @@ private static float getDeployDamage(Game g, WeaponAttackAction waa, List<ECMInf
fHits = expectedHitsByRackSize[wt.getRackSize()];
}
// adjust for previous AMS
ArrayList<Mounted> vCounters = waa.getCounterEquipment();
List<WeaponMounted> vCounters = waa.getCounterEquipment();
if (wt.hasFlag(WeaponType.F_MISSILE) && vCounters != null) {
for (Mounted vCounter : vCounters) {
EquipmentType type = vCounter.getType();
if ((type instanceof WeaponType)
&& type.hasFlag(WeaponType.F_AMS)) {
float fAMS = 3.5f * ((WeaponType) type).getDamage();
for (WeaponMounted vCounter : vCounters) {
WeaponType type = vCounter.getType();
if (type.hasFlag(WeaponType.F_AMS)) {
float fAMS = 3.5f * type.getDamage();
fHits = Math.max(0.0f, fHits - fAMS);
}
}
Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/client/bot/princess/FireControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter,

// Make sure we have ammo.
final WeaponType weaponType = (WeaponType) weapon.getType();
final AmmoMounted firingAmmo;
final Mounted firingAmmo;
if (AmmoType.T_NA != weaponType.getAmmoType()) {
// Use ammo arg if provided, else use linked ammo.
firingAmmo = (ammo == null) ? weapon.getLinkedAmmo() : ammo;
Expand Down Expand Up @@ -704,7 +704,7 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter,
}
// Bays compute arc differently
final boolean inArc = (bayWeapon)
? Compute.isInArc(game, shooter.getId(), (int) weapon.getBayWeapons().get(0), target)
? Compute.isInArc(game, shooter.getId(), weapon.getBayWeapons().get(0).getEquipmentNum(), target)
: isInArc(shooterState.getPosition(), shooterFacing, targetState.getPosition(),
shooter.getWeaponArc(shooter.getEquipmentNum(weapon)));
if (!inArc) {
Expand Down
17 changes: 7 additions & 10 deletions megamek/src/megamek/client/bot/princess/WeaponFireInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,10 @@ private WeaponAttackAction buildBombAttackAction(final HashMap<String, int[]> bo
// bay weapons require special consideration, by looping through all weapons and adding up the damage
// A bay's weapons may have different ranges, most noticeable in laser bays, where the damage potential
// varies with distance to target.
if ((null != weapon.getBayWeapons()) && !weapon.getBayWeapons().isEmpty()) {
if (!weapon.getBayWeapons().isEmpty()) {
int bayDamage = 0;
for (int weaponID : weapon.getBayWeapons()) {
Mounted<?> bayWeapon = weapon.getEntity().getEquipment(weaponID);
WeaponType weaponType = (WeaponType) bayWeapon.getType();
for (WeaponMounted bayWeapon: weapon.getBayWeapons()) {
WeaponType weaponType = bayWeapon.getType();
int maxRange = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_RANGE)
? weaponType.getExtremeRange() : weaponType.getLongRange();
int targetDistance = getShooter().getPosition().distance(getTarget().getPosition());
Expand Down Expand Up @@ -521,16 +520,14 @@ private WeaponAttackAction buildBombAttackAction(final HashMap<String, int[]> bo
* @param weapon The weapon to check.
* @return Generated heat.
*/
int computeHeat(Mounted<?> weapon) {
int computeHeat(WeaponMounted weapon) {
// bay weapons require special consideration, by looping through all weapons and adding up the damage
// A bay's weapons may have different ranges, most noticeable in laser bays, where the damage potential
// varies with distance to target.
if ((null != weapon.getBayWeapons()) && !weapon.getBayWeapons().isEmpty()) {
if (!weapon.getBayWeapons().isEmpty()) {
int bayHeat = 0;
for (int weaponID : weapon.getBayWeapons()) {
Mounted bayWeapon = weapon.getEntity().getEquipment(weaponID);
WeaponType weaponType = (WeaponType) bayWeapon.getType();
bayHeat += weaponType.getHeat();
for (WeaponMounted bayWeapon : weapon.getBayWeapons()) {
bayHeat += bayWeapon.getType().getHeat();
}

return bayHeat;
Expand Down
18 changes: 7 additions & 11 deletions megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,12 @@ public BayMunitionsChoicePanel(Entity entity, Game game) {

for (WeaponMounted bay : entity.getWeaponBayList()) {
Map<List<Integer>,List<AmmoMounted>> ammoByType = new HashMap<>();
for (Integer aNum : bay.getBayAmmo()) {
final AmmoMounted ammo = (AmmoMounted) entity.getEquipment(aNum);
if (null != ammo) {
List<Integer> key = new ArrayList<>(2);
key.add(ammo.getType().getAmmoType());
key.add(ammo.getType().getRackSize());
ammoByType.putIfAbsent(key, new ArrayList<>());
ammoByType.get(key).add(ammo);
}
for (AmmoMounted ammo : bay.getBayAmmo()) {
List<Integer> key = new ArrayList<>(2);
key.add(ammo.getType().getAmmoType());
key.add(ammo.getType().getRackSize());
ammoByType.putIfAbsent(key, new ArrayList<>());
ammoByType.get(key).add(ammo);
}
for (List<Integer> key : ammoByType.keySet()) {
AmmoRowPanel row = new AmmoRowPanel(bay, key.get(0), key.get(1), ammoByType.get(key));
Expand Down Expand Up @@ -148,8 +145,7 @@ class AmmoRowPanel extends JPanel implements ChangeListener {
Dimension spinnerSize =new Dimension(55, 25);

final Optional<WeaponType> wtype = bay.getBayWeapons().stream()
.map(entity::getEquipment)
.map(m -> (WeaponType) m.getType()).findAny();
.map(Mounted::getType).findAny();

// set the bay's tech base to that of any weapon in the bay
// an assumption is made here that bays don't mix clan-only and IS-only tech base
Expand Down
6 changes: 2 additions & 4 deletions megamek/src/megamek/client/ui/swing/CustomMechDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -530,11 +530,9 @@ public void actionPerformed(ActionEvent actionEvent) {
// Artillery bays can mix and match, so limit the bay
// to the shortest range of the weapons in it
int bayShortestRange = 150; // Cruise missile/120
for (int wId : wep.getBayWeapons()) {
WeaponMounted bweap = (WeaponMounted) entity.getEquipment(wId);
WeaponType bwtype = bweap.getType();
for (WeaponMounted bweap : wep.getBayWeapons()) {
// Max TO range in mapsheets - 1 for the actual play area
int currentDistance = (bwtype.getLongRange() - 1);
int currentDistance = (bweap.getType().getLongRange() - 1);
if (currentDistance < bayShortestRange) {
bayShortestRange = currentDistance;
}
Expand Down
48 changes: 21 additions & 27 deletions megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,8 @@ public void displayMech(Entity en) {
if (entity.usesWeaponBays()) {
// if using bay heat option then don't add total arc
if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
for (int wId : mounted.getBayWeapons()) {
currentHeatBuildup += entity.getEquipment(wId).getCurrentHeat();
for (WeaponMounted weapon : mounted.getBayWeapons()) {
currentHeatBuildup += weapon.getCurrentHeat();
}
} else {
// check whether arc has fired
Expand Down Expand Up @@ -1909,12 +1909,7 @@ private void displaySelected() {
m_chBayWeapon.setEnabled(false);
} else {
m_chBayWeapon.setEnabled(true);
for (int wId : mounted.getBayWeapons()) {
WeaponMounted curWeapon = (WeaponMounted) entity.getEquipment(wId);
if (null == curWeapon) {
continue;
}

for (WeaponMounted curWeapon : mounted.getBayWeapons()) {
m_chBayWeapon.addItem(formatBayWeapon(curWeapon));
}

Expand All @@ -1933,7 +1928,7 @@ private void displaySelected() {
if (n == -1) {
n = 0;
}
mounted = (WeaponMounted) entity.getEquipment(mounted.getBayWeapons().get(n));
mounted = mounted.getBayWeapon(n);
wtype = mounted.getType();
}

Expand Down Expand Up @@ -2579,7 +2574,7 @@ else if ((atype.getAmmoType() == AmmoType.T_LRM)

private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) {

List<Integer> bayWeapons = weapon.getBayWeapons();
List<WeaponMounted> bayWeapons = weapon.getBayWeapons();
WeaponType wtype = weapon.getType();

// set default values in case if statement stops
Expand All @@ -2599,15 +2594,14 @@ private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) {
double avExt = 0;
int maxr = WeaponType.RANGE_SHORT;

for (int wId : bayWeapons) {
WeaponMounted m = (WeaponMounted) entity.getEquipment(wId);
for (WeaponMounted m : bayWeapons) {
if (!m.isBreached()
&& !m.isMissing()
&& !m.isDestroyed()
&& !m.isJammed()
&& ((m.getLinked() == null) || (m.getLinked()
.getUsableShotsLeft() > 0))) {
WeaponType bayWType = ((WeaponType) m.getType());
WeaponType bayWType = m.getType();
heat = heat + m.getCurrentHeat();
double mAVShort = bayWType.getShortAV();
double mAVMed = bayWType.getMedAV();
Expand All @@ -2617,8 +2611,7 @@ private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) {

// deal with any ammo adjustments
if (null != m.getLinked()) {
double[] changes = changeAttackValues((AmmoType) m
.getLinked().getType(), mAVShort, mAVMed,
double[] changes = changeAttackValues((AmmoType) m.getLinked().getType(), mAVShort, mAVMed,
mAVLong, mAVExt, mMaxR);
mAVShort = changes[0];
mAVMed = changes[1];
Expand Down Expand Up @@ -2785,20 +2778,21 @@ public void actionPerformed(ActionEvent ev) {
return;
}
//
Mounted<?> sWeap = entity.getEquipment(mWeap.getBayWeapons().get(n));
WeaponMounted sWeap = mWeap.getBayWeapon(n);
// cycle through all weapons of the same type and load with
// this ammo
for (int wid : mWeap.getBayWeapons()) {
WeaponMounted bWeap = (WeaponMounted) entity.getEquipment(wid);
// FIXME: Consider new AmmoType::equals / BombType::equals
if (bWeap.getType().equals(sWeap.getType())) {
entity.loadWeapon(bWeap, mAmmo);
// Alert the server of the update.
clientgui.getClient().sendAmmoChange(
entity.getId(),
entity.getEquipmentNum(bWeap),
entity.getEquipmentNum(mAmmo),
0);
if (sWeap != null) {
for (WeaponMounted bWeap : mWeap.getBayWeapons()) {
// FIXME: Consider new AmmoType::equals / BombType::equals
if (bWeap.getType().equals(sWeap.getType())) {
entity.loadWeapon(bWeap, mAmmo);
// Alert the server of the update.
clientgui.getClient().sendAmmoChange(
entity.getId(),
entity.getEquipmentNum(bWeap),
entity.getEquipmentNum(mAmmo),
0);
}
}
}
} else {
Expand Down
8 changes: 4 additions & 4 deletions megamek/src/megamek/common/Aero.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import megamek.client.ui.swing.calculationReport.CalculationReport;
import megamek.common.cost.AeroCostCalculator;
import megamek.common.enums.AimingMode;
import megamek.common.equipment.AmmoMounted;
import megamek.common.equipment.WeaponMounted;
import megamek.common.options.OptionsConstants;
import megamek.common.planetaryconditions.PlanetaryConditions;
Expand Down Expand Up @@ -3021,14 +3022,13 @@ public List<WeaponMounted> getActiveAMS() {
}

// Make sure ammo is loaded
for (int wId : weapon.getBayWeapons()) {
Mounted<?> bayW = getEquipment(wId);
Mounted<?> bayWAmmo = bayW.getLinked();
for (WeaponMounted bayW : weapon.getBayWeapons()) {
AmmoMounted bayWAmmo = bayW.getLinkedAmmo();
if (!(weapon.getType().hasFlag(WeaponType.F_ENERGY))
&& ((bayWAmmo == null) || (bayWAmmo.getUsableShotsLeft() == 0)
|| bayWAmmo.isDumping())) {
loadWeapon(weapon);
bayWAmmo = weapon.getLinked();
bayWAmmo = weapon.getLinkedAmmo();
}

// try again
Expand Down
29 changes: 21 additions & 8 deletions megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,20 @@ public static float randomFloat() {
return random.randomFloat();
}

/**
* Selects a random element from a list
* @param list The list of items to select from
* @return An element in the list
* @param <T> The list type
*/
public static<T> T randomListElement(List<T> list) {
if (list.isEmpty()) {
throw new IllegalArgumentException("Tried to select random element from empty list");
} else {
return list.get(randomInt(list.size()));
}
}

/**
* Sets the RNG to the desired type
*/
Expand Down Expand Up @@ -3120,8 +3134,8 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa,
int infShootingStrength = 0;
double infDamagePerTrooper = 0;

Mounted<?> weapon = attacker.getEquipment(waa.getWeaponId());
Mounted lnk_guide;
WeaponMounted weapon = (WeaponMounted) attacker.getEquipment(waa.getWeaponId());
Mounted<?> lnk_guide;

ToHitData hitData = waa.toHit(g, allECMInfo);

Expand Down Expand Up @@ -3329,10 +3343,10 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa,
// adjust for previous AMS
if ((wt.getDamage() == WeaponType.DAMAGE_BY_CLUSTERTABLE)
&& wt.hasFlag(WeaponType.F_MISSILE)) {
ArrayList<Mounted> vCounters = waa.getCounterEquipment();
List<WeaponMounted> vCounters = waa.getCounterEquipment();
if (vCounters != null) {
for (int x = 0; x < vCounters.size(); x++) {
EquipmentType type = vCounters.get(x).getType();
for (WeaponMounted vCounter : vCounters) {
EquipmentType type = vCounter.getType();
if ((type instanceof WeaponType) && type.hasFlag(WeaponType.F_AMS)) {
fHits *= 0.6f;
}
Expand Down Expand Up @@ -3371,9 +3385,8 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa,
if (attacker.usesWeaponBays()) {
double av = 0;
double threat = 1;
for (int wId : weapon.getBayWeapons()) {
Mounted bayW = attacker.getEquipment(wId);
WeaponType bayWType = ((WeaponType) bayW.getType());
for (WeaponMounted bayW : weapon.getBayWeapons()) {
WeaponType bayWType = bayW.getType();
//Capital weapons have a different range scale
if (wt.isCapital()) {
// Capital missiles get higher priority than standard missiles:
Expand Down
30 changes: 17 additions & 13 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4032,7 +4032,7 @@ public int getFirstWeapon() {
* @return True if valid, else false
*/
public boolean isWeaponValidForPhase(int weapNum) {
return isWeaponValidForPhase(equipmentList.get(weapNum));
return isWeaponValidForPhase((WeaponMounted) equipmentList.get(weapNum));
}

/**
Expand All @@ -4042,7 +4042,7 @@ public boolean isWeaponValidForPhase(int weapNum) {
* @param mounted
* @return True if valid, else false
*/
public boolean isWeaponValidForPhase(Mounted<?> mounted) {
public boolean isWeaponValidForPhase(WeaponMounted mounted) {
// Start reached, now we can attempt to pick a weapon.
if ((mounted != null)
&& (mounted.isReady())
Expand Down Expand Up @@ -11574,12 +11574,12 @@ public boolean isCommander() {
return isCommander;
}

public boolean hasLinkedMGA(Mounted<?> mounted) {
public boolean hasLinkedMGA(WeaponMounted mounted) {
for (WeaponMounted m : getWeaponList()) {
if ((m.getLocation() == mounted.getLocation())
&& m.getType().hasFlag(WeaponType.F_MGA)
&& !(m.isDestroyed() || m.isBreached())
&& m.getBayWeapons().contains(getEquipmentNum(mounted))
&& m.getBayWeapons().contains(mounted)
&& m.hasModes() && m.curMode().equals("Linked")) {
return true;
}
Expand Down Expand Up @@ -11631,16 +11631,21 @@ public boolean usesWeaponBays() {
}

/**
* return the bay of the current weapon
* return the bay of the current weapon or ammo
*
* @param bayID
* @return
* @param equipmentId The equipment index
* @return The bay mount, or null if the equipment is not in a bay
*/
public WeaponMounted whichBay(int bayID) {
public WeaponMounted whichBay(int equipmentId) {
for (WeaponMounted m : getWeaponBayList()) {
for (int wId : m.getBayWeapons()) {
for (WeaponMounted weapon : m.getBayWeapons()) {
// find the weapon and determine if it is there
if (wId == bayID) {
if (weapon.getEquipmentNum() == equipmentId) {
return m;
}
}
for (AmmoMounted ammo : m.getBayAmmo()) {
if (ammo.getEquipmentNum() == equipmentId) {
return m;
}
}
Expand Down Expand Up @@ -12599,11 +12604,10 @@ public int getQuirkIniBonus() {
* @param mammo
* @return
*/
public WeaponMounted getBayByAmmo(Mounted<?> mammo) {
public WeaponMounted getBayByAmmo(AmmoMounted mammo) {

for (WeaponMounted m : getWeaponBayList()) {
for (int bayAmmoId : m.getBayAmmo()) {
Mounted<?> bayammo = getEquipment(bayAmmoId);
for (AmmoMounted bayammo : m.getBayAmmo()) {
if (bayammo == mammo) {
return m;
}
Expand Down
Loading

0 comments on commit 2db2dca

Please sign in to comment.