From 93b30ee17a69de53da16997665e990831c2dabd1 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 27 Dec 2020 11:09:54 -0500 Subject: [PATCH 01/33] Move Part::findPartImage into GUI namespace --- MekHQ/src/mekhq/campaign/parts/Part.java | 72 ------------ .../mekhq/gui/dialog/AcquisitionsDialog.java | 3 +- MekHQ/src/mekhq/gui/model/TaskTableModel.java | 4 +- .../gui/utilities/PartWorkImageSelector.java | 103 ++++++++++++++++++ 4 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java diff --git a/MekHQ/src/mekhq/campaign/parts/Part.java b/MekHQ/src/mekhq/campaign/parts/Part.java index 9463bde2b9..e1ece142c8 100644 --- a/MekHQ/src/mekhq/campaign/parts/Part.java +++ b/MekHQ/src/mekhq/campaign/parts/Part.java @@ -40,21 +40,17 @@ import org.w3c.dom.NodeList; import megamek.common.Entity; -import megamek.common.EquipmentType; import megamek.common.ITechnology; import megamek.common.SimpleTechLevel; import megamek.common.Tank; import megamek.common.TargetRoll; import megamek.common.TechAdvancement; -import megamek.common.WeaponType; import megamek.common.annotations.Nullable; import mekhq.MekHQ; import mekhq.MekHqXmlSerializable; import mekhq.MekHqXmlUtil; import mekhq.Version; import mekhq.campaign.Campaign; -import mekhq.campaign.parts.equipment.EquipmentPart; -import mekhq.campaign.parts.equipment.MissingEquipmentPart; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.PersonnelOptions; import mekhq.campaign.personnel.SkillType; @@ -1554,74 +1550,6 @@ public String toString() { return sb.toString(); } - public static String[] findPartImage(IPartWork part) { - String imgBase = null; - PartRepairType repairType = IPartWork.findCorrectRepairType(part); - - switch (repairType) { - case ARMOR: - imgBase = "armor"; - break; - case AMMO: - imgBase = "ammo"; - break; - case ACTUATOR: - imgBase = "actuator"; - break; - case ENGINE: - imgBase = "engine"; - break; - case ELECTRONICS: - imgBase = "electronics"; - break; - case HEAT_SINK: - imgBase = "heatsink"; - break; - case WEAPON: - EquipmentType equipmentType = null; - - if (part instanceof EquipmentPart) { - equipmentType = ((EquipmentPart) part).getType(); - } else if (part instanceof MissingEquipmentPart) { - equipmentType = ((MissingEquipmentPart) part).getType(); - } - - if (equipmentType != null) { - if (equipmentType.hasFlag(WeaponType.F_LASER)) { - imgBase = "laser"; - } else if (equipmentType.hasFlag(WeaponType.F_MISSILE)) { - imgBase = "missile"; - } else if (equipmentType.hasFlag(WeaponType.F_BALLISTIC)) { - imgBase = "ballistic"; - } else if (equipmentType.hasFlag(WeaponType.F_ARTILLERY)) { - imgBase = "artillery"; - } - } - - break; - case MEK_LOCATION: - case POD_SPACE: - imgBase = "location_mek"; - break; - case PHYSICAL_WEAPON: - imgBase = "melee"; - break; - default: - break; - } - - if (imgBase == null) { - imgBase = "equipment"; - } - - - String[] imgData = new String[2]; - imgData[0] = "data/images/misc/repair/"; - imgData[1] = imgBase; - - return imgData; - } - public abstract ITechnology getTechAdvancement(); @Override diff --git a/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java b/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java index 506ffac698..9d2694d416 100644 --- a/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java @@ -38,6 +38,7 @@ import mekhq.gui.GuiTabType; import mekhq.gui.RepairTab; import mekhq.gui.preferences.JWindowPreference; +import mekhq.gui.utilities.PartWorkImageSelector; import mekhq.preferences.PreferencesNode; import mekhq.service.PartsAcquisitionService; import mekhq.service.PartsAcquisitionService.PartCountInfo; @@ -399,7 +400,7 @@ private void initComponents() { Insets insetsOriginal = gbcMain.insets; // Set image - String[] imgData = Part.findPartImage(part); + String[] imgData = PartWorkImageSelector.findPartImage(part); String imgPath = imgData[0] + imgData[1] + ".png"; Image imgTool = getToolkit().getImage(imgPath); diff --git a/MekHQ/src/mekhq/gui/model/TaskTableModel.java b/MekHQ/src/mekhq/gui/model/TaskTableModel.java index 3ee9328515..ab73bc0caf 100644 --- a/MekHQ/src/mekhq/gui/model/TaskTableModel.java +++ b/MekHQ/src/mekhq/gui/model/TaskTableModel.java @@ -33,7 +33,6 @@ import megamek.common.TargetRoll; import mekhq.IconPackage; import mekhq.campaign.parts.MissingPart; -import mekhq.campaign.parts.Part; import mekhq.campaign.parts.PartInventory; import mekhq.campaign.parts.PodSpace; import mekhq.campaign.personnel.Person; @@ -42,6 +41,7 @@ import mekhq.gui.CampaignGUI; import mekhq.gui.ITechWorkPanel; import mekhq.gui.RepairTaskInfo; +import mekhq.gui.utilities.PartWorkImageSelector; /** * A table model for displaying work items @@ -217,7 +217,7 @@ public Component getTableCellRendererComponent(JTable table, break; } - String[] imgData = Part.findPartImage(part); + String[] imgData = PartWorkImageSelector.findPartImage(part); String imgPath = imgData[0] + imgData[1] + imgMod + ".png"; Image imgTool = getToolkit().getImage(imgPath); //$NON-NLS-1$ diff --git a/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java b/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java new file mode 100644 index 0000000000..b0cdc5eebc --- /dev/null +++ b/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 MegaMek team + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + +package mekhq.gui.utilities; + +import megamek.common.EquipmentType; +import megamek.common.WeaponType; +import mekhq.campaign.parts.enums.PartRepairType; +import mekhq.campaign.parts.equipment.EquipmentPart; +import mekhq.campaign.parts.equipment.MissingEquipmentPart; +import mekhq.campaign.work.IPartWork; + +public class PartWorkImageSelector { + + /** + * Find the most appropriate image for a given {@see IPartWork}. + * @param part The {@see PartWork} to select the image for. + * @return An array containing the path parts pointing to the image. + */ + public static String[] findPartImage(IPartWork part) { + String imgBase = null; + PartRepairType repairType = IPartWork.findCorrectRepairType(part); + + switch (repairType) { + case ARMOR: + imgBase = "armor"; + break; + case AMMO: + imgBase = "ammo"; + break; + case ACTUATOR: + imgBase = "actuator"; + break; + case ENGINE: + imgBase = "engine"; + break; + case ELECTRONICS: + imgBase = "electronics"; + break; + case HEAT_SINK: + imgBase = "heatsink"; + break; + case WEAPON: + EquipmentType equipmentType = null; + + if (part instanceof EquipmentPart) { + equipmentType = ((EquipmentPart) part).getType(); + } else if (part instanceof MissingEquipmentPart) { + equipmentType = ((MissingEquipmentPart) part).getType(); + } + + if (equipmentType != null) { + if (equipmentType.hasFlag(WeaponType.F_LASER)) { + imgBase = "laser"; + } else if (equipmentType.hasFlag(WeaponType.F_MISSILE)) { + imgBase = "missile"; + } else if (equipmentType.hasFlag(WeaponType.F_BALLISTIC)) { + imgBase = "ballistic"; + } else if (equipmentType.hasFlag(WeaponType.F_ARTILLERY)) { + imgBase = "artillery"; + } + } + + break; + case MEK_LOCATION: + case POD_SPACE: + imgBase = "location_mek"; + break; + case PHYSICAL_WEAPON: + imgBase = "melee"; + break; + default: + break; + } + + if (imgBase == null) { + imgBase = "equipment"; + } + + + String[] imgData = new String[2]; + imgData[0] = "data/images/misc/repair/"; + imgData[1] = imgBase; + + return imgData; + } +} From 271e65c6998b2bbfab63cf1922caa829510ccea5 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 27 Dec 2020 17:06:54 -0500 Subject: [PATCH 02/33] Add basic MekLocation tests --- .../src/mekhq/campaign/parts/MekLocation.java | 2 +- .../mekhq/campaign/parts/MekLocationTest.java | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 90ebb7bc47..6fca93551d 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -333,7 +333,7 @@ public void fix() { } @Override - public MissingPart getMissingPart() { + public MissingMekLocation getMissingPart() { return new MissingMekLocation(loc, getUnitTonnage(), structureType, clan, tsm, forQuad, campaign); } diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 7168c11d65..0188dedde1 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -27,12 +27,148 @@ import org.junit.Test; import megamek.common.CriticalSlot; +import megamek.common.EquipmentType; import megamek.common.LandAirMech; import megamek.common.Mech; import mekhq.campaign.Campaign; import mekhq.campaign.unit.Unit; public class MekLocationTest { + @Test + public void deserializationCtorTest() { + MekLocation loc = new MekLocation(); + assertNotNull(loc); + } + + @Test + public void ctorTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LLEG; + int tonnage = 70; + int structureType = EquipmentType.T_STRUCTURE_ENDO_STEEL; + boolean isClan = true; + boolean hasTSM = true; + boolean isQuad = true; + boolean hasSensors = true; + boolean hasLifeSupport = true; + MekLocation mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + assertEquals(location, mekLocation.getLoc()); + assertEquals(tonnage, mekLocation.getUnitTonnage()); + assertEquals(hasTSM, mekLocation.isTsm()); + assertEquals(structureType, mekLocation.getStructureType()); + assertEquals(isClan, mekLocation.isClan()); + assertEquals(isQuad, mekLocation.forQuad()); + assertEquals(hasSensors, mekLocation.hasSensors()); + assertEquals(hasLifeSupport, mekLocation.hasLifeSupport()); + assertNotNull(mekLocation.getName()); + } + + @Test + public void cloneTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LLEG; + int tonnage = 65; + int structureType = EquipmentType.T_STRUCTURE_ENDO_STEEL; + boolean isClan = true; + boolean hasTSM = true; + boolean isQuad = true; + boolean hasSensors = true; + boolean hasLifeSupport = true; + MekLocation mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + MekLocation clone = mekLocation.clone(); + + assertEquals(mekLocation.getLoc(), clone.getLoc()); + assertEquals(mekLocation.getUnitTonnage(), clone.getUnitTonnage()); + assertEquals(mekLocation.isTsm(), clone.isTsm()); + assertEquals(mekLocation.getStructureType(), clone.getStructureType()); + assertEquals(mekLocation.isClan(), clone.isClan()); + assertEquals(mekLocation.forQuad(), clone.forQuad()); + assertEquals(mekLocation.hasSensors(), clone.hasSensors()); + assertEquals(mekLocation.hasLifeSupport(), clone.hasLifeSupport()); + assertEquals(mekLocation.getName(), clone.getName()); + assertEquals(mekLocation.getPercent(), clone.getPercent(), 0.001); + assertEquals(mekLocation.isBlownOff(), clone.isBlownOff()); + assertEquals(mekLocation.isBreached(), clone.isBreached()); + } + + @Test + public void getMissingPartTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LT; + int tonnage = 65; + int structureType = EquipmentType.T_STRUCTURE_REINFORCED; + boolean isClan = true; + boolean hasTSM = false; + boolean isQuad = true; + boolean hasSensors = false; + boolean hasLifeSupport = false; + MekLocation mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + MissingMekLocation missing = mekLocation.getMissingPart(); + + assertEquals(mekLocation.getLoc(), missing.getLocation()); + assertEquals(mekLocation.getUnitTonnage(), missing.getUnitTonnage()); + assertEquals(mekLocation.isTsm(), missing.isTsm()); + assertEquals(mekLocation.getStructureType(), missing.getStructureType()); + assertEquals(mekLocation.isClan(), missing.isClan()); + assertEquals(mekLocation.forQuad(), missing.forQuad()); + assertEquals(mekLocation.getName(), missing.getName()); + } + + @Test + public void cannotScrapCT() { + Campaign mockCampaign = mock(Campaign.class); + + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 1, 0, false, false, false, false, false, mockCampaign); + + assertNotNull(centerTorso.checkScrappable()); + } + + @Test + public void cannotSalvageCT() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(entity.getWeight()).thenReturn(65.0); + + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 1, 0, false, false, false, false, false, mockCampaign); + centerTorso.setUnit(unit); + + assertFalse(centerTorso.isSalvaging()); + } + + @Test + public void onBadHipOrShoulderTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(entity.getWeight()).thenReturn(65.0); + + int location = Mech.LOC_RT; + MekLocation torso = new MekLocation(location, 1, 0, false, false, false, false, false, mockCampaign); + + // Can't be on a bad hip or shoulder if off a unit + assertFalse(torso.onBadHipOrShoulder()); + + torso.setUnit(unit); + + // Not on a bad hip or shoulder if the unit doesn't say so + assertFalse(torso.onBadHipOrShoulder()); + + doReturn(true).when(unit).hasBadHipOrShoulder(location); + + // Now we're on a bad hip or shoulder + assertTrue(torso.onBadHipOrShoulder()); + } + @Test public void lamTorsoRemovableOnlyWithMissingAvionicsAndLandingGear() { Campaign mockCampaign = mock(Campaign.class); From cb2bd0e37db6a537d43cc1c1df571cc990325c23 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 27 Dec 2020 19:01:03 -0500 Subject: [PATCH 03/33] Fix test issue --- MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 0188dedde1..3ef7101926 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -138,6 +138,7 @@ public void cannotSalvageCT() { Unit unit = mock(Unit.class); Mech entity = mock(Mech.class); when(entity.getWeight()).thenReturn(65.0); + when(unit.getEntity()).thenReturn(entity); MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 1, 0, false, false, false, false, false, mockCampaign); centerTorso.setUnit(unit); @@ -151,6 +152,7 @@ public void onBadHipOrShoulderTest() { Unit unit = mock(Unit.class); Mech entity = mock(Mech.class); when(entity.getWeight()).thenReturn(65.0); + when(unit.getEntity()).thenReturn(entity); int location = Mech.LOC_RT; MekLocation torso = new MekLocation(location, 1, 0, false, false, false, false, false, mockCampaign); From 3b501d59d9a02157c595dbfe0832133fe39e59a7 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Mon, 28 Dec 2020 14:30:18 -0500 Subject: [PATCH 04/33] Add MekLocation::writeToXml test --- .../mekhq/campaign/parts/MekLocationTest.java | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 3ef7101926..1cf0c00c9f 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -22,14 +22,26 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.function.Predicate; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; + import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; import megamek.common.CriticalSlot; import megamek.common.EquipmentType; import megamek.common.LandAirMech; import megamek.common.Mech; +import mekhq.MekHqXmlUtil; +import mekhq.Version; import mekhq.campaign.Campaign; import mekhq.campaign.unit.Unit; @@ -127,7 +139,7 @@ public void getMissingPartTest() { public void cannotScrapCT() { Campaign mockCampaign = mock(Campaign.class); - MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 1, 0, false, false, false, false, false, mockCampaign); + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); assertNotNull(centerTorso.checkScrappable()); } @@ -140,7 +152,7 @@ public void cannotSalvageCT() { when(entity.getWeight()).thenReturn(65.0); when(unit.getEntity()).thenReturn(entity); - MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 1, 0, false, false, false, false, false, mockCampaign); + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 100, 0, false, false, false, false, false, mockCampaign); centerTorso.setUnit(unit); assertFalse(centerTorso.isSalvaging()); @@ -155,7 +167,7 @@ public void onBadHipOrShoulderTest() { when(unit.getEntity()).thenReturn(entity); int location = Mech.LOC_RT; - MekLocation torso = new MekLocation(location, 1, 0, false, false, false, false, false, mockCampaign); + MekLocation torso = new MekLocation(location, 100, 0, false, false, false, false, false, mockCampaign); // Can't be on a bad hip or shoulder if off a unit assertFalse(torso.onBadHipOrShoulder()); @@ -170,6 +182,51 @@ public void onBadHipOrShoulderTest() { // Now we're on a bad hip or shoulder assertTrue(torso.onBadHipOrShoulder()); } + + @Test + public void mekLocationWriteToXmlTest() throws ParserConfigurationException, SAXException, IOException { + Campaign mockCampaign = mock(Campaign.class); + MekLocation mekLocation = new MekLocation(Mech.LOC_CT, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setId(25); + + // Write the MekLocation XML + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + mekLocation.writeToXml(pw, 0); + + // Get the MekLocation XML + String xml = sw.toString(); + assertFalse(xml.trim().isEmpty()); + + // Using factory get an instance of document builder + DocumentBuilder db = MekHqXmlUtil.newSafeDocumentBuilder(); + + // Parse using builder to get DOM representation of the XML file + Document xmlDoc = db.parse(new ByteArrayInputStream(xml.getBytes())); + + Element partElt = xmlDoc.getDocumentElement(); + assertEquals("part", partElt.getNodeName()); + + // Deserialize the MekLocation + Part deserializedPart = Part.generateInstanceFromXML(partElt, new Version("1.0.0")); + assertNotNull(deserializedPart); + assertTrue(deserializedPart instanceof MekLocation); + + MekLocation deserialized = (MekLocation) deserializedPart; + + // Check that we deserialized the part correctly. + assertEquals(mekLocation.getId(), deserialized.getId()); + assertEquals(mekLocation.getName(), deserialized.getName()); + assertEquals(mekLocation.getLoc(), deserialized.getLoc()); + assertEquals(mekLocation.getUnitTonnage(), deserialized.getUnitTonnage()); + assertEquals(mekLocation.getStructureType(), deserialized.getStructureType()); + assertEquals(mekLocation.isClan(), deserialized.isClan()); + assertEquals(mekLocation.isTsm(), deserialized.isTsm()); + assertEquals(mekLocation.forQuad(), deserialized.forQuad()); + assertEquals(mekLocation.hasSensors(), deserialized.hasSensors()); + assertEquals(mekLocation.hasLifeSupport(), deserialized.hasLifeSupport()); + } @Test public void lamTorsoRemovableOnlyWithMissingAvionicsAndLandingGear() { From a4dc1f1b7eeae990cbe1ba2c667940dc4ab2eae9 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Mon, 28 Dec 2020 14:33:23 -0500 Subject: [PATCH 05/33] Remove duplicated code in MekLocation::loadFieldsFromXmlNode --- MekHQ/src/mekhq/campaign/parts/MekLocation.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 6fca93551d..b4f194cd29 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -271,8 +271,6 @@ protected void loadFieldsFromXmlNode(Node wn) { clan = Boolean.parseBoolean(wn2.getTextContent()); } else if (wn2.getNodeName().equalsIgnoreCase("percent")) { percent = Double.parseDouble(wn2.getTextContent()); - } else if (wn2.getNodeName().equalsIgnoreCase("clan")) { - clan = Boolean.parseBoolean(wn2.getTextContent()); } else if (wn2.getNodeName().equalsIgnoreCase("tsm")) { tsm = Boolean.parseBoolean(wn2.getTextContent()); } else if (wn2.getNodeName().equalsIgnoreCase("forQuad")) { From 2b2916b9175bdd4e639d5de1c7fe5559e989a2a6 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Mon, 28 Dec 2020 14:58:05 -0500 Subject: [PATCH 06/33] Add MekLocation::isSamePartType test --- .../src/mekhq/campaign/parts/MekLocation.java | 29 ++-- .../mekhq/campaign/parts/MekLocationTest.java | 133 ++++++++++++++++++ 2 files changed, 152 insertions(+), 10 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index b4f194cd29..81debb96f9 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -191,18 +191,27 @@ public boolean forQuad() { @Override public boolean isSamePartType(Part part) { - return part instanceof MekLocation - && getLoc() == ((MekLocation) part).getLoc() - && getUnitTonnage() == part.getUnitTonnage() - && isTsm() == ((MekLocation) part).isTsm() - && getStructureType() == ((MekLocation) part).getStructureType() + return (part instanceof MekLocation) + && isSamePartType((MekLocation) part); + } + + /** + * Gets a value indicating whether or not {@code other} is the same + * type of {@code MekLocation}. + * @param other A different {@code MekLocation}. + */ + public boolean isSamePartType(MekLocation other) { + return (getLoc() == other.getLoc()) + && (getUnitTonnage() == other.getUnitTonnage()) + && (isTsm() == other.isTsm()) + && (getStructureType() == other.getStructureType()) && ((getStructureType() != EquipmentType.T_STRUCTURE_ENDO_STEEL) - || (isClan() == part.isClan())) - && (!isArm() || forQuad == ((MekLocation) part).forQuad) + || (isClan() == other.isClan())) + && (!isArm() || forQuad() == other.forQuad()) // Sensors and life support only matter if we're comparing two parts in the warehouse. - && ((getUnit() != null) || (part.getUnit() != null) - || (hasSensors() == ((MekLocation) part).hasSensors() - && hasLifeSupport() == ((MekLocation) part).hasLifeSupport())); + && ((getUnit() != null) || (other.getUnit() != null) + || (hasSensors() == other.hasSensors() + && hasLifeSupport() == other.hasLifeSupport())); } @Override diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 1cf0c00c9f..76a730f2e5 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -37,6 +37,7 @@ import org.xml.sax.SAXException; import megamek.common.CriticalSlot; +import megamek.common.Entity; import megamek.common.EquipmentType; import megamek.common.LandAirMech; import megamek.common.Mech; @@ -182,6 +183,138 @@ public void onBadHipOrShoulderTest() { // Now we're on a bad hip or shoulder assertTrue(torso.onBadHipOrShoulder()); } + + @Test + public void isSamePartTypeTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LLEG, otherLocation = Mech.LOC_HEAD; + int tonnage = 70; + int structureType = EquipmentType.T_STRUCTURE_ENDO_STEEL, + otherStructureType = EquipmentType.T_STRUCTURE_REINFORCED; + boolean isClan = true; + boolean hasTSM = true; + boolean isQuad = true; + boolean hasSensors = true; + boolean hasLifeSupport = true; + MekLocation mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + assertTrue(mekLocation.isSamePartType(mekLocation)); + + // Same as our clone + Part other = mekLocation.clone(); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + // Same if structure type is not Endo Steel and we're clan vs not clan + mekLocation = new MekLocation(location, tonnage, EquipmentType.T_STRUCTURE_INDUSTRIAL, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(location, tonnage, EquipmentType.T_STRUCTURE_INDUSTRIAL, !isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + // Clan and IS Endo Steel differ + mekLocation = new MekLocation(location, tonnage, EquipmentType.T_STRUCTURE_ENDO_STEEL, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(location, tonnage, EquipmentType.T_STRUCTURE_ENDO_STEEL, !isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Restore the original setup + mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + // Different locations + other = new MekLocation(otherLocation, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Different tonnage + other = new MekLocation(location, tonnage + 10, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Different structure + other = new MekLocation(location, tonnage, otherStructureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Different TSM + other = new MekLocation(location, tonnage, structureType, isClan, + !hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Arms for quads must match on quad status, but others do not + mekLocation = new MekLocation(Mech.LOC_RARM, tonnage, structureType, isClan, + hasTSM, true, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(Mech.LOC_LARM, tonnage, structureType, isClan, + hasTSM, true, hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + mekLocation = new MekLocation(Mech.LOC_LARM, tonnage, structureType, isClan, + hasTSM, true, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(Mech.LOC_LARM, tonnage, structureType, isClan, + hasTSM, true, hasSensors, hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + mekLocation = new MekLocation(Mech.LOC_LARM, tonnage, structureType, isClan, + hasTSM, false, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(Mech.LOC_LARM, tonnage, structureType, isClan, + hasTSM, false, hasSensors, hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + other = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, !isQuad, hasSensors, hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + // Restore the original setup + mekLocation = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, hasLifeSupport, mockCampaign); + + // Different Sensors (off unit) + other = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, !hasSensors, hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Different Life Support (off unit) + other = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, !hasLifeSupport, mockCampaign); + assertFalse(mekLocation.isSamePartType(other)); + assertFalse(other.isSamePartType(mekLocation)); + + // Put the location on a unit + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn((double) tonnage); + when(unit.getEntity()).thenReturn(entity); + mekLocation.setUnit(unit); + + // Different Sensors (on unit) + other = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, !hasSensors, hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + + // Different Life Support (on unit) + other = new MekLocation(location, tonnage, structureType, isClan, + hasTSM, isQuad, hasSensors, !hasLifeSupport, mockCampaign); + assertTrue(mekLocation.isSamePartType(other)); + assertTrue(other.isSamePartType(mekLocation)); + } @Test public void mekLocationWriteToXmlTest() throws ParserConfigurationException, SAXException, IOException { From 2802536584bfd28a80056b85a7db2e13f53bd4ce Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Mon, 28 Dec 2020 15:07:44 -0500 Subject: [PATCH 07/33] Update MekLocation isSalvagingTest --- MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 76a730f2e5..91563a87f4 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -149,6 +149,7 @@ public void cannotScrapCT() { public void cannotSalvageCT() { Campaign mockCampaign = mock(Campaign.class); Unit unit = mock(Unit.class); + when(unit.isSalvage()).thenReturn(true); Mech entity = mock(Mech.class); when(entity.getWeight()).thenReturn(65.0); when(unit.getEntity()).thenReturn(entity); @@ -157,6 +158,11 @@ public void cannotSalvageCT() { centerTorso.setUnit(unit); assertFalse(centerTorso.isSalvaging()); + + MekLocation otherLocation = new MekLocation(Mech.LOC_HEAD, 100, 0, false, false, false, false, false, mockCampaign); + otherLocation.setUnit(unit); + + assertTrue(otherLocation.isSalvaging()); } @Test From 21516bfe82fcaa3de61751bbeb2cd1b74e91f826 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Mon, 28 Dec 2020 15:24:14 -0500 Subject: [PATCH 08/33] Add basic MekLocation::updateConditionFromEntity test --- .../src/mekhq/campaign/parts/MekLocation.java | 62 +++++++--- .../mekhq/campaign/parts/MekLocationTest.java | 115 ++++++++++++++++++ 2 files changed, 162 insertions(+), 15 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 81debb96f9..d159eb6c74 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -223,6 +223,14 @@ public double getPercent() { return percent; } + /** + * Sets the percent armor remaining. + * @param percent The percent armor remaining, expressed as a fraction. + */ + protected void setPercent(double percent) { + this.percent = Math.max(0.0, Math.min(percent, 1.0)); + } + @Override public void writeToXml(PrintWriter pw1, int indent) { writeToXmlBegin(pw1, indent); @@ -315,7 +323,7 @@ public void fix() { } } } else if (isBreached()) { - breached = false; + setBreached(false); if (null != unit) { unit.getEntity().setLocationStatus(loc, ILocationExposureStatus.NORMAL, true); for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { @@ -332,7 +340,7 @@ public void fix() { } } } else { - percent = 1.0; + setPercent(1.0); if (null != unit) { unit.getEntity().setInternal(unit.getEntity().getOInternal(loc), loc); } @@ -346,8 +354,8 @@ public MissingMekLocation getMissingPart() { @Override public void remove(boolean salvage) { - blownOff = false; - breached = false; + setBlownOff(false); + setBreached(false); if (null != unit) { unit.getEntity().setInternal(IArmorState.ARMOR_DESTROYED, loc); unit.getEntity().setLocationBlownOff(loc, false); @@ -377,10 +385,10 @@ public void remove(boolean salvage) { @Override public void updateConditionFromEntity(boolean checkForDestruction) { if (null != unit) { - blownOff = unit.getEntity().isLocationBlownOff(loc); - breached = unit.isLocationBreached(loc); - percent = ((double) unit.getEntity().getInternalForReal(loc)) / ((double) unit.getEntity().getOInternal(loc)); - if (percent <= 0.0) { + setBlownOff(unit.getEntity().isLocationBlownOff(loc)); + setBreached(unit.isLocationBreached(loc)); + setPercent(unit.getEntity().getInternalForReal(loc) / ((double) unit.getEntity().getOInternal(loc))); + if (getPercent() <= 0.0) { remove(false); } } @@ -429,6 +437,7 @@ public int getBaseTime() { private int getRepairOrSalvageTime() { // StratOps p184 Master Repair Table // NOTE: MissingMekLocation handles destroyed locations + final double percent = getPercent(); if (percent < 0.25) { return 270; } else if (percent < 0.5) { @@ -481,6 +490,7 @@ public int getDifficulty() { private int getRepairOrSalvageDifficulty() { // StrapOps p184 Master Repair Table // NOTE: MissingMekLocation handles destroyed locations + final double percent = getPercent(); if (percent < 0.25) { return 2; } else if (percent < 0.5) { @@ -493,18 +503,40 @@ private int getRepairOrSalvageDifficulty() { } } + /** + * Gets a value indicating whether or not this location is breached. + */ public boolean isBreached() { - return breached; + return (getUnit() != null) && breached; + } + + /** + * Sets a value indicating whether or not the location is breached. + * @param breached A value indicating whether or not the location is breached. + */ + protected void setBreached(boolean breached) { + this.breached = breached; } + /** + * Gets a value indicating whether or not this location is blown off. + */ public boolean isBlownOff() { - return blownOff; + return (getUnit() != null) && blownOff; + } + + /** + * Sets a value indicating whether or not the location is blown off. + * @param blownOff A value indicating whether or not the location is blown off. + */ + protected void setBlownOff(boolean blownOff) { + this.blownOff = blownOff; } @Override public boolean needsFixing() { - return percent < 1.0 || breached || blownOff - || (unit != null && unit.hasBadHipOrShoulder(loc)); + return (getPercent() < 1.0) || isBreached() || isBlownOff() + || (getUnit() == null) || getUnit().hasBadHipOrShoulder(getLoc()); } @Override @@ -523,14 +555,14 @@ public String getDetails(boolean includeRepairDetails) { } else if (isBreached()) { toReturn += " (Breached)"; } else { - toReturn += " (" + Math.round(100*percent) + "%)"; + toReturn += " (" + Math.round(100 * getPercent()) + "%)"; } } return toReturn; } toReturn += getUnitTonnage() + " tons"; if (includeRepairDetails) { - toReturn += " (" + Math.round(100*percent) + "%)"; + toReturn += " (" + Math.round(100 * getPercent()) + "%)"; } if (loc == Mech.LOC_HEAD) { StringJoiner components = new StringJoiner(", "); @@ -550,7 +582,7 @@ public String getDetails(boolean includeRepairDetails) { @Override public void updateConditionFromPart() { if (null != unit) { - unit.getEntity().setInternal((int)Math.round(percent * unit.getEntity().getOInternal(loc)), loc); + unit.getEntity().setInternal((int)Math.round(getPercent() * unit.getEntity().getOInternal(loc)), loc); //TODO: we need to cycle through slots and remove crits on non-hittable ones //We shouldn't have to do this, these slots should not be hit in MM for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 91563a87f4..fdf80a5711 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -367,6 +367,121 @@ public void mekLocationWriteToXmlTest() throws ParserConfigurationException, SAX assertEquals(mekLocation.hasLifeSupport(), deserialized.hasLifeSupport()); } + @Test + public void updateConditionFromEntityTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + doReturn(1).when(entity).getInternalForReal(anyInt()); + doReturn(1).when(entity).getOInternal(anyInt()); + when(unit.getEntity()).thenReturn(entity); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + + assertFalse(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // No unit is a no-op + mekLocation.updateConditionFromEntity(false); + assertFalse(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertFalse(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Add the location to a unit + mekLocation.setUnit(unit); + + // Blow everything off but our location + doReturn(true).when(entity).isLocationBlownOff(anyInt()); + doReturn(false).when(entity).isLocationBlownOff(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertFalse(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertFalse(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Blow off our location + doReturn(true).when(entity).isLocationBlownOff(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertTrue(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertTrue(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Breach everything but our location + doReturn(true).when(unit).isLocationBreached(anyInt()); + doReturn(false).when(unit).isLocationBreached(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertTrue(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertTrue(mekLocation.isBlownOff()); + assertFalse(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Breach our location + doReturn(true).when(unit).isLocationBreached(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Destroy every location but ours + doReturn(0).when(entity).getInternalForReal(anyInt()); + doReturn(1).when(entity).getInternalForReal(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // Damage our location + doReturn(1).when(entity).getInternalForReal(eq(location)); + doReturn(2).when(entity).getOInternal(eq(location)); + + mekLocation.updateConditionFromEntity(false); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1 / 2.0, mekLocation.getPercent(), 0.001); + + mekLocation.updateConditionFromEntity(true); + assertTrue(mekLocation.isBlownOff()); + assertTrue(mekLocation.isBreached()); + assertEquals(1 / 2.0, mekLocation.getPercent(), 0.001); + } + @Test public void lamTorsoRemovableOnlyWithMissingAvionicsAndLandingGear() { Campaign mockCampaign = mock(Campaign.class); From 0d8feb0b9c28c7cdd32b9e93bd4834003be53b74 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 30 Dec 2020 16:02:39 -0500 Subject: [PATCH 09/33] Add some checkFixable and checkSalvagable tests --- .../mekhq/campaign/parts/MekLocationTest.java | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index fdf80a5711..aa44fcdd34 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -482,6 +482,243 @@ public void updateConditionFromEntityTest() { assertEquals(1 / 2.0, mekLocation.getPercent(), 0.001); } + @Test + public void checkFixableNoUnitTest() { + Campaign mockCampaign = mock(Campaign.class); + MekLocation torso = new MekLocation(Mech.LOC_RT, 30, 0, false, false, false, false, false, mockCampaign); + assertNull(torso.checkFixable()); + } + + @Test + public void checkFixableBlownOffTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + when(unit.getEntity()).thenReturn(entity); + + // Everything but the CT is busted + doReturn(true).when(unit).isLocationDestroyed(anyInt()); + doReturn(false).when(unit).isLocationDestroyed(eq(Mech.LOC_CT)); + + // Destroyed leg can be repaired even if everything else is gone + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNull(mekLocation.checkFixable()); + location = Mech.LOC_RLEG; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNull(mekLocation.checkFixable()); + + // Destroyed head can be repaired even if everything else is gone + location = Mech.LOC_HEAD; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNull(mekLocation.checkFixable()); + + // Destroyed torsos can be repaired + location = Mech.LOC_RT; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNull(mekLocation.checkFixable()); + location = Mech.LOC_LT; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNull(mekLocation.checkFixable()); + + // Arms cannot without their respective torsos + location = Mech.LOC_RARM; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNotNull(mekLocation.checkFixable()); + + // Fix the RT ... + doReturn(false).when(unit).isLocationDestroyed(eq(Mech.LOC_RT)); + + // ... now the RARM can be fixed. + assertNull(mekLocation.checkFixable()); + + location = Mech.LOC_LARM; + mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertNotNull(mekLocation.checkFixable()); + + // Fix the LT ... + doReturn(false).when(unit).isLocationDestroyed(eq(Mech.LOC_LT)); + + // ... now the LARM can be fixed. + assertNull(mekLocation.checkFixable()); + } + + @Test + public void checkFixableBustedHipTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // 4 critical + doReturn(4).when(entity).getNumberOfCriticals(eq(location)); + // Null slot + doReturn(null).when(entity).getCritical(eq(location), eq(0)); + // Not hittable slot + CriticalSlot notHittable = mock(CriticalSlot.class); + when(notHittable.isEverHittable()).thenReturn(false); + doReturn(notHittable).when(entity).getCritical(eq(location), eq(1)); + // Not a hip + CriticalSlot notAHip = mock(CriticalSlot.class); + when(notAHip.isEverHittable()).thenReturn(true); + when(notAHip.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(notAHip.getIndex()).thenReturn(Mech.ACTUATOR_FOOT); + doReturn(notAHip).when(entity).getCritical(eq(location), eq(2)); + // The Hip + CriticalSlot mockHip = mock(CriticalSlot.class); + when(mockHip.isEverHittable()).thenReturn(true); + when(mockHip.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(mockHip.getIndex()).thenReturn(Mech.ACTUATOR_HIP); + doReturn(mockHip).when(entity).getCritical(eq(location), eq(3)); + + // Hip is fine + assertNull(mekLocation.checkFixable()); + + // Hip is not fine + when(mockHip.isDestroyed()).thenReturn(true); + assertNotNull(mekLocation.checkFixable()); + } + + @Test + public void checkFixableBustedShoulderTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + + int location = Mech.LOC_RARM; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // 4 critical + doReturn(4).when(entity).getNumberOfCriticals(eq(location)); + // Null slot + doReturn(null).when(entity).getCritical(eq(location), eq(0)); + // Not hittable slot + CriticalSlot notHittable = mock(CriticalSlot.class); + when(notHittable.isEverHittable()).thenReturn(false); + doReturn(notHittable).when(entity).getCritical(eq(location), eq(1)); + // Not a shoulder + CriticalSlot notAShoulder = mock(CriticalSlot.class); + when(notAShoulder.isEverHittable()).thenReturn(true); + when(notAShoulder.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(notAShoulder.getIndex()).thenReturn(Mech.ACTUATOR_HAND); + doReturn(notAShoulder).when(entity).getCritical(eq(location), eq(2)); + // The shoulder + CriticalSlot mockShoulder = mock(CriticalSlot.class); + when(mockShoulder.isEverHittable()).thenReturn(true); + when(mockShoulder.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(mockShoulder.getIndex()).thenReturn(Mech.ACTUATOR_SHOULDER); + doReturn(mockShoulder).when(entity).getCritical(eq(location), eq(3)); + + // Shoulder is fine + assertNull(mekLocation.checkFixable()); + + // Shoulder is not fine + when(mockShoulder.isDestroyed()).thenReturn(true); + assertNotNull(mekLocation.checkFixable()); + } + + @Test + public void checkSalvagableNotSalvagingTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + + MekLocation mekLocation = new MekLocation(Mech.LOC_RARM, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + assertNull(mekLocation.checkSalvagable()); + } + + @Test + public void checkSalvagableBadHipShoulderTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_RARM; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Must scrap a limb with a bad hip or shoulder + doReturn(true).when(unit).hasBadHipOrShoulder(eq(location)); + assertNotNull(mekLocation.checkSalvagable()); + + doReturn(false).when(unit).hasBadHipOrShoulder(eq(location)); + assertNull(mekLocation.checkSalvagable()); + } + + @Test + public void checkSalvagableTorsoWithArmsIntactTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_RT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNotNull(mekLocation.checkSalvagable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNull(mekLocation.checkSalvagable()); + + location = Mech.LOC_LT; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNotNull(mekLocation.checkSalvagable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNull(mekLocation.checkSalvagable()); + } + @Test public void lamTorsoRemovableOnlyWithMissingAvionicsAndLandingGear() { Campaign mockCampaign = mock(Campaign.class); From 34c8842f7bac27fb68a014efe4d0e0e0dc09184f Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 30 Dec 2020 16:18:17 -0500 Subject: [PATCH 10/33] Add checkScrappable with armor test --- .../mekhq/campaign/parts/MekLocationTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index aa44fcdd34..49b9271b62 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -681,9 +681,11 @@ public void checkSalvagableBadHipShoulderTest() { // Must scrap a limb with a bad hip or shoulder doReturn(true).when(unit).hasBadHipOrShoulder(eq(location)); assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); doReturn(false).when(unit).hasBadHipOrShoulder(eq(location)); assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); } @Test @@ -703,9 +705,11 @@ public void checkSalvagableTorsoWithArmsIntactTest() { // Cannot salvage a torso if the attached arm is Okay doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_RARM)); assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_RARM)); assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); location = Mech.LOC_LT; mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); @@ -714,9 +718,42 @@ public void checkSalvagableTorsoWithArmsIntactTest() { // Cannot salvage a torso if the attached arm is Okay doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_LARM)); assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_LARM)); assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + } + + @Test + public void checkSalvagableArmorStillPresentTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // No armor + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + + // Some armor, for real. + doReturn(1).when(entity).getArmorForReal(eq(location), anyBoolean()); + assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); + + // Some rear armor + doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); + doReturn(true).when(entity).hasRearArmor(eq(location)); + doReturn(1).when(entity).getArmorForReal(eq(location), eq(true)); + assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); } @Test From 0b9634d6bf7412399f476a844370286f8940e6d7 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 14:36:43 -0500 Subject: [PATCH 11/33] Round out checkSalvagable/checkScrappable tests --- .../src/mekhq/campaign/parts/MekLocation.java | 12 +- .../mekhq/campaign/parts/MekLocationTest.java | 290 +++++++++++++++++- 2 files changed, 295 insertions(+), 7 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index d159eb6c74..a61112bd2c 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -667,8 +667,8 @@ public String checkFixable() { return "must salvage/scrap left" + limbName + "first"; } //check for armor - if (unit.getEntity().getArmorForReal(loc, false) > 0 - || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmorForReal(loc, true) > 0 )) { + if (unit.getEntity().getArmor(loc, false) > 0 + || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmor(loc, true) > 0 )) { return "must salvage armor in this location first"; } //you can only salvage a location that has nothing left on it @@ -733,11 +733,15 @@ public String checkScrappable() { //otherwise you will get weirdness where armor and actuators are //still attached but everything else is scrapped //cant salvage torsos until arms and legs are gone + String limbName = " arm "; + if (forQuad) { + limbName = " front leg "; + } if (unit.getEntity() instanceof Mech && loc == Mech.LOC_RT && !unit.getEntity().isLocationBad(Mech.LOC_RARM)) { - return "You must first remove the right arm before you scrap the right torso"; + return "You must first remove the right " + limbName + " before you scrap the right torso"; } if (unit.getEntity() instanceof Mech && loc == Mech.LOC_LT && !unit.getEntity().isLocationBad(Mech.LOC_LARM)) { - return "You must first remove the left arm before you scrap the left torso"; + return "You must first remove the left " + limbName + " before you scrap the left torso"; } //check for armor if (unit.getEntity().getArmor(loc, false) > 0 diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 49b9271b62..4cc61d769c 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -725,6 +725,43 @@ public void checkSalvagableTorsoWithArmsIntactTest() { assertNull(mekLocation.checkFixable()); } + @Test + public void checkSalvagableTorsoWithArmsIntactQuadTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_RT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, /*forQuad:*/true, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + + location = Mech.LOC_LT; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + } + @Test public void checkSalvagableArmorStillPresentTest() { Campaign mockCampaign = mock(Campaign.class); @@ -744,17 +781,264 @@ public void checkSalvagableArmorStillPresentTest() { assertNull(mekLocation.checkFixable()); // Some armor, for real. - doReturn(1).when(entity).getArmorForReal(eq(location), anyBoolean()); + doReturn(1).when(entity).getArmor(eq(location), anyBoolean()); assertNotNull(mekLocation.checkSalvagable()); assertNotNull(mekLocation.checkFixable()); // Some rear armor - doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); + doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(true).when(entity).hasRearArmor(eq(location)); + doReturn(1).when(entity).getArmor(eq(location), eq(true)); + assertNotNull(mekLocation.checkSalvagable()); + assertNotNull(mekLocation.checkFixable()); + + // No rear armor + doReturn(0).when(entity).getArmor(eq(location), eq(false)); doReturn(true).when(entity).hasRearArmor(eq(location)); - doReturn(1).when(entity).getArmorForReal(eq(location), eq(true)); + doReturn(0).when(entity).getArmor(eq(location), eq(true)); + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + } + + @Test + public void checkSalvagableOnlyIgnorableSystemsTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + int[] systems = new int[] { Mech.ACTUATOR_HIP, Mech.ACTUATOR_SHOULDER, + Mech.SYSTEM_LIFE_SUPPORT, Mech.SYSTEM_SENSORS + }; + doReturn(systems.length + 1).when(entity).getNumberOfCriticals(eq(location)); + CriticalSlot notHittable = mock(CriticalSlot.class); + doReturn(notHittable).when(entity).getCritical(eq(location), eq(0)); + + for (int ii = 0; ii < systems.length; ++ii) { + CriticalSlot mockIgnoredSystem = mock(CriticalSlot.class); + when(mockIgnoredSystem.isEverHittable()).thenReturn(true); + when(mockIgnoredSystem.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(mockIgnoredSystem.getIndex()).thenReturn(systems[ii]); + doReturn(mockIgnoredSystem).when(entity).getCritical(eq(location), eq(ii + 1)); + } + + // No hittable or repairable systems + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + } + + @Test + public void checkSalvagableRepairableSystemsTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + doReturn(1).when(entity).getNumberOfCriticals(eq(location)); + CriticalSlot repairable = mock(CriticalSlot.class); + when(repairable.isEverHittable()).thenReturn(true); + when(repairable.getType()).thenReturn(CriticalSlot.TYPE_EQUIPMENT); + doReturn(repairable).when(entity).getCritical(eq(location), eq(0)); + + // No repairable systems + assertNull(mekLocation.checkSalvagable()); + assertNull(mekLocation.checkFixable()); + + when(repairable.isRepairable()).thenReturn(true); + + // A repairable systems remains assertNotNull(mekLocation.checkSalvagable()); assertNotNull(mekLocation.checkFixable()); } + + @Test + public void checkScrappableCannotScrapCenterTorsoTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + + MekLocation mekLocation = new MekLocation(Mech.LOC_CT, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + assertNotNull(mekLocation.checkScrappable()); + } + + @Test + public void checkScrappableTorsoWithArmsIntactTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_RT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNotNull(mekLocation.checkScrappable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNull(mekLocation.checkScrappable()); + + location = Mech.LOC_LT; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNotNull(mekLocation.checkScrappable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNull(mekLocation.checkScrappable()); + } + + @Test + public void checkScrappableTorsoWithArmsIntactQuadTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_RT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, /*forQuad:*/true, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNotNull(mekLocation.checkScrappable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_RARM)); + assertNull(mekLocation.checkScrappable()); + + location = Mech.LOC_LT; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Cannot salvage a torso if the attached arm is Okay + doReturn(false).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNotNull(mekLocation.checkScrappable()); + + doReturn(true).when(entity).isLocationBad(eq(Mech.LOC_LARM)); + assertNull(mekLocation.checkScrappable()); + } + + @Test + public void checkScrappableArmorStillPresentTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // No armor + assertNull(mekLocation.checkScrappable()); + + // Some armor, for real. + doReturn(1).when(entity).getArmor(eq(location), anyBoolean()); + assertNotNull(mekLocation.checkScrappable()); + + // Some rear armor + doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(true).when(entity).hasRearArmor(eq(location)); + doReturn(1).when(entity).getArmor(eq(location), eq(true)); + assertNotNull(mekLocation.checkScrappable()); + + // No rear armor + doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(true).when(entity).hasRearArmor(eq(location)); + doReturn(0).when(entity).getArmor(eq(location), eq(true)); + assertNull(mekLocation.checkScrappable()); + } + + @Test + public void checkScrappableOnlyIgnorableSystemsTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + int[] systems = new int[] { Mech.SYSTEM_COCKPIT, Mech.ACTUATOR_HIP, Mech.ACTUATOR_SHOULDER }; + doReturn(systems.length + 1).when(entity).getNumberOfCriticals(eq(location)); + CriticalSlot notHittable = mock(CriticalSlot.class); + doReturn(notHittable).when(entity).getCritical(eq(location), eq(0)); + + for (int ii = 0; ii < systems.length; ++ii) { + CriticalSlot mockIgnoredSystem = mock(CriticalSlot.class); + when(mockIgnoredSystem.isEverHittable()).thenReturn(true); + when(mockIgnoredSystem.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); + when(mockIgnoredSystem.getIndex()).thenReturn(systems[ii]); + doReturn(mockIgnoredSystem).when(entity).getCritical(eq(location), eq(ii + 1)); + } + + // No hittable or repairable systems + assertNull(mekLocation.checkScrappable()); + } + + @Test + public void checkScrappableRepairableSystemsTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(any()); + when(unit.isSalvage()).thenReturn(true); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + doReturn(1).when(entity).getNumberOfCriticals(eq(location)); + CriticalSlot repairable = mock(CriticalSlot.class); + when(repairable.isEverHittable()).thenReturn(true); + when(repairable.getType()).thenReturn(CriticalSlot.TYPE_EQUIPMENT); + doReturn(repairable).when(entity).getCritical(eq(location), eq(0)); + + // No repairable systems + assertNull(mekLocation.checkScrappable()); + + when(repairable.isRepairable()).thenReturn(true); + + // A repairable systems remains + assertNotNull(mekLocation.checkScrappable()); + } @Test public void lamTorsoRemovableOnlyWithMissingAvionicsAndLandingGear() { From 355b57e923484437a34fb4d2424c7896aa3a0a02 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 14:42:55 -0500 Subject: [PATCH 12/33] Simplify bad hip or shoulder in checkFixable --- .../src/mekhq/campaign/parts/MekLocation.java | 31 +++------ .../mekhq/campaign/parts/MekLocationTest.java | 68 ++----------------- 2 files changed, 13 insertions(+), 86 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index a61112bd2c..98df736a51 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -604,41 +604,28 @@ public void updateConditionFromPart() { @Override public String checkFixable() { - if (null == unit) { + if (unit == null) { return null; } + if (isBlownOff() && !isSalvaging()) { if (loc == Mech.LOC_LARM && unit.isLocationDestroyed(Mech.LOC_LT)) { return "must replace left torso first"; } else if (loc == Mech.LOC_RARM && unit.isLocationDestroyed(Mech.LOC_RT)) { return "must replace right torso first"; } else if (unit.isLocationDestroyed(Mech.LOC_CT)) { - //we shouldnt get here - return "cannot replace head on destroyed unit"; + // we shouldnt get here + return "cannot repair part on destroyed unit"; } } else if (isSalvaging()) { return checkSalvagable(); } else if (!isBreached() && !isBlownOff()) { - //check for damaged hips and shoulders - for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { - CriticalSlot slot = unit.getEntity().getCritical(loc, i); - if ((slot == null) || !slot.isEverHittable()) { - continue; - } - if (slot.getType() == CriticalSlot.TYPE_SYSTEM - && slot.getIndex() == Mech.ACTUATOR_HIP - && slot.isDestroyed()) { - return "You cannot repair a leg with a damaged hip. This leg must be scrapped and replaced instead."; - - } - if (slot.getType() == CriticalSlot.TYPE_SYSTEM - && slot.getIndex() == Mech.ACTUATOR_SHOULDER - && slot.isDestroyed()) { - return "You cannot repair an arm with a damaged shoulder. This arm must be scrapped and replaced instead."; - - } + // check for damaged hips and shoulders + if (onBadHipOrShoulder()) { + return "You cannot repair a limb with a busted hip/shoulder. You must scrap and replace it instead."; } } + return null; } @@ -843,7 +830,7 @@ public String getDesc() { @Override public boolean onBadHipOrShoulder() { - return null != unit && unit.hasBadHipOrShoulder(loc); + return (getUnit() != null) && getUnit().hasBadHipOrShoulder(getLoc()); } @Override diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 4cc61d769c..2492467801 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -566,49 +566,7 @@ public void checkFixableBlownOffTest() { } @Test - public void checkFixableBustedHipTest() { - Campaign mockCampaign = mock(Campaign.class); - Unit unit = mock(Unit.class); - Entity entity = mock(Entity.class); - when(unit.getEntity()).thenReturn(entity); - when(entity.getWeight()).thenReturn(30.0); - doCallRealMethod().when(entity).getLocationName(any()); - - int location = Mech.LOC_LLEG; - MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); - mekLocation.setUnit(unit); - - // 4 critical - doReturn(4).when(entity).getNumberOfCriticals(eq(location)); - // Null slot - doReturn(null).when(entity).getCritical(eq(location), eq(0)); - // Not hittable slot - CriticalSlot notHittable = mock(CriticalSlot.class); - when(notHittable.isEverHittable()).thenReturn(false); - doReturn(notHittable).when(entity).getCritical(eq(location), eq(1)); - // Not a hip - CriticalSlot notAHip = mock(CriticalSlot.class); - when(notAHip.isEverHittable()).thenReturn(true); - when(notAHip.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); - when(notAHip.getIndex()).thenReturn(Mech.ACTUATOR_FOOT); - doReturn(notAHip).when(entity).getCritical(eq(location), eq(2)); - // The Hip - CriticalSlot mockHip = mock(CriticalSlot.class); - when(mockHip.isEverHittable()).thenReturn(true); - when(mockHip.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); - when(mockHip.getIndex()).thenReturn(Mech.ACTUATOR_HIP); - doReturn(mockHip).when(entity).getCritical(eq(location), eq(3)); - - // Hip is fine - assertNull(mekLocation.checkFixable()); - - // Hip is not fine - when(mockHip.isDestroyed()).thenReturn(true); - assertNotNull(mekLocation.checkFixable()); - } - - @Test - public void checkFixableBustedShoulderTest() { + public void checkFixableBustedHipOrShoulderTest() { Campaign mockCampaign = mock(Campaign.class); Unit unit = mock(Unit.class); Entity entity = mock(Entity.class); @@ -620,32 +578,14 @@ public void checkFixableBustedShoulderTest() { MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); mekLocation.setUnit(unit); - // 4 critical - doReturn(4).when(entity).getNumberOfCriticals(eq(location)); - // Null slot - doReturn(null).when(entity).getCritical(eq(location), eq(0)); - // Not hittable slot - CriticalSlot notHittable = mock(CriticalSlot.class); - when(notHittable.isEverHittable()).thenReturn(false); - doReturn(notHittable).when(entity).getCritical(eq(location), eq(1)); - // Not a shoulder - CriticalSlot notAShoulder = mock(CriticalSlot.class); - when(notAShoulder.isEverHittable()).thenReturn(true); - when(notAShoulder.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); - when(notAShoulder.getIndex()).thenReturn(Mech.ACTUATOR_HAND); - doReturn(notAShoulder).when(entity).getCritical(eq(location), eq(2)); - // The shoulder - CriticalSlot mockShoulder = mock(CriticalSlot.class); - when(mockShoulder.isEverHittable()).thenReturn(true); - when(mockShoulder.getType()).thenReturn(CriticalSlot.TYPE_SYSTEM); - when(mockShoulder.getIndex()).thenReturn(Mech.ACTUATOR_SHOULDER); - doReturn(mockShoulder).when(entity).getCritical(eq(location), eq(3)); + doReturn(true).when(unit).hasBadHipOrShoulder(anyInt()); + doReturn(false).when(unit).hasBadHipOrShoulder(eq(location)); // Shoulder is fine assertNull(mekLocation.checkFixable()); // Shoulder is not fine - when(mockShoulder.isDestroyed()).thenReturn(true); + doReturn(true).when(unit).hasBadHipOrShoulder(eq(location)); assertNotNull(mekLocation.checkFixable()); } From 139399331df7d4f94327740c9b13c700d62fc6e9 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 14:59:02 -0500 Subject: [PATCH 13/33] Test MekLocation::updateConditionFromPart --- .../mekhq/campaign/parts/MekLocationTest.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 2492467801..1f3faad8c8 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -41,6 +41,7 @@ import megamek.common.EquipmentType; import megamek.common.LandAirMech; import megamek.common.Mech; +import megamek.common.Mounted; import mekhq.MekHqXmlUtil; import mekhq.Version; import mekhq.campaign.Campaign; @@ -482,6 +483,80 @@ public void updateConditionFromEntityTest() { assertEquals(1 / 2.0, mekLocation.getPercent(), 0.001); } + @Test + public void updateConditionFromPartUpdatesEntityArmorTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + int totalArmor = 100; + doReturn(totalArmor).when(entity).getOInternal(anyInt()); + when(unit.getEntity()).thenReturn(entity); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + + // not on unit + mekLocation.updateConditionFromPart(); + + // assign to unit + mekLocation.setUnit(unit); + + // 100% armor + mekLocation.updateConditionFromPart(); + + verify(entity, times(1)).getOInternal(eq(location)); + verify(entity, times(1)).setInternal(eq(totalArmor), eq(location)); + + // 50% armor + mekLocation.setPercent(0.5); + mekLocation.updateConditionFromPart(); + verify(entity, times(1)).setInternal(eq(totalArmor / 2), eq(location)); + + // 1% armor + mekLocation.setPercent(0.01); + mekLocation.updateConditionFromPart(); + verify(entity, times(1)).setInternal(eq(totalArmor / 100), eq(location)); + } + + @Test + public void updateConditionFromPartRestoresNotHittableCriticalSlotsTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + int totalArmor = 100; + doReturn(totalArmor).when(entity).getOInternal(anyInt()); + when(unit.getEntity()).thenReturn(entity); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + mekLocation.setUnit(unit); + + doReturn(3).when(entity).getNumberOfCriticals(eq(location)); + CriticalSlot hittable = mock(CriticalSlot.class); + when(hittable.isEverHittable()).thenReturn(true); + doReturn(hittable).when(entity).getCritical(eq(location), eq(0)); + CriticalSlot notHittable = mock(CriticalSlot.class); + doReturn(notHittable).when(entity).getCritical(eq(location), eq(1)); + Mounted mount = mock(Mounted.class); + when(notHittable.getMount()).thenReturn(mount); + doReturn(null).when(entity).getCritical(eq(location), eq(2)); + + mekLocation.updateConditionFromPart(); + + verify(notHittable, times(1)).setDestroyed(eq(false)); + verify(notHittable, times(1)).setHit(eq(false)); + verify(notHittable, times(1)).setRepairable(eq(true)); + verify(notHittable, times(1)).setMissing(eq(false)); + verify(mount, times(1)).setHit(false); + verify(mount, times(1)).setDestroyed(false); + verify(mount, times(1)).setMissing(false); + verify(mount, times(1)).setRepairable(true); + } + @Test public void checkFixableNoUnitTest() { Campaign mockCampaign = mock(Campaign.class); From 2f90757f8e111159005f85d1a871cbd8e6c95d1b Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 15:04:02 -0500 Subject: [PATCH 14/33] Add needsFixing tests --- .../src/mekhq/campaign/parts/MekLocation.java | 2 +- .../mekhq/campaign/parts/MekLocationTest.java | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 98df736a51..2232b52b07 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -536,7 +536,7 @@ protected void setBlownOff(boolean blownOff) { @Override public boolean needsFixing() { return (getPercent() < 1.0) || isBreached() || isBlownOff() - || (getUnit() == null) || getUnit().hasBadHipOrShoulder(getLoc()); + || ((getUnit() != null) && getUnit().hasBadHipOrShoulder(getLoc())); } @Override diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 1f3faad8c8..09a7f08b57 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -557,6 +557,57 @@ public void updateConditionFromPartRestoresNotHittableCriticalSlotsTest() { verify(mount, times(1)).setRepairable(true); } + @Test + public void needsFixingTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + when(unit.getEntity()).thenReturn(entity); + + int location = Mech.LOC_RT; + MekLocation torso = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + + // Not on a unit + assertFalse(torso.needsFixing()); + + // On a unit which is fine + torso.setUnit(unit); + assertFalse(torso.needsFixing()); + + // Bad hip or shoulder + doReturn(true).when(unit).hasBadHipOrShoulder(eq(location)); + assertTrue(torso.needsFixing()); + + // restore the hip/shoulder + doReturn(false).when(unit).hasBadHipOrShoulder(eq(location)); + assertFalse(torso.needsFixing()); + + // Less than 100% armor + torso.setPercent(0.99); + assertTrue(torso.needsFixing()); + + // restore the armor + torso.setPercent(1.0); + assertFalse(torso.needsFixing()); + + // Breached + torso.setBreached(true); + assertTrue(torso.needsFixing()); + + // Not breached + torso.setBreached(false); + assertFalse(torso.needsFixing()); + + // Blown off + torso.setBlownOff(true); + assertTrue(torso.needsFixing()); + + // Not blown off + torso.setBlownOff(false); + assertFalse(torso.needsFixing()); + } + @Test public void checkFixableNoUnitTest() { Campaign mockCampaign = mock(Campaign.class); From 6eeb8a9f8fca01c18fd29eef951f8e60b43ab92e Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 15:18:24 -0500 Subject: [PATCH 15/33] Test MekLocation::doMaintenanceDamage --- .../src/mekhq/campaign/parts/MekLocation.java | 17 ++++--- .../mekhq/campaign/parts/MekLocationTest.java | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 2232b52b07..0b5b7a73ae 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -384,10 +384,10 @@ public void remove(boolean salvage) { @Override public void updateConditionFromEntity(boolean checkForDestruction) { - if (null != unit) { - setBlownOff(unit.getEntity().isLocationBlownOff(loc)); - setBreached(unit.isLocationBreached(loc)); - setPercent(unit.getEntity().getInternalForReal(loc) / ((double) unit.getEntity().getOInternal(loc))); + if (getUnit() != null) { + setBlownOff(getUnit().getEntity().isLocationBlownOff(getLoc())); + setBreached(getUnit().isLocationBreached(getLoc())); + setPercent(getUnit().getEntity().getInternalForReal(getLoc()) / ((double) getUnit().getEntity().getOInternal(getLoc()))); if (getPercent() <= 0.0) { remove(false); } @@ -880,10 +880,11 @@ private void removeHeadComponents() { @Override public void doMaintenanceDamage(int d) { - int points = unit.getEntity().getInternal(loc); - points = Math.max(points -d, 1); - unit.getEntity().setInternal(points, loc); - updateConditionFromEntity(false); + if ((getUnit() != null) && (d > 0)) { + int points = getUnit().getEntity().getInternal(getLoc()); + getUnit().getEntity().setInternal(Math.max(points - d, 1), getLoc()); + updateConditionFromEntity(false); + } } @Override diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 09a7f08b57..f394eada5e 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -1241,4 +1241,53 @@ public void lamHeadRemovableOnlyWithMissingAvionics() { assertNull(head.checkSalvagable()); assertNull(head.checkScrappable()); } + + @Test + public void doMaintenanceDamageTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + + // not on unit + mekLocation.doMaintenanceDamage(100); + + // No change. + assertEquals(1.0, mekLocation.getPercent(), 0.001); + + // On unit + mekLocation.setUnit(unit); + + // Setup getInternalForReal to return the correct calculation + doAnswer(inv -> { + int armor = inv.getArgument(0); + doReturn(armor).when(entity).getInternalForReal(eq(location)); + return null; + }).when(entity).setInternal(anyInt(), eq(location)); + int startingArmor = 10; + doReturn(startingArmor).when(entity).getOInternal(eq(location)); + + // No damage + mekLocation.doMaintenanceDamage(0); + verify(entity, times(0)).setInternal(anyInt(), eq(location)); + + // Some damage + doReturn(startingArmor).when(entity).getInternal(eq(location)); + int damage = 3; + + mekLocation.doMaintenanceDamage(damage); + + verify(entity, times(1)).setInternal(eq(startingArmor - damage), eq(location)); + + // More than enough damage (but will never destroy the location) + damage = startingArmor; + + mekLocation.doMaintenanceDamage(damage); + + verify(entity, times(1)).setInternal(eq(1), eq(location)); + } } From be7bb5da1b7204173916c1e93f11c1b80874840d Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 15:45:02 -0500 Subject: [PATCH 16/33] Add basic MekLocation::remove tests --- MekHQ/src/mekhq/campaign/Warehouse.java | 3 + .../src/mekhq/campaign/parts/MekLocation.java | 42 +-- .../mekhq/campaign/parts/MekLocationTest.java | 270 ++++++++++++++++++ 3 files changed, 299 insertions(+), 16 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/Warehouse.java b/MekHQ/src/mekhq/campaign/Warehouse.java index 6a870b261b..45140bd4be 100644 --- a/MekHQ/src/mekhq/campaign/Warehouse.java +++ b/MekHQ/src/mekhq/campaign/Warehouse.java @@ -99,6 +99,9 @@ public Part addPart(Part part, boolean mergeWithExisting) { if (isNewPart) { MekHQ.triggerEvent(new PartNewEvent(part)); + } else { + // Part was removed from a unit, or something similar + MekHQ.triggerEvent(new PartChangedEvent(part)); } return part; diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 0b5b7a73ae..19d322555b 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -43,6 +43,7 @@ import mekhq.campaign.Campaign; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.SkillType; +import mekhq.campaign.unit.Unit; import mekhq.campaign.work.WorkTime; /** @@ -356,30 +357,39 @@ public MissingMekLocation getMissingPart() { public void remove(boolean salvage) { setBlownOff(false); setBreached(false); - if (null != unit) { - unit.getEntity().setInternal(IArmorState.ARMOR_DESTROYED, loc); - unit.getEntity().setLocationBlownOff(loc, false); - unit.getEntity().setLocationStatus(loc, ILocationExposureStatus.NORMAL, true); - Part spare = campaign.getWarehouse().checkForExistingSparePart(this); - if (!salvage) { - campaign.getWarehouse().removePart(this); - } else if (null != spare) { - spare.incrementQuantity(); - campaign.getWarehouse().removePart(this); - } - //if this is a head. check for life support and sensors - if (loc == Mech.LOC_HEAD) { + + final Unit unit = getUnit(); + if (unit != null) { + unit.getEntity().setInternal(IArmorState.ARMOR_DESTROYED, getLoc()); + unit.getEntity().setLocationBlownOff(getLoc(), false); + unit.getEntity().setLocationStatus(getLoc(), ILocationExposureStatus.NORMAL, true); + + // If this is a head. check for life support and sensors + if (getLoc() == Mech.LOC_HEAD) { removeHeadComponents(); } + unit.removePart(this); - if (loc != Mech.LOC_CT) { + setUnit(null); + + if (salvage) { + // Return this part to the warehouse as a spare + getCampaign().getWarehouse().addPart(this); + } else { + // Remove this part from the campaign + getCampaign().getWarehouse().removePart(this); + } + + if (getLoc() != Mech.LOC_CT) { Part missing = getMissingPart(); + assert(missing != null); + unit.addPart(missing); campaign.getQuartermaster().addPart(missing, 0); + + missing.updateConditionFromEntity(false); } } - setUnit(null); - updateConditionFromEntity(false); } @Override diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index f394eada5e..f2d13b0bb6 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -26,6 +26,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; import java.util.function.Predicate; import javax.xml.parsers.DocumentBuilder; @@ -45,6 +47,8 @@ import mekhq.MekHqXmlUtil; import mekhq.Version; import mekhq.campaign.Campaign; +import mekhq.campaign.Quartermaster; +import mekhq.campaign.Warehouse; import mekhq.campaign.unit.Unit; public class MekLocationTest { @@ -1290,4 +1294,270 @@ public void doMaintenanceDamageTest() { verify(entity, times(1)).setInternal(eq(1), eq(location)); } + + @Test + public void removeRestoresBlownOffTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + + // Removal + mekLocation.setBlownOff(true); + mekLocation.remove(false); + assertFalse(mekLocation.isBlownOff()); + + // Salvage + mekLocation.setBlownOff(true); + mekLocation.remove(true); + assertFalse(mekLocation.isBlownOff()); + } + + @Test + public void removeRestoresBreachedTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + + // Removal + mekLocation.setBreached(true); + mekLocation.remove(false); + assertFalse(mekLocation.isBreached()); + + // Salvage + mekLocation.setBreached(true); + mekLocation.remove(true); + assertFalse(mekLocation.isBreached()); + } + + @Test + public void removeSimpleTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + mekLocation.remove(false); + + assertFalse(mekLocation.getId() > 0); + assertNull(mekLocation.getUnit()); + assertFalse(warehouse.getParts().contains(mekLocation)); + + // Only one part! + MissingMekLocation missingPart = null; + for (Part part : warehouse.getParts()) { + assertTrue(part instanceof MissingMekLocation); + assertNull(missingPart); + missingPart = (MissingMekLocation) part; + } + + assertEquals(location, missingPart.getLocation()); + } + + @Test + public void removeHeadWithoutComponentsTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_HEAD; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + mekLocation.remove(false); + + // No head components, so they don't get these + assertFalse(mekLocation.hasSensors()); + assertFalse(mekLocation.hasLifeSupport()); + } + + @Test + public void removeHeadWithSensorComponentTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_HEAD; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + // Unit has sensors in the head + MekSensor sensors = mock(MekSensor.class); + when(unit.getParts()).thenReturn(Collections.singletonList(sensors)); + + mekLocation.remove(false); + + // Has sensors but no life support + assertTrue(mekLocation.hasSensors()); + assertFalse(mekLocation.hasLifeSupport()); + + verify(sensors, times(1)).remove(eq(false)); + } + + @Test + public void removeHeadWithLifeSupportComponentTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_HEAD; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + // Unit has life support in the head + MekLifeSupport lifeSupport = mock(MekLifeSupport.class); + when(unit.getParts()).thenReturn(Collections.singletonList(lifeSupport)); + + mekLocation.remove(false); + + // Has life support but no sensors + assertFalse(mekLocation.hasSensors()); + assertTrue(mekLocation.hasLifeSupport()); + + verify(lifeSupport, times(1)).remove(eq(false)); + } + + @Test + public void removeHeadWithComponentsTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_HEAD; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + // Unit has components in the head + MekSensor sensors = mock(MekSensor.class); + MekLifeSupport lifeSupport = mock(MekLifeSupport.class); + when(unit.getParts()).thenReturn(Arrays.asList(sensors, lifeSupport)); + + mekLocation.remove(false); + + // Has both sensors and life support + assertTrue(mekLocation.hasSensors()); + assertTrue(mekLocation.hasLifeSupport()); + + verify(sensors, times(1)).remove(eq(false)); + verify(lifeSupport, times(1)).remove(eq(false)); + } + + @Test + public void removeSimpleSalvageTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + mekLocation.remove(true); + + assertTrue(mekLocation.getId() > 0); + assertNull(mekLocation.getUnit()); + assertTrue(mekLocation.isSpare()); + assertTrue(warehouse.getParts().contains(mekLocation)); + + // Two parts + MissingMekLocation missingPart = null; + for (Part part : warehouse.getParts()) { + if (part instanceof MissingMekLocation) { + assertNull(missingPart); + missingPart = (MissingMekLocation) part; + } else { + assertEquals(mekLocation, part); + } + } + + assertEquals(location, missingPart.getLocation()); + } } From 87cc9375d6270d0e798d957bc4f977e4e011d556 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 16:01:21 -0500 Subject: [PATCH 17/33] Match armor to getInternalForReal calls --- .../src/mekhq/campaign/parts/MekLocation.java | 8 ++++---- .../mekhq/campaign/parts/MekLocationTest.java | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 19d322555b..7ca5997751 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -664,8 +664,8 @@ public String checkFixable() { return "must salvage/scrap left" + limbName + "first"; } //check for armor - if (unit.getEntity().getArmor(loc, false) > 0 - || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmor(loc, true) > 0 )) { + if (unit.getEntity().getArmorForReal(loc, false) > 0 + || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmorForReal(loc, true) > 0 )) { return "must salvage armor in this location first"; } //you can only salvage a location that has nothing left on it @@ -741,8 +741,8 @@ public String checkScrappable() { return "You must first remove the left " + limbName + " before you scrap the left torso"; } //check for armor - if (unit.getEntity().getArmor(loc, false) > 0 - || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmor(loc, true) > 0 )) { + if (unit.getEntity().getArmorForReal(loc, false) > 0 + || (unit.getEntity().hasRearArmor(loc) && unit.getEntity().getArmorForReal(loc, true) > 0 )) { return "You must first remove the armor from this location before you scrap it"; } //you can only salvage a location that has nothing left on it diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index f2d13b0bb6..75f82a0f82 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -851,21 +851,21 @@ public void checkSalvagableArmorStillPresentTest() { assertNull(mekLocation.checkFixable()); // Some armor, for real. - doReturn(1).when(entity).getArmor(eq(location), anyBoolean()); + doReturn(1).when(entity).getArmorForReal(eq(location), anyBoolean()); assertNotNull(mekLocation.checkSalvagable()); assertNotNull(mekLocation.checkFixable()); // Some rear armor - doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); doReturn(true).when(entity).hasRearArmor(eq(location)); - doReturn(1).when(entity).getArmor(eq(location), eq(true)); + doReturn(1).when(entity).getArmorForReal(eq(location), eq(true)); assertNotNull(mekLocation.checkSalvagable()); assertNotNull(mekLocation.checkFixable()); // No rear armor - doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); doReturn(true).when(entity).hasRearArmor(eq(location)); - doReturn(0).when(entity).getArmor(eq(location), eq(true)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(true)); assertNull(mekLocation.checkSalvagable()); assertNull(mekLocation.checkFixable()); } @@ -1034,19 +1034,19 @@ public void checkScrappableArmorStillPresentTest() { assertNull(mekLocation.checkScrappable()); // Some armor, for real. - doReturn(1).when(entity).getArmor(eq(location), anyBoolean()); + doReturn(1).when(entity).getArmorForReal(eq(location), anyBoolean()); assertNotNull(mekLocation.checkScrappable()); // Some rear armor - doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); doReturn(true).when(entity).hasRearArmor(eq(location)); - doReturn(1).when(entity).getArmor(eq(location), eq(true)); + doReturn(1).when(entity).getArmorForReal(eq(location), eq(true)); assertNotNull(mekLocation.checkScrappable()); // No rear armor - doReturn(0).when(entity).getArmor(eq(location), eq(false)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(false)); doReturn(true).when(entity).hasRearArmor(eq(location)); - doReturn(0).when(entity).getArmor(eq(location), eq(true)); + doReturn(0).when(entity).getArmorForReal(eq(location), eq(true)); assertNull(mekLocation.checkScrappable()); } From c2970d1c5759fda7efff892f079f1f55a7034544 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sat, 2 Jan 2021 16:11:01 -0500 Subject: [PATCH 18/33] Add missing updateConditionFromEntity test --- .../mekhq/campaign/parts/MekLocationTest.java | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 75f82a0f82..1fb1614a65 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -34,6 +34,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; @@ -1517,7 +1518,74 @@ public void removeHeadWithComponentsTest() { } @Test - public void removeSimpleSalvageTest() { + public void removeCenterTorsoDoesntAddMissingPartTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_CT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + mekLocation.remove(false); + + assertFalse(mekLocation.getId() > 0); + assertNull(mekLocation.getUnit()); + assertTrue(warehouse.getParts().isEmpty()); + } + + @Test + public void updateConditionFromEntityNoInternalsRemovesLocationTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse mockWarehouse = mock(Warehouse.class); + when(mockCampaign.getWarehouse()).thenReturn(mockWarehouse); + Quartermaster mockQuartermaster = mock(Quartermaster.class); + when(mockCampaign.getQuartermaster()).thenReturn(mockQuartermaster); + Unit unit = mock(Unit.class); + Entity entity = mock(Entity.class); + when(entity.getWeight()).thenReturn(100.0); + when(unit.getEntity()).thenReturn(entity); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 100, EquipmentType.T_STRUCTURE_INDUSTRIAL, + true, true, true, true, true, mockCampaign); + + // Add the location to a unit + mekLocation.setUnit(unit); + + // Destroy the limb + doReturn(0).when(entity).getInternalForReal(anyInt()); + doReturn(1).when(entity).getOInternal(anyInt()); + + mekLocation.updateConditionFromEntity(false); + + // We should have removed the limb + verify(mockWarehouse, times(1)).removePart(eq(mekLocation)); + + ArgumentCaptor partCaptor = ArgumentCaptor.forClass(Part.class); + verify(mockQuartermaster, times(1)).addPart(partCaptor.capture(), eq(0)); + + Part part = partCaptor.getValue(); + assertTrue(part instanceof MissingMekLocation); + assertEquals(location, ((MissingMekLocation) part).getLocation()); + } + + @Test + public void salvageSimpleTest() { Campaign mockCampaign = mock(Campaign.class); Warehouse warehouse = new Warehouse(); when(mockCampaign.getWarehouse()).thenReturn(warehouse); @@ -1560,4 +1628,41 @@ public void removeSimpleSalvageTest() { assertEquals(location, missingPart.getLocation()); } + + @Test + public void salvageCenterTorsoDoesntAddMissingPartTest() { + Campaign mockCampaign = mock(Campaign.class); + Warehouse warehouse = new Warehouse(); + when(mockCampaign.getWarehouse()).thenReturn(warehouse); + Quartermaster quartermaster = new Quartermaster(mockCampaign); + when(mockCampaign.getQuartermaster()).thenReturn(quartermaster); + Unit unit = mock(Unit.class); + doAnswer(inv -> { + Part part = inv.getArgument(0); + part.setUnit(unit); + return null; + }).when(unit).addPart(any()); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_CT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setId(25); + mekLocation.setUnit(unit); + + warehouse.addPart(mekLocation); + + mekLocation.remove(true); + + assertTrue(mekLocation.getId() > 0); + assertNull(mekLocation.getUnit()); + assertTrue(mekLocation.isSpare()); + assertTrue(warehouse.getParts().contains(mekLocation)); + + // No missing parts in the warehouse if a CT + for (Part part : warehouse.getParts()) { + assertFalse(part instanceof MissingMekLocation); + } + } } From 0af50a247e7783810f890ec70b02b8aea6cba7dd Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 08:14:24 -0500 Subject: [PATCH 19/33] Add tiny tests --- .../src/mekhq/campaign/parts/MekLocation.java | 4 +- .../mekhq/campaign/parts/MekLocationTest.java | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 7ca5997751..71e7b229a6 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -880,11 +880,11 @@ private void removeHeadComponents() { } if (null != sensor) { sensor.remove(false); - sensors = true; + setSensors(true); } if (null != support) { support.remove(false); - lifeSupport = true; + setLifeSupport(true); } } diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 1fb1614a65..4b3f347228 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -50,6 +50,8 @@ import mekhq.campaign.Campaign; import mekhq.campaign.Quartermaster; import mekhq.campaign.Warehouse; +import mekhq.campaign.parts.enums.PartRepairType; +import mekhq.campaign.personnel.SkillType; import mekhq.campaign.unit.Unit; public class MekLocationTest { @@ -1665,4 +1667,49 @@ public void salvageCenterTorsoDoesntAddMissingPartTest() { assertFalse(part instanceof MissingMekLocation); } } + + @Test + public void isRightTechTypeTest() { + Campaign mockCampaign = mock(Campaign.class); + + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); + + assertTrue(centerTorso.isRightTechType(SkillType.S_TECH_MECH)); + assertFalse(centerTorso.isRightTechType(SkillType.S_TECH_MECHANIC)); + } + + @Test + public void getTechAdvancementTest() { + Campaign mockCampaign = mock(Campaign.class); + + int structureType = EquipmentType.T_STRUCTURE_ENDO_STEEL; + boolean isClan = true; + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 25, structureType, isClan, false, false, false, false, mockCampaign); + + assertNotNull(centerTorso.getTechAdvancement()); + + structureType = EquipmentType.T_STRUCTURE_ENDO_STEEL; + isClan = false; + centerTorso = new MekLocation(Mech.LOC_CT, 25, structureType, isClan, false, false, false, false, mockCampaign); + + assertNotNull(centerTorso.getTechAdvancement()); + } + + @Test + public void getMassRepairOptionTypeTest() { + Campaign mockCampaign = mock(Campaign.class); + + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); + + assertEquals(PartRepairType.GENERAL_LOCATION, centerTorso.getMassRepairOptionType()); + } + + @Test + public void getRepairPartTypeTest() { + Campaign mockCampaign = mock(Campaign.class); + + MekLocation centerTorso = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); + + assertEquals(PartRepairType.MEK_LOCATION, centerTorso.getRepairPartType()); + } } From c37ffa8a4033d3f5d03454ee576539f76302ebcd Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 08:22:38 -0500 Subject: [PATCH 20/33] Add MekLocation::getDifficulty test --- .../mekhq/campaign/parts/MekLocationTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 4b3f347228..ade55e9fbc 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -1668,6 +1668,67 @@ public void salvageCenterTorsoDoesntAddMissingPartTest() { } } + @Test + public void getDifficultyTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + // Blown off non-head + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertEquals(+1, mekLocation.getDifficulty()); + + // Blown off head + location = Mech.LOC_HEAD; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertEquals(+2, mekLocation.getDifficulty()); + + // Salvaging the blown off location + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setBlownOff(true); + when(unit.isSalvage()).thenReturn(true); + mekLocation.setUnit(unit); + assertEquals(0, mekLocation.getDifficulty()); + + when(unit.isSalvage()).thenReturn(false); + + // Breached location + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBreached(true); + assertEquals(0, mekLocation.getDifficulty()); + + // Otherwise we're by percent for both repair and salvage + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setPercent(0.01); + assertEquals(+2, mekLocation.getDifficulty()); + mekLocation.setPercent(0.25); + assertEquals(+1, mekLocation.getDifficulty()); + mekLocation.setPercent(0.5); + assertEquals(0, mekLocation.getDifficulty()); + mekLocation.setPercent(0.75); + assertEquals(-1, mekLocation.getDifficulty()); + + // Assign to a salvaging unit + when(unit.isSalvage()).thenReturn(true); + mekLocation.setUnit(unit); + mekLocation.setPercent(0.01); + assertEquals(+2, mekLocation.getDifficulty()); + mekLocation.setPercent(0.25); + assertEquals(+1, mekLocation.getDifficulty()); + mekLocation.setPercent(0.5); + assertEquals(0, mekLocation.getDifficulty()); + mekLocation.setPercent(0.75); + assertEquals(-1, mekLocation.getDifficulty()); + } + @Test public void isRightTechTypeTest() { Campaign mockCampaign = mock(Campaign.class); From 9c78420250057d774c23aeb8e5e032a3302a088d Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 10:36:53 -0500 Subject: [PATCH 21/33] Test MekLocation::getBaseTime --- .../mekhq/campaign/parts/MekLocationTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index ade55e9fbc..8e73211b25 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -1729,6 +1729,67 @@ public void getDifficultyTest() { assertEquals(-1, mekLocation.getDifficulty()); } + @Test + public void getBaseTimeTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + // Blown off non-head + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertEquals(180, mekLocation.getBaseTime()); + + // Blown off head + location = Mech.LOC_HEAD; + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBlownOff(true); + assertEquals(200, mekLocation.getBaseTime()); + + // Salvaging the blown off location + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setBlownOff(true); + when(unit.isSalvage()).thenReturn(true); + mekLocation.setUnit(unit); + assertEquals(0, mekLocation.getBaseTime()); + + when(unit.isSalvage()).thenReturn(false); + + // Breached location + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setBreached(true); + assertEquals(60, mekLocation.getBaseTime()); + + // Otherwise we're by percent for both repair and salvage + mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setPercent(0.01); + assertEquals(270, mekLocation.getBaseTime()); + mekLocation.setPercent(0.25); + assertEquals(180, mekLocation.getBaseTime()); + mekLocation.setPercent(0.5); + assertEquals(135, mekLocation.getBaseTime()); + mekLocation.setPercent(0.75); + assertEquals(90, mekLocation.getBaseTime()); + + // Assign to a salvaging unit + when(unit.isSalvage()).thenReturn(true); + mekLocation.setUnit(unit); + mekLocation.setPercent(0.01); + assertEquals(270, mekLocation.getBaseTime()); + mekLocation.setPercent(0.25); + assertEquals(180, mekLocation.getBaseTime()); + mekLocation.setPercent(0.5); + assertEquals(135, mekLocation.getBaseTime()); + mekLocation.setPercent(0.75); + assertEquals(90, mekLocation.getBaseTime()); + } + @Test public void isRightTechTypeTest() { Campaign mockCampaign = mock(Campaign.class); From b13ff6470254b16bce1bf1e3bc22a46a8593cd6e Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 10:54:35 -0500 Subject: [PATCH 22/33] Add MekLocation::fix tests --- .../src/mekhq/campaign/parts/MekLocation.java | 72 ++++++------ .../mekhq/campaign/parts/MekLocationTest.java | 111 ++++++++++++++++++ 2 files changed, 149 insertions(+), 34 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 71e7b229a6..7a9dab633e 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -306,43 +306,45 @@ protected void loadFieldsFromXmlNode(Node wn) { @Override public void fix() { super.fix(); - if (isBlownOff()) { - blownOff = false; - if (null != unit) { - unit.getEntity().setLocationBlownOff(loc, false); - for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { - CriticalSlot slot = unit.getEntity().getCritical(loc, i); - // ignore empty & non-hittable slots - if (slot == null) { - continue; - } - slot.setMissing(false); - Mounted m = slot.getMount(); - if (null != m) { - m.setMissing(false); - } + + final Unit unit = getUnit(); + if ((unit != null) && isBlownOff()) { + setBlownOff(false); + + unit.getEntity().setLocationBlownOff(loc, false); + for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { + CriticalSlot slot = unit.getEntity().getCritical(loc, i); + // ignore empty slots + if (slot == null) { + continue; + } + + slot.setMissing(false); + Mounted m = slot.getMount(); + if (null != m) { + m.setMissing(false); } } - } else if (isBreached()) { + } else if ((unit != null) && isBreached()) { setBreached(false); - if (null != unit) { - unit.getEntity().setLocationStatus(loc, ILocationExposureStatus.NORMAL, true); - for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { - CriticalSlot slot = unit.getEntity().getCritical(loc, i); - // ignore empty & non-hittable slots - if (slot == null) { - continue; - } - slot.setBreached(false); - Mounted m = slot.getMount(); - if (null != m) { - m.setBreached(false); - } + + unit.getEntity().setLocationStatus(loc, ILocationExposureStatus.NORMAL, true); + for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { + CriticalSlot slot = unit.getEntity().getCritical(loc, i); + // ignore empty slots + if (slot == null) { + continue; + } + + slot.setBreached(false); + Mounted m = slot.getMount(); + if (null != m) { + m.setBreached(false); } } } else { setPercent(1.0); - if (null != unit) { + if (unit != null) { unit.getEntity().setInternal(unit.getEntity().getOInternal(loc), loc); } } @@ -603,10 +605,12 @@ public void updateConditionFromPart() { slot.setRepairable(true); slot.setMissing(false); Mounted m = slot.getMount(); - m.setHit(false); - m.setDestroyed(false); - m.setMissing(false); - m.setRepairable(true); + if (m != null) { + m.setHit(false); + m.setDestroyed(false); + m.setMissing(false); + m.setRepairable(true); + } } } } diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 8e73211b25..56f8cea5f8 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -42,6 +42,7 @@ import megamek.common.CriticalSlot; import megamek.common.Entity; import megamek.common.EquipmentType; +import megamek.common.ILocationExposureStatus; import megamek.common.LandAirMech; import megamek.common.Mech; import megamek.common.Mounted; @@ -1668,6 +1669,116 @@ public void salvageCenterTorsoDoesntAddMissingPartTest() { } } + @Test + public void fixSimpleTest() { + Campaign mockCampaign = mock(Campaign.class); + + int location = Mech.LOC_CT; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setPercent(0.5); + + // Fix the part in the warehouse + mekLocation.fix(); + + assertEquals(1.0, mekLocation.getPercent(), 0.001); + assertFalse(mekLocation.needsFixing()); + + // Place the location on a unit + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + int originalInternal = 10; + doReturn(originalInternal).when(entity).getOInternal(eq(location)); + when(entity.getWeight()).thenReturn(30.0); + + mekLocation.setUnit(unit); + mekLocation.setPercent(0.01); + + assertTrue(mekLocation.needsFixing()); + + // Fix the location on the unit + mekLocation.fix(); + + assertEquals(1.0, mekLocation.getPercent(), 0.001); + assertFalse(mekLocation.needsFixing()); + + verify(entity, times(1)).setInternal(eq(originalInternal), eq(location)); + } + + @Test + public void fixBlownOffTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setBlownOff(true); + mekLocation.setUnit(unit); + + // Setup the critical slots + doReturn(3).when(entity).getNumberOfCriticals(eq(location)); + doReturn(null).when(entity).getCritical(eq(location), eq(0)); // empty + CriticalSlot mockSlot = mock(CriticalSlot.class); + Mounted mounted = mock(Mounted.class); + when(mockSlot.getMount()).thenReturn(mounted); + doReturn(mockSlot).when(entity).getCritical(eq(location), eq(1)); + CriticalSlot mockSlotNoMount = mock(CriticalSlot.class); + doReturn(mockSlotNoMount).when(entity).getCritical(eq(location), eq(2)); // no mount + + assertTrue(mekLocation.needsFixing()); + assertTrue(mekLocation.isBlownOff()); + + // Reattach the blown off location on the unit + mekLocation.fix(); + + assertFalse(mekLocation.needsFixing()); + assertFalse(mekLocation.isBlownOff()); + + verify(entity, times(1)).setLocationBlownOff(eq(location), eq(false)); + verify(mockSlot, times(1)).setMissing(eq(false)); + verify(mounted, times(1)).setMissing(eq(false)); + } + + @Test + public void fixBreachedTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_LLEG; + MekLocation mekLocation = new MekLocation(location, 30, 0, false, false, false, false, false, mockCampaign); + mekLocation.setBreached(true); + mekLocation.setUnit(unit); + + // Setup the critical slots + doReturn(3).when(entity).getNumberOfCriticals(eq(location)); + doReturn(null).when(entity).getCritical(eq(location), eq(0)); // empty + CriticalSlot mockSlot = mock(CriticalSlot.class); + Mounted mounted = mock(Mounted.class); + when(mockSlot.getMount()).thenReturn(mounted); + doReturn(mockSlot).when(entity).getCritical(eq(location), eq(1)); + CriticalSlot mockSlotNoMount = mock(CriticalSlot.class); + doReturn(mockSlotNoMount).when(entity).getCritical(eq(location), eq(2)); // no mount + + assertTrue(mekLocation.needsFixing()); + assertTrue(mekLocation.isBreached()); + + // Reattach the blown off location on the unit + mekLocation.fix(); + + assertFalse(mekLocation.needsFixing()); + assertFalse(mekLocation.isBreached()); + + verify(entity, times(1)).setLocationStatus(eq(location), eq(ILocationExposureStatus.NORMAL), eq(true)); + verify(mockSlot, times(1)).setBreached(eq(false)); + verify(mounted, times(1)).setBreached(eq(false)); + } + @Test public void getDifficultyTest() { Campaign mockCampaign = mock(Campaign.class); From 7c64fa90151ba5de48e4a151ee395dae8a0cfcf3 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 13:34:27 -0500 Subject: [PATCH 23/33] Improve getDetails to include hip/shoulder issues --- .../src/mekhq/campaign/parts/MekLocation.java | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index 7a9dab633e..aadd19b374 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -558,24 +558,15 @@ public String getDetails() { @Override public String getDetails(boolean includeRepairDetails) { - String toReturn = ""; - if (null != unit) { - toReturn = unit.getEntity().getLocationName(loc); - if (includeRepairDetails) { - if (isBlownOff()) { - toReturn += " (Blown Off)"; - } else if (isBreached()) { - toReturn += " (Breached)"; - } else { - toReturn += " (" + Math.round(100 * getPercent()) + "%)"; - } - } - return toReturn; + if (getUnit() != null) { + return getDetailsOnUnit(includeRepairDetails); } - toReturn += getUnitTonnage() + " tons"; + + String toReturn = getUnitTonnage() + " tons"; if (includeRepairDetails) { toReturn += " (" + Math.round(100 * getPercent()) + "%)"; } + if (loc == Mech.LOC_HEAD) { StringJoiner components = new StringJoiner(", "); if (hasSensors()) { @@ -588,6 +579,26 @@ public String getDetails(boolean includeRepairDetails) { toReturn += " [" + components.toString() + "]"; } } + + return toReturn; + } + + private String getDetailsOnUnit(boolean includeRepairDetails) { + assert(getUnit() != null); + + String toReturn = getUnit().getEntity().getLocationName(loc); + if (includeRepairDetails) { + if (isBlownOff()) { + toReturn += " (Blown Off)"; + } else if (isBreached()) { + toReturn += " (Breached)"; + } else if (onBadHipOrShoulder()) { + toReturn += " (Bad Hip/Shoulder)"; + } else { + toReturn += " (" + Math.round(100 * getPercent()) + "%)"; + } + } + return toReturn; } From 5fb955a7c88a4a6370626518d1c098ac2906771d Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 13:40:53 -0500 Subject: [PATCH 24/33] Test MekLocation::getDetails --- .../mekhq/campaign/parts/MekLocationTest.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 56f8cea5f8..5627a55ad6 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -1945,4 +1945,71 @@ public void getRepairPartTypeTest() { assertEquals(PartRepairType.MEK_LOCATION, centerTorso.getRepairPartType()); } + + @Test + public void getDetailsSpareTest() { + Campaign mockCampaign = mock(Campaign.class); + + MekLocation mekLocation = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setPercent(0.1); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation = new MekLocation(Mech.LOC_HEAD, 25, 0, false, false, false, false, false, mockCampaign); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setSensors(true); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setLifeSupport(true); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + } + + @Test + public void getDetailsOnUnitTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + doCallRealMethod().when(entity).getLocationName(anyInt()); + + MekLocation mekLocation = new MekLocation(Mech.LOC_RARM, 25, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setPercent(0.1); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setBlownOff(true); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + mekLocation.setBlownOff(false); + mekLocation.setBreached(true); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + + doReturn(true).when(unit).hasBadHipOrShoulder(eq(mekLocation.getLoc())); + + assertNotNull(mekLocation.getDetails()); + assertNotNull(mekLocation.getDetails(false)); + } } From 1e8735caccb59fa14e7bdcc75be5bad2c4427b45 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 13:44:32 -0500 Subject: [PATCH 25/33] Remove unnecessary nags --- MekHQ/src/mekhq/gui/RepairTab.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/MekHQ/src/mekhq/gui/RepairTab.java b/MekHQ/src/mekhq/gui/RepairTab.java index af8cdd21b7..e2c20f5ff3 100644 --- a/MekHQ/src/mekhq/gui/RepairTab.java +++ b/MekHQ/src/mekhq/gui/RepairTab.java @@ -599,23 +599,7 @@ private void doTask() { return; } if (part instanceof Part && ((Part) part).onBadHipOrShoulder() && !part.isSalvaging()) { - if (part instanceof MekLocation && ((MekLocation) part).isBreached() - && 0 != JOptionPane.showConfirmDialog(getFrame(), - "You are sealing a limb with a bad shoulder or hip.\n" - + "You may continue, but this limb cannot be repaired and you will have to\n" - + "scrap it in order to repair the internal structure and fix the shoulder/hip.\n" - + "Do you wish to continue?", - "Busted Hip/Shoulder", JOptionPane.YES_NO_OPTION)) { - return; - } else if (part instanceof MekLocation && ((MekLocation) part).isBlownOff() - && 0 != JOptionPane.showConfirmDialog(getFrame(), - "You are re-attaching a limb with a bad shoulder or hip.\n" - + "You may continue, but this limb cannot be repaired and you will have to\n" - + "scrap it in order to repair the internal structure and fix the shoulder/hip.\n" - + "Do you wish to continue?", - "Busted Hip/Shoulder", JOptionPane.YES_NO_OPTION)) { - return; - } else if (0 != JOptionPane.showConfirmDialog(getFrame(), + if (0 != JOptionPane.showConfirmDialog(getFrame(), "You are repairing/replacing a part on a limb with a bad shoulder or hip.\n" + "You may continue, but this limb cannot be repaired and you will have to\n" + "remove this equipment if you wish to scrap and then replace the limb.\n" From eb8e0b77b190d2f1da9e0f3a6836c9d2217db3a1 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 13:45:09 -0500 Subject: [PATCH 26/33] Fix getDetailsOnUnitTest conditions --- MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 5627a55ad6..88ff0ef600 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -2007,6 +2007,7 @@ public void getDetailsOnUnitTest() { assertNotNull(mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + mekLocation.setBreached(false); doReturn(true).when(unit).hasBadHipOrShoulder(eq(mekLocation.getLoc())); assertNotNull(mekLocation.getDetails()); From da762cafdf413c22b9b0a810b2f308a96826e4cb Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 15:46:19 -0500 Subject: [PATCH 27/33] Add getAllMods tests --- .../mekhq/campaign/parts/MekLocationTest.java | 112 +++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 88ff0ef600..e0a3093cbd 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -46,12 +46,16 @@ import megamek.common.LandAirMech; import megamek.common.Mech; import megamek.common.Mounted; +import megamek.common.TargetRoll; import mekhq.MekHqXmlUtil; import mekhq.Version; import mekhq.campaign.Campaign; +import mekhq.campaign.CampaignOptions; import mekhq.campaign.Quartermaster; import mekhq.campaign.Warehouse; import mekhq.campaign.parts.enums.PartRepairType; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.personnel.PersonnelOptions; import mekhq.campaign.personnel.SkillType; import mekhq.campaign.unit.Unit; @@ -1953,27 +1957,43 @@ public void getDetailsSpareTest() { MekLocation mekLocation = new MekLocation(Mech.LOC_CT, 25, 0, false, false, false, false, false, mockCampaign); assertNotNull(mekLocation.getDetails()); + assertTrue(mekLocation.getDetails().startsWith("25 tons")); + assertTrue(mekLocation.getDetails().contains("(100%)")); assertNotNull(mekLocation.getDetails(false)); + assertEquals("25 tons", mekLocation.getDetails(false)); - mekLocation.setPercent(0.1); + mekLocation.setPercent(0.01); assertNotNull(mekLocation.getDetails()); + assertTrue(mekLocation.getDetails().contains("(1%)")); assertNotNull(mekLocation.getDetails(false)); + assertEquals("25 tons", mekLocation.getDetails(false)); mekLocation = new MekLocation(Mech.LOC_HEAD, 25, 0, false, false, false, false, false, mockCampaign); assertNotNull(mekLocation.getDetails()); + assertTrue(mekLocation.getDetails().startsWith("25 tons")); + assertTrue(mekLocation.getDetails().contains("(100%)")); assertNotNull(mekLocation.getDetails(false)); + assertEquals("25 tons", mekLocation.getDetails(false)); mekLocation.setSensors(true); assertNotNull(mekLocation.getDetails()); + assertTrue(mekLocation.getDetails().startsWith("25 tons")); + assertTrue(mekLocation.getDetails().contains("(100%)")); + assertTrue(mekLocation.getDetails().contains("[Sensors]")); assertNotNull(mekLocation.getDetails(false)); + assertEquals("25 tons [Sensors]", mekLocation.getDetails(false)); mekLocation.setLifeSupport(true); assertNotNull(mekLocation.getDetails()); + assertTrue(mekLocation.getDetails().startsWith("25 tons")); + assertTrue(mekLocation.getDetails().contains("(100%)")); + assertTrue(mekLocation.getDetails().contains("[Sensors, Life Support]")); assertNotNull(mekLocation.getDetails(false)); + assertEquals("25 tons [Sensors, Life Support]", mekLocation.getDetails(false)); } @Test @@ -1983,34 +2003,120 @@ public void getDetailsOnUnitTest() { Mech entity = mock(Mech.class); when(unit.getEntity()).thenReturn(entity); when(entity.getWeight()).thenReturn(30.0); - doCallRealMethod().when(entity).getLocationName(anyInt()); - MekLocation mekLocation = new MekLocation(Mech.LOC_RARM, 25, 0, false, false, false, false, false, mockCampaign); + int location = Mech.LOC_RARM; + doReturn("Right Arm").when(entity).getLocationName(eq(location)); + + MekLocation mekLocation = new MekLocation(location, 25, 0, false, false, false, false, false, mockCampaign); mekLocation.setUnit(unit); assertNotNull(mekLocation.getDetails()); + assertEquals("Right Arm (100%)", mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + assertEquals("Right Arm", mekLocation.getDetails(false)); mekLocation.setPercent(0.1); assertNotNull(mekLocation.getDetails()); + assertEquals("Right Arm (10%)", mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + assertEquals("Right Arm", mekLocation.getDetails(false)); mekLocation.setBlownOff(true); assertNotNull(mekLocation.getDetails()); + assertEquals("Right Arm (Blown Off)", mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + assertEquals("Right Arm", mekLocation.getDetails(false)); mekLocation.setBlownOff(false); mekLocation.setBreached(true); assertNotNull(mekLocation.getDetails()); + assertEquals("Right Arm (Breached)", mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + assertEquals("Right Arm", mekLocation.getDetails(false)); mekLocation.setBreached(false); doReturn(true).when(unit).hasBadHipOrShoulder(eq(mekLocation.getLoc())); assertNotNull(mekLocation.getDetails()); + assertEquals("Right Arm (Bad Hip/Shoulder)", mekLocation.getDetails()); assertNotNull(mekLocation.getDetails(false)); + assertEquals("Right Arm", mekLocation.getDetails(false)); + } + + @Test + public void getAllModsBreachedTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_RARM; + doReturn("Right Arm").when(entity).getLocationName(eq(location)); + + MekLocation mekLocation = new MekLocation(location, 25, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Breached but not salvaging + mekLocation.setBreached(true); + + TargetRoll roll = mekLocation.getAllMods(mock(Person.class)); + assertEquals(TargetRoll.AUTOMATIC_SUCCESS, roll.getValue()); + } + + @Test + public void getAllModsBlownOffTest() { + Campaign mockCampaign = mock(Campaign.class); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(unit.isSalvage()).thenReturn(true); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_RARM; + doReturn("Right Arm").when(entity).getLocationName(eq(location)); + + MekLocation mekLocation = new MekLocation(location, 25, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + + // Blown Off and salvaging + mekLocation.setBlownOff(true); + + TargetRoll roll = mekLocation.getAllMods(mock(Person.class)); + assertEquals(TargetRoll.AUTOMATIC_SUCCESS, roll.getValue()); + } + + @Test + public void getAllModsSimpleTest() { + Campaign mockCampaign = mock(Campaign.class); + CampaignOptions mockCampaignOptions = mock(CampaignOptions.class); + when(mockCampaign.getCampaignOptions()).thenReturn(mockCampaignOptions); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(unit.isSalvage()).thenReturn(true); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_RARM; + doReturn("Right Arm").when(entity).getLocationName(eq(location)); + + MekLocation mekLocation = new MekLocation(location, 25, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setPercent(0.5); + + TargetRoll siteMod = new TargetRoll(1, "site mod"); + when(unit.getSiteMod()).thenReturn(siteMod); + + Person tech = mock(Person.class); + PersonnelOptions mockOptions = mock(PersonnelOptions.class); + when(tech.getOptions()).thenReturn(mockOptions); + TargetRoll roll = mekLocation.getAllMods(tech); + + assertNotNull(roll); + // 1 (difficulty) + 1 (site mod) + 0 (D) + assertTrue(roll.getValue() >= siteMod.getValue()); } } From 422d432e98b88ff256a6da8a98bec454d70617f3 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 15:57:43 -0500 Subject: [PATCH 28/33] Test MekLocation::getDesc --- .../mekhq/campaign/parts/MekLocationTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index e0a3093cbd..1487911a55 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -2119,4 +2119,41 @@ public void getAllModsSimpleTest() { // 1 (difficulty) + 1 (site mod) + 0 (D) assertTrue(roll.getValue() >= siteMod.getValue()); } + + @Test + public void getDescSimpleTest() { + Campaign mockCampaign = mock(Campaign.class); + CampaignOptions mockCampaignOptions = mock(CampaignOptions.class); + when(mockCampaign.getCampaignOptions()).thenReturn(mockCampaignOptions); + Unit unit = mock(Unit.class); + Mech entity = mock(Mech.class); + when(unit.getEntity()).thenReturn(entity); + when(entity.getWeight()).thenReturn(30.0); + + int location = Mech.LOC_RARM; + doReturn("Right Arm").when(entity).getLocationName(eq(location)); + + MekLocation mekLocation = new MekLocation(location, 25, 0, false, false, false, false, false, mockCampaign); + mekLocation.setUnit(unit); + mekLocation.setPercent(0.75); + + // default + assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("90 minutes")); + + mekLocation.setBlownOff(true); + assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("Re-attach ")); + assertTrue(mekLocation.getDesc().contains("180 minutes")); + + mekLocation.setBlownOff(false); + mekLocation.setBreached(true); + assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("Seal ")); + assertTrue(mekLocation.getDesc().contains("60 minutes")); + + // Breached, but too hard to handle + mekLocation.setSkillMin(SkillType.EXP_ELITE + 1); + assertTrue(mekLocation.getDesc().contains("Impossible")); + } } From c0d7e971732f60ac5dfada6e5c87683df63a1ee8 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 16:03:04 -0500 Subject: [PATCH 29/33] Round out simple getDesc test --- .../mekhq/campaign/parts/MekLocationTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index 1487911a55..f1762700b7 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -58,6 +58,7 @@ import mekhq.campaign.personnel.PersonnelOptions; import mekhq.campaign.personnel.SkillType; import mekhq.campaign.unit.Unit; +import mekhq.campaign.work.WorkTime; public class MekLocationTest { @Test @@ -2139,8 +2140,16 @@ public void getDescSimpleTest() { // default assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("Repair")); assertTrue(mekLocation.getDesc().contains("90 minutes")); + // default, salvage + when(unit.isSalvage()).thenReturn(true); + assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("Salvage")); + + when(unit.isSalvage()).thenReturn(false); + mekLocation.setBlownOff(true); assertNotNull(mekLocation.getDesc()); assertTrue(mekLocation.getDesc().contains("Re-attach ")); @@ -2152,6 +2161,13 @@ public void getDescSimpleTest() { assertTrue(mekLocation.getDesc().contains("Seal ")); assertTrue(mekLocation.getDesc().contains("60 minutes")); + mekLocation.setTech(mock(Person.class)); + assertNotNull(mekLocation.getDesc()); + assertTrue(mekLocation.getDesc().contains("(scheduled)")); + + mekLocation.setMode(WorkTime.EXTRA_2); + assertTrue(mekLocation.getDesc().contains(mekLocation.getCurrentModeName())); + // Breached, but too hard to handle mekLocation.setSkillMin(SkillType.EXP_ELITE + 1); assertTrue(mekLocation.getDesc().contains("Impossible")); From 9c2ee335b3a017fb67bedaa8fc7fa497aa4cb226 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Sun, 3 Jan 2021 16:30:40 -0500 Subject: [PATCH 30/33] Fix test failure --- MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java index f1762700b7..579dc35110 100644 --- a/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java +++ b/MekHQ/unittests/mekhq/campaign/parts/MekLocationTest.java @@ -2165,6 +2165,8 @@ public void getDescSimpleTest() { assertNotNull(mekLocation.getDesc()); assertTrue(mekLocation.getDesc().contains("(scheduled)")); + mekLocation.setBlownOff(true); + mekLocation.setBreached(false); mekLocation.setMode(WorkTime.EXTRA_2); assertTrue(mekLocation.getDesc().contains(mekLocation.getCurrentModeName())); From 491ba08f02d01bba60e6f72ebf248871156c0150 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 9 Apr 2021 08:22:11 -0400 Subject: [PATCH 31/33] Apply suggestions from code review Co-authored-by: Justin Bowen <39067288+Windchild292@users.noreply.github.com> --- MekHQ/src/mekhq/campaign/parts/MekLocation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index aadd19b374..c52c7eecdf 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -605,7 +605,7 @@ private String getDetailsOnUnit(boolean includeRepairDetails) { @Override public void updateConditionFromPart() { if (null != unit) { - unit.getEntity().setInternal((int)Math.round(getPercent() * unit.getEntity().getOInternal(loc)), loc); + unit.getEntity().setInternal((int) Math.round(getPercent() * unit.getEntity().getOInternal(loc)), loc); //TODO: we need to cycle through slots and remove crits on non-hittable ones //We shouldn't have to do this, these slots should not be hit in MM for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { From fcb52f69ad44233b563697da90aedaae89d590dd Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 9 Apr 2021 08:34:49 -0400 Subject: [PATCH 32/33] Fix merge conflicts --- MekHQ/src/mekhq/campaign/parts/Part.java | 72 ++++++++++++ .../mekhq/gui/dialog/AcquisitionsDialog.java | 4 +- MekHQ/src/mekhq/gui/model/TaskTableModel.java | 4 +- .../gui/utilities/PartWorkImageSelector.java | 103 ------------------ 4 files changed, 76 insertions(+), 107 deletions(-) delete mode 100644 MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java diff --git a/MekHQ/src/mekhq/campaign/parts/Part.java b/MekHQ/src/mekhq/campaign/parts/Part.java index e1ece142c8..9463bde2b9 100644 --- a/MekHQ/src/mekhq/campaign/parts/Part.java +++ b/MekHQ/src/mekhq/campaign/parts/Part.java @@ -40,17 +40,21 @@ import org.w3c.dom.NodeList; import megamek.common.Entity; +import megamek.common.EquipmentType; import megamek.common.ITechnology; import megamek.common.SimpleTechLevel; import megamek.common.Tank; import megamek.common.TargetRoll; import megamek.common.TechAdvancement; +import megamek.common.WeaponType; import megamek.common.annotations.Nullable; import mekhq.MekHQ; import mekhq.MekHqXmlSerializable; import mekhq.MekHqXmlUtil; import mekhq.Version; import mekhq.campaign.Campaign; +import mekhq.campaign.parts.equipment.EquipmentPart; +import mekhq.campaign.parts.equipment.MissingEquipmentPart; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.PersonnelOptions; import mekhq.campaign.personnel.SkillType; @@ -1550,6 +1554,74 @@ public String toString() { return sb.toString(); } + public static String[] findPartImage(IPartWork part) { + String imgBase = null; + PartRepairType repairType = IPartWork.findCorrectRepairType(part); + + switch (repairType) { + case ARMOR: + imgBase = "armor"; + break; + case AMMO: + imgBase = "ammo"; + break; + case ACTUATOR: + imgBase = "actuator"; + break; + case ENGINE: + imgBase = "engine"; + break; + case ELECTRONICS: + imgBase = "electronics"; + break; + case HEAT_SINK: + imgBase = "heatsink"; + break; + case WEAPON: + EquipmentType equipmentType = null; + + if (part instanceof EquipmentPart) { + equipmentType = ((EquipmentPart) part).getType(); + } else if (part instanceof MissingEquipmentPart) { + equipmentType = ((MissingEquipmentPart) part).getType(); + } + + if (equipmentType != null) { + if (equipmentType.hasFlag(WeaponType.F_LASER)) { + imgBase = "laser"; + } else if (equipmentType.hasFlag(WeaponType.F_MISSILE)) { + imgBase = "missile"; + } else if (equipmentType.hasFlag(WeaponType.F_BALLISTIC)) { + imgBase = "ballistic"; + } else if (equipmentType.hasFlag(WeaponType.F_ARTILLERY)) { + imgBase = "artillery"; + } + } + + break; + case MEK_LOCATION: + case POD_SPACE: + imgBase = "location_mek"; + break; + case PHYSICAL_WEAPON: + imgBase = "melee"; + break; + default: + break; + } + + if (imgBase == null) { + imgBase = "equipment"; + } + + + String[] imgData = new String[2]; + imgData[0] = "data/images/misc/repair/"; + imgData[1] = imgBase; + + return imgData; + } + public abstract ITechnology getTechAdvancement(); @Override diff --git a/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java b/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java index 8904787ff8..7ef685f64a 100644 --- a/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/AcquisitionsDialog.java @@ -399,7 +399,7 @@ private void initComponents() { Insets insetsOriginal = gbcMain.insets; // Set image - String[] imgData = PartWorkImageSelector.findPartImage(part); + String[] imgData = Part.findPartImage(part); String imgPath = imgData[0] + imgData[1] + ".png"; Image imgTool = getToolkit().getImage(imgPath); @@ -559,4 +559,4 @@ private JPanel createActionButtons() { return actionButtons; } } -} +} \ No newline at end of file diff --git a/MekHQ/src/mekhq/gui/model/TaskTableModel.java b/MekHQ/src/mekhq/gui/model/TaskTableModel.java index 6aca16ce3b..4b18c65517 100644 --- a/MekHQ/src/mekhq/gui/model/TaskTableModel.java +++ b/MekHQ/src/mekhq/gui/model/TaskTableModel.java @@ -33,6 +33,7 @@ import megamek.common.TargetRoll; import mekhq.IconPackage; import mekhq.campaign.parts.MissingPart; +import mekhq.campaign.parts.Part; import mekhq.campaign.parts.PartInventory; import mekhq.campaign.parts.PodSpace; import mekhq.campaign.personnel.Person; @@ -41,7 +42,6 @@ import mekhq.gui.CampaignGUI; import mekhq.gui.ITechWorkPanel; import mekhq.gui.RepairTaskInfo; -import mekhq.gui.utilities.PartWorkImageSelector; /** * A table model for displaying work items @@ -217,7 +217,7 @@ public Component getTableCellRendererComponent(JTable table, break; } - String[] imgData = PartWorkImageSelector.findPartImage(part); + String[] imgData = Part.findPartImage(part); String imgPath = imgData[0] + imgData[1] + imgMod + ".png"; Image imgTool = getToolkit().getImage(imgPath); //$NON-NLS-1$ diff --git a/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java b/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java deleted file mode 100644 index b0cdc5eebc..0000000000 --- a/MekHQ/src/mekhq/gui/utilities/PartWorkImageSelector.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2020 MegaMek team - * - * This file is part of MekHQ. - * - * MekHQ is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MekHQ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with MekHQ. If not, see . - */ - -package mekhq.gui.utilities; - -import megamek.common.EquipmentType; -import megamek.common.WeaponType; -import mekhq.campaign.parts.enums.PartRepairType; -import mekhq.campaign.parts.equipment.EquipmentPart; -import mekhq.campaign.parts.equipment.MissingEquipmentPart; -import mekhq.campaign.work.IPartWork; - -public class PartWorkImageSelector { - - /** - * Find the most appropriate image for a given {@see IPartWork}. - * @param part The {@see PartWork} to select the image for. - * @return An array containing the path parts pointing to the image. - */ - public static String[] findPartImage(IPartWork part) { - String imgBase = null; - PartRepairType repairType = IPartWork.findCorrectRepairType(part); - - switch (repairType) { - case ARMOR: - imgBase = "armor"; - break; - case AMMO: - imgBase = "ammo"; - break; - case ACTUATOR: - imgBase = "actuator"; - break; - case ENGINE: - imgBase = "engine"; - break; - case ELECTRONICS: - imgBase = "electronics"; - break; - case HEAT_SINK: - imgBase = "heatsink"; - break; - case WEAPON: - EquipmentType equipmentType = null; - - if (part instanceof EquipmentPart) { - equipmentType = ((EquipmentPart) part).getType(); - } else if (part instanceof MissingEquipmentPart) { - equipmentType = ((MissingEquipmentPart) part).getType(); - } - - if (equipmentType != null) { - if (equipmentType.hasFlag(WeaponType.F_LASER)) { - imgBase = "laser"; - } else if (equipmentType.hasFlag(WeaponType.F_MISSILE)) { - imgBase = "missile"; - } else if (equipmentType.hasFlag(WeaponType.F_BALLISTIC)) { - imgBase = "ballistic"; - } else if (equipmentType.hasFlag(WeaponType.F_ARTILLERY)) { - imgBase = "artillery"; - } - } - - break; - case MEK_LOCATION: - case POD_SPACE: - imgBase = "location_mek"; - break; - case PHYSICAL_WEAPON: - imgBase = "melee"; - break; - default: - break; - } - - if (imgBase == null) { - imgBase = "equipment"; - } - - - String[] imgData = new String[2]; - imgData[0] = "data/images/misc/repair/"; - imgData[1] = imgBase; - - return imgData; - } -} From bc441678a4e2c857a2c5a33554b8724ed173608c Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 9 Apr 2021 08:42:41 -0400 Subject: [PATCH 33/33] Address review comments --- .../src/mekhq/campaign/parts/MekLocation.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/parts/MekLocation.java b/MekHQ/src/mekhq/campaign/parts/MekLocation.java index cd3fa0e507..1fb2f2cfbf 100644 --- a/MekHQ/src/mekhq/campaign/parts/MekLocation.java +++ b/MekHQ/src/mekhq/campaign/parts/MekLocation.java @@ -193,16 +193,11 @@ public boolean forQuad() { @Override public boolean isSamePartType(Part part) { - return (part instanceof MekLocation) - && isSamePartType((MekLocation) part); - } + if (!(part instanceof MekLocation)) { + return false; + } - /** - * Gets a value indicating whether or not {@code other} is the same - * type of {@code MekLocation}. - * @param other A different {@code MekLocation}. - */ - public boolean isSamePartType(MekLocation other) { + MekLocation other = (MekLocation) part; return (getLoc() == other.getLoc()) && (getUnitTonnage() == other.getUnitTonnage()) && (isTsm() == other.isTsm()) @@ -669,10 +664,7 @@ public String checkFixable() { return "You cannot salvage a limb with a busted hip/shoulder. You must scrap it instead."; } //cant salvage torsos until arms and legs are gone - String limbName = " arm "; - if (forQuad) { - limbName = " front leg "; - } + String limbName = forQuad ? " front leg " : " arm "; if (unit.getEntity() instanceof Mech && loc == Mech.LOC_RT && !unit.getEntity().isLocationBad(Mech.LOC_RARM)) { return "must salvage/scrap right" + limbName + "first"; }