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

Issue 4259: Fixing Dropship Heat-by-Arc for Players and Princess #6276

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
51 changes: 40 additions & 11 deletions megamek/src/megamek/client/bot/princess/MultiTargetFireControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import megamek.common.Entity;
import megamek.common.Game;
import megamek.common.Mounted;
import megamek.common.Targetable;
import megamek.common.equipment.AmmoMounted;
import megamek.common.equipment.WeaponMounted;
Expand Down Expand Up @@ -259,6 +260,26 @@
// damage values by arc: arc #, arc damage
Map<Integer, Double> arcDamage = new HashMap<>();

int heatCapacity = shooter.getHeatCapacity();
shooter.getWeapons();
shooter.getWeaponList();
logger.error(String.format("Weapons Length: %s", shooter.getWeaponList().size()));
for ( WeaponMounted weapon : shooter.getWeaponList()){
Fixed Show fixed Hide fixed

}
for ( WeaponMounted weapon : shooter.getWeaponList().stream().filter(Mounted::isUsedThisRound).toList()){
logger.error(String.format("Weapon in list: %s", weapon.getName()));
int arc = weapon.isRearMounted() ? -shooter.getWeaponArc(weapon.getLocation()) : shooter.getWeaponArc(weapon.getLocation());
if (!arcShots.containsKey(arc)) {
heatCapacity -= shooter.getHeatInArc(weapon.getLocation(), weapon.isRearMounted());
arcShots.put(arc, new ArrayList<>());
arcHeat.put(arc, 0);
arcDamage.put(arc, 1.0);

logger.error(String.format("Arc: %s Heat: %s", arc, arcHeat.get(arc)));
}
}

// assemble the data we'll need to solve the backpack problem
for (WeaponFireInfo shot : shotList) {
int arc = shooter.getWeaponArc(shooter.getEquipmentNum(shot.getWeapon()));
Expand All @@ -267,44 +288,51 @@
arc = -arc;
}

logger.error(String.format("Shot: %s Rear: %s Arc: %s Raw arc: %s", shot.getWeapon().getName(), shot.getWeapon().isRearMounted(), arc,shooter.getWeaponArc(shooter.getEquipmentNum(shot.getWeapon())) ));

if (!arcShots.containsKey(arc)) {
arcShots.put(arc, new ArrayList<>());
arcHeat.put(arc,
shooter.getHeatInArc(shot.getWeapon().getLocation(), shot.getWeapon().isRearMounted()));
arcDamage.put(arc, 0.0);

logger.error(String.format("Arc: %s Heat: %s", arc, arcHeat.get(arc)));
}

arcShots.get(arc).add(shot);
arcDamage.put(arc, arcDamage.get(arc) + shot.getExpectedDamage());
logger.error(String.format("Arc: %s Damage: %s", arc, arcDamage.get(arc)));
}

// initialize the backpack
Map<Integer, Map<Integer, List<Integer>>> arcBackpack = new HashMap<>();
for (int x = 0; x < arcShots.keySet().size(); x++) {
for (int x = 0; x <= arcShots.keySet().size(); x++) {
arcBackpack.put(x, new HashMap<>());

for (int y = 0; y < shooter.getHeatCapacity(); y++) {
for (int y = 0; y <= heatCapacity; y++) {
arcBackpack.get(x).put(y, new ArrayList<>());
}
}

double[][] damageBackpack = new double[arcShots.keySet().size()][shooter.getHeatCapacity()];
double[][] damageBackpack = new double[arcShots.keySet().size() + 1][heatCapacity + 1];
Integer[] arcHeatKeyArray = new Integer[arcHeat.keySet().size()];
System.arraycopy(arcHeat.keySet().toArray(), 0, arcHeatKeyArray, 0, arcHeat.keySet().size());

logger.error(String.format("Heat Key Array Length: %s Attempted Output: %s", arcHeatKeyArray.length, arcHeatKeyArray));
Fixed Show fixed Hide fixed

// now, we essentially solve the backpack problem, where the arcs are the items:
// arc expected damage is the "value", and arc heat is the "weight", while the
// backpack capacity is the unit's heat capacity.
// while we're at it, we assemble the list of arcs fired for each cell
for (int arcIndex = 0; arcIndex < arcHeatKeyArray.length; arcIndex++) {
for (int heatIndex = 0; heatIndex < shooter.getHeatCapacity(); heatIndex++) {
int previousArc = arcIndex > 0 ? arcHeatKeyArray[arcIndex - 1] : 0;
for (int arcIndex = 0; arcIndex <= arcHeatKeyArray.length; arcIndex++) {
for (int heatIndex = 0; heatIndex <= heatCapacity; heatIndex++) {
int currentArc = arcIndex > 0 ? arcHeatKeyArray[arcIndex - 1] : 0;

if (arcIndex == 0 || heatIndex == 0) {
damageBackpack[arcIndex][heatIndex] = 0;
} else if (arcHeat.get(previousArc) <= heatIndex) {
int previousHeatIndex = heatIndex - arcHeat.get(previousArc);
double currentArcDamage = arcDamage.get(previousArc)
} else if (arcHeat.get(currentArc) <= heatIndex) {
int previousHeatIndex = heatIndex - arcHeat.get(currentArc);
double currentArcDamage = arcDamage.get(currentArc)
+ damageBackpack[arcIndex - 1][previousHeatIndex];
double accumulatedPreviousArcDamage = damageBackpack[arcIndex - 1][heatIndex];

Expand All @@ -315,7 +343,7 @@
// make sure we don't accidentally update the cell we're examining
List<Integer> appendedArcList = new ArrayList<>(
arcBackpack.get(arcIndex - 1).get(previousHeatIndex));
appendedArcList.add(previousArc);
appendedArcList.add(currentArc);
arcBackpack.get(arcIndex).put(heatIndex, appendedArcList);
} else {
// we *can* add this arc to the list, but it won't take us past the damage
Expand All @@ -336,7 +364,8 @@
// solution
// unless there is no firing solution at all, in which case we skip this part
if (!arcBackpack.isEmpty()) {
for (int arc : arcBackpack.get(arcBackpack.size() - 1).get(shooter.getHeatCapacity() - 1)) {
for (int arc : arcBackpack.get(arcBackpack.size() - 1).get(heatCapacity - 1)) {
logger.error(String.format("final arc: %s", arc));
retVal.addAll(arcShots.get(arc));
}
}
Expand Down
19 changes: 11 additions & 8 deletions megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1195,12 +1195,10 @@ public void displayMek(Entity en) {
&& game.getPhase().isFiring()) {
hasFiredWeapons = true;
// add heat from weapons fire to heat tracker
if (entity.usesWeaponBays()) {
if (entity.isLargeCraft()) {
psikomonkie marked this conversation as resolved.
Show resolved Hide resolved
// if using bay heat option then don't add total arc
if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
for (WeaponMounted weapon : mounted.getBayWeapons()) {
currentHeatBuildup += weapon.getCurrentHeat();
}
currentHeatBuildup += mounted.getCurrentHeat();
} else {
// check whether arc has fired
int loc = mounted.getLocation();
Expand Down Expand Up @@ -1257,17 +1255,22 @@ public void displayMek(Entity en) {

// change what is visible based on type
if (entity.usesWeaponBays()) {
wArcHeatL.setVisible(true);
wArcHeatR.setVisible(true);
m_chBayWeapon.setVisible(true);
wBayWeapon.setVisible(true);
} else {
wArcHeatL.setVisible(false);
wArcHeatR.setVisible(false);
m_chBayWeapon.setVisible(false);
wBayWeapon.setVisible(false);
}

if (entity.isLargeCraft()) {
wArcHeatL.setVisible(true);
wArcHeatR.setVisible(true);
}
else {
wArcHeatL.setVisible(false);
wArcHeatR.setVisible(false);
}

wDamageTrooperL.setVisible(false);
wDamageTrooperR.setVisible(false);
wInfantryRange0L.setVisible(false);
Expand Down
1 change: 1 addition & 0 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -11636,6 +11636,7 @@ public int getHeatInArc(int location, boolean rearMount) {
if ((mounted.getLocation() == location)
&& (mounted.isRearMounted() == rearMount)) {
arcHeat += mounted.getCurrentHeat();
logger.error(String.format("Location: %s Rear Mount: %s Weapon: %s Heat: %s Arc Heat %s", location, rearMount, mounted.getName(), mounted.getCurrentHeat(), arcHeat));
}
}
return arcHeat;
Expand Down
50 changes: 31 additions & 19 deletions megamek/src/megamek/common/actions/WeaponAttackAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@
}

// are we bracing a location that's not where the weapon is located?
if (ae.isBracing() && (ae.braceLocation() != weapon.getLocation())) {

Check warning

Code scanning / CodeQL

Dereferenced variable may be null Warning

Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
Variable
weapon
may be null at this access as suggested by
this
null guard.
return String.format(Messages.getString("WeaponAttackAction.BracingOtherLocation"),
ae.getLocationName(ae.braceLocation()), ae.getLocationName(weapon.getLocation()));
}
Expand Down Expand Up @@ -1486,28 +1486,30 @@

// limit large craft to zero net heat and to heat by arc
final int heatCapacity = ae.getHeatCapacity();
if (ae.usesWeaponBays() && (weapon != null) && !weapon.getBayWeapons().isEmpty()) {
if (ae.isLargeCraft() && (weapon != null)) {
int totalHeat = 0;

// first check to see if there are any usable weapons
boolean usable = false;
for (WeaponMounted m : weapon.getBayWeapons()) {
WeaponType bayWType = m.getType();
boolean bayWUsesAmmo = (bayWType.getAmmoType() != AmmoType.T_NA);
if (m.canFire()) {
if (bayWUsesAmmo) {
if ((m.getLinked() != null) && (m.getLinked().getUsableShotsLeft() > 0)) {
// first check to see if there are any usable bay weapons
if (!weapon.getBayWeapons().isEmpty()) {
boolean usable = false;
for (WeaponMounted m : weapon.getBayWeapons()) {
WeaponType bayWType = m.getType();
boolean bayWUsesAmmo = (bayWType.getAmmoType() != AmmoType.T_NA);
if (m.canFire()) {
if (bayWUsesAmmo) {
if ((m.getLinked() != null) && (m.getLinked().getUsableShotsLeft() > 0)) {
usable = true;
break;
}
} else {
usable = true;
break;
}
} else {
usable = true;
break;
}
}
}
if (!usable) {
return Messages.getString("WeaponAttackAction.BayNotReady");
if (!usable) {
return Messages.getString("WeaponAttackAction.BayNotReady");
}
}

// create an array of booleans of locations
Expand All @@ -1534,8 +1536,13 @@
int loc = prevWeapon.getLocation();
boolean rearMount = prevWeapon.isRearMounted();
if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
for (WeaponMounted bWeapon : prevWeapon.getBayWeapons()) {
totalHeat += bWeapon.getCurrentHeat();
if (!weapon.getBayWeapons().isEmpty()) {
for (WeaponMounted bWeapon : prevWeapon.getBayWeapons()) {
totalHeat += bWeapon.getCurrentHeat();
}
}
else {
totalHeat += prevWeapon.getCurrentHeat();
}
} else {
if (!rearMount) {
Expand All @@ -1560,8 +1567,13 @@
int currentHeat = ae.getHeatInArc(loc, rearMount);
if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
currentHeat = 0;
for (WeaponMounted bWeapon : weapon.getBayWeapons()) {
currentHeat += bWeapon.getCurrentHeat();
if (!weapon.getBayWeapons().isEmpty()) {
for (WeaponMounted bWeapon : weapon.getBayWeapons()) {
currentHeat += bWeapon.getCurrentHeat();
}
}
else {
currentHeat += weapon.getCurrentHeat();
}
}
// check to see if this is currently the only arc being fired
Expand Down
39 changes: 34 additions & 5 deletions megamek/src/megamek/common/weapons/WeaponHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public int getSalvoBonus() {
* TeleMissile entity in the physical phase
*/
protected int getLargeCraftHeat(Entity e) {
int totalheat = 0;
int totalHeat = 0;
if (e.hasETypeFlag(Entity.ETYPE_DROPSHIP)
|| e.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) {
if (e.usesWeaponBays()) {
Expand All @@ -163,7 +163,35 @@ protected int getLargeCraftHeat(Entity e) {
if (prevAttack.getEntityId() == e.getId()) {
WeaponMounted prevWeapon = (WeaponMounted) e.getEquipment(prevAttack.getWeaponId());
for (WeaponMounted bayW : prevWeapon.getBayWeapons()) {
totalheat += bayW.getCurrentHeat();
totalHeat += bayW.getCurrentHeat();
}
}
}
} else if (!game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
// create an array of booleans of locations
boolean[] usedFrontArc = new boolean[ae.locations()];
boolean[] usedRearArc = new boolean[ae.locations()];
for (int i = 0; i < ae.locations(); i++) {
usedFrontArc[i] = false;
usedRearArc[i] = false;
}
for (Enumeration<AttackHandler> i = game.getAttacks(); i.hasMoreElements();) {
AttackHandler ah = i.nextElement();
WeaponAttackAction prevAttack = ah.getWaa();
if (prevAttack.getEntityId() == e.getId()) {
WeaponMounted prevWeapon = (WeaponMounted) e.getEquipment(prevAttack.getWeaponId());
boolean rearMount = prevWeapon.isRearMounted();
int loc = prevWeapon.getLocation();
if (!rearMount) {
if (!usedFrontArc[loc]) {
totalHeat += ae.getHeatInArc(loc, rearMount);
usedFrontArc[loc] = true;
}
} else {
if (!usedRearArc[loc]) {
totalHeat += ae.getHeatInArc(loc, rearMount);
usedRearArc[loc] = true;
}
}
}
}
Expand All @@ -173,12 +201,12 @@ protected int getLargeCraftHeat(Entity e) {
WeaponAttackAction prevAttack = ah.getWaa();
if (prevAttack.getEntityId() == e.getId()) {
Mounted<?> prevWeapon = e.getEquipment(prevAttack.getWeaponId());
totalheat += prevWeapon.getCurrentHeat();
totalHeat += prevWeapon.getCurrentHeat();
}
}
}
}
return totalheat;
return totalHeat;
}

/**
Expand Down Expand Up @@ -1903,12 +1931,13 @@ protected void addHeat() {
return;
}
if (!(toHit.getValue() == TargetRoll.IMPOSSIBLE)) {
if (ae.usesWeaponBays() && !game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
if (ae.isLargeCraft() && !game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) {
int loc = weapon.getLocation();
boolean rearMount = weapon.isRearMounted();
if (!ae.hasArcFired(loc, rearMount)) {
ae.heatBuildup += ae.getHeatInArc(loc, rearMount);
ae.setArcFired(loc, rearMount);
logger.error(String.format("Arc Heat: %s Buildup: %s", ae.getHeatInArc(loc, rearMount), ae.heatBuildup));
}
} else {
ae.heatBuildup += (weapon.getCurrentHeat());
Expand Down
Loading