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

Making Supercooled Myomer operational #4111

Merged
merged 7 commits into from
Jan 15, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
36 changes: 33 additions & 3 deletions megamek/src/megamek/client/ui/swing/UnitEditorDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,30 @@ private void setupAeroSystemPanel() {
}
}

/** Applies the given number of total crits to a Super-Cooled Myomer (which is spread over 6 locations). */
public void damageSCM(Entity entity, int eqNum, int hits) {
int nhits = 0;
Mounted m = entity.getEquipment(eqNum);
for (int loc = 0; loc < entity.locations(); loc++) {
for (int i = 0; i < entity.getNumberOfCriticals(loc); i++) {
CriticalSlot cs = entity.getCritical(loc, i);
if ((cs == null) || (cs.getType() != CriticalSlot.TYPE_EQUIPMENT)
|| ((m != cs.getMount()) && (m != cs.getMount2()))) {
continue;
}
if (nhits < hits) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
if (nhits < hits) {
}
if (nhits < hits) {

cs.setHit(true);
cs.setDestroyed(true);
nhits++;
} else {
cs.setHit(false);
cs.setDestroyed(false);
cs.setRepairable(true);
}
}
}
}

private void btnOkayActionPerformed(java.awt.event.ActionEvent evt) {
for (int i = 0; i < entity.locations(); i++) {
if (null != spnInternal[i]) {
Expand Down Expand Up @@ -1186,9 +1210,15 @@ private void btnOkayActionPerformed(java.awt.event.ActionEvent evt) {
CheckCritPanel crit = equipCrits.get(eqNum);
if (null != crit) {
int hits = crit.getHits();
m.setDestroyed(hits > 0);
m.setHit(hits > 0);
entity.damageSystem(CriticalSlot.TYPE_EQUIPMENT, eqNum, hits);
if (m.is(EquipmentTypeLookup.SCM)) {
m.setDestroyed(hits >= 6);
m.setHit(hits >= 6);
damageSCM(entity, eqNum, hits);
} else {
m.setDestroyed(hits > 0);
m.setHit(hits > 0);
entity.damageSystem(CriticalSlot.TYPE_EQUIPMENT, eqNum, hits);
}
}
}
if (entity instanceof Infantry) {
Expand Down
22 changes: 11 additions & 11 deletions megamek/src/megamek/common/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -590,54 +590,54 @@ public int[] getSideTorsoCriticalSlots() {
* @return the heat generated while the mech is standing still.
*/
public int getStandingHeat() {
if (engineType == XXL_ENGINE) {
return 2;
}
return 0;
return (engineType == XXL_ENGINE) ? 2 : 0;
}

/**
* @return the heat generated while the mech is walking.
*/
public int getWalkHeat(Entity e) {
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
boolean hasSCM = (e instanceof Mech) && ((Mech) e).hasWorkingSCM();

switch (engineType) {
case COMBUSTION_ENGINE:
case FUEL_CELL:
return 0;
case XXL_ENGINE:
return 4;
return hasSCM ? 3 : 4;
default:
return 1;
return hasSCM ? 0 : 1;
}
}

/**
* @return the heat generated while the mech is running.
*/
public int getRunHeat(Entity e) {
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
boolean hasSCM = (e instanceof Mech) && ((Mech) e).hasWorkingSCM();

switch (engineType) {
case COMBUSTION_ENGINE:
case FUEL_CELL:
return 0;
case XXL_ENGINE:
return 6;
return hasSCM ? 4 : 6;
default:
return 2;
return hasSCM ? 0 : 2;
}
}

/**
* @return the heat generated while the mech is sprinting.
*/
public int getSprintHeat() {
public int getSprintHeat(Entity e) {
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
boolean hasSCM = ((e instanceof Mech) && ((Mech) e).hasWorkingSCM());
boolean hasSCM = (e instanceof Mech) && ((Mech) e).hasWorkingSCM();

switch (engineType) {
case COMBUSTION_ENGINE:
case FUEL_CELL:
return 0;
case XXL_ENGINE:
return 9;
return hasSCM ? 6 : 9;
default:
return 3;
return hasSCM ? 0 : 3;
}
}

Expand Down
145 changes: 57 additions & 88 deletions megamek/src/megamek/common/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

Expand Down Expand Up @@ -4566,6 +4567,34 @@ public boolean hasWorkingWeapon(BigInteger flag, int secondary, int location) {
return false;
}

/** @return True when this unit has a RISC Super-Cooled Myomer System (even if the SCM is destroyed). */
public boolean hasSCM() {
return miscList.stream().anyMatch(m -> m.is(EquipmentTypeLookup.SCM));
}

/** @return True when this unit has an operable RISC Super-Cooled Myomer System. */
public boolean hasWorkingSCM() {
return miscList.stream().filter(m -> m.is(EquipmentTypeLookup.SCM)).anyMatch(Mounted::isOperable);
}

public int damagedSCMCritCount() {
return scmCritStateCount(CriticalSlot::isDamaged);
}

protected int scmCritStateCount(Predicate<CriticalSlot> slotState) {
int stateAppliesCount = 0;
for (int location = 0; location < locations(); location++) {
for (int index = 0; index < crits[location].length; index++) {
final CriticalSlot slot = crits[location][index];
if ((slot != null) && (slot.getType() == CriticalSlot.TYPE_EQUIPMENT)
&& slot.getMount().is(EquipmentTypeLookup.SCM) && slotState.test(slot)) {
stateAppliesCount++;
}
}
}
return stateAppliesCount;
}

/**
* Returns the amount of heat that the entity can sink each turn.
*/
Expand Down Expand Up @@ -4742,107 +4771,49 @@ public int getGoodCriticals(CriticalSlot cs, int loc) {
* the location
*/
public int getGoodCriticals(int type, int index, int loc) {
int operational = 0;
Mounted m = null;
if (type == CriticalSlot.TYPE_EQUIPMENT) {
m = getEquipment(index);
}

int numberOfCriticals = getNumberOfCriticals(loc);
for (int i = 0; i < numberOfCriticals; i++) {
CriticalSlot ccs = getCritical(loc, i);

// Check to see if this crit mounts the supplied item
// For systems, we can compare the index, but for equipment we
// need to get the Mounted that is mounted in that index and
// compare types. Superheavies may have two Mounted in each crit
if ((ccs != null) && (ccs.getType() == type)) {
if (!ccs.isDestroyed() && !ccs.isBreached()) {
if ((type == CriticalSlot.TYPE_SYSTEM) && (ccs.getIndex() == index)) {
operational++;
} else if ((type == CriticalSlot.TYPE_EQUIPMENT) && (m.equals(ccs.getMount()) || m.equals(ccs
.getMount2()))) {
operational++;
}
}
}
}
return operational;
return critStateCount(type, index, loc, cs -> !cs.isDestroyed() && !cs.isBreached());
}

/**
* The number of critical slots that are destroyed or breached in the
* location or missing along with it (if it was blown off).
*/
public int getBadCriticals(int type, int index, int loc) {
int hits = 0;
Mounted m = null;
if (type == CriticalSlot.TYPE_EQUIPMENT) {
m = getEquipment(index);
}

int numberOfCriticals = getNumberOfCriticals(loc);
for (int i = 0; i < numberOfCriticals; i++) {
CriticalSlot ccs = getCritical(loc, i);

// Check to see if this crit mounts the supplied item
// For systems, we can compare the index, but for equipment we
// need to get the Mounted that is mounted in that index and
// compare types. Superheavies may have two Mounted in each crit
if ((ccs != null) && (ccs.getType() == type)) {
if (ccs.isDestroyed() || ccs.isBreached() || ccs.isMissing()) {
if ((type == CriticalSlot.TYPE_SYSTEM) && (ccs.getIndex() == index)) {
hits++;
} else if ((type == CriticalSlot.TYPE_EQUIPMENT) &&
((m != null) && (m.equals(ccs.getMount()) || m.equals(ccs.getMount2())))) {
hits++;
}
}
}
}
return hits;
return critStateCount(type, index, loc, cs -> cs.isDestroyed() || cs.isBreached() || cs.isMissing());
}

/**
* Number of slots damaged (but not breached) in a location
*/
public int getDamagedCriticals(int type, int index, int loc) {
int hits = 0;
Mounted m = null;
if (type == CriticalSlot.TYPE_EQUIPMENT) {
m = getEquipment(index);
}

int numberOfCriticals = getNumberOfCriticals(loc);
for (int i = 0; i < numberOfCriticals; i++) {
CriticalSlot ccs = getCritical(loc, i);

// Check to see if this crit mounts the supplied item
// For systems, we can compare the index, but for equipment we
// need to get the Mounted that is mounted in that index and
// compare types. Superheavies may have two Mounted in each crit
if ((ccs != null) && (ccs.getType() == type)) {
if (ccs.isDamaged()) {
if ((type == CriticalSlot.TYPE_SYSTEM) && (ccs.getIndex() == index)) {
hits++;
} else if ((type == CriticalSlot.TYPE_EQUIPMENT) && (m.equals(ccs.getMount()) || m.equals(ccs
.getMount2()))) {
hits++;
}
}
}
}
return hits;
return critStateCount(type, index, loc, CriticalSlot::isDamaged);
}

/**
* Number of slots doomed, missing or destroyed in a location
*/
public int getHitCriticals(int type, int index, int loc) {
int hits = 0;
return critStateCount(type, index, loc, cs -> cs.isDamaged() || cs.isBreached() || cs.isMissing());
}

/**
* @returns the number of critical slots of the equipment given as index for {@link #getEquipment(int)} in
* location loc wherein the type is the critical slot type that fit the slot state given as slotState Predicate
* such as {@link CriticalSlot#isDestroyed()}. The critslots tested are only those in location loc except
* for Super-Cooled Myomer where all locations are considered.
*/
protected int critStateCount(int type, int index, int loc, Predicate<CriticalSlot> slotState) {
int stateAppliesCount = 0;
Mounted m = null;
if (type == CriticalSlot.TYPE_EQUIPMENT) {
m = getEquipment(index);
if (m == null) {
LogManager.getLogger().error("Null Equipment found in equipment list of entity " + this);
return 0;
}
if ((this instanceof Mech) && m.is(EquipmentTypeLookup.SCM)) {
return ((Mech) this).scmCritStateCount(slotState);
}
}

int numberOfCriticals = getNumberOfCriticals(loc);
Expand All @@ -4853,18 +4824,16 @@ public int getHitCriticals(int type, int index, int loc) {
// For systems, we can compare the index, but for equipment we
// need to get the Mounted that is mounted in that index and
// compare types. Superheavies may have two Mounted in each crit
if ((ccs != null) && (ccs.getType() == type)) {
if (ccs.isDamaged() || ccs.isBreached() || ccs.isMissing()) {
if ((type == CriticalSlot.TYPE_SYSTEM) && (ccs.getIndex() == index)) {
hits++;
} else if ((type == CriticalSlot.TYPE_EQUIPMENT) && (m.equals(ccs.getMount()) || m.equals(ccs
.getMount2()))) {
hits++;
}
if ((ccs != null) && (ccs.getType() == type) && slotState.test(ccs)) {
if ((type == CriticalSlot.TYPE_SYSTEM) && (ccs.getIndex() == index)) {
stateAppliesCount++;
} else if ((type == CriticalSlot.TYPE_EQUIPMENT)
&& (m.equals(ccs.getMount()) || m.equals(ccs.getMount2()))) {
stateAppliesCount++;
}
}
}
return hits;
return stateAppliesCount;
}

protected abstract int[] getNoOfSlots();
Expand Down
24 changes: 19 additions & 5 deletions megamek/src/megamek/common/EquipmentType.java
Original file line number Diff line number Diff line change
Expand Up @@ -1488,14 +1488,28 @@ public String getSortingName() {
}

/**
* Returns true if this equipment is any of those identified by the given type Strings.
* Returns true if this equipment is any of those identified by the given type Strings. The
* given typeInternalNames are compared to the internal name of this EquipmentType, not the (display) name!
* Best use the constants defined in EquipmentTypeLookup.
*
* @param eType An equipment type to check
* @param eTypes More equipment types to check
* @param typeInternalName An Equipment internal name to check
* @param typeInternalNames More Equipment internal names to check
* @return true if the internalName of this equipment matches any of the given types
*/
public boolean isAnyOf(String eType, String... eTypes) {
return internalName.equals(eType) || Arrays.asList(eTypes).contains(internalName);
public boolean isAnyOf(String typeInternalName, String... typeInternalNames) {
return internalName.equals(typeInternalName) || Arrays.asList(typeInternalNames).contains(internalName);
}

/**
* Returns true if this equipment is that identified by the given typeInternalName String. The
* given typeInternalName is compared to the internal name of this EquipmentType, not the (display) name!
* Best use the constants defined in EquipmentTypeLookup. Calling this is equivalent to
* {@link #isAnyOf(String, String...)} with only the one parameter.
*
* @param typeInternalName An Equipment internal name to check
* @return true if the internalName of this equipment matches the given type
*/
public boolean is(String typeInternalName) {
return isAnyOf(typeInternalName);
}
}
Loading