From 207318390fd1924218be9687d36d7acf84ef738c Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 4 Jan 2024 23:57:25 +0100 Subject: [PATCH 1/5] Separate UnitUtil (new classes commit) --- .../src/megameklab/printing/PrintUtil.java | 147 ++ .../src/megameklab/ui/EquipmentToolTip.java | 132 + megameklab/src/megameklab/util/AeroUtil.java | 313 +++ .../src/megameklab/util/BattleArmorUtil.java | 127 + .../src/megameklab/util/InfantryUtil.java | 132 + megameklab/src/megameklab/util/MekUtil.java | 1442 +++++++++++ .../src/megameklab/util/ProtoMekUtil.java | 109 + megameklab/src/megameklab/util/TankUtil.java | 163 ++ megameklab/src/megameklab/util/UnitUtil.java | 2149 +---------------- 9 files changed, 2655 insertions(+), 2059 deletions(-) create mode 100644 megameklab/src/megameklab/printing/PrintUtil.java create mode 100644 megameklab/src/megameklab/ui/EquipmentToolTip.java create mode 100644 megameklab/src/megameklab/util/AeroUtil.java create mode 100644 megameklab/src/megameklab/util/BattleArmorUtil.java create mode 100644 megameklab/src/megameklab/util/InfantryUtil.java create mode 100644 megameklab/src/megameklab/util/MekUtil.java create mode 100644 megameklab/src/megameklab/util/ProtoMekUtil.java create mode 100644 megameklab/src/megameklab/util/TankUtil.java diff --git a/megameklab/src/megameklab/printing/PrintUtil.java b/megameklab/src/megameklab/printing/PrintUtil.java new file mode 100644 index 000000000..edb2bb47c --- /dev/null +++ b/megameklab/src/megameklab/printing/PrintUtil.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.printing; + +import megamek.common.*; +import megamek.common.weapons.LegAttack; +import megamek.common.weapons.StopSwarmAttack; +import megamek.common.weapons.SwarmAttack; +import megamek.common.weapons.SwarmWeaponAttack; +import megamek.common.weapons.infantry.InfantryRifleAutoRifleWeapon; +import megameklab.util.UnitUtil; + +public final class PrintUtil { + + public static boolean isPrintableEquipment(EquipmentType eq) { + return isPrintableEquipment(eq, false); + } + + /** + * simple method to let us know if eq should be printed on the weapons and + * equipment section of the Record sheet. + * + * @param eq The equipment to test The equipment + * @param entity The Entity it's mounted on + * @return Whether the equipment should be shown on the record sheet + */ + public static boolean isPrintableEquipment(EquipmentType eq, Entity entity) { + if (eq instanceof AmmoType) { + return ((AmmoType) eq).getAmmoType() == AmmoType.T_COOLANT_POD; + } else if (entity instanceof BattleArmor) { + return isPrintableBAEquipment(eq); + } else { + return isPrintableEquipment(eq, entity instanceof Mech); + } + } + + /** + * simple method to let us know if eq should be printed on the weapons and + * equipment section of the Record sheet. + * + * @param eq The equipment to test The equipment + * @param isMech Whether the equipment is mounted on a mech + * @return Whether the equipment should be shown on the record sheet + */ + public static boolean isPrintableEquipment(EquipmentType eq, boolean isMech) { + if (UnitUtil.isArmorOrStructure(eq)) { + return false; + } + + if (UnitUtil.isFixedLocationSpreadEquipment(eq) + && !(eq instanceof MiscType) && eq.hasFlag(MiscType.F_TALON)) { + return false; + } + + if (UnitUtil.isJumpJet(eq)) { + return false; + } + if (!eq.isHittable() && isMech) { + return false; + } + + if ((eq instanceof MiscType) + && (eq.hasFlag(MiscType.F_CASE) + || eq.hasFlag(MiscType.F_ARTEMIS) + || eq.hasFlag(MiscType.F_ARTEMIS_PROTO) + || eq.hasFlag(MiscType.F_ARTEMIS_V) + || eq.hasFlag(MiscType.F_APOLLO) + || eq.hasFlag(MiscType.F_PPC_CAPACITOR) + || (eq.hasFlag(MiscType.F_MASC) && isMech) + || eq.hasFlag(MiscType.F_HARJEL) + || eq.hasFlag(MiscType.F_MASS) + || eq.hasFlag(MiscType.F_CHASSIS_MODIFICATION) + || eq.hasFlag(MiscType.F_SPONSON_TURRET)) + || eq.hasFlag(MiscType.F_EXTERNAL_STORES_HARDPOINT) + || eq.hasFlag(MiscType.F_BASIC_FIRECONTROL) + || eq.hasFlag(MiscType.F_ADVANCED_FIRECONTROL)) { + return false; + } + + if (UnitUtil.isHeatSink(eq)) { + return false; + } + + return true; + } + + private PrintUtil() { } + + /** + * simple method to let us know if eq should be printed on the weapons and + * equipment section of the Record sheet. + * + * @param eq + * @return + */ + public static boolean isPrintableBAEquipment(EquipmentType eq) { + if (UnitUtil.isArmorOrStructure(eq)) { + return false; + } + + if (UnitUtil.isJumpJet(eq)) { + return false; + } + + if ((eq instanceof MiscType) + && ((eq.hasFlag(MiscType.F_AP_MOUNT) && !eq.hasFlag(MiscType.F_BA_MANIPULATOR)) + || eq.hasFlag(MiscType.F_FIRE_RESISTANT) + || eq.hasFlag(MiscType.F_STEALTH) + || eq.hasFlag(MiscType.F_ARTEMIS) + || eq.hasFlag(MiscType.F_ARTEMIS_V) + || eq.hasFlag(MiscType.F_APOLLO) + || eq.hasFlag(MiscType.F_HARJEL) + || eq.hasFlag(MiscType.F_MASS) + || eq.hasFlag(MiscType.F_DETACHABLE_WEAPON_PACK))) { + return false; + } + + if (UnitUtil.isHeatSink(eq)) { + return false; + } + + if ((eq instanceof LegAttack) || (eq instanceof SwarmAttack) + || (eq instanceof StopSwarmAttack) + || (eq instanceof InfantryRifleAutoRifleWeapon) + || (eq instanceof SwarmWeaponAttack)) { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/ui/EquipmentToolTip.java b/megameklab/src/megameklab/ui/EquipmentToolTip.java new file mode 100644 index 000000000..25e30e684 --- /dev/null +++ b/megameklab/src/megameklab/ui/EquipmentToolTip.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.ui; + +import megamek.common.*; +import megamek.common.verifier.TestEntity; +import megamek.common.weapons.infantry.InfantryWeapon; +import megamek.common.weapons.missiles.MMLWeapon; +import megamek.common.weapons.srms.SRMWeapon; +import megamek.common.weapons.srms.SRTWeapon; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +public final class EquipmentToolTip { + + public static String getToolTipInfo(Entity unit, Mounted eq) { + DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(); + unusualSymbols.setDecimalSeparator('.'); + unusualSymbols.setGroupingSeparator(','); + DecimalFormat myFormatter = new DecimalFormat("#,##0", unusualSymbols); + StringBuilder sb = new StringBuilder(""); + sb.append(eq.getName()); + if (eq.getType() instanceof AmmoType) { + sb.append(" (").append(eq.getBaseShotsLeft()).append(" shot"); + sb.append((eq.getBaseShotsLeft() == 1) ? ")" : "s)"); + } + if ((eq.getType().hasFlag(MiscType.F_DETACHABLE_WEAPON_PACK) + || eq.getType().hasFlag(MiscType.F_AP_MOUNT)) + && (eq.getLinked() != null)) { + sb.append(" (attached ").append(eq.getLinked().getName()).append(")"); + } + if (eq.isSquadSupportWeapon()) { + sb.append(" (squad support weapon)"); + } + if (eq.getType() instanceof InfantryWeapon) { + sb.append("
Damage/Trooper: "); + double infDamage = ((InfantryWeapon) eq.getType()).getInfantryDamage(); + sb.append(infDamage); + sb.append("
Range Class: "); + sb.append(((InfantryWeapon) eq.getType()).getInfantryRange()); + } else { + sb.append("
Crits: "); + sb.append(eq.getCriticals()); + sb.append("
Mass: "); + if (TestEntity.usesKgStandard(unit)) { + sb.append(Math.round(eq.getTonnage() * 1000)); + sb.append(" Kg"); + } else { + sb.append(eq.getTonnage()); + sb.append(" tons"); + } + + if (eq.getType() instanceof WeaponType) { + sb.append("
Heat: "); + sb.append(eq.getType().getHeat()); + sb.append("
Maximum Damage: "); + sb.append(getWeaponDamageInfo((WeaponType) eq.getType())); + } + } + sb.append("
Cost: "); + + double cost = eq.getType().getCost(unit, false, eq.getLocation()); + + sb.append(myFormatter.format(cost)); + sb.append(" CBills"); + + if (eq.isRearMounted()) { + sb.append("
Rear Facing"); + } + if (eq.isMechTurretMounted()) { + sb.append("
Turret mounted"); + } + if (eq.isArmored()) { + sb.append("
Armored"); + } + if ((unit instanceof BattleArmor) + && eq.getType().hasFlag(WeaponType.F_INF_SUPPORT)) { + sb.append("
* Infantry support weapons must be held in an " + + "Armored Glove"); + } else if ((unit instanceof BattleArmor) + && eq.getType().hasFlag(WeaponType.F_INFANTRY)) { + sb.append("
* Infantry weapons must be mounted in AP Mounts"); + } + + sb.append(""); + return sb.toString(); + } + + private static String getWeaponDamageInfo(WeaponType wType) { + if (wType.getDamage() == WeaponType.DAMAGE_BY_CLUSTERTABLE) { + int perMissile = 1; + if ((wType instanceof SRMWeapon) || (wType instanceof SRTWeapon) ||(wType instanceof MMLWeapon)) { + perMissile = 2; + } + return Integer.toString(wType.getRackSize() * perMissile); + } else if (wType.getDamage() == WeaponType.DAMAGE_VARIABLE) { + return Integer.toString(wType.getDamage(1)); + } else if (wType.getDamage() == WeaponType.DAMAGE_SPECIAL) { + return "Special"; + } else if (wType.getDamage() == WeaponType.DAMAGE_ARTILLERY) { + return Integer.toString(wType.getRackSize()); + } else { + int damage = wType.getDamage(); + if (wType.getAmmoType() == AmmoType.T_AC_ROTARY) { + damage *= 6; + } else if ((wType.getAmmoType() == AmmoType.T_AC_ULTRA) + || (wType.getAmmoType() == AmmoType.T_AC_ULTRA_THB)) { + damage *= 2; + } + return Integer.toString(damage); + } + } + + private EquipmentToolTip() { } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/AeroUtil.java b/megameklab/src/megameklab/util/AeroUtil.java new file mode 100644 index 000000000..0a2588f55 --- /dev/null +++ b/megameklab/src/megameklab/util/AeroUtil.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.verifier.TestAero; +import megamek.common.verifier.TestSmallCraft; +import megamek.common.verifier.TestTank; +import megamek.common.weapons.capitalweapons.CapitalMissileWeapon; +import megamek.common.weapons.infantry.InfantryWeapon; +import megamek.common.weapons.lrms.LRMWeapon; +import megamek.common.weapons.lrms.LRTWeapon; +import megamek.common.weapons.missiles.MRMWeapon; +import megamek.common.weapons.missiles.RLWeapon; +import megamek.common.weapons.srms.SRMWeapon; +import megamek.common.weapons.srms.SRTWeapon; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class AeroUtil { + + public static boolean isAeroWeapon(EquipmentType eq, Aero unit) { + if (!(eq instanceof WeaponType)) { + return false; + + } + if (eq instanceof InfantryWeapon) { + return false; + } + // Fixed wing, airship, and satellite vehicles use vehicle construction rules. + if (unit.isSupportVehicle()) { + return eq.hasFlag(WeaponType.F_TANK_WEAPON) + && TestTank.legalForMotiveType(eq, unit.getMovementMode(), true); + } + + WeaponType weapon = (WeaponType) eq; + + if (weapon.hasFlag(WeaponType.F_BOMB_WEAPON)) { + return false; + } + + // small craft only; lacks aero weapon flag + if (weapon.getAmmoType() == AmmoType.T_C3_REMOTE_SENSOR) { + return unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT) + && !unit.hasETypeFlag(Entity.ETYPE_DROPSHIP); + } + + if (weapon.hasFlag(WeaponType.F_ARTILLERY) && !weapon.hasFlag(WeaponType.F_BA_WEAPON)) { + return (weapon.getAmmoType() == AmmoType.T_ARROW_IV) + || unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT) + || unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); + } + + if (weapon.isSubCapital() || (weapon instanceof CapitalMissileWeapon) + || (weapon.getAtClass() == WeaponType.CLASS_SCREEN)) { + return unit.hasETypeFlag(Entity.ETYPE_DROPSHIP) + || unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); + } + + if (weapon.isCapital()) { + return unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); + } + + if (!weapon.hasFlag(WeaponType.F_AERO_WEAPON)) { + return false; + } + + if (weapon.getTonnage(unit) <= 0) { + return false; + } + + if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) + && (weapon.getRackSize() != 5) + && (weapon.getRackSize() != 10) + && (weapon.getRackSize() != 15) + && (weapon.getRackSize() != 20)) { + return false; + } + if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) + && (weapon.getRackSize() != 2) + && (weapon.getRackSize() != 4) + && (weapon.getRackSize() != 6)) { + return false; + } + if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon + .getAmmoType() == AmmoType.T_PLASMA))) { + + if (weapon.hasFlag(WeaponType.F_ENERGY) + && weapon.hasFlag(WeaponType.F_PLASMA) + && (weapon.getAmmoType() == AmmoType.T_NA)) { + return false; + } + } + return true; + } + + public static boolean isAeroEquipment(EquipmentType eq, Aero unit) { + + if (UnitUtil.isArmorOrStructure(eq)) { + return false; + } + + if ((eq instanceof AmmoType) + && (((AmmoType)eq).getAmmoType() == AmmoType.T_COOLANT_POD)) { + return !unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT); + } + + if ((eq instanceof MiscType)) { + if (unit.hasETypeFlag(Entity.ETYPE_SPACE_STATION)) { + return eq.hasFlag(MiscType.F_SS_EQUIPMENT); + } else if (unit.hasETypeFlag(Entity.ETYPE_WARSHIP)) { + return eq.hasFlag(MiscType.F_WS_EQUIPMENT); + } else if (unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) { + return eq.hasFlag(MiscType.F_JS_EQUIPMENT); + } else if (unit.hasETypeFlag(Entity.ETYPE_DROPSHIP)) { + return eq.hasFlag(MiscType.F_DS_EQUIPMENT); + } else if (unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT)) { + return eq.hasFlag(MiscType.F_SC_EQUIPMENT); + } else if (eq.hasFlag(MiscType.F_FLOTATION_HULL)) { + return unit.hasETypeFlag(Entity.ETYPE_CONV_FIGHTER) + && !unit.hasETypeFlag(Entity.ETYPE_FIXED_WING_SUPPORT); + } else if (unit.isSupportVehicle()) { + return eq.hasFlag(MiscType.F_SUPPORT_TANK_EQUIPMENT) + && TestTank.legalForMotiveType(eq, unit.getMovementMode(), true); + } else { + return eq.hasFlag(MiscType.F_FIGHTER_EQUIPMENT); + } + } + + if (eq instanceof AmmoType) { + return ((AmmoType) eq).canAeroUse(); + } + + return isAeroWeapon(eq, unit); + } + + /** + * Adjusts the number of crew quarters of a given type on an aerospace vessel. + * + * @param aero The aerospace unit to change crew quarters sizes for + * @param quarters The type of crew quarters to change + * @param size The number of personnel that can be housed in the designated type of quarters + */ + public static void setQuarters(Aero aero, TestAero.Quarters quarters, int size) { + List toRemove = new ArrayList<>(); + for (Bay bay : aero.getTransportBays()) { + if (TestAero.Quarters.getQuartersForBay(bay) == quarters) { + toRemove.add(bay); + } + } + for (Bay bay : toRemove) { + aero.removeTransporter(bay); + } + if (size > 0) { + aero.addTransporter(quarters.newQuarters(size)); + } + } + + /** + * Adjusts the number of all types of crew quarters on an aerospace vessel. + * + * @param aero The vessel + * @param officer The number of officer/first class quarters + * @param standard The number of standard crew quarters + * @param secondclass The number second class passenger quarters + * @param steerage The number of steerage class crew/passenger quarters + */ + public static void assignQuarters(Aero aero, int officer, int standard, int secondclass, int steerage) { + Map sizes = TestAero.Quarters.getQuartersByType(aero); + if (sizes.get(TestAero.Quarters.FIRST_CLASS) != officer) { + setQuarters(aero, TestAero.Quarters.FIRST_CLASS, officer); + } + if (sizes.get(TestAero.Quarters.STANDARD) != standard) { + setQuarters(aero, TestAero.Quarters.STANDARD, standard); + } + if (sizes.get(TestAero.Quarters.SECOND_CLASS) != secondclass) { + setQuarters(aero, TestAero.Quarters.SECOND_CLASS, secondclass); + } + if (sizes.get(TestAero.Quarters.STEERAGE) != steerage) { + setQuarters(aero, TestAero.Quarters.STEERAGE, steerage); + } + } + + /** + * Adjusts the number of quarters of each to match the crew and passenger needs. If no quarters + * are already assigned, this will put all officers in officer/first class cabins, enlisted crew + * in standard crew quarters, and passengers in second class cabins. If there are already more + * officer/first class cabins assigned than there are officers, the extra will be used as first + * class passenger cabins. Any steerage quarters will be assigned first to marines, then to passengers, + * then to remaining enlisted. + * + * @param aero The vessel to assign quarters for. + */ + public static void autoAssignQuarters(Aero aero) { + int marines = aero.getNMarines() + aero.getNBattleArmor(); + int enlistedNeeds = aero.getNCrew() + marines - aero.getBayPersonnel() - aero.getNOfficers(); + Map quartersCount = TestAero.Quarters.getQuartersByType(aero); + + // Standard crew quarters should not be larger than the crew needs, but may be smaller as + // some crew may have officer or steerage housing. + int standardCrew = Math.min(enlistedNeeds, quartersCount.get(TestAero.Quarters.STANDARD)); + // Limit the first class quarters to number of officers + passengers. It is possible to house + // enlisted in first class quarters, but that is beyond the scope of this and will need to + // be done by hand. + int officer1stC = Math.min(aero.getNOfficers() + aero.getNPassenger(), + quartersCount.get(TestAero.Quarters.FIRST_CLASS)); + officer1stC = Math.max(officer1stC, aero.getNOfficers()); + int firstClass = Math.max(0, officer1stC - aero.getNOfficers()); + int officer = officer1stC - firstClass; + + // Limit the steerage quarters to the number of crew that have not been assigned standard + // or officer quarters and passengers that have not been assigned first class. + int steeragePsgr = Math.min(aero.getNPassenger() - firstClass + enlistedNeeds - standardCrew, + quartersCount.get(TestAero.Quarters.STEERAGE)); + // Assign any existing steerage quarters first to marines that have not already been assigned standard + // quarters + int steerageCrew = 0; + if (enlistedNeeds > standardCrew) { + steerageCrew = Math.min(steeragePsgr, marines); + steeragePsgr -= steerageCrew; + } + // Assign any remaining steerage quarters to passengers first, then remaining crew. + if (steeragePsgr > aero.getNPassenger() - firstClass) { + int excess = steeragePsgr - aero.getNPassenger() - firstClass; + steerageCrew += excess; + steeragePsgr -= excess; + } + + // Any leftovers go to standard crew or second class + standardCrew = enlistedNeeds - steerageCrew; + int secondClass = aero.getNPassenger() - firstClass - steeragePsgr; + + assignQuarters(aero, officer + firstClass, standardCrew, secondClass, steerageCrew + steeragePsgr); + } + + private AeroUtil() { } + + public static void updateLoadedAero(Aero unit) { + if (unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT)) { + if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_STANDARD) { + unit.setArmorType(EquipmentType.T_ARMOR_AEROSPACE); + } else if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_PRIMITIVE) { + unit.setArmorType(EquipmentType.T_ARMOR_PRIMITIVE_AERO); + } + if (unit.isPrimitive() && (unit instanceof Dropship)) { + if (unit.getYear() < Dropship.getCollarTA().getIntroductionDate()) { + ((Dropship)unit).setCollarType(Dropship.COLLAR_NO_BOOM); + } else if ((unit.getYear() < Dropship.getCollarTA().getIntroductionDate()) + && (((Dropship)unit).getCollarType() == Dropship.COLLAR_STANDARD)) { + ((Dropship)unit).setCollarType(Dropship.COLLAR_PROTOTYPE); + } + } + // Minimum crew levels + ((SmallCraft) unit).setNGunners(Math.max(unit.getNGunners(), + TestSmallCraft.requiredGunners(unit))); + unit.setNCrew(Math.max(unit.getNCrew(), + unit.getNGunners() + unit.getBayPersonnel() + + TestSmallCraft.minimumBaseCrew((SmallCraft) unit))); + if (unit.getNOfficers() == 0) { + ((SmallCraft) unit).setNOfficers((int) Math.ceil((unit.getNCrew() - unit.getBayPersonnel()) / 5.0)); + } + // Check whether there are any quarters allocated. If not, assign standard levels + if (unit.getTransportBays().stream().noneMatch(Bay::isQuarters)) { + unit.addTransporter(TestAero.Quarters.FIRST_CLASS.newQuarters(unit.getNOfficers())); + unit.addTransporter(TestAero.Quarters.SECOND_CLASS.newQuarters(unit.getNPassenger())); + int std = unit.getNCrew() - unit.getBayPersonnel() - unit.getNOfficers() + + unit.getNMarines() + unit.getNBattleArmor(); + if (std > 0) { + unit.addTransporter(TestAero.Quarters.STANDARD.newQuarters(std)); + } + } + } else if (unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) { + if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_STANDARD) { + unit.setArmorType(EquipmentType.T_ARMOR_AEROSPACE); + } + } else { + if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_PRIMITIVE) { + unit.setArmorType(EquipmentType.T_ARMOR_PRIMITIVE_FIGHTER); + } + } + List weaponGroups = new ArrayList<>(unit.getWeaponGroupList()); + for (Mounted group : weaponGroups) { + UnitUtil.removeMounted(unit, group); + } + } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/BattleArmorUtil.java b/megameklab/src/megameklab/util/BattleArmorUtil.java new file mode 100644 index 000000000..265f923f0 --- /dev/null +++ b/megameklab/src/megameklab/util/BattleArmorUtil.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.annotations.Nullable; +import megamek.common.weapons.LegAttack; +import megamek.common.weapons.StopSwarmAttack; +import megamek.common.weapons.SwarmAttack; +import megamek.common.weapons.infantry.InfantryWeapon; + +public final class BattleArmorUtil { + + /** + * @param eq A {@link WeaponType} or {@link MiscType} + * @param ba The BattleArmor instance + * @return Whether the BA can use the equipment + */ + public static boolean isBAEquipment(EquipmentType eq, BattleArmor ba) { + if (eq instanceof MiscType) { + return eq.hasFlag(MiscType.F_BA_EQUIPMENT); + } else if (eq instanceof WeaponType) { + return isBattleArmorWeapon(eq, ba); + } + // This leaves ammotype, which is filtered according to having a weapon that can use it + return false; + } + + public static boolean isBattleArmorAPWeapon(@Nullable EquipmentType etype) { + if (!(etype instanceof InfantryWeapon)) { + return false; + } else { + InfantryWeapon infWeap = (InfantryWeapon) etype; + return infWeap.hasFlag(WeaponType.F_INFANTRY) + && !infWeap.hasFlag(WeaponType.F_INF_POINT_BLANK) + && !infWeap.hasFlag(WeaponType.F_INF_ARCHAIC) + && (infWeap.getCrew() < 2); + } + } + + public static boolean isBattleArmorWeapon(EquipmentType eq, Entity unit) { + if (eq instanceof WeaponType) { + WeaponType weapon = (WeaponType) eq; + + if (!weapon.hasFlag(WeaponType.F_BA_WEAPON)) { + return false; + } + + if (weapon.getTonnage(unit) <= 0) { + return false; + } + + if (weapon.isCapital() || weapon.isSubCapital()) { + return false; + } + + if ((eq instanceof SwarmAttack) || (eq instanceof StopSwarmAttack) + || (eq instanceof LegAttack)) { + return false; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon + .getAmmoType() == AmmoType.T_PLASMA))) { + return true; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) && (weapon.hasFlag(WeaponType.F_PLASMA)) + && (weapon.hasFlag(WeaponType.F_BA_WEAPON))) { + return true; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + && weapon.hasFlag(WeaponType.F_PLASMA) + && (weapon.getAmmoType() == AmmoType.T_NA)) + { + return false; + } + + return true; + } + + return false; + } + + public static boolean canSwarm(BattleArmor ba) { + for (Mounted eq : ba.getEquipment()) { + if ((eq.getType() instanceof SwarmAttack) + || (eq.getType() instanceof StopSwarmAttack)) { + return true; + } + } + return false; + } + + public static boolean canLegAttack(BattleArmor ba) { + for (Mounted eq : ba.getEquipment()) { + if (eq.getType() instanceof LegAttack) { + return true; + } + } + return false; + } + + private BattleArmorUtil() { } + + public static boolean isBAMultiMount(EquipmentType equip) { + return (equip instanceof WeaponType) + && (equip.hasFlag(WeaponType.F_TASER) || (((WeaponType) equip).getAmmoType() == AmmoType.T_NARC)); + } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/InfantryUtil.java b/megameklab/src/megameklab/util/InfantryUtil.java new file mode 100644 index 000000000..8b4550514 --- /dev/null +++ b/megameklab/src/megameklab/util/InfantryUtil.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.weapons.infantry.InfantryWeapon; +import org.apache.logging.log4j.LogManager; + +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public final class InfantryUtil { + + public static void replaceMainWeapon(Infantry unit, InfantryWeapon weapon, boolean secondary) { + Mounted existingInfantryMount = null; + for (Mounted m : unit.getWeaponList()) { + if ((m.getType() instanceof InfantryWeapon) + && (m.getLocation() == Infantry.LOC_INFANTRY)) { + existingInfantryMount = m; + break; + } + } + if (null != existingInfantryMount) { + UnitUtil.removeMounted(unit, existingInfantryMount); + } + if (secondary) { + unit.setSecondaryWeapon(weapon); + } else { + unit.setPrimaryWeapon(weapon); + } + // if there is more than one secondary weapon per squad, then add that + // to the unit otherwise add the primary weapon (unless the secondary + // is TAG, in which case both are added. + if (unit.getSecondaryWeapon() != null && unit.getSecondaryWeapon().hasFlag(WeaponType.F_TAG)) { + try { + unit.addEquipment(unit.getPrimaryWeapon(), Infantry.LOC_INFANTRY); + unit.addEquipment(unit.getSecondaryWeapon(), Infantry.LOC_INFANTRY); + } catch (LocationFullException ignored) { + + } + } else if ((unit.getSecondaryWeaponsPerSquad() < 2) || (null == unit.getSecondaryWeapon())) { + try { + unit.addEquipment(unit.getPrimaryWeapon(), Infantry.LOC_INFANTRY); + } catch (LocationFullException ignored) { + + } + } else { + try { + unit.addEquipment(unit.getSecondaryWeapon(), Infantry.LOC_INFANTRY); + } catch (LocationFullException ignored) { + + } + } + } + + public static void replaceFieldGun(Infantry unit, WeaponType fieldGun, int num) { + List toRemove = unit.getEquipment().stream() + .filter(m -> m.getLocation() == Infantry.LOC_FIELD_GUNS) + .collect(Collectors.toList()); + unit.getEquipment().removeAll(toRemove); + unit.getWeaponList().removeAll(toRemove); + unit.getAmmo().removeAll(toRemove); + final EnumSet munition; + if (fieldGun != null && num > 0) { + if (fieldGun.getAmmoType() == AmmoType.T_AC_LBX + || fieldGun.getAmmoType() == AmmoType.T_AC_LBX_THB) { + munition = EnumSet.of(AmmoType.Munitions.M_CLUSTER); + } else { + munition = EnumSet.of(AmmoType.Munitions.M_STANDARD); + } + Optional ammo = AmmoType.getMunitionsFor(fieldGun.getAmmoType()).stream() + .filter(eq -> (eq.getMunitionType().equals(munition)) + && (eq.getRackSize() == fieldGun.getRackSize())) + .findFirst(); + if (ammo.isEmpty()) { + ammo = AmmoType.getMunitionsFor(fieldGun.getAmmoType()).stream().findFirst(); + } + + for (int i = 0; i < num; i++) { + try { + unit.addEquipment(fieldGun, Infantry.LOC_FIELD_GUNS); + if (ammo.isPresent()) { + unit.addEquipment(ammo.get(), Infantry.LOC_FIELD_GUNS); + } else { + LogManager.getLogger().error("Could not find ammo for field gun " + fieldGun.getName()); + } + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + } + + public static String trimInfantryWeaponNames(String wname) { + return wname.replace("Infantry ", ""); + } + + public static void resetInfantryArmor(Infantry unit) { + unit.setArmorEncumbering(false); + unit.setSpaceSuit(false); + unit.setDEST(false); + unit.setSneakCamo(false); + unit.setSneakECM(false); + unit.setSneakIR(false); + unit.setArmorDamageDivisor(1.0); + } + + private InfantryUtil() { } + + public static boolean isInfantryEquipment(EquipmentType eq, Entity unit) { + // TODO: adjust for field guns and artillery + return eq instanceof InfantryWeapon; + } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/MekUtil.java b/megameklab/src/megameklab/util/MekUtil.java new file mode 100644 index 000000000..6b54a2007 --- /dev/null +++ b/megameklab/src/megameklab/util/MekUtil.java @@ -0,0 +1,1442 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMekLab. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.weapons.c3.ISC3M; +import megamek.common.weapons.c3.ISC3MBS; +import megamek.common.weapons.infantry.InfantryWeapon; +import megamek.common.weapons.lrms.LRMWeapon; +import megamek.common.weapons.lrms.LRTWeapon; +import megamek.common.weapons.missiles.MRMWeapon; +import megamek.common.weapons.missiles.RLWeapon; +import megamek.common.weapons.other.*; +import megamek.common.weapons.srms.SRMWeapon; +import megamek.common.weapons.srms.SRTWeapon; +import megamek.common.weapons.tag.CLLightTAG; +import megamek.common.weapons.tag.CLTAG; +import megamek.common.weapons.tag.ISTAG; +import megameklab.ui.PopupMessages; +import org.apache.logging.log4j.LogManager; + +import javax.swing.*; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; + +import static java.util.stream.Collectors.toSet; +import static megameklab.util.UnitUtil.*; + +public final class MekUtil { + + /** + * Checks for Clan DHS + * + * @param unit + * @return + */ + public static boolean hasClanDoubleHeatSinks(Mech unit) { + if (!unit.hasDoubleHeatSinks()) { + return false; + } + + for (Mounted mounted : unit.getMisc()) { + if (mounted.getType().hasFlag(MiscType.F_LASER_HEAT_SINK)) { + return false; + } + + if (mounted.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { + return mounted.getType().getInternalName().equals("CLDoubleHeatSink"); + } + } + + return false; + } + + /** + * Removes the specified number of heat sinks from the mek Heat sinks are + * removed first fwith LOC_NONE above the free crit limit then they are + * removed with a location, and lastly they are removed below the free crit + * limit + * + * @param unit + */ + public static void removeHeatSinks(Mech unit, int number) { + Vector toRemove = new Vector<>(); + int base = UnitUtil.getCriticalFreeHeatSinks(unit, unit.hasCompactHeatSinks()); + boolean splitCompact = false; + if (unit.hasCompactHeatSinks()) { + // first check to see if there is a single compact heat sink outside of the engine and + // remove this first if so + Mounted mount = getSingleCompactHeatSink(unit); + if ((null != mount) && (number > 0)) { + UnitUtil.removeMounted(unit, mount); + number--; + } + // if number is now uneven, then note that we will need to split a compact + if ((number % 2) == 1) { + splitCompact = true; + number--; + } + } + Vector unassigned = new Vector<>(); + Vector assigned = new Vector<>(); + Vector free = new Vector<>(); + for (Mounted m : unit.getMisc()) { + if (UnitUtil.isHeatSink(m)) { + if (m.getLocation() == Entity.LOC_NONE) { + if (base > 0) { + free.add(m); + base--; + } else { + unassigned.add(m); + } + } else { + assigned.add(m); + } + } + } + toRemove.addAll(unassigned); + toRemove.addAll(assigned); + toRemove.addAll(free); + if (unit.hasCompactHeatSinks()) { + // need to do some number magic here. The unassigned and assigned slots should each + // contain two heat sinks, but if we dip into the free then we are looking at one heat + // sink. + int numberDouble = Math.min(number / 2, unassigned.size() + assigned.size()); + int numberSingle = Math.max(0, number - (2 * numberDouble)); + number = numberDouble + numberSingle; + } + number = Math.min(number, toRemove.size()); + for (int i = 0; i < number; i++) { + Mounted eq = toRemove.get(i); + UnitUtil.removeMounted(unit, eq); + } + + if (splitCompact) { + Mounted eq = toRemove.get(number); + int loc = eq.getLocation(); + // remove singleCompact mount and replace with a double + UnitUtil.removeMounted(unit, eq); + if (!eq.getType().hasFlag(MiscType.F_HEAT_SINK)) { + try { + UnitUtil.addMounted(unit, + new Mounted(unit, EquipmentType.get("IS1 Compact Heat Sink")), loc, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + } + + /** + * adds all heat sinks to the mech + * + * @param unit + * @param hsAmount + * @param hsType + */ + public static void addHeatSinkMounts(Mech unit, int hsAmount, String hsType) { + addHeatSinkMounts(unit, hsAmount, EquipmentType.get(UnitUtil.getHeatSinkType(hsType, unit.isClan()))); + } + + /** + * adds all heat sinks to the mech + * + * @param unit + * @param hsAmount + * @param sinkType + */ + public static void addHeatSinkMounts(Mech unit, int hsAmount, EquipmentType sinkType) { + if (sinkType.hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { + addCompactHeatSinkMounts(unit, hsAmount); + } else { + for (; hsAmount > 0; hsAmount--) { + try { + unit.addEquipment(new Mounted(unit, sinkType), Entity.LOC_NONE, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + } + + public static void addCompactHeatSinkMounts(Mech unit, int hsAmount) { + // first we need to figure out how many single compacts we need to add/ for the engine, if any + int currentSinks = countActualHeatSinks(unit); + int engineCompacts = Math.min(hsAmount, UnitUtil.getCriticalFreeHeatSinks(unit, true)); + int engineToAdd = Math.max(0, engineCompacts - currentSinks); + unit.addEngineSinks("IS1 Compact Heat Sink", engineToAdd); + int restHS = hsAmount - engineToAdd; + Mounted singleCompact = getSingleCompactHeatSink(unit); + if ((restHS % 2) == 1) { + if (null == singleCompact) { + try { + unit.addEquipment(new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1)), + Entity.LOC_NONE, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } else { + int loc = singleCompact.getLocation(); + // remove singleCompact mount and replace with a double + UnitUtil.removeMounted(unit, singleCompact); + try { + UnitUtil.addMounted(unit,new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2)), + loc, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + restHS -= 1; + } + for (; restHS > 0; restHS -= 2) { + try { + unit.addEquipment(new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2)), + Entity.LOC_NONE, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + + /** + * get the single non-compact heat sink that is a non-engine sink, if it + * exits + * + * @param unit + */ + public static Mounted getSingleCompactHeatSink(Mech unit) { + int base = UnitUtil.getCriticalFreeHeatSinks(unit, true); + for (Mounted m : unit.getMisc()) { + if (m.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK) + && m.getType().hasFlag(MiscType.F_HEAT_SINK)) { + if (base <= 0) { + return m; + } else { + base--; + } + } + } + return null; + } + + public static boolean hasSameHeatSinkType(Mech unit, String type) { + // this seems like a total hack, but at present we apparently have no + // good static integer codes for this on entity + String heatSinkType = UnitUtil.getHeatSinkType(type, unit.isClan()); + for (Mounted mounted : unit.getMisc()) { + if (type.equals("Compact") + && mounted.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { + return true; + } + if (mounted.getType().hasFlag(MiscType.F_HEAT_SINK) + || mounted.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK) + || mounted.getType().hasFlag(MiscType.F_LASER_HEAT_SINK)) { + return mounted.getType().getInternalName().equals(heatSinkType); + } + } + return false; + } + + /** + * updates the heat sinks. + * + * @param unit + * @param hsAmount + * @param hsType + */ + public static void updateHeatSinks(Mech unit, int hsAmount, String hsType) { + // if we have the same type of heat sink, then we should not remove the + // existing heat sinks + int currentSinks = countActualHeatSinks(unit); + if (hasSameHeatSinkType(unit, hsType)) { + if (hsAmount < currentSinks) { + removeHeatSinks(unit, currentSinks - hsAmount); + } else if (hsAmount > currentSinks) { + addHeatSinkMounts(unit, hsAmount - currentSinks, hsType); + } + } else { + removeHeatSinks(unit, hsAmount); + addHeatSinkMounts(unit, hsAmount, hsType); + } + unit.resetSinks(); + } + + /** + * This will cycle through the heat sinks and make sure that enough of them + * are set LOC_NONE based on the basechassisheat sinks + * + * @param unit + */ + public static void updateAutoSinks(Mech unit, boolean compact) { + if (compact) { + updateCompactHeatSinks(unit); + return; + } + int base = UnitUtil.getCriticalFreeHeatSinks(unit, compact); + List unassigned = new ArrayList<>(); + List assigned = new ArrayList<>(); + for (Mounted m : unit.getMisc()) { + if (UnitUtil.isHeatSink(m)) { + if (m.getLocation() == Entity.LOC_NONE) { + unassigned.add(m); + } else if (!m.getType().hasFlag(MiscType.F_IS_DOUBLE_HEAT_SINK_PROTOTYPE)) { + // Prototype double heat sinks can never be integrated into the engine + assigned.add(m); + } + } + } + int needed = base - unassigned.size(); + if (needed <= 0) { + return; + } + for (Mounted m : assigned) { + if (needed <= 0) { + return; + } + UnitUtil.removeCriticals(unit, m); + m.setLocation(Entity.LOC_NONE); + needed--; + } + // There may be more crit-free heatsinks, but if the 'mech doesn't + // have that many heatsinks, the additional space is unused. + } + + /** + * Adjusts compact heat sinks to fulfill engine capacity. This is more complex than other heat sink + * types because the engine heat sinks always have one per mount, and those outside the engine + * are paired in a slot with one single if there are an odd number. + * + * @param mech The mech to adjust heat sinks for + */ + public static void updateCompactHeatSinks(Mech mech) { + int base = UnitUtil.getCriticalFreeHeatSinks(mech, true); + List unallocatedSingle = new ArrayList<>(); + List unallocatedPair = new ArrayList<>(); + List allocatedSingle = new ArrayList<>(); + List allocatedPair = new ArrayList<>(); + for (Mounted m : mech.getMisc()) { + if (UnitUtil.isHeatSink(m)) { + if (m.getLocation() == Entity.LOC_NONE) { + if (m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { + unallocatedPair.add(m); + } else { + unallocatedSingle.add(m); + } + } else { + if (m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { + allocatedPair.add(m); + } else { + allocatedSingle.add(m); + } + } + } + } + + int needed = base - unallocatedSingle.size(); + int toAdd = 0; + // If there are more single heat sinks than there is space for in the engine remove them so they + // can be paired up + if (needed < 0) { + int count = removeCompactHeatSinks(-needed, mech, unallocatedSingle); + needed += count; + toAdd += count; + } + // If we have more space in the engine, start by splitting unallocated double heat sinks + if (needed > 0) { + int count = removeCompactHeatSinks(needed, mech, unallocatedPair); + needed -= count; + toAdd += count; + } + // Next we pull a single out of its location, if any + if (needed > 0) { + int count = removeCompactHeatSinks(needed, mech, allocatedSingle); + needed -= count; + toAdd += count; + } + // Finally we remove as many paired heat sinks as we need to fill the engine + if (needed > 0) { + toAdd += removeCompactHeatSinks(needed, mech, allocatedPair); + } + // Now we add heat sinks back + try { + // First we add as many single heat sinks to LOC_NONE as we need to fill the engine + int engineAdd = Math.min(toAdd, base - unallocatedSingle.size()); + for (int i = 0; i < engineAdd; i++) { + mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1), Entity.LOC_NONE); + toAdd--; + } + // If we have an odd number to add and there is a single already allocated, remove it and pair them. + // Unallocated singles in excess of engine capacity have already been removed. + if (((toAdd & 1) == 1) && !allocatedSingle.isEmpty()) { + UnitUtil.removeMounted(mech, allocatedSingle.remove(0)); + mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2), Entity.LOC_NONE); + toAdd--; + } + // If we still have an odd number, add one single. + if ((toAdd & 1) == 1) { + mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1), Entity.LOC_NONE); + toAdd--; + } + // Add the remainder as unallocated pairs + for (int i = 0; i < toAdd; i += 2) { + mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2), Entity.LOC_NONE); + } + } catch (LocationFullException ignored) { + // We're added to LOC_NONE + } + } + + /** + * Removes all jump jets from the mek + * + * @param unit + */ + public static void removeJumpJets(Mech unit, int number) { + Vector toRemove = new Vector<>(); + ArrayList misceq = unit.getMisc(); + for (Mounted eq : misceq) { + if (UnitUtil.isJumpJet(eq)) { + toRemove.add(eq); + if (toRemove.size() >= number) { + break; + } + } + } + + for (Mounted eq : toRemove) { + UnitUtil.removeMounted(unit, eq); + } + } + + /** + * updates the Jump Jets. + * + * @param unit + * @param jjAmount + * @param jjType + */ + public static void updateJumpJets(Mech unit, int jjAmount, int jjType) { + unit.setOriginalJumpMP(jjAmount); + int ctype = unit.getJumpType(); + if (jjType == ctype) { + int currentJJ = (int) unit.getMisc().stream() + .filter(m -> m.getType() + .hasFlag(MiscType.F_JUMP_JET)) + .count(); + if (jjAmount < currentJJ) { + removeJumpJets(unit, currentJJ - jjAmount); + return; + } else if (jjAmount > currentJJ) { + jjAmount = jjAmount - currentJJ; + } else { + return; // No change, get the fuck outta here! + } + } else { + removeJumpJets(unit, unit.getJumpMP()); + } + // if this is the same jump jet type, then only remove if too many + // and add if too low + if (jjType == Mech.JUMP_BOOSTER) { + removeJumpJets(unit, unit.getJumpMP()); + createSpreadMounts( + unit, + EquipmentType.get(UnitUtil.getJumpJetType(jjType))); + } else { + while (jjAmount > 0) { + try { + unit.addEquipment( + new Mounted(unit, EquipmentType.get(UnitUtil.getJumpJetType(jjType))), + Entity.LOC_NONE, false); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + jjAmount--; + } + } + } + + /** + * Removes all enhancements (TSM and MASC) from the mek + * + * @param unit + */ + public static void removeEnhancements(Mech unit) { + ConcurrentLinkedQueue equipmentList = new ConcurrentLinkedQueue<>(unit.getMisc()); + for (Mounted eq : equipmentList) { + if (UnitUtil.isTSM(eq.getType()) || UnitUtil.isMASC(eq.getType()) + || ((eq.getType() instanceof MiscType) && eq.getType().hasFlag(MiscType.F_SCM))) { + UnitUtil.removeCriticals(unit, eq); + } + } + for (Mounted eq : equipmentList) { + if (UnitUtil.isTSM(eq.getType()) || UnitUtil.isMASC(eq.getType()) + || ((eq.getType() instanceof MiscType) && eq.getType().hasFlag(MiscType.F_SCM))) { + unit.getMisc().remove(eq); + unit.getEquipment().remove(eq); + } + } + } + + /** + * Compacts the crit slots in all locations of the given Mek, moving Empty slots to the bottom. + */ + public static void compactCriticals(Mech mek) { + for (int loc = 0; loc < mek.locations(); loc++) { + compactCriticals(mek, loc); + } + } + + /** + * Compacts the crit slots in the given location of the given Mek, moving Empty slots to the bottom. + */ + public static void compactCriticals(Mech mek, int location) { + List presentGear = MekUtil.extricateCritSlots(mek, location); + MekUtil.refillCritSlots(mek, location, presentGear); + } + + /** + * Expands crits that are a single mount by have multiple spreadable crits + * Such as TSM, Endo Steel, Reactive armor. + * + * @param unit + */ + public static void expandUnitMounts(Mech unit) { + for (int location = 0; location < unit.locations(); location++) { + for (int slot = 0; slot < unit.getNumberOfCriticals(location); slot++) { + CriticalSlot cs = unit.getCritical(location, slot); + if ((cs == null) || (cs.getType() == CriticalSlot.TYPE_SYSTEM)) { + continue; + } + Mounted mount = cs.getMount(); + + if (!UnitUtil.isFixedLocationSpreadEquipment(mount.getType()) + && (UnitUtil.isTSM(mount.getType()) + || UnitUtil.isArmorOrStructure(mount.getType()))) { + Mounted newMount = new Mounted(unit, mount.getType()); + newMount.setLocation(location, mount.isRearMounted()); + newMount.setArmored(mount.isArmored()); + cs.setMount(newMount); + cs.setArmored(mount.isArmored()); + unit.getEquipment().remove(mount); + unit.getMisc().remove(mount); + unit.getEquipment().add(newMount); + unit.getMisc().add(newMount); + } + } + } + } + + /** + * create a Mounted and corresponding CriticalSlots for the passed in + * EquipmentType on the passed in Mech + * + * @param unit + * @param equip + * @return + */ + public static Mounted createSpreadMounts(Mech unit, EquipmentType equip) { + // how many non-spreadable contiguous blocks of crits? + int blocks = equip.getCriticals(unit); + + boolean isMisc = equip instanceof MiscType; + + List locations = new ArrayList<>(); + + if (isMisc) { + if ((equip.hasFlag(MiscType.F_INDUSTRIAL_TSM) || equip.hasFlag(MiscType.F_TSM))) { + // all crits user placeable + for (int i = 0; i < equip.getCriticals(unit); i++) { + locations.add(Entity.LOC_NONE); + } + } else if (equip.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING)) { + // 1 crit in each location + for (int i = 0; i < unit.locations(); i++) { + locations.add(i); + } + } else if (equip.hasFlag(MiscType.F_STEALTH)) { + // 2 in arms, legs, side torsos + locations.add(Mech.LOC_LLEG); + locations.add(Mech.LOC_RLEG); + locations.add(Mech.LOC_LARM); + locations.add(Mech.LOC_RARM); + locations.add(Mech.LOC_LT); + locations.add(Mech.LOC_RT); + blocks = 6; + // Need to account for the center leg + if (unit instanceof TripodMech) { + locations.add(Mech.LOC_CLEG); + blocks++; + } + } else if (equip.hasFlag(MiscType.F_SCM)) { + // 1 in arms, legs, side torsos + locations.add(Mech.LOC_LLEG); + locations.add(Mech.LOC_RLEG); + locations.add(Mech.LOC_LARM); + locations.add(Mech.LOC_RARM); + locations.add(Mech.LOC_LT); + locations.add(Mech.LOC_RT); + blocks = 6; + } else if ((equip.hasFlag(MiscType.F_TRACKS) || equip.hasFlag(MiscType.F_TALON) + || equip.hasFlag(MiscType.F_JUMP_BOOSTER))) { + // 1 block in each leg + locations.add(Mech.LOC_LLEG); + locations.add(Mech.LOC_RLEG); + if (unit instanceof QuadMech) { + locations.add(Mech.LOC_LARM); + locations.add(Mech.LOC_RARM); + } + blocks = (unit instanceof BipedMech ? 2 : 4); + // Need to account for the center leg + if (unit instanceof TripodMech) { + locations.add(Mech.LOC_CLEG); + blocks = 3; + } + } else if (equip.hasFlag(MiscType.F_PARTIAL_WING)) { + // one block in each side torso + locations.add(Mech.LOC_LT); + locations.add(Mech.LOC_RT); + blocks = 2; + } else if (equip.hasFlag(MiscType.F_RAM_PLATE)) { + // one block in each torso + locations.add(Mech.LOC_LT); + locations.add(Mech.LOC_RT); + locations.add(Mech.LOC_CT); + blocks = 3; + } else if ((equip.hasFlag(MiscType.F_VOIDSIG) + || equip.hasFlag(MiscType.F_NULLSIG) + || equip.hasFlag(MiscType.F_BLUE_SHIELD))) { + // Need to account for the center leg + if (unit instanceof TripodMech) { + blocks++; + } + // 1 crit in each location, except the head + for (int i = Mech.LOC_CT; i < unit.locations(); i++) { + locations.add(i); + } + } else if (equip.hasFlag(MiscType.F_CHAMELEON_SHIELD)) { + // Need to account for the center leg + if (unit instanceof TripodMech) { + blocks++; + } + // 1 crit in each location except head and CT + for (int i = Mech.LOC_RT; i < unit.locations(); i++) { + locations.add(i); + } + } + } + + boolean firstBlock = true; + Mounted mount = new Mounted(unit, equip); + for (; blocks > 0; blocks--) { + // how many crits per block? + int crits = UnitUtil.getCritsUsed(mount); + for (int i = 0; i < crits; i++) { + try { + if (firstBlock || (locations.get(0) == Entity.LOC_NONE)) { + // create only one mount per equipment, for BV and stuff + UnitUtil.addMounted(unit, mount, locations.get(0), false); + if (firstBlock) { + firstBlock = false; + } + if (locations.get(0) == Entity.LOC_NONE) { + // only user-placable spread stuff gets location none + // for those, we need to create a mount for each crit, + // otherwise we can't correctly let the user place them + // luckily, that only affects TSM, so BV works out correctly + mount = new Mounted(unit, equip); + } + } else { + CriticalSlot cs = new CriticalSlot(mount); + if (!unit.addCritical(locations.get(0), cs)) { + UnitUtil.removeCriticals(unit, mount); + JOptionPane.showMessageDialog( + null, + "No room for equipment", + mount.getName() + + " does not fit into " + + unit.getLocationName(locations.get(0)), + JOptionPane.INFORMATION_MESSAGE); + unit.getMisc().remove(mount); + unit.getEquipment().remove(mount); + return null; + } + } + } catch (LocationFullException lfe) { + PopupMessages.showLocationFullError(null, mount.getName()); + LogManager.getLogger().error(lfe); + unit.getMisc().remove(mount); + unit.getEquipment().remove(mount); + return null; + } + } + locations.remove(0); + } + return mount; + } + + public static boolean isLastMechCrit(Mech unit, CriticalSlot cs, int slot, int location) { + if (cs == null) { + return true; + } + // extra check for the last crit in a location, it shouldn't get a border + if ((slot + 1) >= unit.getNumberOfCriticals(location)) { + return false; + } + + int lastIndex = 0; + if (cs.getType() == CriticalSlot.TYPE_SYSTEM) { + + for (int position = 0; position < unit.getNumberOfCriticals(location); position++) { + if ((cs.getIndex() == Mech.SYSTEM_ENGINE) && (slot >= 3) && (position < 3)) { + position = 3; + } + CriticalSlot crit = unit.getCritical(location, position); + + if ((crit != null) + && (crit.getType() == CriticalSlot.TYPE_SYSTEM) + && (crit.getIndex() == cs.getIndex())) { + lastIndex = position; + } else if (position > slot) { + break; + } + } + } else { + CriticalSlot nextCrit = unit.getCritical(location, slot + 1); + return (nextCrit == null) || (nextCrit.getMount() == null) || !nextCrit.getMount().equals(cs.getMount()); + } + + return slot == lastIndex; + } + + public static void updateLoadedMech(Mech unit) { + expandUnitMounts(unit); + UnitUtil.checkArmor(unit); + } + + public static int countUsedCriticals(Mech unit) { + int nCrits = 0; + for (int i = 0; i < unit.locations(); i++) { + for (int j = 0; j < unit.getNumberOfCriticals(i); j++) { + CriticalSlot cs = unit.getCritical(i, j); + if (null != cs) { + nCrits++; + } + } + } + return nCrits + countUnallocatedCriticals(unit); + } + + public static int countUnallocatedCriticals(Mech unit) { + int nCrits = 0; + int engineHeatSinkCount = UnitUtil.getCriticalFreeHeatSinks(unit, + unit.hasCompactHeatSinks()); + for (Mounted mount : unit.getMisc()) { + if (UnitUtil.isHeatSink(mount) + && (mount.getLocation() == Entity.LOC_NONE)) { + if (engineHeatSinkCount > 0) { + engineHeatSinkCount--; + continue; + } + } + if ((mount.getLocation() == Entity.LOC_NONE)) { + nCrits += UnitUtil.getCritsUsed(mount); + } + } + for (Mounted mount : unit.getWeaponList()) { + if (mount.getLocation() == Entity.LOC_NONE) { + nCrits += UnitUtil.getCritsUsed(mount); + } + } + for (Mounted mount : unit.getAmmo()) { + if ((mount.getLocation() == Entity.LOC_NONE) && !mount.isOneShotAmmo()) { + nCrits += UnitUtil.getCritsUsed(mount); + } + } + return nCrits; + } + + // gives total number of sinks, not just critical slots + public static int countActualHeatSinks(Mech unit) { + int sinks = 0; + for (Mounted mounted : unit.getMisc()) { + if (!UnitUtil.isHeatSink(mounted)) { + continue; + } + if (mounted.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { + if (mounted.getType().hasFlag(MiscType.F_HEAT_SINK)) { + sinks++; + } else if (mounted.getType().hasFlag( + MiscType.F_DOUBLE_HEAT_SINK)) { + sinks++; + sinks++; + } + } else { + sinks++; + } + } + return sinks; + } + + public static void removeHand(Mech mech, int location) { + if (mech.hasSystem(Mech.ACTUATOR_HAND, location)) { + mech.setCritical(location, 3, null); + } + } + + public static void removeArm(Mech mech, int location) { + if (mech.hasSystem(Mech.ACTUATOR_LOWER_ARM, location)) { + mech.setCritical(location, 2, null); + // Only remove the next slot of it actually is a hand + if (mech.hasSystem(Mech.ACTUATOR_HAND, location)) { + removeHand(mech, location); + } + } + } + + /** + * Called by {@link MekUtil#updateCompactHeatSinks(Mech)} to remove heat sinks up to a certain number. + * The actual number removed could be higher if count is odd and we're removing pairs, or + * lower if there aren't enough in the list. + * + * @param count The number of heat sinks to remove + * @param mech The mech to remove heat sinks from + * @param hsList The list of heat sinks available for removal + * @return The actual number removed + */ + private static int removeCompactHeatSinks(int count, Mech mech, List hsList) { + int removed = 0; + for (Iterator iter = hsList.iterator(); iter.hasNext(); ) { + Mounted m = iter.next(); + UnitUtil.removeMounted(mech, m); + removed += m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK) ? 2 : 1; + iter.remove(); + if (removed >= count) { + break; + } + } + return removed; + } + + private MekUtil() { } + + /** + * Clears all links of the given equipment to other equipment and unallocates + * it (assigns to LOC_NONE). Note: Does not clear the equipment's crit slots from its + * former location. For this, use {@link UnitUtil#removeCriticals(Entity, Mounted)} + */ + public static void clearMountedLocationAndLinked(Mounted equipment) { + if ((Entity.LOC_NONE != equipment.getLocation()) && !equipment.isOneShot()) { + if (equipment.getLinked() != null) { + equipment.getLinked().setLinkedBy(null); + equipment.setLinked(null); + } + if (equipment.getLinkedBy() != null) { + equipment.getLinkedBy().setLinked(null); + equipment.setLinkedBy(null); + } + } + equipment.setLocation(Entity.LOC_NONE, false); + equipment.setSecondLocation(Entity.LOC_NONE, false); + equipment.setSplit(false); + } + + /** + * Moves all equipment that is freely movable and unhittable (e.g. Endo Steel and + * Ferro-Fibrous but not CASE) ("FMU") that is currently unallocated (LOC_NONE) to free + * locations on the Mek as long as there are any. + */ + public static void fillInFMU(Mech mek) { + // Work with a copy because the equipment list may be modified. + for (Mounted mount : new ArrayList<>(mek.getEquipment())) { + if (!isFMU(mount) || (mount.getLocation() != Entity.LOC_NONE)) { + continue; + } + for (int location = 0; location < mek.locations(); location++) { + if (!isValidLocation(mek, mount.getType(), location) + || (getMaxContiguousNumOfCrits(mek, location, false) < getCritsUsed(mount))) { + continue; + } + try { + addMounted(mek, mount, location, false); + changeMountStatus(mek, mount, location, Entity.LOC_NONE, false); + break; + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + } + + /** + * Removes all equipment that is freely movable and unhittable (e.g. Endo Steel and + * Ferro-Fibrous but not CASE) ("FMU") from the given location, affecting numOfSlots + * slots beginning at startingSlot. + */ + public static void removeFMU(Entity mech, int location, int startingSlot, int numOfSlots) { + for (int slot = startingSlot; slot < startingSlot + numOfSlots; slot++) { + CriticalSlot critSlot = mech.getCritical(location, slot); + if ((critSlot != null) && isFMU(critSlot.getMount())) { + Mounted mounted = critSlot.getMount(); + UnitUtil.removeCriticals(mech, mounted); + UnitUtil.changeMountStatus(mech, mounted, Entity.LOC_NONE, Entity.LOC_NONE, false); + } + } + } + + /** + * Moves all equipment that is currently unallocated (LOC_NONE) to free + * locations on the Mek as long as there are any. + */ + public static void fillInAllEquipment(Mech mek) { + int externalEngineHS = UnitUtil.getCriticalFreeHeatSinks(mek, mek.hasCompactHeatSinks()); + for (Mounted mount : mek.getEquipment()) { + if ((mount.getLocation() != Entity.LOC_NONE) + || (UnitUtil.isHeatSink(mount) && (externalEngineHS-- > 0))) { + continue; + } + for (int location = Mech.LOC_HEAD; location < mek.locations(); location++) { + if (!UnitUtil.isValidLocation(mek, mount.getType(), location)) { + continue; + } + int critsUsed = UnitUtil.getCritsUsed(mount); + if (critsUsed > UnitUtil.getHighestContinuousNumberOfCrits(mek, location)) { + continue; + } + try { + if (mount.getType().isSpreadable() || (mount.isSplitable() && (critsUsed > 1))) { + for (int count = 0; count < critsUsed; count++) { + UnitUtil.addMounted(mek, mount, location, false); + } + } else { + UnitUtil.addMounted(mek, mount, location, false); + } + UnitUtil.changeMountStatus(mek, mount, location, Entity.LOC_NONE, false); + break; + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + } + } + + /** + * Returns true when a slot's equipment is unhittable and freely movable ("FMU"), such + * as Endo Steel and Ferro-Fibrous Armor but not CASE (which is unhittable but not + * freely movable as its location is important). + */ + public static boolean isFMU(Mounted equipment) { + return (equipment != null) + && !equipment.getType().isHittable() + && (equipment.getType() instanceof MiscType) + && !equipment.getType().hasFlag(MiscType.F_CASE) + && !equipment.getType().hasFlag(MiscType.F_CASEP) + && !equipment.getType().hasFlag(MiscType.F_CASEII); + } + + /** + * Sorts the allocated equipment on all locations (except HD) of the Mek using + * the officially used sort order. + */ + public static void sortCrits(Mech mek) { + for (int location = 0; location < mek.locations(); location++) { + if (location != Mech.LOC_HEAD) { + sortCritSlots(mek, location); + } + } + } + + /** + * Sorts the crits within the given location. This extricates all non-system + * crits from the location, sorts them and then refills the location. + */ + public static void sortCritSlots(Mech mek, int location) { + List presentGear = extricateCritSlots(mek, location); + presentGear.sort(new MekCritSlotSorter(mek)); + presentGear = reOrderLinkedEquipment(presentGear); + refillCritSlots(mek, location, presentGear); + } + + /** + * Removes all crit slots from the given location except for system crit slots + * (e.g. engine) and returns them as a list. + */ + public static List extricateCritSlots(Mech mek, int location) { + List presentGear = new ArrayList<>(); + for (int slot = 0; slot < mek.getNumberOfCriticals(location); slot++) { + CriticalSlot critSlot = mek.getCritical(location, slot); + if ((critSlot != null) && (critSlot.getType() == CriticalSlot.TYPE_EQUIPMENT)) { + presentGear.add(critSlot); + mek.setCritical(location, slot, null); + } + } + return presentGear; + } + + /** + * Fills the given list of crit slots into the given location. This does not check + * or change the respective mounteds' locations, so care must be taken that all + * mounteds are indeed allocated to this location or that the crit slots have been + * taken from this location, e.g. with {@link #extricateCritSlots(Mech, int)}. + */ + public static void refillCritSlots(Mech mek, int location, List critList) { + //TODO: If they somehow dont fit, unallocate the mounted and remove all its critslots + critList.forEach(critSlot -> mek.addCritical(location, critSlot)); + } + + /** + * Returns a reordered version of the given presentGear list of critslots wherein + * LinkedBy mounteds such as Artemis and PPC Capacitors are placed directly behind + * their weapon. + */ + public static List reOrderLinkedEquipment(List presentGear) { + List resortedList = new ArrayList<>(); + Set presentMounteds = presentGear.stream().map(CriticalSlot::getMount).collect(toSet()); + // Assemble all the linked gear that is not ammo (ammo is sorted differently) + Set linkedMounteds = presentMounteds.stream() + .map(Mounted::getLinkedBy) + .filter(Objects::nonNull) + .filter(linked -> linked.getType() instanceof MiscType) + .filter(presentMounteds::contains) + .collect(toSet()); + + // Now rebuild the list by adding the linkedMounteds behind their weapon + Mounted lastMounted = null; + for (CriticalSlot critSlot : presentGear) { + Mounted currentMounted = critSlot.getMount(); + // after one mounted is fully added, see if there's a linkedMounted to add below it + if ((lastMounted != null) + && (currentMounted != lastMounted) + && (lastMounted.getLinkedBy() != null) + && (linkedMounteds.contains(lastMounted.getLinkedBy()))) { + for (CriticalSlot linkedSlot : presentGear) { + if (linkedSlot.getMount() == lastMounted.getLinkedBy()) { + resortedList.add(linkedSlot); + } + } + } + // Add the current crit slot but exclude the linkedMounteds as they are added behind their weapon + if (!linkedMounteds.contains(critSlot.getMount())) { + resortedList.add(critSlot); + } + lastMounted = currentMounted; + } + return resortedList; + } + + /** + * Returns a number indicating the order in which equipment should be sorted + * within a location according to the official crit slot sorting. Weapons and + * ammo require further internal sorting and linked equipment such as Artemis and PPC + * Capacitors also require extra treatment to be placed behind their weapon. + */ + public static int getCoarseOrdering(Mech mek, Mounted mounted) { + if (isPartialWing(mounted)) { + return 1; + } else if (UnitUtil.isHeatSink(mounted)) { + return 2; + } else if (UnitUtil.isJumpJet(mounted)) { + return 3; + } else if (isMechWeapon(mounted.getType(), mek)) { + return 4; + } else if (mounted.getType() instanceof AmmoType) { + return 5; + } else if (mounted.getType().isHittable()) { + return 6; + } else if (isCASE(mounted)) { + return 7; + } else if (EquipmentType.isStructureType(mounted.getType())) { + return 8; + } else if (EquipmentType.isArmorType(mounted.getType())) { + return 9; + } else { + return 10; + } + } + + public static boolean isPartialWing(Mounted mounted) { + return (mounted.getType() instanceof MiscType) + && mounted.getType().hasFlag(MiscType.F_PARTIAL_WING); + } + + public static boolean isCASE(Mounted mounted) { + return (mounted.getType() instanceof MiscType) + && (mounted.getType().hasFlag(MiscType.F_CASE) + || mounted.getType().hasFlag(MiscType.F_CASEP) + || mounted.getType().hasFlag(MiscType.F_CASEII)); + } + + /** + * Returns the highest number of contiguous free crit slots available in the given location. + * When ignoreFMU is true, slots that contain unhittable and freely moveable (FMU) equipment + * such as Endo Steel are counted as being free. + */ + public static int getMaxContiguousNumOfCrits(Mech mek, int location, boolean ignoreFMU) { + if ((location == Entity.LOC_DESTROYED) || (location == Entity.LOC_NONE)) { + return 0; + } + int maxNumOfCrits = 0; + for (int slot = 0; slot < mek.getNumberOfCriticals(location); slot++) { + maxNumOfCrits = Math.max(availableContiguousCrits(mek, location, slot, ignoreFMU), maxNumOfCrits); + } + return maxNumOfCrits; + } + + /** + * Returns the first slot in the location that together with following slots + * forms a contiguous block of the given length as size where all slots + * are either empty of contain freely movable crits such as Endo Steel. + * Returns -1 if there is no such slot. + */ + public static int findSlotWithContiguousNumOfCrits(Entity mech, int location, int length) { + for (int slot = 0; slot < mech.getNumberOfCriticals(location); slot++) { + if (canFreeContiguousCrits(mech, location, slot, length)) { + return slot; + } + } + return -1; + } + + /** + * Returns true when numOfSlots contiguous slots starting from startingSlot are either free or + * can be freed by removing unhittable and movable equipment such as Endo Steel. + */ + public static boolean canFreeContiguousCrits(Entity mek, int location, int startingSlot, int numOfSlots) { + return availableContiguousCrits(mek, location, startingSlot, true) >= numOfSlots; + } + + /** + * Returns the number of contiguous slots starting from startingSlot that are either free or + * can be freed by removing unhittable and movable (FMU) equipment such as Endo Steel. + * When ignoreFMU is true, slots that contain unhittable and freely moveable (FMU) equipment + * such as Endo Steel are counted as being free. + */ + public static int availableContiguousCrits(Entity mek, int location, int startingSlot, boolean ignoreFMU) { + for (int slot = startingSlot; slot < mek.getNumberOfCriticals(location); slot++) { + CriticalSlot critSlot = mek.getCritical(location, slot); + if ((critSlot != null) && !(ignoreFMU && isFMU(critSlot.getMount()))) { + return slot - startingSlot; + } + } + return mek.getNumberOfCriticals(location) - startingSlot; + } + + /** Add a vehicular grenade launcher, asking the user for the facing. */ + public static boolean addVGL(Mech mek, Mounted vgl, int location, int slotNumber) + throws LocationFullException { + String[] facings; + if (location == Mech.LOC_LT) { + facings = new String[4]; + facings[0] = "Front"; + facings[1] = "Front-Left"; + facings[2] = "Rear-Left"; + facings[3] = "Rear"; + } else if (location == Mech.LOC_RT) { + facings = new String[4]; + facings[0] = "Front"; + facings[1] = "Front-Right"; + facings[2] = "Rear-Right"; + facings[3] = "Rear"; + } else if (location == Mech.LOC_CT) { + facings = new String[2]; + facings[0] = "Front"; + facings[1] = "Rear"; + } else { + JOptionPane.showMessageDialog(null, + "VGL must be placed in torso location!", + "Invalid location", + JOptionPane.WARNING_MESSAGE); + return false; + } + String facing = (String)JOptionPane.showInputDialog(null, + "Please choose the facing of the VGL", + "Choose Facing", JOptionPane.QUESTION_MESSAGE, + null, facings, facings[0]); + if (facing == null) { + return false; + } + mek.addEquipment(vgl, location, false, slotNumber); + UnitUtil.changeMountStatus(mek, vgl, location, -1, false); + if (facing.equals("Front-Left")) { + vgl.setFacing(5); + } else if (facing.equals("Front-Right")) { + vgl.setFacing(1); + } else if (facing.equals("Rear-Right")) { + vgl.setFacing(2); + } else if (facing.equals("Rear-Left")) { + vgl.setFacing(4); + } else if (facing.equals("Rear")) { + vgl.setFacing(3); + UnitUtil.changeMountStatus(mek, vgl, location, -1, true); + } + return true; + } + + /** + * For the given Mek, adds Clan CASE in every location that has potentially + * explosive equipment (this includes PPC Capacitors) and removes it from all + * other locations. + * Calls {@link Mech#addClanCase()}. This method does not check if other + * CASE types are already present on a location. + * + * @param mek the mek to update + */ + public static void updateClanCasePlacement(Mech mek) { + if (mek.isClan()) { + removeAllMounteds(mek, EquipmentType.get(EquipmentTypeLookup.CLAN_CASE)); + mek.addClanCase(); + } + } + + /** + * Returns true if the given Equipment is available as equipment to the given Mek. + * Only valid to use for MiscTypes, not WeaponTypes nor AmmoTypes, also physical + * weapons return false despite being MiscType. + * + * @param eq The tested equipment + * @param unit The Mek unit + * @return true if the equipment is usable by the Mek + */ + // TODO: Make this behave like the other isXYZEquipment + public static boolean isMechEquipment(EquipmentType eq, Mech unit) { + if (UnitUtil.isArmorOrStructure(eq)) { + return false; + } + + if ((eq instanceof CLTAG) || (eq instanceof ISC3MBS) + || (eq instanceof ISC3M) || (eq instanceof ISTAG) + || (eq instanceof AmmoType && ((AmmoType) eq).getAmmoType() == AmmoType.T_COOLANT_POD) + || (eq instanceof CLLightTAG) || (eq instanceof ISAMS) + || (eq instanceof CLAMS) || (eq instanceof ISLaserAMS) + || (eq instanceof CLLaserAMS) || (eq instanceof ISAPDS)) { + return true; + } + + if ((eq instanceof MiscType)) { + if (eq.isAnyOf(EquipmentTypeLookup.LAM_FUEL_TANK, EquipmentTypeLookup.LAM_BOMB_BAY) + && !(unit instanceof LandAirMech)) { + return false; + } + if ((eq.hasFlag(MiscType.F_QUAD_TURRET) || eq.hasFlag(MiscType.F_RAM_PLATE)) + && !(unit instanceof QuadMech)) { + return false; + } + + if (!((unit instanceof BipedMech) || (unit instanceof TripodMech)) + && (eq.hasFlag(MiscType.F_SHOULDER_TURRET))) { + return false; + } + + if (unit.isSuperHeavy() + && (eq.hasFlag(MiscType.F_ACTUATOR_ENHANCEMENT_SYSTEM) + || eq.hasFlag(MiscType.F_MASC) // to catch Supercharger + || eq.hasFlag(MiscType.F_SCM) + || eq.hasFlag(MiscType.F_MODULAR_ARMOR) + || eq.hasFlag(MiscType.F_PARTIAL_WING) + || eq.hasFlag(MiscType.F_UMU))) { + return false; + } + + if ((unit instanceof LandAirMech) + && ((eq.hasFlag(MiscType.F_MASC) && eq.getSubType() == MiscType.S_SUPERCHARGER) + || eq.hasFlag(MiscType.F_MODULAR_ARMOR) + || eq.hasFlag(MiscType.F_JUMP_BOOSTER) + || eq.hasFlag(MiscType.F_PARTIAL_WING) + || eq.hasFlag(MiscType.F_VOIDSIG) + || eq.hasFlag(MiscType.F_NULLSIG) + || eq.hasFlag(MiscType.F_BLUE_SHIELD) + || eq.hasFlag(MiscType.F_CHAMELEON_SHIELD) + || eq.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING) + || eq.hasFlag(MiscType.F_DUMPER) + || eq.hasFlag(MiscType.F_HEAVY_BRIDGE_LAYER) + || eq.hasFlag(MiscType.F_MEDIUM_BRIDGE_LAYER) + || eq.hasFlag(MiscType.F_LIGHT_BRIDGE_LAYER) + || (eq.hasFlag(MiscType.F_CLUB) + && (eq.getSubType() == MiscType.S_BACKHOE) + || (eq.getSubType() == MiscType.S_COMBINE)))) { + return false; + } + + if (eq.hasFlag(MiscType.F_FUEL)) { + return unit.isIndustrial() + && ((unit.getEngine().getEngineType() == Engine.COMBUSTION_ENGINE) + || (unit.getEngine().getEngineType() == Engine.FUEL_CELL)); + } + if (eq.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING) || eq.is("Cargo Container (10 tons)")) { + return unit.isIndustrial(); + } + + if (eq.hasFlag(MiscType.F_MECH_EQUIPMENT) + && !eq.hasFlag(MiscType.F_CLUB) + && !eq.hasFlag(MiscType.F_HAND_WEAPON) + && !eq.hasFlag(MiscType.F_TALON)) { + return true; + } + + if (eq.hasFlag(MiscType.F_IS_DOUBLE_HEAT_SINK_PROTOTYPE)) { + return true; + } + } + + return false; + } + + public static boolean isMechWeapon(EquipmentType eq, Entity unit) { + if (eq instanceof InfantryWeapon) { + return false; + } + + if (UnitUtil.isHeatSink(eq) || UnitUtil.isArmorOrStructure(eq) + || UnitUtil.isJumpJet(eq) + || isMechEquipment(eq, (Mech) unit)) { + return false; + } + + if (eq instanceof AmmoType) { + return false; + } + + if (eq instanceof WeaponType) { + + WeaponType weapon = (WeaponType) eq; + + if (!weapon.hasFlag(WeaponType.F_MECH_WEAPON)) { + return false; + } + + if (weapon.getTonnage(unit) <= 0) { + return false; + } + + if (weapon.isCapital() || weapon.isSubCapital()) { + return false; + } + + if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) + && (weapon.getRackSize() != 5) + && (weapon.getRackSize() != 10) + && (weapon.getRackSize() != 15) + && (weapon.getRackSize() != 20)) { + return false; + } + if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) + && (weapon.getRackSize() != 2) + && (weapon.getRackSize() != 4) + && (weapon.getRackSize() != 6)) { + return false; + } + if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon + .getAmmoType() == AmmoType.T_PLASMA))) { + + if (weapon.hasFlag(WeaponType.F_ENERGY) + && weapon.hasFlag(WeaponType.F_PLASMA) + && (weapon.getAmmoType() == AmmoType.T_NA)) { + return false; + } + } + + if ((unit instanceof LandAirMech) + && (weapon.getAmmoType() == AmmoType.T_GAUSS_HEAVY + || weapon.getAmmoType() == AmmoType.T_IGAUSS_HEAVY)) { + return false; + } + + return true; + } + return false; + } + + /** + * A location CriticalSlot sorter using the official sort order (mostly) + */ + public static class MekCritSlotSorter implements Comparator { + + private final MekMountedSorter mountedSorter; + + public MekCritSlotSorter(Mech mek) { + mountedSorter = new MekMountedSorter(mek); + } + + @Override + public int compare(CriticalSlot critA, CriticalSlot critB) { + return mountedSorter.compare(critA.getMount(), critB.getMount()); + } + } + + /** + * A Mounted sorter using the official sort order (mostly) + */ + public static class MekMountedSorter implements Comparator { + + private final Mech mek; + + public MekMountedSorter(Mech mek) { + this.mek = mek; + } + + @Override + public int compare(Mounted mountedA, Mounted mountedB) { + int coarseOrderA = getCoarseOrdering(mek, mountedA); + int coarseOrderB = getCoarseOrdering(mek, mountedB); + if ((coarseOrderA == 4) && (coarseOrderB == 4)) { + // compare average damage; using Aero damage here + double dmgA = 0; + double dmgB = 0; + if (mountedA.getType() instanceof WeaponType) { + dmgA = ((WeaponType) mountedA.getType()).getShortAV(); + } + if (mountedB.getType() instanceof WeaponType) { + dmgB = ((WeaponType) mountedB.getType()).getShortAV(); + } + if (dmgA != dmgB) { + return (dmgA > dmgB) ? -1 : 1; + } else { + // equal damage, compare crits + int critsA = mountedA.getCriticals(); + int critsB = mountedB.getCriticals(); + if (critsA != critsB) { + return (critsA > critsB) ? -1 : 1; + } else { + // equal crits, compare weight + double weightA = mountedA.getType().getTonnage(mek); + double weightB = mountedB.getType().getTonnage(mek); + return Double.compare(weightB, weightA); + } + } + } else if ((coarseOrderA == 5) && (coarseOrderB == 5)) { + AmmoType ammoA = (AmmoType) mountedA.getType(); + AmmoType ammoB = (AmmoType) mountedB.getType(); + int dmgA = ammoA.getRackSize() * ammoA.getDamagePerShot(); + int dmgB = ammoB.getRackSize() * ammoB.getDamagePerShot(); + return Integer.compare(dmgB, dmgA); + } else { + return Integer.compare(coarseOrderA, coarseOrderB); + } + } + } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/ProtoMekUtil.java b/megameklab/src/megameklab/util/ProtoMekUtil.java new file mode 100644 index 000000000..494e56287 --- /dev/null +++ b/megameklab/src/megameklab/util/ProtoMekUtil.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.verifier.TestProtomech; + +public final class ProtoMekUtil { + + public static boolean isProtomechEquipment(EquipmentType eq, Protomech proto) { + return isProtomechEquipment(eq, proto, false); + } + + public static boolean isProtomechEquipment(EquipmentType eq, Protomech proto, boolean checkConfiguration) { + if (checkConfiguration && (eq instanceof MiscType)) { + if (eq.hasFlag(MiscType.F_MAGNETIC_CLAMP) && (proto.isQuad() || proto.isGlider())) { + return false; + } + if (eq.hasFlag(MiscType.F_CLUB) && eq.hasSubType(MiscType.S_PROTOMECH_WEAPON) && proto.isQuad()) { + return false; + } + if (eq.hasFlag(MiscType.F_CLUB) && eq.hasSubType(MiscType.S_PROTO_QMS) && !proto.isQuad()) { + return false; + } + } + if (eq instanceof MiscType) { + return eq.hasFlag(MiscType.F_PROTOMECH_EQUIPMENT); + } else if (eq instanceof WeaponType) { + return eq.hasFlag(WeaponType.F_PROTO_WEAPON); + } + return true; + } + + /** Adds the given number of shots to the already present given ammo on the given ProtoMek. */ + public static void addProtoMechAmmo(Protomech entity, EquipmentType ammo, int shots) throws LocationFullException { + Mounted aMount = entity.getAmmo().stream() + .filter(m -> ammo.equals(m.getType())).findFirst().orElse(null); + if (null != aMount) { + aMount.setShotsLeft(aMount.getUsableShotsLeft() + shots); + } else { + Mounted mount = new Mounted(entity, ammo); + entity.addEquipment(mount, Protomech.LOC_BODY, false); + mount.setShotsLeft(shots); + } + } + + /** + * Subtracts the given number of shots from the given ammo on the given ProtoMek. + * May remove the entire Mounted from the ProtoMek. + */ + public static void reduceProtoMechAmmo(Protomech entity, EquipmentType ammo, int shots) { + Mounted aMount = entity.getAmmo().stream() + .filter(m -> ammo.equals(m.getType())).findFirst().orElse(null); + if (aMount != null) { + if (aMount.getUsableShotsLeft() <= shots) { + UnitUtil.removeMounted(entity, aMount); + } else { + aMount.setShotsLeft(aMount.getUsableShotsLeft() - shots); + } + } + } + + private ProtoMekUtil() { } + + /** + * Checks whether the space has room for the equipment within the slot and weight limits. + * + * @param location A ProtoMek location + * @param mount The equipment to be added to the location + * @return Whether the equipment can be added without exceeding the limits. + */ + public static boolean protomechHasRoom(Protomech proto, int location, Mounted mount) { + if (!TestProtomech.requiresSlot(mount.getType())) { + return true; + } + int slots = TestProtomech.maxSlotsByLocation(location, proto) - 1; + double weight = TestProtomech.maxWeightByLocation(location, proto) + - mount.getTonnage(); + if ((slots < 0) || (weight < 0)) { + return false; + } + for (Mounted m : proto.getEquipment()) { + if (m.getLocation() == location) { + slots--; + weight -= m.getTonnage(); + if ((slots < 0) || (weight < 0)) { + return false; + } + } + } + return true; + } +} diff --git a/megameklab/src/megameklab/util/TankUtil.java b/megameklab/src/megameklab/util/TankUtil.java new file mode 100644 index 000000000..32d721dd4 --- /dev/null +++ b/megameklab/src/megameklab/util/TankUtil.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megameklab.util; + +import megamek.common.*; +import megamek.common.verifier.TestTank; +import megamek.common.weapons.c3.ISC3M; +import megamek.common.weapons.c3.ISC3MBS; +import megamek.common.weapons.infantry.InfantryWeapon; +import megamek.common.weapons.lrms.LRMWeapon; +import megamek.common.weapons.lrms.LRTWeapon; +import megamek.common.weapons.missiles.MRMWeapon; +import megamek.common.weapons.missiles.RLWeapon; +import megamek.common.weapons.srms.SRMWeapon; +import megamek.common.weapons.srms.SRTWeapon; +import megamek.common.weapons.tag.CLLightTAG; +import megamek.common.weapons.tag.CLTAG; +import megamek.common.weapons.tag.ISTAG; + +public final class TankUtil { + + public static boolean isTankWeapon(EquipmentType eq, Entity unit) { + if (eq instanceof InfantryWeapon) { + return false; + } + // Some weapons such as TAG and C3M should show as non-weapon equipment + if (isTankMiscEquipment(eq, unit)) { + return false; + } + + if (eq instanceof WeaponType) { + + WeaponType weapon = (WeaponType) eq; + + if (!weapon.hasFlag(WeaponType.F_TANK_WEAPON)) { + return false; + } + + if (weapon.getTonnage(unit) <= 0) { + return false; + } + + if (weapon.isCapital() || weapon.isSubCapital()) { + return false; + } + + if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) + && (weapon.getRackSize() != 5) + && (weapon.getRackSize() != 10) + && (weapon.getRackSize() != 15) + && (weapon.getRackSize() != 20)) { + return false; + } + if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) + && (weapon.getRackSize() != 2) + && (weapon.getRackSize() != 4) + && (weapon.getRackSize() != 6)) { + return false; + } + if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { + return false; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon.getAmmoType() == AmmoType.T_PLASMA))) { + + if (weapon.hasFlag(WeaponType.F_ENERGY) + && weapon.hasFlag(WeaponType.F_PLASMA) + && (weapon.getAmmoType() == AmmoType.T_NA)) { + return false; + } + } + + return TestTank.legalForMotiveType(weapon, unit.getMovementMode(), unit.isSupportVehicle()); + } + return false; + } + + /** + * Tests whether equipment should be shown on the equipment tab for the unit. This is + * used for both combat vehicles and non-aerospace support vehicles. + * @param eq The equipment to show + * @param tank The tank + * @return Whether the equipment should show on the table + */ + public static boolean isTankEquipment(EquipmentType eq, Tank tank) { + return isTankMiscEquipment(eq, tank) || isTankWeapon(eq, tank); + } + + /** + * Tests whether equipment should be shown on the equipment tab for the unit as non-weapon + * equipment. This is used for both combat vehicles and non-aerospace support vehicles. + * @param eq The equipment to show + * @param tank The tank + * @return Whether the equipment should show on the table + */ + public static boolean isTankMiscEquipment(EquipmentType eq, Entity tank) { + if (UnitUtil.isArmorOrStructure(eq)) { + return false; + } + + // Display AMS as equipment (even though it's a weapon) + if (eq.hasFlag(WeaponType.F_AMS) + && eq.hasFlag(WeaponType.F_TANK_WEAPON)) { + return true; + } + + if ((eq instanceof CLTAG) || (eq instanceof ISC3M) + || (eq instanceof ISC3MBS) + || (eq instanceof ISTAG) || (eq instanceof CLLightTAG)) { + return true; + } + + if (eq instanceof MiscType) { + if (!TestTank.legalForMotiveType(eq, tank.getMovementMode(), tank.isSupportVehicle())) { + return false; + } + // Can't use supercharger with solar or external power pickup + if (eq.hasFlag(MiscType.F_MASC) && (!tank.hasEngine() + || tank.getEngine().getEngineType() == Engine.SOLAR + || tank.getEngine().getEngineType() == Engine.EXTERNAL)) { + return false; + } + // External fuel tanks are only allowed on ICE and fuel cell engines + if (eq.hasFlag(MiscType.F_FUEL) && (!tank.hasEngine() + || (tank.getEngine().getEngineType() != Engine.COMBUSTION_ENGINE + && tank.getEngine().getEngineType() != Engine.FUEL_CELL))) { + return false; + } + if (eq.hasFlag(MiscType.F_VTOL_EQUIPMENT) && (tank instanceof VTOL)) { + return true; + } + if (tank.isSupportVehicle()) { + return eq.hasFlag(MiscType.F_SUPPORT_TANK_EQUIPMENT); + } else { + return eq.hasFlag(MiscType.F_TANK_EQUIPMENT); + } + } + return false; + } + + private TankUtil() { } +} \ No newline at end of file diff --git a/megameklab/src/megameklab/util/UnitUtil.java b/megameklab/src/megameklab/util/UnitUtil.java index 3a88b6de5..dcfd1b3d0 100644 --- a/megameklab/src/megameklab/util/UnitUtil.java +++ b/megameklab/src/megameklab/util/UnitUtil.java @@ -1,80 +1,56 @@ /* - * Copyright (c) 2008-2022 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2008-2024 - The MegaMek Team. All Rights Reserved. * - * This program 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 2 of the License, or (at your option) any later - * version. + * This file is part of MegaMek. * - * This program 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. + * MegaMek 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. + * + * MegaMek 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 MegaMek. If not, see . */ package megameklab.util; -import megamek.client.ui.dialogs.BVDisplayDialog; -import megamek.client.ui.dialogs.CostDisplayDialog; import megamek.common.*; import megamek.common.annotations.Nullable; import megamek.common.verifier.*; -import megamek.common.verifier.TestAero.Quarters; import megamek.common.verifier.TestEntity.Ceil; import megamek.common.verifier.TestProtomech.ProtomechArmor; import megamek.common.weapons.*; import megamek.common.weapons.autocannons.HVACWeapon; import megamek.common.weapons.autocannons.UACWeapon; import megamek.common.weapons.bayweapons.BayWeapon; -import megamek.common.weapons.c3.ISC3M; -import megamek.common.weapons.c3.ISC3MBS; -import megamek.common.weapons.capitalweapons.CapitalMissileWeapon; import megamek.common.weapons.defensivepods.BPodWeapon; import megamek.common.weapons.defensivepods.MPodWeapon; import megamek.common.weapons.flamers.VehicleFlamerWeapon; import megamek.common.weapons.gaussrifles.GaussWeapon; -import megamek.common.weapons.infantry.InfantryRifleAutoRifleWeapon; import megamek.common.weapons.infantry.InfantryWeapon; import megamek.common.weapons.lasers.CLChemicalLaserWeapon; -import megamek.common.weapons.lrms.LRMWeapon; -import megamek.common.weapons.lrms.LRTWeapon; import megamek.common.weapons.lrms.StreakLRMWeapon; import megamek.common.weapons.mgs.MGWeapon; -import megamek.common.weapons.missiles.MMLWeapon; -import megamek.common.weapons.missiles.MRMWeapon; -import megamek.common.weapons.missiles.RLWeapon; import megamek.common.weapons.missiles.ThunderBoltWeapon; -import megamek.common.weapons.other.*; import megamek.common.weapons.ppc.CLPlasmaCannon; import megamek.common.weapons.ppc.ISPlasmaRifle; -import megamek.common.weapons.srms.SRMWeapon; -import megamek.common.weapons.srms.SRTWeapon; import megamek.common.weapons.srms.StreakSRMWeapon; -import megamek.common.weapons.tag.CLLightTAG; -import megamek.common.weapons.tag.CLTAG; -import megamek.common.weapons.tag.ISTAG; import megameklab.ui.PopupMessages; -import megameklab.ui.mek.BMUtils; import org.apache.logging.log4j.LogManager; import javax.swing.*; -import javax.swing.text.DefaultCaret; -import javax.swing.text.html.HTMLEditorKit; import java.awt.*; import java.io.File; import java.math.BigInteger; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.util.List; import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; public class UnitUtil { - public static int TECH_INTRO = 0; - public static int TECH_STANDARD = 1; - public static int TECH_ADVANCED = 2; - public static int TECH_EXPERIMENTAL = 3; - public static int TECH_UNOFFICAL = 4; private static Font rsFont = null; private static Font rsBoldFont = null; @@ -83,7 +59,7 @@ public class UnitUtil { * tells is EquipementType is an equipment that uses crits/mounted and is * spread across multiple locations * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isFixedLocationSpreadEquipment(EquipmentType eq) { @@ -113,7 +89,7 @@ public static boolean isFixedLocationSpreadEquipment(EquipmentType eq) { /** * tells if the EquipmentType is a type of armor * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isArmor(EquipmentType eq) { @@ -123,7 +99,7 @@ public static boolean isArmor(EquipmentType eq) { /** * tells if the EquipmentType is a type of armor * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isStructure(EquipmentType eq) { @@ -139,7 +115,7 @@ public static boolean isStructure(EquipmentType eq) { /** * tells if EquipmentType is TSM or TargetComp * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isTSM(EquipmentType eq) { @@ -148,7 +124,7 @@ public static boolean isTSM(EquipmentType eq) { } /** - * @param eq The equipmentType to check + * @param eq The equipment to test The equipmentType to check * @return true if this is a Remote Sensor Dispenser (BA or vehicular) */ public static boolean isRemoteSensorDispenser(EquipmentType eq) { @@ -156,7 +132,7 @@ public static boolean isRemoteSensorDispenser(EquipmentType eq) { } /** - * @param eq The equipmentType to check + * @param eq The equipment to test The equipmentType to check * @return true if this is a Mine Dispenser (BA or vehicular) */ public static boolean isMineDispenser(EquipmentType eq) { @@ -166,7 +142,7 @@ public static boolean isMineDispenser(EquipmentType eq) { /** * tells if EquipmentType is MASC * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isMASC(EquipmentType eq) { @@ -214,7 +190,7 @@ public static int getCritsUsed(Mounted mount) { /** * Removes a piece of equipment from the Entity * - * @param unit The Entity + * @param unit The entity The Entity * @param mount The equipment */ public static void removeMounted(Entity unit, Mounted mount) { @@ -369,8 +345,8 @@ public static void removeMounted(Entity unit, Mounted mount) { /** * Sets the corresponding critical slots to null for the Mounted object. * - * @param unit - * @param eq + * @param unit The entity + * @param eq The equipment to test */ public static void removeCriticals(Entity unit, Mounted eq) { if (eq.getLocation() == Entity.LOC_NONE) { @@ -405,7 +381,7 @@ public static void addMounted(Entity unit, Mounted mounted, int loc, boolean rea unit.addEquipment(mounted, loc, rearMounted); mounted.setOmniPodMounted(canPodMount(unit, mounted)); if (unit instanceof Mech) { - BMUtils.updateClanCasePlacement((Mech) unit); + MekUtil.updateClanCasePlacement((Mech) unit); } } @@ -413,7 +389,7 @@ public static void addMounted(Entity unit, Mounted mounted, int loc, boolean rea * Updates TC Crits and Mounts based on weapons on a unit or if the TC has * been removed. * - * @param unit + * @param unit The entity */ public static Mounted updateTC(Entity unit, EquipmentType tc) { UnitUtil.removeTC(unit); @@ -423,7 +399,7 @@ public static Mounted updateTC(Entity unit, EquipmentType tc) { /** * Creates TC Mount. * - * @param unit + * @param unit The entity */ public static @Nullable Mounted createTCMounts(Entity unit, EquipmentType tc) { try { @@ -436,7 +412,7 @@ public static Mounted updateTC(Entity unit, EquipmentType tc) { /** * Checks to see if unit can use the techlevel * - * @param unit + * @param unit The entity * @param tech * @return Boolean if the tech level is legal for the passed unit */ @@ -460,34 +436,10 @@ public static boolean isLegal(Entity unit, ITechnology tech) { unit.isClan())) <= TechConstants.convertFromNormalToSimple(unit.getTechLevel()); } - /*** - * Checks for Clan DHS - * - * @param unit - * @return - */ - public static boolean hasClanDoubleHeatSinks(Mech unit) { - if (!unit.hasDoubleHeatSinks()) { - return false; - } - - for (Mounted mounted : unit.getMisc()) { - if (mounted.getType().hasFlag(MiscType.F_LASER_HEAT_SINK)) { - return false; - } - - if (mounted.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { - return mounted.getType().getInternalName().equals("CLDoubleHeatSink"); - } - } - - return false; - } - /** * checks if Mounted is a heat sink * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isHeatSink(Mounted eq) { @@ -497,7 +449,7 @@ public static boolean isHeatSink(Mounted eq) { /** * Checks if EquipmentType is a heat sink * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isHeatSink(EquipmentType eq) { @@ -519,7 +471,7 @@ public static boolean isHeatSink(EquipmentType eq, boolean ignoreprototype) { /** * Checks if EquipmentType is a Mech Physical weapon. * - * @param eq The equipment to check + * @param eq The equipment to test The equipment to check * @return Whether the equipment is a physical weapon */ public static boolean isPhysicalWeapon(EquipmentType eq) { @@ -535,174 +487,6 @@ public static boolean isPhysicalWeapon(EquipmentType eq) { || eq.hasFlag(MiscType.F_RAM_PLATE); } - /** - * Removes the specified number of heat sinks from the mek Heat sinks are - * removed first fwith LOC_NONE above the free crit limit then they are - * removed with a location, and lastly they are removed below the free crit - * limit - * - * @param unit - */ - public static void removeHeatSinks(Mech unit, int number) { - Vector toRemove = new Vector<>(); - int base = UnitUtil.getCriticalFreeHeatSinks(unit, unit.hasCompactHeatSinks()); - boolean splitCompact = false; - if (unit.hasCompactHeatSinks()) { - // first check to see if there is a single compact heat sink outside of the engine and - // remove this first if so - Mounted mount = UnitUtil.getSingleCompactHeatSink(unit); - if ((null != mount) && (number > 0)) { - UnitUtil.removeMounted(unit, mount); - number--; - } - // if number is now uneven, then note that we will need to split a compact - if ((number % 2) == 1) { - splitCompact = true; - number--; - } - } - Vector unassigned = new Vector<>(); - Vector assigned = new Vector<>(); - Vector free = new Vector<>(); - for (Mounted m : unit.getMisc()) { - if (UnitUtil.isHeatSink(m)) { - if (m.getLocation() == Entity.LOC_NONE) { - if (base > 0) { - free.add(m); - base--; - } else { - unassigned.add(m); - } - } else { - assigned.add(m); - } - } - } - toRemove.addAll(unassigned); - toRemove.addAll(assigned); - toRemove.addAll(free); - if (unit.hasCompactHeatSinks()) { - // need to do some number magic here. The unassigned and assigned slots should each - // contain two heat sinks, but if we dip into the free then we are looking at one heat - // sink. - int numberDouble = Math.min(number / 2, unassigned.size() + assigned.size()); - int numberSingle = Math.max(0, number - (2 * numberDouble)); - number = numberDouble + numberSingle; - } - number = Math.min(number, toRemove.size()); - for (int i = 0; i < number; i++) { - Mounted eq = toRemove.get(i); - UnitUtil.removeMounted(unit, eq); - } - - if (splitCompact) { - Mounted eq = toRemove.get(number); - int loc = eq.getLocation(); - // remove singleCompact mount and replace with a double - UnitUtil.removeMounted(unit, eq); - if (!eq.getType().hasFlag(MiscType.F_HEAT_SINK)) { - try { - UnitUtil.addMounted(unit, - new Mounted(unit, EquipmentType.get("IS1 Compact Heat Sink")), loc, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - } - - /** - * adds all heat sinks to the mech - * - * @param unit - * @param hsAmount - * @param hsType - */ - public static void addHeatSinkMounts(Mech unit, int hsAmount, String hsType) { - addHeatSinkMounts(unit, hsAmount, EquipmentType.get(UnitUtil.getHeatSinkType(hsType, unit.isClan()))); - } - - /** - * adds all heat sinks to the mech - * - * @param unit - * @param hsAmount - * @param sinkType - */ - public static void addHeatSinkMounts(Mech unit, int hsAmount, EquipmentType sinkType) { - if (sinkType.hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { - UnitUtil.addCompactHeatSinkMounts(unit, hsAmount); - } else { - for (; hsAmount > 0; hsAmount--) { - try { - unit.addEquipment(new Mounted(unit, sinkType), Entity.LOC_NONE, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - } - - public static void addCompactHeatSinkMounts(Mech unit, int hsAmount) { - // first we need to figure out how many single compacts we need to add/ for the engine, if any - int currentSinks = UnitUtil.countActualHeatSinks(unit); - int engineCompacts = Math.min(hsAmount, UnitUtil.getCriticalFreeHeatSinks(unit, true)); - int engineToAdd = Math.max(0, engineCompacts - currentSinks); - unit.addEngineSinks("IS1 Compact Heat Sink", engineToAdd); - int restHS = hsAmount - engineToAdd; - Mounted singleCompact = getSingleCompactHeatSink(unit); - if ((restHS % 2) == 1) { - if (null == singleCompact) { - try { - unit.addEquipment(new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1)), - Entity.LOC_NONE, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } else { - int loc = singleCompact.getLocation(); - // remove singleCompact mount and replace with a double - UnitUtil.removeMounted(unit, singleCompact); - try { - addMounted(unit,new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2)), - loc, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - restHS -= 1; - } - for (; restHS > 0; restHS -= 2) { - try { - unit.addEquipment(new Mounted(unit, EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2)), - Entity.LOC_NONE, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - - /** - * get the single non-compact heat sink that is a non-engine sink, if it - * exits - * - * @param unit - */ - public static Mounted getSingleCompactHeatSink(Mech unit) { - int base = UnitUtil.getCriticalFreeHeatSinks(unit, true); - for (Mounted m : unit.getMisc()) { - if (m.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK) - && m.getType().hasFlag(MiscType.F_HEAT_SINK)) { - if (base <= 0) { - return m; - } else { - base--; - } - } - } - return null; - } - public static String getHeatSinkType(String type, boolean clan) { String heatSinkType; @@ -735,197 +519,6 @@ public static String getHeatSinkType(String type, boolean clan) { return heatSinkType; } - public static boolean hasSameHeatSinkType(Mech unit, String type) { - // this seems like a total hack, but at present we apparently have no - // good static integer codes for this on entity - String heatSinkType = UnitUtil.getHeatSinkType(type, unit.isClan()); - for (Mounted mounted : unit.getMisc()) { - if (type.equals("Compact") - && mounted.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { - return true; - } - if (mounted.getType().hasFlag(MiscType.F_HEAT_SINK) - || mounted.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK) - || mounted.getType().hasFlag(MiscType.F_LASER_HEAT_SINK)) { - return mounted.getType().getInternalName().equals(heatSinkType); - } - } - return false; - } - - /** - * updates the heat sinks. - * - * @param unit - * @param hsAmount - * @param hsType - */ - public static void updateHeatSinks(Mech unit, int hsAmount, String hsType) { - // if we have the same type of heat sink, then we should not remove the - // existing heat sinks - int currentSinks = UnitUtil.countActualHeatSinks(unit); - if (UnitUtil.hasSameHeatSinkType(unit, hsType)) { - if (hsAmount < currentSinks) { - UnitUtil.removeHeatSinks(unit, currentSinks - hsAmount); - } else if (hsAmount > currentSinks) { - UnitUtil.addHeatSinkMounts(unit, hsAmount - currentSinks, hsType); - } - } else { - UnitUtil.removeHeatSinks(unit, hsAmount); - UnitUtil.addHeatSinkMounts(unit, hsAmount, hsType); - } - unit.resetSinks(); - } - - /** - * This will cycle through the heat sinks and make sure that enough of them - * are set LOC_NONE based on the basechassisheat sinks - * - * @param unit - */ - public static void updateAutoSinks(Mech unit, boolean compact) { - if (compact) { - updateCompactHeatSinks(unit); - return; - } - int base = UnitUtil.getCriticalFreeHeatSinks(unit, compact); - List unassigned = new ArrayList<>(); - List assigned = new ArrayList<>(); - for (Mounted m : unit.getMisc()) { - if (UnitUtil.isHeatSink(m)) { - if (m.getLocation() == Entity.LOC_NONE) { - unassigned.add(m); - } else if (!m.getType().hasFlag(MiscType.F_IS_DOUBLE_HEAT_SINK_PROTOTYPE)) { - // Prototype double heat sinks can never be integrated into the engine - assigned.add(m); - } - } - } - int needed = base - unassigned.size(); - if (needed <= 0) { - return; - } - for (Mounted m : assigned) { - if (needed <= 0) { - return; - } - UnitUtil.removeCriticals(unit, m); - m.setLocation(Entity.LOC_NONE); - needed--; - } - // There may be more crit-free heatsinks, but if the 'mech doesn't - // have that many heatsinks, the additional space is unused. - } - - /** - * Adjusts compact heat sinks to fulfill engine capacity. This is more complex than other heat sink - * types because the engine heat sinks always have one per mount, and those outside the engine - * are paired in a slot with one single if there are an odd number. - * - * @param mech The mech to adjust heat sinks for - */ - public static void updateCompactHeatSinks(Mech mech) { - int base = UnitUtil.getCriticalFreeHeatSinks(mech, true); - List unallocatedSingle = new ArrayList<>(); - List unallocatedPair = new ArrayList<>(); - List allocatedSingle = new ArrayList<>(); - List allocatedPair = new ArrayList<>(); - for (Mounted m : mech.getMisc()) { - if (UnitUtil.isHeatSink(m)) { - if (m.getLocation() == Entity.LOC_NONE) { - if (m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { - unallocatedPair.add(m); - } else { - unallocatedSingle.add(m); - } - } else { - if (m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK)) { - allocatedPair.add(m); - } else { - allocatedSingle.add(m); - } - } - } - } - - int needed = base - unallocatedSingle.size(); - int toAdd = 0; - // If there are more single heat sinks than there is space for in the engine remove them so they - // can be paired up - if (needed < 0) { - int count = removeCompactHeatSinks(-needed, mech, unallocatedSingle); - needed += count; - toAdd += count; - } - // If we have more space in the engine, start by splitting unallocated double heat sinks - if (needed > 0) { - int count = removeCompactHeatSinks(needed, mech, unallocatedPair); - needed -= count; - toAdd += count; - } - // Next we pull a single out of its location, if any - if (needed > 0) { - int count = removeCompactHeatSinks(needed, mech, allocatedSingle); - needed -= count; - toAdd += count; - } - // Finally we remove as many paired heat sinks as we need to fill the engine - if (needed > 0) { - toAdd += removeCompactHeatSinks(needed, mech, allocatedPair); - } - // Now we add heat sinks back - try { - // First we add as many single heat sinks to LOC_NONE as we need to fill the engine - int engineAdd = Math.min(toAdd, base - unallocatedSingle.size()); - for (int i = 0; i < engineAdd; i++) { - mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1), Entity.LOC_NONE); - toAdd--; - } - // If we have an odd number to add and there is a single already allocated, remove it and pair them. - // Unallocated singles in excess of engine capacity have already been removed. - if (((toAdd & 1) == 1) && !allocatedSingle.isEmpty()) { - UnitUtil.removeMounted(mech, allocatedSingle.remove(0)); - mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2), Entity.LOC_NONE); - toAdd--; - } - // If we still have an odd number, add one single. - if ((toAdd & 1) == 1) { - mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_1), Entity.LOC_NONE); - toAdd--; - } - // Add the remainder as unallocated pairs - for (int i = 0; i < toAdd; i += 2) { - mech.addEquipment(EquipmentType.get(EquipmentTypeLookup.COMPACT_HS_2), Entity.LOC_NONE); - } - } catch (LocationFullException ignored) { - // We're added to LOC_NONE - } - } - - /** - * Called by {@link #updateCompactHeatSinks(Mech)} to remove heat sinks up to a certain number. - * The actual number removed could be higher if count is odd and we're removing pairs, or - * lower if there aren't enough in the list. - * - * @param count The number of heat sinks to remove - * @param mech The mech to remove heat sinks from - * @param hsList The list of heat sinks available for removal - * @return The actual number removed - */ - private static int removeCompactHeatSinks(int count, Mech mech, List hsList) { - int removed = 0; - for (Iterator iter = hsList.iterator(); iter.hasNext(); ) { - Mounted m = iter.next(); - UnitUtil.removeMounted(mech, m); - removed += m.getType().hasFlag(MiscType.F_DOUBLE_HEAT_SINK) ? 2 : 1; - iter.remove(); - if (removed >= count) { - break; - } - } - return removed; - } - public static boolean isJumpJet(Mounted m) { return (m.getType() instanceof MiscType) && (m.getType().hasFlag(MiscType.F_JUMP_JET) @@ -950,75 +543,6 @@ public static String getJumpJetType(int type) { return EquipmentTypeLookup.JUMP_JET; } - /** - * Removes all jump jets from the mek - * - * @param unit - */ - public static void removeJumpJets(Mech unit, int number) { - Vector toRemove = new Vector<>(); - ArrayList misceq = unit.getMisc(); - for (Mounted eq : misceq) { - if (UnitUtil.isJumpJet(eq)) { - toRemove.add(eq); - if (toRemove.size() >= number) { - break; - } - } - } - - for (Mounted eq : toRemove) { - UnitUtil.removeMounted(unit, eq); - } - } - - /** - * updates the Jump Jets. - * - * @param unit - * @param jjAmount - * @param jjType - */ - public static void updateJumpJets(Mech unit, int jjAmount, int jjType) { - unit.setOriginalJumpMP(jjAmount); - int ctype = unit.getJumpType(); - if (jjType == ctype) { - int currentJJ = (int) unit.getMisc().stream() - .filter(m -> m.getType() - .hasFlag(MiscType.F_JUMP_JET)) - .count(); - if (jjAmount < currentJJ) { - UnitUtil.removeJumpJets(unit, currentJJ - jjAmount); - return; - } else if (jjAmount > currentJJ) { - jjAmount = jjAmount - currentJJ; - } else { - return; // No change, get the fuck outta here! - } - } else { - UnitUtil.removeJumpJets(unit, unit.getJumpMP()); - } - // if this is the same jump jet type, then only remove if too many - // and add if too low - if (jjType == Mech.JUMP_BOOSTER) { - UnitUtil.removeJumpJets(unit, unit.getJumpMP()); - createSpreadMounts( - unit, - EquipmentType.get(UnitUtil.getJumpJetType(jjType))); - } else { - while (jjAmount > 0) { - try { - unit.addEquipment( - new Mounted(unit, EquipmentType.get(UnitUtil.getJumpJetType(jjType))), - Entity.LOC_NONE, false); - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - jjAmount--; - } - } - } - /** * Checks whether equipment can be linked to a weapon to enhance it (e.g. Artemis, PPC Capacitor, etc). @@ -1035,149 +559,6 @@ public static boolean isWeaponEnhancement(EquipmentType type) { || type.hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)); } - /** - * Removes all enhancements (TSM and MASC) from the mek - * - * @param unit - */ - public static void removeEnhancements(Mech unit) { - ConcurrentLinkedQueue equipmentList = new ConcurrentLinkedQueue<>(unit.getMisc()); - for (Mounted eq : equipmentList) { - if (UnitUtil.isTSM(eq.getType()) || UnitUtil.isMASC(eq.getType()) - || ((eq.getType() instanceof MiscType) && eq.getType().hasFlag(MiscType.F_SCM))) { - UnitUtil.removeCriticals(unit, eq); - } - } - for (Mounted eq : equipmentList) { - if (UnitUtil.isTSM(eq.getType()) || UnitUtil.isMASC(eq.getType()) - || ((eq.getType() instanceof MiscType) && eq.getType().hasFlag(MiscType.F_SCM))) { - unit.getMisc().remove(eq); - unit.getEquipment().remove(eq); - } - } - } - - public static boolean isPrintableEquipment(EquipmentType eq) { - return UnitUtil.isPrintableEquipment(eq, false); - } - - /** - * simple method to let us know if eq should be printed on the weapons and - * equipment section of the Record sheet. - * - * @param eq The equipment - * @param entity The Entity it's mounted on - * @return Whether the equipment should be shown on the record sheet - */ - public static boolean isPrintableEquipment(EquipmentType eq, Entity entity) { - if (eq instanceof AmmoType) { - return ((AmmoType) eq).getAmmoType() == AmmoType.T_COOLANT_POD; - } else if (entity instanceof BattleArmor) { - return isPrintableBAEquipment(eq); - } else { - return isPrintableEquipment(eq, entity instanceof Mech); - } - } - - /** - * simple method to let us know if eq should be printed on the weapons and - * equipment section of the Record sheet. - * - * @param eq The equipment - * @param isMech Whether the equipment is mounted on a mech - * @return Whether the equipment should be shown on the record sheet - */ - public static boolean isPrintableEquipment(EquipmentType eq, boolean isMech) { - if (UnitUtil.isArmorOrStructure(eq)) { - return false; - } - - if (UnitUtil.isFixedLocationSpreadEquipment(eq) - && !(eq instanceof MiscType) && eq.hasFlag(MiscType.F_TALON)) { - return false; - } - - if (UnitUtil.isJumpJet(eq)) { - return false; - } - if (!eq.isHittable() && isMech) { - return false; - } - - if ((eq instanceof MiscType) - && (eq.hasFlag(MiscType.F_CASE) - || eq.hasFlag(MiscType.F_ARTEMIS) - || eq.hasFlag(MiscType.F_ARTEMIS_PROTO) - || eq.hasFlag(MiscType.F_ARTEMIS_V) - || eq.hasFlag(MiscType.F_APOLLO) - || eq.hasFlag(MiscType.F_PPC_CAPACITOR) - || (eq.hasFlag(MiscType.F_MASC) && isMech) - || eq.hasFlag(MiscType.F_HARJEL) - || eq.hasFlag(MiscType.F_MASS) - || eq.hasFlag(MiscType.F_CHASSIS_MODIFICATION) - || eq.hasFlag(MiscType.F_SPONSON_TURRET)) - || eq.hasFlag(MiscType.F_EXTERNAL_STORES_HARDPOINT) - || eq.hasFlag(MiscType.F_BASIC_FIRECONTROL) - || eq.hasFlag(MiscType.F_ADVANCED_FIRECONTROL)) { - return false; - } - - if (UnitUtil.isHeatSink(eq)) { - return false; - } - - return true; - - } - - /** - * simple method to let us know if eq should be printed on the weapons and - * equipment section of the Record sheet. - * - * @param eq - * @return - */ - public static boolean isPrintableBAEquipment(EquipmentType eq) { - if (UnitUtil.isArmorOrStructure(eq)) { - return false; - } - - if (UnitUtil.isJumpJet(eq)) { - return false; - } - - if ((eq instanceof MiscType) - && ((eq.hasFlag(MiscType.F_AP_MOUNT) && !eq.hasFlag(MiscType.F_BA_MANIPULATOR)) - || eq.hasFlag(MiscType.F_FIRE_RESISTANT) - || eq.hasFlag(MiscType.F_STEALTH) - || eq.hasFlag(MiscType.F_ARTEMIS) - || eq.hasFlag(MiscType.F_ARTEMIS_V) - || eq.hasFlag(MiscType.F_APOLLO) - || eq.hasFlag(MiscType.F_HARJEL) - || eq.hasFlag(MiscType.F_MASS) - || eq.hasFlag(MiscType.F_DETACHABLE_WEAPON_PACK))) { - return false; - } - - if (UnitUtil.isHeatSink(eq)) { - return false; - } - - if ((eq instanceof LegAttack) || (eq instanceof SwarmAttack) - || (eq instanceof StopSwarmAttack) - || (eq instanceof InfantryRifleAutoRifleWeapon) - || (eq instanceof SwarmWeaponAttack)) { - return false; - } - - return true; - } - - public static boolean isBAMultiMount(EquipmentType equip) { - return (equip instanceof WeaponType) - && (equip.hasFlag(WeaponType.F_TASER) || (((WeaponType) equip).getAmmoType() == AmmoType.T_NARC)); - } - /** * Changes the location for a Mounted instance. Note: for BattleArmor, this * effects which suit the equipment is placed on (as that is what @@ -1185,8 +566,8 @@ public static boolean isBAMultiMount(EquipmentType equip) { * it's located (ie, BAMountLocation isn't affected). BattleArmor should * change this outside of this method. * - * @param unit The unit being modified - * @param eq The equipment mount to move + * @param unit The entity The unit being modified + * @param eq The equipment to test The equipment mount to move * @param location The location to move the mount to * @param secondaryLocation The secondary location for split equipment, otherwise {@link Entity#LOC_NONE Entity.LOC_NONE} * @param rear Whether to mount with a rear facing @@ -1215,7 +596,7 @@ public static void changeMountStatus(Entity unit, Mounted eq, int location, } } if (unit instanceof Mech) { - BMUtils.updateClanCasePlacement((Mech) unit); + MekUtil.updateClanCasePlacement((Mech) unit); } } @@ -1267,7 +648,7 @@ public static void resizeMount(Mounted mount, double newSize) { * Find unallocated ammo of the same type. Used by large aerospace units when removing ammo * from a location to find the group to add it to. * - * @param unit The Entity + * @param unit The entity The Entity * @param at The type of armor to match * @return An unallocated non-oneshot ammo mount of the same type, or null if there is not one. */ @@ -1288,8 +669,8 @@ public static Mounted findUnallocatedAmmo(Entity unit, EquipmentType at) { * equipment itself can never be pod-mounted (such as armor, structure, or myomer enhancements), * or the number of fixed heat sinks have not been assigned locations. * - * @param unit - * @param eq + * @param unit The entity + * @param eq The equipment to test * @return */ public static boolean canPodMount(Entity unit, Mounted eq) { @@ -1320,7 +701,7 @@ public static boolean canPodMount(Entity unit, Mounted eq) { /** * Removes all pod-mounted equipment from an omni unit - * @param unit + * @param unit The entity */ public static void resetBaseChassis(Entity unit) { if (!unit.isOmni()) { @@ -1556,7 +937,7 @@ public static double getSIBonusArmorPoints(Entity entity) { /** * NOTE: only use for non-patchwork armor * - * @param unit + * @param unit The entity * @param armorTons * @return */ @@ -1569,7 +950,7 @@ public static int getArmorPoints(Entity unit, double armorTons) { /** * NOTE: only use for non-patchwork armor * - * @param unit + * @param unit The entity * @param armorTons * @return */ @@ -1623,9 +1004,9 @@ public static double getArmorPointsPerTon(Entity en, int at, int techLevel) { public static void compactCriticals(Entity unit) { for (int loc = 0; loc < unit.locations(); loc++) { if (unit instanceof Mech) { - UnitUtil.compactCriticals((Mech) unit, loc); + MekUtil.compactCriticals((Mech) unit, loc); } else { - UnitUtil.compactCriticals(unit, loc); + compactCriticals(unit, loc); } } } @@ -1676,37 +1057,6 @@ public static void compactCriticals(Entity unit, int loc) { } } - public static void compactCriticals(Mech unit) { - for (int loc = 0; loc < unit.locations(); loc++) { - UnitUtil.compactCriticals(unit, loc); - } - } - - private static void compactCriticals(Mech mech, int loc) { - if (loc == Mech.LOC_HEAD) { - // This location has an empty slot in-between systems crits - // which will mess up parsing if compacted. - return; - } - int firstEmpty = -1; - for (int slot = 0; slot < mech.getNumberOfCriticals(loc); slot++) { - CriticalSlot cs = mech.getCritical(loc, slot); - - if ((cs == null) && (firstEmpty == -1)) { - firstEmpty = slot; - } - if ((firstEmpty != -1) && (cs != null)) { - // move this to the first empty slot - mech.setCritical(loc, firstEmpty, cs); - // mark the old slot empty - mech.setCritical(loc, slot, null); - // restart just after the moved slot's new location - slot = firstEmpty; - firstEmpty = -1; - } - } - } - public static boolean isAMS(WeaponType weapon) { return weapon.hasFlag(WeaponType.F_AMS); } @@ -1722,198 +1072,18 @@ public static boolean hasSwitchableAmmo(WeaponType weapon) { && !UnitUtil.isAMS(weapon); } - /** - * Expands crits that are a single mount by have multiple spreadable crits - * Such as TSM, Endo Steel, Reactive armor. - * - * @param unit - */ - public static void expandUnitMounts(Mech unit) { - for (int location = 0; location < unit.locations(); location++) { - for (int slot = 0; slot < unit.getNumberOfCriticals(location); slot++) { - CriticalSlot cs = unit.getCritical(location, slot); - if ((cs == null) || (cs.getType() == CriticalSlot.TYPE_SYSTEM)) { - continue; - } - Mounted mount = cs.getMount(); - - if (!UnitUtil.isFixedLocationSpreadEquipment(mount.getType()) - && (UnitUtil.isTSM(mount.getType()) - || UnitUtil.isArmorOrStructure(mount.getType()))) { - Mounted newMount = new Mounted(unit, mount.getType()); - newMount.setLocation(location, mount.isRearMounted()); - newMount.setArmored(mount.isArmored()); - cs.setMount(newMount); - cs.setArmored(mount.isArmored()); - unit.getEquipment().remove(mount); - unit.getMisc().remove(mount); - unit.getEquipment().add(newMount); - unit.getMisc().add(newMount); - } - } + public static void loadFonts() { + Font font = Font.decode(CConfig.getParam(CConfig.RS_FONT, "Eurostile")); + // If the font is not installed, use system default sans + if (null == font) { + font = Font.decode(Font.SANS_SERIF); } - } - - /** - * create a Mounted and corresponding CriticalSlots for the passed in - * EquipmentType on the passed in Mech - * - * @param unit - * @param equip - * @return - */ - public static Mounted createSpreadMounts(Mech unit, EquipmentType equip) { - // how many non-spreadable contiguous blocks of crits? - int blocks = equip.getCriticals(unit); - - boolean isMisc = equip instanceof MiscType; - - List locations = new ArrayList<>(); - - if (isMisc) { - if ((equip.hasFlag(MiscType.F_INDUSTRIAL_TSM) || equip.hasFlag(MiscType.F_TSM))) { - // all crits user placeable - for (int i = 0; i < equip.getCriticals(unit); i++) { - locations.add(Entity.LOC_NONE); - } - } else if (equip.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING)) { - // 1 crit in each location - for (int i = 0; i < unit.locations(); i++) { - locations.add(i); - } - } else if (equip.hasFlag(MiscType.F_STEALTH)) { - // 2 in arms, legs, side torsos - locations.add(Mech.LOC_LLEG); - locations.add(Mech.LOC_RLEG); - locations.add(Mech.LOC_LARM); - locations.add(Mech.LOC_RARM); - locations.add(Mech.LOC_LT); - locations.add(Mech.LOC_RT); - blocks = 6; - // Need to account for the center leg - if (unit instanceof TripodMech) { - locations.add(Mech.LOC_CLEG); - blocks++; - } - } else if (equip.hasFlag(MiscType.F_SCM)) { - // 1 in arms, legs, side torsos - locations.add(Mech.LOC_LLEG); - locations.add(Mech.LOC_RLEG); - locations.add(Mech.LOC_LARM); - locations.add(Mech.LOC_RARM); - locations.add(Mech.LOC_LT); - locations.add(Mech.LOC_RT); - blocks = 6; - } else if ((equip.hasFlag(MiscType.F_TRACKS) || equip.hasFlag(MiscType.F_TALON) - || equip.hasFlag(MiscType.F_JUMP_BOOSTER))) { - // 1 block in each leg - locations.add(Mech.LOC_LLEG); - locations.add(Mech.LOC_RLEG); - if (unit instanceof QuadMech) { - locations.add(Mech.LOC_LARM); - locations.add(Mech.LOC_RARM); - } - blocks = (unit instanceof BipedMech ? 2 : 4); - // Need to account for the center leg - if (unit instanceof TripodMech) { - locations.add(Mech.LOC_CLEG); - blocks = 3; - } - } else if (equip.hasFlag(MiscType.F_PARTIAL_WING)) { - // one block in each side torso - locations.add(Mech.LOC_LT); - locations.add(Mech.LOC_RT); - blocks = 2; - } else if (equip.hasFlag(MiscType.F_RAM_PLATE)) { - // one block in each torso - locations.add(Mech.LOC_LT); - locations.add(Mech.LOC_RT); - locations.add(Mech.LOC_CT); - blocks = 3; - } else if ((equip.hasFlag(MiscType.F_VOIDSIG) - || equip.hasFlag(MiscType.F_NULLSIG) - || equip.hasFlag(MiscType.F_BLUE_SHIELD))) { - // Need to account for the center leg - if (unit instanceof TripodMech) { - blocks++; - } - // 1 crit in each location, except the head - for (int i = Mech.LOC_CT; i < unit.locations(); i++) { - locations.add(i); - } - } else if (equip.hasFlag(MiscType.F_CHAMELEON_SHIELD)) { - // Need to account for the center leg - if (unit instanceof TripodMech) { - blocks++; - } - // 1 crit in each location except head and CT - for (int i = Mech.LOC_RT; i < unit.locations(); i++) { - locations.add(i); - } - } - } - - boolean firstBlock = true; - Mounted mount = new Mounted(unit, equip); - for (; blocks > 0; blocks--) { - // how many crits per block? - int crits = UnitUtil.getCritsUsed(mount); - for (int i = 0; i < crits; i++) { - try { - if (firstBlock || (locations.get(0) == Entity.LOC_NONE)) { - // create only one mount per equipment, for BV and stuff - addMounted(unit, mount, locations.get(0), false); - if (firstBlock) { - firstBlock = false; - } - if (locations.get(0) == Entity.LOC_NONE) { - // only user-placable spread stuff gets location none - // for those, we need to create a mount for each crit, - // otherwise we can't correctly let the user place them - // luckily, that only affects TSM, so BV works out correctly - mount = new Mounted(unit, equip); - } - } else { - CriticalSlot cs = new CriticalSlot(mount); - if (!unit.addCritical(locations.get(0), cs)) { - UnitUtil.removeCriticals(unit, mount); - JOptionPane.showMessageDialog( - null, - "No room for equipment", - mount.getName() - + " does not fit into " - + unit.getLocationName(locations.get(0)), - JOptionPane.INFORMATION_MESSAGE); - unit.getMisc().remove(mount); - unit.getEquipment().remove(mount); - return null; - } - } - } catch (LocationFullException lfe) { - PopupMessages.showLocationFullError(null, mount.getName()); - LogManager.getLogger().error(lfe); - unit.getMisc().remove(mount); - unit.getEquipment().remove(mount); - return null; - } - } - locations.remove(0); - } - return mount; - } - - public static void loadFonts() { - Font font = Font.decode(CConfig.getParam(CConfig.RS_FONT, "Eurostile")); - // If the font is not installed, use system default sans - if (null == font) { - font = Font.decode(Font.SANS_SERIF); - } - // If that still doesn't work, get the default dialog font - if (null == font) { - font = Font.decode(null); - } - rsFont = font.deriveFont(Font.PLAIN, 8); - rsBoldFont = font.deriveFont(Font.BOLD, 8); + // If that still doesn't work, get the default dialog font + if (null == font) { + font = Font.decode(null); + } + rsFont = font.deriveFont(Font.PLAIN, 8); + rsBoldFont = font.deriveFont(Font.BOLD, 8); } public static Font deriveFont(float pointSize) { @@ -1989,7 +1159,7 @@ public static boolean hasAmmo(Entity unit, int location) { /** * Checks to see if something is a Jump Jet * - * @param eq + * @param eq The equipment to test * @return */ public static boolean isJumpJet(EquipmentType eq) { @@ -2021,109 +1191,11 @@ public static String getCritName(Entity unit, EquipmentType eq) { return name; } - public static String getToolTipInfo(Entity unit, Mounted eq) { - DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(); - unusualSymbols.setDecimalSeparator('.'); - unusualSymbols.setGroupingSeparator(','); - DecimalFormat myFormatter = new DecimalFormat("#,##0", unusualSymbols); - StringBuilder sb = new StringBuilder(""); - sb.append(eq.getName()); - if (eq.getType() instanceof AmmoType) { - sb.append(" (" + eq.getBaseShotsLeft() + " shot"); - sb.append((eq.getBaseShotsLeft() == 1) ? ")" : "s)"); - } - if ((eq.getType().hasFlag(MiscType.F_DETACHABLE_WEAPON_PACK) - || eq.getType().hasFlag(MiscType.F_AP_MOUNT)) - && (eq.getLinked() != null)) { - sb.append(" (attached " + eq.getLinked().getName() + ")"); - } - if (eq.isSquadSupportWeapon()) { - sb.append(" (squad support weapon)"); - } - if (eq.getType() instanceof InfantryWeapon) { - sb.append("
Damage/Trooper: "); - double infDamage = ((InfantryWeapon) eq.getType()).getInfantryDamage(); - sb.append(infDamage); - sb.append("
Range Class: "); - sb.append(((InfantryWeapon) eq.getType()).getInfantryRange()); - } else { - sb.append("
Crits: "); - sb.append(eq.getCriticals()); - sb.append("
Mass: "); - if (TestEntity.usesKgStandard(unit)) { - sb.append(Math.round(eq.getTonnage() * 1000)); - sb.append(" Kg"); - } else { - sb.append(eq.getTonnage()); - sb.append(" tons"); - } - - if (eq.getType() instanceof WeaponType) { - sb.append("
Heat: "); - sb.append(eq.getType().getHeat()); - sb.append("
Maximum Damage: "); - sb.append(getWeaponDamageInfo((WeaponType) eq.getType())); - } - } - sb.append("
Cost: "); - - double cost = eq.getType().getCost(unit, false, eq.getLocation()); - - sb.append(myFormatter.format(cost)); - sb.append(" CBills"); - - if (eq.isRearMounted()) { - sb.append("
Rear Facing"); - } - if (eq.isMechTurretMounted()) { - sb.append("
Turret mounted"); - } - if (eq.isArmored()) { - sb.append("
Armored"); - } - if ((unit instanceof BattleArmor) - && eq.getType().hasFlag(WeaponType.F_INF_SUPPORT)) { - sb.append("
* Infantry support weapons must be held in an " + - "Armored Glove"); - } else if ((unit instanceof BattleArmor) - && eq.getType().hasFlag(WeaponType.F_INFANTRY)) { - sb.append("
* Infantry weapons must be mounted in AP Mounts"); - } - - sb.append(""); - return sb.toString(); - } - - private static String getWeaponDamageInfo(WeaponType wType) { - if (wType.getDamage() == WeaponType.DAMAGE_BY_CLUSTERTABLE) { - int perMissile = 1; - if ((wType instanceof SRMWeapon) || (wType instanceof SRTWeapon) ||(wType instanceof MMLWeapon)) { - perMissile = 2; - } - return Integer.toString(wType.getRackSize() * perMissile); - } else if (wType.getDamage() == WeaponType.DAMAGE_VARIABLE) { - return Integer.toString(wType.getDamage(1)); - } else if (wType.getDamage() == WeaponType.DAMAGE_SPECIAL) { - return "Special"; - } else if (wType.getDamage() == WeaponType.DAMAGE_ARTILLERY) { - return Integer.toString(wType.getRackSize()); - } else { - int damage = wType.getDamage(); - if (wType.getAmmoType() == AmmoType.T_AC_ROTARY) { - damage *= 6; - } else if ((wType.getAmmoType() == AmmoType.T_AC_ULTRA) - || (wType.getAmmoType() == AmmoType.T_AC_ULTRA_THB)) { - damage *= 2; - } - return Integer.toString(damage); - } - } - /** * Return the number of critical-space free heatsinks that the given entity * can have. * - * @param unit + * @param unit The entity * The unit mounting the heatsinks * @param compact * Whether the heatsinks are compact or not @@ -2151,50 +1223,16 @@ public static boolean isPreviousCritEmpty(Entity unit, CriticalSlot cs, int slot public static boolean isLastCrit(Entity unit, CriticalSlot cs, int slot, int location) { if (unit instanceof Mech) { - return UnitUtil.isLastMechCrit((Mech) unit, cs, slot, location); + return MekUtil.isLastMechCrit((Mech) unit, cs, slot, location); } return true; } - public static boolean isLastMechCrit(Mech unit, CriticalSlot cs, int slot, int location) { - if (cs == null) { - return true; - } - // extra check for the last crit in a location, it shouldn't get a border - if ((slot + 1) >= unit.getNumberOfCriticals(location)) { - return false; - } - - int lastIndex = 0; - if (cs.getType() == CriticalSlot.TYPE_SYSTEM) { - - for (int position = 0; position < unit.getNumberOfCriticals(location); position++) { - if ((cs.getIndex() == Mech.SYSTEM_ENGINE) && (slot >= 3) && (position < 3)) { - position = 3; - } - CriticalSlot crit = unit.getCritical(location, position); - - if ((crit != null) - && (crit.getType() == CriticalSlot.TYPE_SYSTEM) - && (crit.getIndex() == cs.getIndex())) { - lastIndex = position; - } else if (position > slot) { - break; - } - } - } else { - CriticalSlot nextCrit = unit.getCritical(location, slot + 1); - return (nextCrit == null) || (nextCrit.getMount() == null) || !nextCrit.getMount().equals(cs.getMount()); - } - - return slot == lastIndex; - } - /** * Finds all the critical slots in the location containing the mount and sets or clears the * armored component flag in accordance with the flag on the mount. * - * @param unit The unit the equipment is mounted on + * @param unit The entity The unit the equipment is mounted on * @param mount The mount * @param location The location to check */ @@ -2215,7 +1253,7 @@ public static void updateCritsArmoredStatus(Entity unit, Mounted mount, int loca * Sets the armored component flag on all critical slots occupied by an equipment mount to * be the same as the flag on the mount. * - * @param unit The unit the equipment is on + * @param unit The entity The unit the equipment is on * @param mount The equipment mount */ public static void updateCritsArmoredStatus(Entity unit, Mounted mount) { @@ -2282,7 +1320,7 @@ public static boolean isArmorable(@Nullable CriticalSlot cs) { return true; } else { Mounted mount = cs.getMount(); - return ((mount != null) && isArmorable(mount.getType())); + return (mount != null) && isArmorable(mount.getType()); } } @@ -2312,9 +1350,9 @@ public static void updateLoadedUnit(Entity unit) { UnitUtil.removeOneShotAmmo(unit); if (unit instanceof Mech) { - UnitUtil.updateLoadedMech((Mech) unit); + MekUtil.updateLoadedMech((Mech) unit); } else if (unit instanceof Aero) { - UnitUtil.updateLoadedAero((Aero) unit); + AeroUtil.updateLoadedAero((Aero) unit); } // Replace bay weapon and ammo equipment numbers with the current index by looking // up the old index in the old list @@ -2330,476 +1368,46 @@ public static void updateLoadedUnit(Entity unit) { } } - public static void updateLoadedMech(Mech unit) { - UnitUtil.expandUnitMounts(unit); - UnitUtil.checkArmor(unit); - } - - public static void updateLoadedAero(Aero unit) { - if (unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT)) { - if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_STANDARD) { - unit.setArmorType(EquipmentType.T_ARMOR_AEROSPACE); - } else if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_PRIMITIVE) { - unit.setArmorType(EquipmentType.T_ARMOR_PRIMITIVE_AERO); - } - if (unit.isPrimitive() && (unit instanceof Dropship)) { - if (unit.getYear() < Dropship.getCollarTA().getIntroductionDate()) { - ((Dropship)unit).setCollarType(Dropship.COLLAR_NO_BOOM); - } else if ((unit.getYear() < Dropship.getCollarTA().getIntroductionDate()) - && (((Dropship)unit).getCollarType() == Dropship.COLLAR_STANDARD)) { - ((Dropship)unit).setCollarType(Dropship.COLLAR_PROTOTYPE); - } - } - // Minimum crew levels - ((SmallCraft) unit).setNGunners(Math.max(unit.getNGunners(), - TestSmallCraft.requiredGunners(unit))); - unit.setNCrew(Math.max(unit.getNCrew(), - unit.getNGunners() + unit.getBayPersonnel() - + TestSmallCraft.minimumBaseCrew((SmallCraft) unit))); - if (unit.getNOfficers() == 0) { - ((SmallCraft) unit).setNOfficers((int) Math.ceil((unit.getNCrew() - unit.getBayPersonnel()) / 5.0)); - } - // Check whether there are any quarters allocated. If not, assign standard levels - if (unit.getTransportBays().stream().noneMatch(Bay::isQuarters)) { - unit.addTransporter(Quarters.FIRST_CLASS.newQuarters(unit.getNOfficers())); - unit.addTransporter(Quarters.SECOND_CLASS.newQuarters(unit.getNPassenger())); - int std = unit.getNCrew() - unit.getBayPersonnel() - unit.getNOfficers() - + unit.getNMarines() + unit.getNBattleArmor(); - if (std > 0) { - unit.addTransporter(Quarters.STANDARD.newQuarters(std)); - } - } - } else if (unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) { - if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_STANDARD) { - unit.setArmorType(EquipmentType.T_ARMOR_AEROSPACE); - } - } else { - if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_PRIMITIVE) { - unit.setArmorType(EquipmentType.T_ARMOR_PRIMITIVE_FIGHTER); - } - } - List weaponGroups = new ArrayList<>(unit.getWeaponGroupList()); - for (Mounted group : weaponGroups) { - UnitUtil.removeMounted(unit, group); - } - } - public static boolean isUnitWeapon(EquipmentType eq, Entity unit) { if (unit instanceof Tank) { - return UnitUtil.isTankWeapon(eq, unit); + return TankUtil.isTankWeapon(eq, unit); } if (unit instanceof BattleArmor) { - return UnitUtil.isBattleArmorWeapon(eq, unit); + return BattleArmorUtil.isBattleArmorWeapon(eq, unit); } if (unit instanceof Infantry) { - return UnitUtil.isInfantryEquipment(eq, unit); - } - - return UnitUtil.isMechWeapon(eq, unit); - } - - public static boolean isMechWeapon(EquipmentType eq, Entity unit) { - if (eq instanceof InfantryWeapon) { - return false; - } - - if (UnitUtil.isHeatSink(eq) || UnitUtil.isArmorOrStructure(eq) - || UnitUtil.isJumpJet(eq) - || UnitUtil.isMechEquipment(eq, (Mech) unit)) { - return false; - } - - if (eq instanceof AmmoType) { - return false; - } - - if (eq instanceof WeaponType) { - - WeaponType weapon = (WeaponType) eq; - - if (!weapon.hasFlag(WeaponType.F_MECH_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (weapon.isCapital() || weapon.isSubCapital()) { - return false; - } - - if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) - && (weapon.getRackSize() != 5) - && (weapon.getRackSize() != 10) - && (weapon.getRackSize() != 15) - && (weapon.getRackSize() != 20)) { - return false; - } - if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) - && (weapon.getRackSize() != 2) - && (weapon.getRackSize() != 4) - && (weapon.getRackSize() != 6)) { - return false; - } - if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon - .getAmmoType() == AmmoType.T_PLASMA))) { - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } - } - - if ((unit instanceof LandAirMech) - && (weapon.getAmmoType() == AmmoType.T_GAUSS_HEAVY - || weapon.getAmmoType() == AmmoType.T_IGAUSS_HEAVY)) { - return false; - } - - return true; - } - return false; - } - - public static boolean isAeroWeapon(EquipmentType eq, Aero unit) { - if (!(eq instanceof WeaponType)) { - return false; - - } - if (eq instanceof InfantryWeapon) { - return false; - } - // Fixed wing, airship, and satellite vehicles use vehicle construction rules. - if (unit.isSupportVehicle()) { - return eq.hasFlag(WeaponType.F_TANK_WEAPON) - && TestTank.legalForMotiveType(eq, unit.getMovementMode(), true); - } - - WeaponType weapon = (WeaponType) eq; - - if (weapon.hasFlag(WeaponType.F_BOMB_WEAPON)) { - return false; - } - - // small craft only; lacks aero weapon flag - if (weapon.getAmmoType() == AmmoType.T_C3_REMOTE_SENSOR) { - return unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT) - && !unit.hasETypeFlag(Entity.ETYPE_DROPSHIP); - } - - if (weapon.hasFlag(WeaponType.F_ARTILLERY) && !weapon.hasFlag(WeaponType.F_BA_WEAPON)) { - return (weapon.getAmmoType() == AmmoType.T_ARROW_IV) - || unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT) - || unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); - } - - if (weapon.isSubCapital() || (weapon instanceof CapitalMissileWeapon) - || (weapon.getAtClass() == WeaponType.CLASS_SCREEN)) { - return unit.hasETypeFlag(Entity.ETYPE_DROPSHIP) - || unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); - } - - if (weapon.isCapital()) { - return unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP); - } - - if (!weapon.hasFlag(WeaponType.F_AERO_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) - && (weapon.getRackSize() != 5) - && (weapon.getRackSize() != 10) - && (weapon.getRackSize() != 15) - && (weapon.getRackSize() != 20)) { - return false; - } - if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) - && (weapon.getRackSize() != 2) - && (weapon.getRackSize() != 4) - && (weapon.getRackSize() != 6)) { - return false; - } - if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { - return false; + return InfantryUtil.isInfantryEquipment(eq, unit); } - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon - .getAmmoType() == AmmoType.T_PLASMA))) { - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } - } - return true; - } - - public static boolean isAeroEquipment(EquipmentType eq, Aero unit) { - - if (UnitUtil.isArmorOrStructure(eq)) { - return false; - } - - if ((eq instanceof AmmoType) - && (((AmmoType)eq).getAmmoType() == AmmoType.T_COOLANT_POD)) { - return !unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT); - } - - if ((eq instanceof MiscType)) { - if (unit.hasETypeFlag(Entity.ETYPE_SPACE_STATION)) { - return eq.hasFlag(MiscType.F_SS_EQUIPMENT); - } else if (unit.hasETypeFlag(Entity.ETYPE_WARSHIP)) { - return eq.hasFlag(MiscType.F_WS_EQUIPMENT); - } else if (unit.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) { - return eq.hasFlag(MiscType.F_JS_EQUIPMENT); - } else if (unit.hasETypeFlag(Entity.ETYPE_DROPSHIP)) { - return eq.hasFlag(MiscType.F_DS_EQUIPMENT); - } else if (unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT)) { - return eq.hasFlag(MiscType.F_SC_EQUIPMENT); - } else if (eq.hasFlag(MiscType.F_FLOTATION_HULL)) { - return unit.hasETypeFlag(Entity.ETYPE_CONV_FIGHTER) - && !unit.hasETypeFlag(Entity.ETYPE_FIXED_WING_SUPPORT); - } else if (unit.isSupportVehicle()) { - return eq.hasFlag(MiscType.F_SUPPORT_TANK_EQUIPMENT) - && TestTank.legalForMotiveType(eq, unit.getMovementMode(), true); - } else { - return eq.hasFlag(MiscType.F_FIGHTER_EQUIPMENT); - } - } - - if (eq instanceof AmmoType) { - return ((AmmoType) eq).canAeroUse(); - } - - return isAeroWeapon(eq, unit); + return MekUtil.isMechWeapon(eq, unit); } public static boolean isEntityEquipment(EquipmentType eq, Entity en) { if (en instanceof Mech) { - return isMechEquipment(eq, (Mech) en); + return MekUtil.isMechEquipment(eq, (Mech) en); } else if (en instanceof Protomech) { - return isProtomechEquipment(eq, (Protomech) en); + return ProtoMekUtil.isProtomechEquipment(eq, (Protomech) en); } else if (en.isSupportVehicle()) { return isSupportVehicleEquipment(eq, en); } else if (en instanceof Tank) { - return isTankEquipment(eq, (Tank) en); + return TankUtil.isTankEquipment(eq, (Tank) en); } else if (en instanceof BattleArmor) { - return isBAEquipment(eq, (BattleArmor) en); + return BattleArmorUtil.isBAEquipment(eq, (BattleArmor) en); } else if (en instanceof Aero) { - return isAeroEquipment(eq, (Aero) en); + return AeroUtil.isAeroEquipment(eq, (Aero) en); } else { return true; } } - /** - * Returns true if the given Equipment is available as equipment to the given Mek. - * Only valid to use for MiscTypes, not WeaponTypes nor AmmoTypes, also physical - * weapons return false despite being MiscType. - * - * @param eq The tested equipment - * @param unit The Mek unit - * @return true if the equipment is usable by the Mek - */ - // TODO: Make this behave like the other isXYZEquipment - public static boolean isMechEquipment(EquipmentType eq, Mech unit) { - if (UnitUtil.isArmorOrStructure(eq)) { - return false; - } - - if ((eq instanceof CLTAG) || (eq instanceof ISC3MBS) - || (eq instanceof ISC3M) || (eq instanceof ISTAG) - || (eq instanceof AmmoType && ((AmmoType) eq).getAmmoType() == AmmoType.T_COOLANT_POD) - || (eq instanceof CLLightTAG) || (eq instanceof ISAMS) - || (eq instanceof CLAMS) || (eq instanceof ISLaserAMS) - || (eq instanceof CLLaserAMS) || (eq instanceof ISAPDS)) { - return true; - } - - if ((eq instanceof MiscType)) { - if (eq.isAnyOf(EquipmentTypeLookup.LAM_FUEL_TANK, EquipmentTypeLookup.LAM_BOMB_BAY) - && !(unit instanceof LandAirMech)) { - return false; - } - if ((eq.hasFlag(MiscType.F_QUAD_TURRET) || eq.hasFlag(MiscType.F_RAM_PLATE)) - && !(unit instanceof QuadMech)) { - return false; - } - - if (!((unit instanceof BipedMech) || (unit instanceof TripodMech)) - && (eq.hasFlag(MiscType.F_SHOULDER_TURRET))) { - return false; - } - - if (unit.isSuperHeavy() - && (eq.hasFlag(MiscType.F_ACTUATOR_ENHANCEMENT_SYSTEM) - || eq.hasFlag(MiscType.F_MASC) // to catch Supercharger - || eq.hasFlag(MiscType.F_SCM) - || eq.hasFlag(MiscType.F_MODULAR_ARMOR) - || eq.hasFlag(MiscType.F_PARTIAL_WING) - || eq.hasFlag(MiscType.F_UMU))) { - return false; - } - - if ((unit instanceof LandAirMech) - && ((eq.hasFlag(MiscType.F_MASC) && eq.getSubType() == MiscType.S_SUPERCHARGER) - || eq.hasFlag(MiscType.F_MODULAR_ARMOR) - || eq.hasFlag(MiscType.F_JUMP_BOOSTER) - || eq.hasFlag(MiscType.F_PARTIAL_WING) - || eq.hasFlag(MiscType.F_VOIDSIG) - || eq.hasFlag(MiscType.F_NULLSIG) - || eq.hasFlag(MiscType.F_BLUE_SHIELD) - || eq.hasFlag(MiscType.F_CHAMELEON_SHIELD) - || eq.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING) - || eq.hasFlag(MiscType.F_DUMPER) - || eq.hasFlag(MiscType.F_HEAVY_BRIDGE_LAYER) - || eq.hasFlag(MiscType.F_MEDIUM_BRIDGE_LAYER) - || eq.hasFlag(MiscType.F_LIGHT_BRIDGE_LAYER) - || (eq.hasFlag(MiscType.F_CLUB) - && (eq.getSubType() == MiscType.S_BACKHOE) - || (eq.getSubType() == MiscType.S_COMBINE)))) { - return false; - } - - if (eq.hasFlag(MiscType.F_FUEL)) { - return unit.isIndustrial() - && ((unit.getEngine().getEngineType() == Engine.COMBUSTION_ENGINE) - || (unit.getEngine().getEngineType() == Engine.FUEL_CELL)); - } - if (eq.hasFlag(MiscType.F_ENVIRONMENTAL_SEALING) || eq.is("Cargo Container (10 tons)")) { - return unit.isIndustrial(); - } - - if (eq.hasFlag(MiscType.F_MECH_EQUIPMENT) - && !eq.hasFlag(MiscType.F_CLUB) - && !eq.hasFlag(MiscType.F_HAND_WEAPON) - && !eq.hasFlag(MiscType.F_TALON)) { - return true; - } - - if (eq.hasFlag(MiscType.F_IS_DOUBLE_HEAT_SINK_PROTOTYPE)) { - return true; - } - } - - return false; - } - - public static boolean isProtomechEquipment(EquipmentType eq, Protomech proto) { - return isProtomechEquipment(eq, proto, false); - } - - public static boolean isProtomechEquipment(EquipmentType eq, Protomech proto, boolean checkConfiguration) { - if (checkConfiguration && (eq instanceof MiscType)) { - if (eq.hasFlag(MiscType.F_MAGNETIC_CLAMP) && (proto.isQuad() || proto.isGlider())) { - return false; - } - if (eq.hasFlag(MiscType.F_CLUB) && eq.hasSubType(MiscType.S_PROTOMECH_WEAPON) && proto.isQuad()) { - return false; - } - if (eq.hasFlag(MiscType.F_CLUB) && eq.hasSubType(MiscType.S_PROTO_QMS) && !proto.isQuad()) { - return false; - } - } - if (eq instanceof MiscType) { - return eq.hasFlag(MiscType.F_PROTOMECH_EQUIPMENT); - } else if (eq instanceof WeaponType) { - return eq.hasFlag(WeaponType.F_PROTO_WEAPON); - } - return true; - } - - public static boolean isTankWeapon(EquipmentType eq, Entity unit) { - if (eq instanceof InfantryWeapon) { - return false; - } - // Some weapons such as TAG and C3M should show as non-weapon equipment - if (isTankMiscEquipment(eq, unit)) { - return false; - } - - if (eq instanceof WeaponType) { - - WeaponType weapon = (WeaponType) eq; - - if (!weapon.hasFlag(WeaponType.F_TANK_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (weapon.isCapital() || weapon.isSubCapital()) { - return false; - } - - if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) - && (weapon.getRackSize() != 5) - && (weapon.getRackSize() != 10) - && (weapon.getRackSize() != 15) - && (weapon.getRackSize() != 20)) { - return false; - } - if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) - && (weapon.getRackSize() != 2) - && (weapon.getRackSize() != 4) - && (weapon.getRackSize() != 6)) { - return false; - } - if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon.getAmmoType() == AmmoType.T_PLASMA))) { - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } - } - - return TestTank.legalForMotiveType(weapon, unit.getMovementMode(), unit.isSupportVehicle()); - } - return false; - } - /** * Returns true if the given Equipment is available as equipment to the given Support * Vehicle. Includes WeaponTypes, AmmoTypes and MiscTypes. * - * @param eq The tested equipment - * @param unit The support vehicles. May be an Aero or Tank subtype + * @param eq The equipment to test The tested equipment + * @param unit The entity The support vehicles. May be an Aero or Tank subtype * @return true if the equipment is usable by the entity */ public static boolean isSupportVehicleEquipment(EquipmentType eq, Entity unit) { @@ -2819,175 +1427,16 @@ public static boolean isSupportVehicleEquipment(EquipmentType eq, Entity unit) { return true; } if (unit.isAero()) { - return isAeroEquipment(eq, (Aero) unit); - } else { - return isTankEquipment(eq, (Tank) unit); - } - } - - /** - * @param eq A {@link WeaponType} or {@link MiscType} - * @param ba The BattleArmor instance - * @return Whether the BA can use the equipment - */ - public static boolean isBAEquipment(EquipmentType eq, BattleArmor ba) { - if (eq instanceof MiscType) { - return eq.hasFlag(MiscType.F_BA_EQUIPMENT); - } else if (eq instanceof WeaponType) { - return isBattleArmorWeapon(eq, ba); - } - // This leaves ammotype, which is filtered according to having a weapon that can use it - return false; - } - - public static boolean isBattleArmorAPWeapon(@Nullable EquipmentType etype) { - if (!(etype instanceof InfantryWeapon)) { - return false; + return AeroUtil.isAeroEquipment(eq, (Aero) unit); } else { - InfantryWeapon infWeap = (InfantryWeapon) etype; - return infWeap.hasFlag(WeaponType.F_INFANTRY) - && !infWeap.hasFlag(WeaponType.F_INF_POINT_BLANK) - && !infWeap.hasFlag(WeaponType.F_INF_ARCHAIC) - && (infWeap.getCrew() < 2); - } - } - - public static boolean isBattleArmorWeapon(EquipmentType eq, Entity unit) { - if (eq instanceof WeaponType) { - WeaponType weapon = (WeaponType) eq; - - if (!weapon.hasFlag(WeaponType.F_BA_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (weapon.isCapital() || weapon.isSubCapital()) { - return false; - } - - if ((eq instanceof SwarmAttack) || (eq instanceof StopSwarmAttack) - || (eq instanceof LegAttack)) { - return false; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon - .getAmmoType() == AmmoType.T_PLASMA))) { - return true; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) && (weapon.hasFlag(WeaponType.F_PLASMA)) - && (weapon.hasFlag(WeaponType.F_BA_WEAPON))) { - return true; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) - { - return false; - } - - return true; + return TankUtil.isTankEquipment(eq, (Tank) unit); } - - return false; - } - - public static boolean isInfantryEquipment(EquipmentType eq, Entity unit) { - // TODO: adjust for field guns and artillery - return eq instanceof InfantryWeapon; - } - - /** - * Tests whether equipment should be shown on the equipment tab for the unit. This is - * used for both combat vehicles and non-aerospace support vehicles. - * @param eq The equipment to show - * @param tank The tank - * @return Whether the equipment should show on the table - */ - public static boolean isTankEquipment(EquipmentType eq, Tank tank) { - return isTankMiscEquipment(eq, tank) || isTankWeapon(eq, tank); - } - - /** - * Tests whether equipment should be shown on the equipment tab for the unit as non-weapon - * equipment. This is used for both combat vehicles and non-aerospace support vehicles. - * @param eq The equipment to show - * @param tank The tank - * @return Whether the equipment should show on the table - */ - public static boolean isTankMiscEquipment(EquipmentType eq, Entity tank) { - if (UnitUtil.isArmorOrStructure(eq)) { - return false; - } - - // Display AMS as equipment (even though it's a weapon) - if (eq.hasFlag(WeaponType.F_AMS) - && eq.hasFlag(WeaponType.F_TANK_WEAPON)) { - return true; - } - - if ((eq instanceof CLTAG) || (eq instanceof ISC3M) - || (eq instanceof ISC3MBS) - || (eq instanceof ISTAG) || (eq instanceof CLLightTAG)) { - return true; - } - - if (eq instanceof MiscType) { - if (!TestTank.legalForMotiveType(eq, tank.getMovementMode(), tank.isSupportVehicle())) { - return false; - } - // Can't use supercharger with solar or external power pickup - if (eq.hasFlag(MiscType.F_MASC) && (!tank.hasEngine() - || tank.getEngine().getEngineType() == Engine.SOLAR - || tank.getEngine().getEngineType() == Engine.EXTERNAL)) { - return false; - } - // External fuel tanks are only allowed on ICE and fuel cell engines - if (eq.hasFlag(MiscType.F_FUEL) && (!tank.hasEngine() - || (tank.getEngine().getEngineType() != Engine.COMBUSTION_ENGINE - && tank.getEngine().getEngineType() != Engine.FUEL_CELL))) { - return false; - } - if (eq.hasFlag(MiscType.F_VTOL_EQUIPMENT) && (tank instanceof VTOL)) { - return true; - } - if (tank.isSupportVehicle()) { - return eq.hasFlag(MiscType.F_SUPPORT_TANK_EQUIPMENT); - } else { - return eq.hasFlag(MiscType.F_TANK_EQUIPMENT); - } - } - return false; - } - - public static boolean canSwarm(BattleArmor ba) { - for (Mounted eq : ba.getEquipment()) { - if ((eq.getType() instanceof SwarmAttack) - || (eq.getType() instanceof StopSwarmAttack)) { - return true; - } - } - return false; - } - - public static boolean canLegAttack(BattleArmor ba) { - for (Mounted eq : ba.getEquipment()) { - if (eq.getType() instanceof LegAttack) { - return true; - } - } - return false; } /** * remove all CriticalSlots on the passed unit that are internal structure or armor * - * @param unit the Entity + * @param unit The entity the Entity * @param internalStructure true to remove IS, false to remove armor */ public static void removeISorArmorCrits(Entity unit, boolean internalStructure) { @@ -3027,7 +1476,7 @@ public static void removeISorArmorCrits(Entity unit, boolean internalStructure) * remove all Mounted on the passed unit that are internal structure or * armor * - * @param unit the Entity + * @param unit The entity the Entity * @param internalStructure true to remove IS, false to remove armor */ public static void removeISorArmorMounts(Entity unit, boolean internalStructure) { @@ -3078,7 +1527,7 @@ public static void removeISorArmorMounts(Entity unit, boolean internalStructure) * Remove all mounts for the current armor type from a single location on the passed unit * and sets the armor type in that location to standard. * - * @param unit The Entity + * @param unit The entity The Entity * @param loc The location from which to remove the armor mounts. */ public static void resetArmor(Entity unit, int loc) { @@ -3164,7 +1613,7 @@ public static void checkArmor(Entity unit) { } /** - * @param unit the supplied entity + * @param unit The entity the supplied entity * @return a TestEntity instance for the supplied Entity. */ public static TestEntity getEntityVerifier(Entity unit) { @@ -3198,7 +1647,7 @@ public static TestEntity getEntityVerifier(Entity unit) { /** * check that the unit is vaild * - * @param unit + * @param unit The entity * @return */ public static String validateUnit(Entity unit) { @@ -3241,8 +1690,8 @@ public static void removeTC(Entity unit) { /** * Checks whether the equipment can be added to the location on the build tab - * @param unit The Entity being designed - * @param eq The equipment + * @param unit The entity The Entity being designed + * @param eq The equipment to test The equipment * @param location The location to add it * @return Whether the location is valid */ @@ -3413,35 +1862,6 @@ public static void removeHiddenAmmo(Mounted mounted) { } } - /** - * Checks whether the space has room for the equipment within the slot and weight limits. - * - * @param location A ProtoMek location - * @param mount The equipment to be added to the location - * @return Whether the equipment can be added without exceeding the limits. - */ - public static boolean protomechHasRoom(Protomech proto, int location, Mounted mount) { - if (!TestProtomech.requiresSlot(mount.getType())) { - return true; - } - int slots = TestProtomech.maxSlotsByLocation(location, proto) - 1; - double weight = TestProtomech.maxWeightByLocation(location, proto) - - mount.getTonnage(); - if ((slots < 0) || (weight < 0)) { - return false; - } - for (Mounted m : proto.getEquipment()) { - if (m.getLocation() == location) { - slots--; - weight -= m.getTonnage(); - if ((slots < 0) || (weight < 0)) { - return false; - } - } - } - return true; - } - public static void showValidation(Entity entity, JFrame frame) { final String validation = UnitUtil.validateUnit(entity); if (validation.isBlank()) { @@ -3451,100 +1871,11 @@ public static void showValidation(Entity entity, JFrame frame) { } } - public static void showUnitSpecs(Entity unit, JFrame frame) { - HTMLEditorKit kit = new HTMLEditorKit(); - - MechView mechView; - try { - mechView = new MechView(unit, true); - } catch (Exception ex) { - // error unit didn't load right. this is bad news. - LogManager.getLogger().error("", ex); - return; - } - - StringBuffer unitSpecs = new StringBuffer(""); - unitSpecs.append(mechView.getMechReadoutBasic()); - unitSpecs.append(mechView.getMechReadoutLoadout()); - unitSpecs.append(""); - - JEditorPane textPane = new JEditorPane("text/html", ""); - JScrollPane scroll = new JScrollPane(); - - textPane.setEditable(false); - textPane.setCaret(new DefaultCaret()); - textPane.setEditorKit(kit); - - scroll.setViewportView(textPane); - scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - scroll.getVerticalScrollBar().setUnitIncrement(20); - - textPane.setText(unitSpecs.toString()); - - scroll.setVisible(true); - - JDialog jdialog = new JDialog(); - - jdialog.add(scroll); - - jdialog.pack(); - - jdialog.setLocationRelativeTo(frame); - jdialog.setVisible(true); - - try { - textPane.setSelectionStart(0); - textPane.setSelectionEnd(0); - } catch (Exception ignored) { - - } - } - - public static void showUnitWeightBreakDown(Entity unit, JFrame frame) { - TestEntity testEntity = getEntityVerifier(unit); - - JTextPane textPane = new JTextPane(); - JScrollPane scroll = new JScrollPane(); - - textPane.setText(testEntity.printEntity().toString()); - textPane.setEditable(false); - textPane.setCaret(new DefaultCaret()); - - scroll.setViewportView(textPane); - scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - scroll.getVerticalScrollBar().setUnitIncrement(20); - - scroll.setVisible(true); - - JDialog jdialog = new JDialog(); - - jdialog.add(scroll); - jdialog.pack(); - jdialog.setLocationRelativeTo(frame); - jdialog.setVisible(true); - - try { - textPane.setSelectionStart(0); - textPane.setSelectionEnd(0); - } catch (Exception ignored) { - - } - } - - public static void showBVCalculations(final JFrame frame, final @Nullable Entity entity) { - if (entity == null) { - return; - } - new BVDisplayDialog(frame, entity).setVisible(true); - } - /** * Checks whether the unit has an weapon that uses the ammo type and the munition is legal for the * type of unit. * - * @param unit The unit + * @param unit The entity The unit * @param atype The ammo * @param includeOneShot If false, ignores one-shot weapons * @return Whether the unit can make use of the ammo @@ -3576,70 +1907,6 @@ public static boolean canUseAmmo(Entity unit, AmmoType atype, boolean includeOne return false; } - public static int countUsedCriticals(Mech unit) { - int nCrits = 0; - for (int i = 0; i < unit.locations(); i++) { - for (int j = 0; j < unit.getNumberOfCriticals(i); j++) { - CriticalSlot cs = unit.getCritical(i, j); - if (null != cs) { - nCrits++; - } - } - } - return nCrits + countUnallocatedCriticals(unit); - } - - public static int countUnallocatedCriticals(Mech unit) { - int nCrits = 0; - int engineHeatSinkCount = UnitUtil.getCriticalFreeHeatSinks(unit, - unit.hasCompactHeatSinks()); - for (Mounted mount : unit.getMisc()) { - if (UnitUtil.isHeatSink(mount) - && (mount.getLocation() == Entity.LOC_NONE)) { - if (engineHeatSinkCount > 0) { - engineHeatSinkCount--; - continue; - } - } - if ((mount.getLocation() == Entity.LOC_NONE)) { - nCrits += UnitUtil.getCritsUsed(mount); - } - } - for (Mounted mount : unit.getWeaponList()) { - if (mount.getLocation() == Entity.LOC_NONE) { - nCrits += UnitUtil.getCritsUsed(mount); - } - } - for (Mounted mount : unit.getAmmo()) { - if ((mount.getLocation() == Entity.LOC_NONE) && !mount.isOneShotAmmo()) { - nCrits += UnitUtil.getCritsUsed(mount); - } - } - return nCrits; - } - - // gives total number of sinks, not just critical slots - public static int countActualHeatSinks(Mech unit) { - int sinks = 0; - for (Mounted mounted : unit.getMisc()) { - if (!UnitUtil.isHeatSink(mounted)) { - continue; - } - if (mounted.getType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)) { - if (mounted.getType().hasFlag(MiscType.F_HEAT_SINK)) { - sinks++; - } else if (mounted.getType().hasFlag( - MiscType.F_DOUBLE_HEAT_SINK)) { - sinks++; - sinks++; - } - } else { - sinks++; - } - } - return sinks; - } - /** * @deprecated Use {@link UnitUtil#checkEquipmentByTechLevel(Entity, ITechManager)} instead */ @@ -3668,12 +1935,12 @@ public static void checkEquipmentByTechLevel(Entity unit) { Infantry pbi = (Infantry) unit; if ((null != pbi.getPrimaryWeapon()) && !UnitUtil.isLegal(unit, pbi.getPrimaryWeapon())) { - UnitUtil.replaceMainWeapon((Infantry) unit, + InfantryUtil.replaceMainWeapon((Infantry) unit, (InfantryWeapon) EquipmentType.get("Infantry Auto Rifle"), false); } if ((null != pbi.getSecondaryWeapon()) && !UnitUtil.isLegal(unit, pbi.getSecondaryWeapon())) { - UnitUtil.replaceMainWeapon((Infantry) unit, null, true); + InfantryUtil.replaceMainWeapon((Infantry) unit, null, true); } } } @@ -3681,7 +1948,7 @@ public static void checkEquipmentByTechLevel(Entity unit) { /** * Checks for any equipment that is added on the equipment tab and removes any that is * no longer legal for the current year/tech base/tech level - * @param unit The unit to check + * @param unit The entity The unit to check * @param techManager The manager that handles the checking * @return Whether any changes were made */ @@ -3721,257 +1988,19 @@ public static boolean checkEquipmentByTechLevel(Entity unit, ITechManager techMa if ((null != pbi.getPrimaryWeapon()) && techManager.isLegal(pbi.getPrimaryWeapon())) { dirty = true; - UnitUtil.replaceMainWeapon((Infantry) unit, + InfantryUtil.replaceMainWeapon((Infantry) unit, (InfantryWeapon) EquipmentType .get("Infantry Auto Rifle"), false); } if ((null != pbi.getSecondaryWeapon()) && !techManager.isLegal(pbi.getSecondaryWeapon())) { dirty = true; - UnitUtil.replaceMainWeapon((Infantry) unit, null, true); + InfantryUtil.replaceMainWeapon((Infantry) unit, null, true); } } return dirty; } - public static void replaceMainWeapon(Infantry unit, InfantryWeapon weapon, boolean secondary) { - Mounted existingInfantryMount = null; - for (Mounted m : unit.getWeaponList()) { - if ((m.getType() instanceof InfantryWeapon) - && (m.getLocation() == Infantry.LOC_INFANTRY)) { - existingInfantryMount = m; - break; - } - } - if (null != existingInfantryMount) { - UnitUtil.removeMounted(unit, existingInfantryMount); - } - if (secondary) { - unit.setSecondaryWeapon(weapon); - } else { - unit.setPrimaryWeapon(weapon); - } - // if there is more than one secondary weapon per squad, then add that - // to the unit otherwise add the primary weapon (unless the secondary - // is TAG, in which case both are added. - if (unit.getSecondaryWeapon() != null && unit.getSecondaryWeapon().hasFlag(WeaponType.F_TAG)) { - try { - unit.addEquipment(unit.getPrimaryWeapon(), Infantry.LOC_INFANTRY); - unit.addEquipment(unit.getSecondaryWeapon(), Infantry.LOC_INFANTRY); - } catch (LocationFullException ignored) { - - } - } else if ((unit.getSecondaryWeaponsPerSquad() < 2) || (null == unit.getSecondaryWeapon())) { - try { - unit.addEquipment(unit.getPrimaryWeapon(), Infantry.LOC_INFANTRY); - } catch (LocationFullException ignored) { - - } - } else { - try { - unit.addEquipment(unit.getSecondaryWeapon(), Infantry.LOC_INFANTRY); - } catch (LocationFullException ignored) { - - } - } - } - - public static void replaceFieldGun(Infantry unit, WeaponType fieldGun, int num) { - List toRemove = unit.getEquipment().stream() - .filter(m -> m.getLocation() == Infantry.LOC_FIELD_GUNS) - .collect(Collectors.toList()); - unit.getEquipment().removeAll(toRemove); - unit.getWeaponList().removeAll(toRemove); - unit.getAmmo().removeAll(toRemove); - final EnumSet munition; - if (fieldGun != null && num > 0) { - if (fieldGun.getAmmoType() == AmmoType.T_AC_LBX - || fieldGun.getAmmoType() == AmmoType.T_AC_LBX_THB) { - munition = EnumSet.of(AmmoType.Munitions.M_CLUSTER); - } else { - munition = EnumSet.of(AmmoType.Munitions.M_STANDARD); - } - Optional ammo = AmmoType.getMunitionsFor(fieldGun.getAmmoType()).stream() - .filter(eq -> (eq.getMunitionType().equals(munition)) - && (eq.getRackSize() == fieldGun.getRackSize())) - .findFirst(); - if (ammo.isEmpty()) { - ammo = AmmoType.getMunitionsFor(fieldGun.getAmmoType()).stream().findFirst(); - } - - for (int i = 0; i < num; i++) { - try { - unit.addEquipment(fieldGun, Infantry.LOC_FIELD_GUNS); - if (ammo.isPresent()) { - unit.addEquipment(ammo.get(), Infantry.LOC_FIELD_GUNS); - } else { - LogManager.getLogger().error("Could not find ammo for field gun " + fieldGun.getName()); - } - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - } - - public static String trimInfantryWeaponNames(String wname) { - return wname.replace("Infantry ", ""); - } - - public static void resetInfantryArmor(Infantry unit) { - unit.setArmorEncumbering(false); - unit.setSpaceSuit(false); - unit.setDEST(false); - unit.setSneakCamo(false); - unit.setSneakECM(false); - unit.setSneakIR(false); - unit.setArmorDamageDivisor(1.0); - } - - public static void removeHand(Mech mech, int location) { - if (mech.hasSystem(Mech.ACTUATOR_HAND, location)) { - mech.setCritical(location, 3, null); - } - } - - public static void removeArm(Mech mech, int location) { - if (mech.hasSystem(Mech.ACTUATOR_LOWER_ARM, location)) { - mech.setCritical(location, 2, null); - // Only remove the next slot of it actually is a hand - if (mech.hasSystem(Mech.ACTUATOR_HAND, location)) { - removeHand(mech, location); - } - } - } - - /** - * Adjusts the number of crew quarters of a given type on an aerospace vessel. - * - * @param aero The aerospace unit to change crew quarters sizes for - * @param quarters The type of crew quarters to change - * @param size The number of personnel that can be housed in the designated type of quarters - */ - public static void setQuarters(Aero aero, Quarters quarters, int size) { - List toRemove = new ArrayList<>(); - for (Bay bay : aero.getTransportBays()) { - if (Quarters.getQuartersForBay(bay) == quarters) { - toRemove.add(bay); - } - } - for (Bay bay : toRemove) { - aero.removeTransporter(bay); - } - if (size > 0) { - aero.addTransporter(quarters.newQuarters(size)); - } - } - - /** - * Adjusts the number of all types of crew quarters on an aerospace vessel. - * - * @param aero The vessel - * @param officer The number of officer/first class quarters - * @param standard The number of standard crew quarters - * @param secondclass The number second class passenger quarters - * @param steerage The number of steerage class crew/passenger quarters - */ - public static void assignQuarters(Aero aero, int officer, int standard, int secondclass, int steerage) { - Map sizes = Quarters.getQuartersByType(aero); - if (sizes.get(Quarters.FIRST_CLASS) != officer) { - UnitUtil.setQuarters(aero, Quarters.FIRST_CLASS, officer); - } - if (sizes.get(Quarters.STANDARD) != standard) { - UnitUtil.setQuarters(aero, Quarters.STANDARD, standard); - } - if (sizes.get(Quarters.SECOND_CLASS) != secondclass) { - UnitUtil.setQuarters(aero, Quarters.SECOND_CLASS, secondclass); - } - if (sizes.get(Quarters.STEERAGE) != steerage) { - UnitUtil.setQuarters(aero, Quarters.STEERAGE, steerage); - } - } - - /** - * Adjusts the number of quarters of each to match the crew and passenger needs. If no quarters - * are already assigned, this will put all officers in officer/first class cabins, enlisted crew - * in standard crew quarters, and passengers in second class cabins. If there are already more - * officer/first class cabins assigned than there are officers, the extra will be used as first - * class passenger cabins. Any steerage quarters will be assigned first to marines, then to passengers, - * then to remaining enlisted. - * - * @param aero The vessel to assign quarters for. - */ - public static void autoAssignQuarters(Aero aero) { - int marines = aero.getNMarines() + aero.getNBattleArmor(); - int enlistedNeeds = aero.getNCrew() + marines - aero.getBayPersonnel() - aero.getNOfficers(); - Map quartersCount = Quarters.getQuartersByType(aero); - - // Standard crew quarters should not be larger than the crew needs, but may be smaller as - // some crew may have officer or steerage housing. - int standardCrew = Math.min(enlistedNeeds, quartersCount.get(Quarters.STANDARD)); - // Limit the first class quarters to number of officers + passengers. It is possible to house - // enlisted in first class quarters, but that is beyond the scope of this and will need to - // be done by hand. - int officer1stC = Math.min(aero.getNOfficers() + aero.getNPassenger(), - quartersCount.get(Quarters.FIRST_CLASS)); - officer1stC = Math.max(officer1stC, aero.getNOfficers()); - int firstClass = Math.max(0, officer1stC - aero.getNOfficers()); - int officer = officer1stC - firstClass; - - // Limit the steerage quarters to the number of crew that have not been assigned standard - // or officer quarters and passengers that have not been assigned first class. - int steeragePsgr = Math.min(aero.getNPassenger() - firstClass + enlistedNeeds - standardCrew, - quartersCount.get(Quarters.STEERAGE)); - // Assign any existing steerage quarters first to marines that have not already been assigned standard - // quarters - int steerageCrew = 0; - if (enlistedNeeds > standardCrew) { - steerageCrew = Math.min(steeragePsgr, marines); - steeragePsgr -= steerageCrew; - } - // Assign any remaining steerage quarters to passengers first, then remaining crew. - if (steeragePsgr > aero.getNPassenger() - firstClass) { - int excess = steeragePsgr - aero.getNPassenger() - firstClass; - steerageCrew += excess; - steeragePsgr -= excess; - } - - // Any leftovers go to standard crew or second class - standardCrew = enlistedNeeds - steerageCrew; - int secondClass = aero.getNPassenger() - firstClass - steeragePsgr; - - assignQuarters(aero, officer + firstClass, standardCrew, secondClass, steerageCrew + steeragePsgr); - } - - /** Adds the given number of shots to the already present given ammo on the given ProtoMek. */ - public static void addProtoMechAmmo(Protomech entity, EquipmentType ammo, int shots) throws LocationFullException { - Mounted aMount = entity.getAmmo().stream() - .filter(m -> ammo.equals(m.getType())).findFirst().orElse(null); - if (null != aMount) { - aMount.setShotsLeft(aMount.getUsableShotsLeft() + shots); - } else { - Mounted mount = new Mounted(entity, ammo); - entity.addEquipment(mount, Protomech.LOC_BODY, false); - mount.setShotsLeft(shots); - } - } - - /** - * Subtracts the given number of shots from the given ammo on the given ProtoMek. - * May remove the entire Mounted from the ProtoMek. - */ - public static void reduceProtoMechAmmo(Protomech entity, EquipmentType ammo, int shots) { - Mounted aMount = entity.getAmmo().stream() - .filter(m -> ammo.equals(m.getType())).findFirst().orElse(null); - if (aMount != null) { - if (aMount.getUsableShotsLeft() <= shots) { - removeMounted(entity, aMount); - } else { - aMount.setShotsLeft(aMount.getUsableShotsLeft() - shots); - } - } - } - /** * Updates the manual BV value of the given entity. When manualBV is 0 or less, * the entity is set to not use a manual BV value and the manual BV is set to -1. @@ -3991,4 +2020,6 @@ public static void setVariableSizeMiscTypeMinimumSize(Mounted mounted) { mounted.setSize(mounted.getType().variableStepSize()); } } -} + + private UnitUtil() { } +} \ No newline at end of file From 9d5473760a25d93faad17703925ee5b38de4fdd7 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 4 Jan 2024 23:57:51 +0100 Subject: [PATCH 2/5] Separate UnitUtil (reference updates) --- .../megameklab/printing/InventoryWriter.java | 2 +- .../megameklab/printing/PrintBattleArmor.java | 8 +- .../megameklab/printing/PrintDropship.java | 4 +- megameklab/src/megameklab/ui/MenuBar.java | 103 +++- .../ui/battleArmor/BABuildView.java | 5 +- .../battleArmor/BAEquipmentDatabaseView.java | 3 +- .../ui/battleArmor/BAEquipmentTab.java | 5 +- .../ui/battleArmor/BAEquipmentView.java | 5 +- .../ui/combatVehicle/CVEquipmentView.java | 5 +- .../ui/infantry/CIEquipmentView.java | 4 +- .../ui/infantry/CIFieldGunView.java | 6 +- .../ui/infantry/CISpecializationView.java | 7 +- .../ui/infantry/CIStructureTab.java | 11 +- .../megameklab/ui/infantry/CIWeaponView.java | 6 +- .../ui/largeAero/DSStructureTab.java | 5 +- .../ui/largeAero/WSStructureTab.java | 5 +- .../src/megameklab/ui/mek/BMBuildTab.java | 15 +- .../src/megameklab/ui/mek/BMBuildView.java | 7 +- .../ui/mek/BMCriticalTransferHandler.java | 29 +- .../ui/mek/BMEquipmentDatabaseView.java | 3 +- .../src/megameklab/ui/mek/BMMainUI.java | 8 +- .../src/megameklab/ui/mek/BMStatusBar.java | 4 +- .../src/megameklab/ui/mek/BMStructureTab.java | 41 +- .../src/megameklab/ui/mek/BMSummaryView.java | 5 +- megameklab/src/megameklab/ui/mek/BMUtils.java | 491 ------------------ .../megameklab/ui/protoMek/PMBuildTab.java | 3 +- .../megameklab/ui/protoMek/PMBuildView.java | 3 +- .../ui/protoMek/PMStructureTab.java | 3 +- .../util/AbstractEquipmentDatabaseView.java | 10 +- .../ui/util/BAASBMDropTargetCriticalList.java | 5 +- .../src/megameklab/ui/util/CritCellUtil.java | 3 +- .../ui/util/CriticalTableModel.java | 3 +- .../ui/util/CriticalTransferHandler.java | 3 +- .../ui/util/EquipmentDatabaseCategory.java | 3 +- .../ui/util/EquipmentTableModel.java | 4 +- .../megameklab/ui/util/ProtomekMountList.java | 5 +- .../ui/util/WeaponListCellRenderer.java | 3 +- .../src/megameklab/util/UnitPrintManager.java | 2 +- 38 files changed, 230 insertions(+), 607 deletions(-) delete mode 100644 megameklab/src/megameklab/ui/mek/BMUtils.java diff --git a/megameklab/src/megameklab/printing/InventoryWriter.java b/megameklab/src/megameklab/printing/InventoryWriter.java index 51b64234f..0121424ec 100644 --- a/megameklab/src/megameklab/printing/InventoryWriter.java +++ b/megameklab/src/megameklab/printing/InventoryWriter.java @@ -235,7 +235,7 @@ private void parseEquipment() { ammo.merge(m.getShortName(), m.getBaseShotsLeft(), Integer::sum); } if ((m.getLocation() == Entity.LOC_NONE) - || !UnitUtil.isPrintableEquipment(m.getType(), sheet.getEntity())) { + || !PrintUtil.isPrintableEquipment(m.getType(), sheet.getEntity())) { continue; } if ((sheet.getEntity() instanceof QuadVee) diff --git a/megameklab/src/megameklab/printing/PrintBattleArmor.java b/megameklab/src/megameklab/printing/PrintBattleArmor.java index 84aa28345..79e88f376 100644 --- a/megameklab/src/megameklab/printing/PrintBattleArmor.java +++ b/megameklab/src/megameklab/printing/PrintBattleArmor.java @@ -15,7 +15,7 @@ import megamek.common.*; import megamek.common.battlevalue.BattleArmorBVCalculator; -import megameklab.util.UnitUtil; +import megameklab.util.BattleArmorUtil; import org.apache.batik.util.SVGConstants; import org.w3c.dom.Element; import org.w3c.dom.svg.SVGRectElement; @@ -86,8 +86,8 @@ protected void writeTextFields() { break; } hideElement(CHECK_MECHANIZED, !battleArmor.canDoMechanizedBA()); - hideElement(CHECK_SWARM, !UnitUtil.canSwarm(battleArmor)); - hideElement(CHECK_LEG, !UnitUtil.canLegAttack(battleArmor)); + hideElement(CHECK_SWARM, !BattleArmorUtil.canSwarm(battleArmor)); + hideElement(CHECK_LEG, !BattleArmorUtil.canLegAttack(battleArmor)); hideElement(CHECK_AP, battleArmor.countWorkingMisc(MiscType.F_AP_MOUNT) == 0); setTextField(BV, battleArmor.calculateBattleValue(true, !showPilotInfo()) @@ -144,7 +144,7 @@ protected String formatWalk() { public String formatMiscNotes() { final StringJoiner sj = new StringJoiner(" "); if (battleArmor.isBurdened() && ((battleArmor.getJumpMP(MPCalculationSetting.BA_UNBURDENED) > 0) - || UnitUtil.canLegAttack(battleArmor) || UnitUtil.canSwarm(battleArmor))) { + || BattleArmorUtil.canLegAttack(battleArmor) || BattleArmorUtil.canSwarm(battleArmor))) { sj.add("Must detach missiles before jumping or swarm/leg attacks."); } if (battleArmor.hasDWP()) { diff --git a/megameklab/src/megameklab/printing/PrintDropship.java b/megameklab/src/megameklab/printing/PrintDropship.java index 877d2d0f3..66cf25c32 100644 --- a/megameklab/src/megameklab/printing/PrintDropship.java +++ b/megameklab/src/megameklab/printing/PrintDropship.java @@ -15,12 +15,10 @@ import megamek.common.*; import megameklab.util.ImageHelper; -import megameklab.util.UnitUtil; import org.w3c.dom.Element; import org.w3c.dom.svg.SVGRectElement; import java.awt.print.PageFormat; -import java.io.File; import java.time.LocalDate; import java.util.*; @@ -332,7 +330,7 @@ public String formatFeatures() { StringJoiner sj = new StringJoiner(", "); Map eqCount = new HashMap<>(); for (Mounted mount : ship.getMisc()) { - if (UnitUtil.isPrintableEquipment(mount.getType())) { + if (PrintUtil.isPrintableEquipment(mount.getType())) { eqCount.merge(mount.getShortName(), 1, Integer::sum); } } diff --git a/megameklab/src/megameklab/ui/MenuBar.java b/megameklab/src/megameklab/ui/MenuBar.java index 1a615bb58..56762f700 100644 --- a/megameklab/src/megameklab/ui/MenuBar.java +++ b/megameklab/src/megameklab/ui/MenuBar.java @@ -14,12 +14,14 @@ */ package megameklab.ui; +import megamek.client.ui.dialogs.BVDisplayDialog; import megamek.client.ui.dialogs.CostDisplayDialog; import megamek.client.ui.swing.UnitLoadingDialog; import megamek.common.*; import megamek.common.annotations.Nullable; import megamek.common.loaders.BLKFile; import megamek.common.templates.TROView; +import megamek.common.verifier.TestEntity; import megameklab.MMLConstants; import megameklab.ui.dialog.MMLFileChooser; import megameklab.ui.dialog.MegaMekLabUnitSelectorDialog; @@ -35,6 +37,8 @@ import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.text.DefaultCaret; +import javax.swing.text.html.HTMLEditorKit; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; @@ -702,7 +706,7 @@ private JMenu createUnitBVBreakdownMenu() { final JMenuItem miCurrentUnitBVBreakdown = new JMenuItem(resources.getString("CurrentUnit.text")); miCurrentUnitBVBreakdown.setName("miCurrentUnitBVBreakdown"); miCurrentUnitBVBreakdown.setMnemonic(KeyEvent.VK_U); - miCurrentUnitBVBreakdown.addActionListener(evt -> UnitUtil.showBVCalculations(owner.getFrame(), owner.getEntity())); + miCurrentUnitBVBreakdown.addActionListener(evt -> showBVCalculations(owner.getFrame(), owner.getEntity())); miCurrentUnitBVBreakdown.setEnabled(isUnitGui()); unitBVBreakdownMenu.add(miCurrentUnitBVBreakdown); @@ -756,7 +760,7 @@ private JMenu createUnitWeightBreakdownMenu() { final JMenuItem miCurrentUnitWeightBreakdown = new JMenuItem(resources.getString("CurrentUnit.text")); miCurrentUnitWeightBreakdown.setName("miCurrentUnitWeightBreakdown"); miCurrentUnitWeightBreakdown.setMnemonic(KeyEvent.VK_U); - miCurrentUnitWeightBreakdown.addActionListener(evt -> UnitUtil.showUnitWeightBreakDown(owner.getEntity(), owner.getFrame())); + miCurrentUnitWeightBreakdown.addActionListener(evt -> showUnitWeightBreakDown(owner.getEntity(), owner.getFrame())); miCurrentUnitWeightBreakdown.setEnabled(isUnitGui()); unitWeightBreakdownMenu.add(miCurrentUnitWeightBreakdown); @@ -833,7 +837,7 @@ private void jMenuGetUnitWeightBreakdownFromCache_actionPerformed() { Entity chosenEntity = viewer.getChosenEntity(); if (chosenEntity != null) { - UnitUtil.showUnitWeightBreakDown(chosenEntity, owner.getFrame()); + showUnitWeightBreakDown(chosenEntity, owner.getFrame()); } viewer.dispose(); } @@ -845,7 +849,7 @@ private void jMenuGetUnitBVFromFile_actionPerformed() { } try { - UnitUtil.showBVCalculations(owner.getFrame(), new MechFileParser(unitFile).getEntity()); + showBVCalculations(owner.getFrame(), new MechFileParser(unitFile).getEntity()); } catch (Exception ex) { PopupMessages.showFileReadError(owner.getFrame(), unitFile.toString(), ex.getMessage()); } @@ -898,7 +902,7 @@ private void jMenuGetUnitWeightBreakdownFromFile_actionPerformed() { try { Entity tempEntity = new MechFileParser(unitFile).getEntity(); - UnitUtil.showUnitWeightBreakDown(tempEntity, owner.getFrame()); + showUnitWeightBreakDown(tempEntity, owner.getFrame()); } catch (Exception ex) { PopupMessages.showFileReadError(owner.getFrame(), unitFile.toString(), ex.getMessage()); } @@ -912,7 +916,7 @@ private void jMenuGetUnitSpecsFromFile_actionPerformed() { try { Entity tempEntity = new MechFileParser(unitFile).getEntity(); - UnitUtil.showUnitSpecs(tempEntity, owner.getFrame()); + showUnitSpecs(tempEntity, owner.getFrame()); } catch (Exception ex) { PopupMessages.showFileReadError(owner.getFrame(), unitFile.toString(), ex.getMessage()); } @@ -1313,4 +1317,91 @@ public void importSettings() { File settingsFile = new File(fileChooser.getSelectedFile(), CConfig.CONFIG_FILE); CConfig.importSettings(owner, settingsFile); } + + public static void showUnitSpecs(Entity unit, JFrame frame) { + HTMLEditorKit kit = new HTMLEditorKit(); + + MechView mechView; + try { + mechView = new MechView(unit, true); + } catch (Exception ex) { + // error unit didn't load right. this is bad news. + LogManager.getLogger().error("", ex); + return; + } + + String unitSpecs = "" + mechView.getMechReadoutBasic() + + mechView.getMechReadoutLoadout() + ""; + + JEditorPane textPane = new JEditorPane("text/html", ""); + JScrollPane scroll = new JScrollPane(); + + textPane.setEditable(false); + textPane.setCaret(new DefaultCaret()); + textPane.setEditorKit(kit); + + scroll.setViewportView(textPane); + scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + scroll.getVerticalScrollBar().setUnitIncrement(20); + + textPane.setText(unitSpecs); + + scroll.setVisible(true); + + JDialog jdialog = new JDialog(); + + jdialog.add(scroll); + + jdialog.pack(); + + jdialog.setLocationRelativeTo(frame); + jdialog.setVisible(true); + + try { + textPane.setSelectionStart(0); + textPane.setSelectionEnd(0); + } catch (Exception ignored) { + + } + } + + public static void showUnitWeightBreakDown(Entity unit, JFrame frame) { + TestEntity testEntity = UnitUtil.getEntityVerifier(unit); + + JTextPane textPane = new JTextPane(); + JScrollPane scroll = new JScrollPane(); + + textPane.setText(testEntity.printEntity().toString()); + textPane.setEditable(false); + textPane.setCaret(new DefaultCaret()); + + scroll.setViewportView(textPane); + scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + scroll.getVerticalScrollBar().setUnitIncrement(20); + + scroll.setVisible(true); + + JDialog jdialog = new JDialog(); + + jdialog.add(scroll); + jdialog.pack(); + jdialog.setLocationRelativeTo(frame); + jdialog.setVisible(true); + + try { + textPane.setSelectionStart(0); + textPane.setSelectionEnd(0); + } catch (Exception ignored) { + + } + } + + public static void showBVCalculations(final JFrame frame, final @Nullable Entity entity) { + if (entity == null) { + return; + } + new BVDisplayDialog(frame, entity).setVisible(true); + } } \ No newline at end of file diff --git a/megameklab/src/megameklab/ui/battleArmor/BABuildView.java b/megameklab/src/megameklab/ui/battleArmor/BABuildView.java index aed0a217c..36cfff171 100644 --- a/megameklab/src/megameklab/ui/battleArmor/BABuildView.java +++ b/megameklab/src/megameklab/ui/battleArmor/BABuildView.java @@ -23,6 +23,7 @@ import megameklab.ui.util.CriticalTransferHandler; import megameklab.ui.util.IView; import megameklab.ui.util.RefreshListener; +import megameklab.util.BattleArmorUtil; import megameklab.util.StringUtils; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -111,8 +112,8 @@ private void loadEquipmentTable() { continue; } if ((mount.getBaMountLoc() == BattleArmor.MOUNT_LOC_NONE) - && (UnitUtil.isBattleArmorWeapon(mount.getType(), getBattleArmor()) - || UnitUtil.isBattleArmorAPWeapon(mount.getType()))) { + && (BattleArmorUtil.isBattleArmorWeapon(mount.getType(), getBattleArmor()) + || BattleArmorUtil.isBattleArmorAPWeapon(mount.getType()))) { masterEquipmentList.add(mount); } } diff --git a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentDatabaseView.java b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentDatabaseView.java index e8646e75b..573ac8d93 100644 --- a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentDatabaseView.java +++ b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentDatabaseView.java @@ -17,6 +17,7 @@ import megamek.common.*; import megameklab.ui.EntitySource; import megameklab.ui.util.AbstractEquipmentDatabaseView; +import megameklab.util.BattleArmorUtil; import megameklab.util.UnitUtil; import java.util.Collection; @@ -47,7 +48,7 @@ protected void addEquipment(EquipmentType equip, int count) { } } else { try { - if (UnitUtil.isBAMultiMount(equip)) { + if (BattleArmorUtil.isBAMultiMount(equip)) { for (int t = 1; t <= getBattleArmor().getTroopers(); t++) { Mounted mount = new Mounted(getBattleArmor(), equip); mount.setBaMountLoc(BattleArmor.MOUNT_LOC_NONE); diff --git a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentTab.java b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentTab.java index 6f3634d9b..20cb64044 100644 --- a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentTab.java +++ b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentTab.java @@ -19,6 +19,7 @@ import megameklab.ui.EntitySource; import megameklab.ui.generalUnit.AbstractEquipmentTab; import megameklab.ui.util.AbstractEquipmentDatabaseView; +import megameklab.util.BattleArmorUtil; import megameklab.util.UnitUtil; /** @@ -48,8 +49,8 @@ protected boolean showInLoadout(Mounted mount) { } private boolean showWeaponInLoadout(Mounted mount) { - return UnitUtil.isBattleArmorWeapon(mount.getType(), getBattleArmor()) - || UnitUtil.isBattleArmorAPWeapon(mount.getType()); + return BattleArmorUtil.isBattleArmorWeapon(mount.getType(), getBattleArmor()) + || BattleArmorUtil.isBattleArmorAPWeapon(mount.getType()); } private boolean showAmmoInLoadout(Mounted mount) { diff --git a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentView.java b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentView.java index 5d2a7f77a..dd5790dd2 100644 --- a/megameklab/src/megameklab/ui/battleArmor/BAEquipmentView.java +++ b/megameklab/src/megameklab/ui/battleArmor/BAEquipmentView.java @@ -20,6 +20,7 @@ import megamek.common.Mounted; import megameklab.ui.EntitySource; import megameklab.ui.util.*; +import megameklab.util.BattleArmorUtil; import megameklab.util.StringUtils; import megameklab.util.UnitUtil; @@ -97,7 +98,7 @@ public BAEquipmentView(EntitySource eSource) { while (miscTypes.hasMoreElements()) { EquipmentType eq = miscTypes.nextElement(); - if (UnitUtil.isBAEquipment(eq, getBattleArmor())) { + if (BattleArmorUtil.isBAEquipment(eq, getBattleArmor())) { masterEquipmentList.add(eq); } } @@ -134,7 +135,7 @@ private void loadEquipmentTable() { if (UnitUtil.isArmorOrStructure(mount.getType())) { continue; } - if (UnitUtil.isBAEquipment(mount.getType(), getBattleArmor())) { + if (BattleArmorUtil.isBAEquipment(mount.getType(), getBattleArmor())) { equipmentList.addCrit(mount); } } diff --git a/megameklab/src/megameklab/ui/combatVehicle/CVEquipmentView.java b/megameklab/src/megameklab/ui/combatVehicle/CVEquipmentView.java index 289a437f5..1781fb305 100644 --- a/megameklab/src/megameklab/ui/combatVehicle/CVEquipmentView.java +++ b/megameklab/src/megameklab/ui/combatVehicle/CVEquipmentView.java @@ -22,6 +22,7 @@ import megameklab.ui.EntitySource; import megameklab.ui.util.*; import megameklab.util.StringUtils; +import megameklab.util.TankUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -89,7 +90,7 @@ public CVEquipmentView(EntitySource eSource) { while (miscTypes.hasMoreElements()) { EquipmentType eq = miscTypes.nextElement(); - if (UnitUtil.isTankEquipment(eq, getTank())) { + if (TankUtil.isTankEquipment(eq, getTank())) { masterEquipmentList.add(eq); } } @@ -126,7 +127,7 @@ private void loadEquipmentTable() { if (UnitUtil.isHeatSink(mount) || UnitUtil.isArmorOrStructure(mount.getType())) { continue; } - if (UnitUtil.isTankEquipment(mount.getType(), getTank())) { + if (TankUtil.isTankEquipment(mount.getType(), getTank())) { equipmentList.addCrit(mount); } } diff --git a/megameklab/src/megameklab/ui/infantry/CIEquipmentView.java b/megameklab/src/megameklab/ui/infantry/CIEquipmentView.java index 5cbbabcfb..7ee22da4a 100644 --- a/megameklab/src/megameklab/ui/infantry/CIEquipmentView.java +++ b/megameklab/src/megameklab/ui/infantry/CIEquipmentView.java @@ -26,7 +26,7 @@ import megameklab.ui.util.EquipmentTableModel; import megameklab.ui.util.IView; import megameklab.ui.util.RefreshListener; -import megameklab.util.UnitUtil; +import megameklab.util.InfantryUtil; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -246,7 +246,7 @@ public void actionPerformed(ActionEvent evt) { int selected = masterEquipmentTable.convertRowIndexToModel(view); EquipmentType equip = masterEquipmentList.getType(selected); if (equip instanceof InfantryWeapon) { - UnitUtil.replaceMainWeapon(getInfantry(), (InfantryWeapon) equip, isSecondary); + InfantryUtil.replaceMainWeapon(getInfantry(), (InfantryWeapon) equip, isSecondary); if (equip.hasFlag(WeaponType.F_TAG)) { getInfantry().setSpecializations(getInfantry().getSpecializations() | Infantry.TAG_TROOPS); getInfantry().setSecondaryWeaponsPerSquad(2); diff --git a/megameklab/src/megameklab/ui/infantry/CIFieldGunView.java b/megameklab/src/megameklab/ui/infantry/CIFieldGunView.java index b0d34eb5a..f236beb23 100644 --- a/megameklab/src/megameklab/ui/infantry/CIFieldGunView.java +++ b/megameklab/src/megameklab/ui/infantry/CIFieldGunView.java @@ -26,7 +26,7 @@ import megameklab.ui.util.EquipmentTableModel; import megameklab.ui.util.IView; import megameklab.ui.util.RefreshListener; -import megameklab.util.UnitUtil; +import megameklab.util.InfantryUtil; import javax.swing.*; import javax.swing.RowSorter.SortKey; @@ -284,9 +284,9 @@ public void actionPerformed(ActionEvent e) { int crewReq = Math.max(2, (int) Math.ceil(equip.getTonnage(getInfantry()))); num = getInfantry().getShootingStrength() / crewReq; } - UnitUtil.replaceFieldGun(getInfantry(), (WeaponType) equip, num); + InfantryUtil.replaceFieldGun(getInfantry(), (WeaponType) equip, num); } else if (e.getSource().equals(btnRemoveGun)) { - UnitUtil.replaceFieldGun(getInfantry(), null, 0); + InfantryUtil.replaceFieldGun(getInfantry(), null, 0); } else { return; } diff --git a/megameklab/src/megameklab/ui/infantry/CISpecializationView.java b/megameklab/src/megameklab/ui/infantry/CISpecializationView.java index 7c99d7f2b..25ce6e545 100644 --- a/megameklab/src/megameklab/ui/infantry/CISpecializationView.java +++ b/megameklab/src/megameklab/ui/infantry/CISpecializationView.java @@ -16,14 +16,13 @@ package megameklab.ui.infantry; import megamek.client.ui.models.XTableColumnModel; -import megamek.common.EntityMovementMode; import megamek.common.Infantry; import megamek.common.TechAdvancement; import megamek.common.verifier.TestInfantry; import megameklab.ui.EntitySource; import megameklab.ui.listeners.InfantryBuildListener; import megameklab.ui.util.IView; -import megameklab.util.UnitUtil; +import megameklab.util.InfantryUtil; import javax.swing.*; import javax.swing.event.TableModelEvent; @@ -229,13 +228,13 @@ public void setValueAt(Object value, int row, int col) { if ((Infantry.TAG_TROOPS != spec) && getInfantry().hasSpecialization(Infantry.TAG_TROOPS) && TestInfantry.maxSecondaryWeapons(getInfantry()) < 2) { - UnitUtil.replaceMainWeapon(getInfantry(), null, true); + InfantryUtil.replaceMainWeapon(getInfantry(), null, true); getInfantry().setSecondaryWeaponsPerSquad(0); getInfantry().setSpecializations(getInfantry().getSpecializations() & ~Infantry.TAG_TROOPS); } else if (TestInfantry.maxSecondaryWeapons(getInfantry()) > getInfantry().getSecondaryWeaponsPerSquad()) { getInfantry().setSecondaryWeaponsPerSquad(TestInfantry.maxSecondaryWeapons(getInfantry())); if (getInfantry().getSecondaryWeaponsPerSquad() == 0) { - UnitUtil.replaceMainWeapon(getInfantry(), null, true); + InfantryUtil.replaceMainWeapon(getInfantry(), null, true); } } fireTableCellUpdated(row, col); diff --git a/megameklab/src/megameklab/ui/infantry/CIStructureTab.java b/megameklab/src/megameklab/ui/infantry/CIStructureTab.java index e5d7904bf..805255c48 100644 --- a/megameklab/src/megameklab/ui/infantry/CIStructureTab.java +++ b/megameklab/src/megameklab/ui/infantry/CIStructureTab.java @@ -44,6 +44,7 @@ import megameklab.ui.listeners.InfantryBuildListener; import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; +import megameklab.util.InfantryUtil; import megameklab.util.UnitUtil; public class CIStructureTab extends ITab implements InfantryBuildListener { @@ -281,7 +282,7 @@ private void updateSpecializations() { && ((getInfantry().getSecondaryWeaponsPerSquad() < 2) || (getInfantry().getSecondaryWeapon() == null) || !getInfantry().getSecondaryWeapon().hasFlag(WeaponType.F_TAG))) { - UnitUtil.replaceMainWeapon(getInfantry(), + InfantryUtil.replaceMainWeapon(getInfantry(), (InfantryWeapon)EquipmentType.get(EquipmentTypeLookup.INFANTRY_TAG), true); getInfantry().setSecondaryWeaponsPerSquad(2); } @@ -354,7 +355,7 @@ public void updateTechLevel() { } getInfantry().setTechLevel(panBasicInfo.getTechLevel().getCompoundTechLevel(panBasicInfo.useClanTechBase())); UnitUtil.checkEquipmentByTechLevel(getInfantry(), panBasicInfo); - UnitUtil.resetInfantryArmor(getInfantry()); + InfantryUtil.resetInfantryArmor(getInfantry()); panPlatoonType.setFromEntity(getInfantry()); panWeapons.setFromEntity(getInfantry()); updateSpecializations(); @@ -408,7 +409,7 @@ public void motiveTypeChanged(EntityMovementMode movementMode, boolean alt) { if (getInfantry().getMovementMode() != EntityMovementMode.INF_MOTORIZED && getInfantry().getMovementMode() != EntityMovementMode.TRACKED && getInfantry().getMovementMode() != EntityMovementMode.WHEELED) { - UnitUtil.replaceFieldGun(getInfantry(), null, 0); + InfantryUtil.replaceFieldGun(getInfantry(), null, 0); } enableTabs(); panPlatoonType.setFromEntity(getInfantry()); @@ -445,7 +446,7 @@ public void numSecondaryChanged(final int count) { getInfantry().setSecondaryWeaponsPerSquad(0); } else { if (count == 0) { - UnitUtil.replaceMainWeapon(getInfantry(), null, true); + InfantryUtil.replaceMainWeapon(getInfantry(), null, true); getInfantry().setSpecializations(getInfantry().getSpecializations() & ~Infantry.TAG_TROOPS); } getInfantry().setSecondaryWeaponsPerSquad(count); @@ -460,7 +461,7 @@ public void numFieldGunsChanged(final int count) { .stream().filter(m -> m.getLocation() == Infantry.LOC_FIELD_GUNS) .map(Mounted::getType).filter(eq -> eq instanceof WeaponType) .findAny(); - UnitUtil.replaceFieldGun(getInfantry(), (WeaponType)fieldGun.orElse(null), + InfantryUtil.replaceFieldGun(getInfantry(), (WeaponType)fieldGun.orElse(null), count); refresh.refreshStatus(); refresh.refreshPreview(); diff --git a/megameklab/src/megameklab/ui/infantry/CIWeaponView.java b/megameklab/src/megameklab/ui/infantry/CIWeaponView.java index af6da885e..02201d36d 100644 --- a/megameklab/src/megameklab/ui/infantry/CIWeaponView.java +++ b/megameklab/src/megameklab/ui/infantry/CIWeaponView.java @@ -19,7 +19,7 @@ import megamek.common.weapons.artillery.ArtilleryWeapon; import megameklab.ui.generalUnit.BuildView; import megameklab.ui.listeners.InfantryBuildListener; -import megameklab.util.UnitUtil; +import megameklab.util.InfantryUtil; import javax.swing.*; import java.awt.*; @@ -147,12 +147,12 @@ private void initUI() { public void setFromEntity(Infantry inf) { if (inf.getPrimaryWeapon() != null) { - txtPrimary.setText(UnitUtil.trimInfantryWeaponNames(inf.getPrimaryWeapon().getName())); + txtPrimary.setText(InfantryUtil.trimInfantryWeaponNames(inf.getPrimaryWeapon().getName())); } else { txtPrimary.setText(noneMsg); } if (inf.getSecondaryWeapon() != null) { - txtSecondary.setText(UnitUtil.trimInfantryWeaponNames(inf.getSecondaryWeapon().getName())); + txtSecondary.setText(InfantryUtil.trimInfantryWeaponNames(inf.getSecondaryWeapon().getName())); } else { txtSecondary.setText(noneMsg); } diff --git a/megameklab/src/megameklab/ui/largeAero/DSStructureTab.java b/megameklab/src/megameklab/ui/largeAero/DSStructureTab.java index 215a01f4d..d2039714f 100644 --- a/megameklab/src/megameklab/ui/largeAero/DSStructureTab.java +++ b/megameklab/src/megameklab/ui/largeAero/DSStructureTab.java @@ -31,6 +31,7 @@ import megameklab.ui.listeners.DropshipBuildListener; import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; +import megameklab.util.AeroUtil; import megameklab.util.UnitUtil; /** @@ -557,7 +558,7 @@ public void baMarinesChanged(int nBAMarines) { @Override public void quartersChanged(int officer, int standard, int secondclass, int steerage) { - UnitUtil.assignQuarters(getSmallCraft(), officer, standard, secondclass, steerage); + AeroUtil.assignQuarters(getSmallCraft(), officer, standard, secondclass, steerage); panCrew.setFromEntity(getSmallCraft()); refreshSummary(); refresh.refreshStatus(); @@ -566,7 +567,7 @@ public void quartersChanged(int officer, int standard, int secondclass, int stee @Override public void autoAssignQuarters() { - UnitUtil.autoAssignQuarters(getSmallCraft()); + AeroUtil.autoAssignQuarters(getSmallCraft()); panCrew.setFromEntity(getSmallCraft()); refreshSummary(); refresh.refreshStatus(); diff --git a/megameklab/src/megameklab/ui/largeAero/WSStructureTab.java b/megameklab/src/megameklab/ui/largeAero/WSStructureTab.java index 1fc2147a2..2410543bf 100644 --- a/megameklab/src/megameklab/ui/largeAero/WSStructureTab.java +++ b/megameklab/src/megameklab/ui/largeAero/WSStructureTab.java @@ -32,6 +32,7 @@ import megameklab.ui.listeners.ArmorAllocationListener; import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; +import megameklab.util.AeroUtil; import megameklab.util.UnitUtil; /** @@ -606,7 +607,7 @@ public void baMarinesChanged(int nBAMarines) { @Override public void quartersChanged(int officer, int standard, int secondclass, int steerage) { - UnitUtil.assignQuarters(getJumpship(), officer, standard, secondclass, steerage); + AeroUtil.assignQuarters(getJumpship(), officer, standard, secondclass, steerage); panCrew.setFromEntity(getJumpship()); refreshSummary(); refresh.refreshStatus(); @@ -615,7 +616,7 @@ public void quartersChanged(int officer, int standard, int secondclass, int stee @Override public void autoAssignQuarters() { - UnitUtil.autoAssignQuarters(getJumpship()); + AeroUtil.autoAssignQuarters(getJumpship()); panCrew.setFromEntity(getJumpship()); refreshSummary(); refresh.refreshStatus(); diff --git a/megameklab/src/megameklab/ui/mek/BMBuildTab.java b/megameklab/src/megameklab/ui/mek/BMBuildTab.java index 1ad347020..a78d5b610 100644 --- a/megameklab/src/megameklab/ui/mek/BMBuildTab.java +++ b/megameklab/src/megameklab/ui/mek/BMBuildTab.java @@ -21,6 +21,7 @@ import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; import megameklab.util.CConfig; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import javax.swing.*; @@ -125,12 +126,12 @@ public void refresh() { private void autoFillUnHittables() { if (autoFillUnHittables.isSelected()) { - BMUtils.fillInFMU(getMech()); + MekUtil.fillInFMU(getMech()); } } private void fillInEquipment() { - BMUtils.fillInAllEquipment(getMech()); + MekUtil.fillInAllEquipment(getMech()); refresh.refreshAll(); } @@ -138,7 +139,7 @@ private void resetCrits() { for (Mounted mounted : getMech().getEquipment()) { if (!UnitUtil.isFixedLocationSpreadEquipment(mounted.getType())) { UnitUtil.removeCriticals(getMech(), mounted); - BMUtils.clearMountedLocationAndLinked(mounted); + MekUtil.clearMountedLocationAndLinked(mounted); } } refresh.refreshAll(); @@ -151,7 +152,7 @@ private void resetCrits() { */ private void autoCompactCrits() { if (autoCompact.isSelected() && !autoSort.isSelected()) { - BMUtils.compactCriticals(getMech()); + MekUtil.compactCriticals(getMech()); } } @@ -160,7 +161,7 @@ private void autoCompactCrits() { * calls a refresh and will result in a loop! */ private void compactCrits() { - BMUtils.compactCriticals(getMech()); + MekUtil.compactCriticals(getMech()); refresh.refreshAll(); } @@ -169,7 +170,7 @@ private void compactCrits() { * calls a refresh and will result in a loop! */ private void sortCrits() { - BMUtils.sortCrits(getMech()); + MekUtil.sortCrits(getMech()); refresh(); } @@ -179,7 +180,7 @@ private void sortCrits() { */ private void autoSortCrits() { if (autoSort.isSelected()) { - BMUtils.sortCrits(getMech()); + MekUtil.sortCrits(getMech()); } } diff --git a/megameklab/src/megameklab/ui/mek/BMBuildView.java b/megameklab/src/megameklab/ui/mek/BMBuildView.java index 0600fdbba..5f994a3bc 100644 --- a/megameklab/src/megameklab/ui/mek/BMBuildView.java +++ b/megameklab/src/megameklab/ui/mek/BMBuildView.java @@ -24,6 +24,7 @@ import megameklab.ui.util.CriticalTransferHandler; import megameklab.ui.util.IView; import megameklab.ui.util.RefreshListener; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -101,7 +102,7 @@ private void loadEquipmentTable() { .filter(m -> !m.isOneShotAmmo()) .forEach(masterEquipmentList::add); - masterEquipmentList.sort(new BMUtils.MekMountedSorter(getMech())); + masterEquipmentList.sort(new MekUtil.MekMountedSorter(getMech())); masterEquipmentList.forEach(equipmentList::addCrit); } @@ -343,9 +344,9 @@ private void addEquipment(int location, int selectedRow) { } try { if ((eq.getType() instanceof WeaponType) && eq.getType().hasFlag(WeaponType.F_VGL)) { - int slotNumber = BMUtils.findSlotWithContiguousNumOfCrits(getMech(), location, + int slotNumber = MekUtil.findSlotWithContiguousNumOfCrits(getMech(), location, UnitUtil.getCritsUsed(eq)); - BMUtils.addVGL(getMech(), eq, location, slotNumber); + MekUtil.addVGL(getMech(), eq, location, slotNumber); } else { UnitUtil.addMounted(getMech(), eq, location, false); } diff --git a/megameklab/src/megameklab/ui/mek/BMCriticalTransferHandler.java b/megameklab/src/megameklab/ui/mek/BMCriticalTransferHandler.java index b9ecfcad5..86044a87b 100644 --- a/megameklab/src/megameklab/ui/mek/BMCriticalTransferHandler.java +++ b/megameklab/src/megameklab/ui/mek/BMCriticalTransferHandler.java @@ -27,6 +27,7 @@ import megameklab.ui.util.BAASBMDropTargetCriticalList; import megameklab.ui.util.CriticalTableModel; import megameklab.ui.util.RefreshListener; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -69,19 +70,19 @@ private boolean addEquipmentMech(Mech mek, Mounted eq, int slotNumber) throws Lo slotNumber = locationSize - neededCrits; } - if (BMUtils.isFMU(eq)) { + if (MekUtil.isFMU(eq)) { // Endo Steel and the like don't move aside other Endo Steels mek.addEquipment(eq, location, false, slotNumber); changeMountStatus(eq, location); return true; - } else if (BMUtils.canFreeContiguousCrits(mek, location, slotNumber, neededCrits)) { + } else if (MekUtil.canFreeContiguousCrits(mek, location, slotNumber, neededCrits)) { // The equipment can be placed at the drop slot, possibly by removing Endo Steel and the like return addSingleLocationEquipment(mek, eq, slotNumber); - } else if (BMUtils.findSlotWithContiguousNumOfCrits(mek, location, neededCrits) > -1) { + } else if (MekUtil.findSlotWithContiguousNumOfCrits(mek, location, neededCrits) > -1) { // The equipment can be placed elsewhere in the location by removing Endo Steel and the like - slotNumber = BMUtils.findSlotWithContiguousNumOfCrits(mek, location, neededCrits); + slotNumber = MekUtil.findSlotWithContiguousNumOfCrits(mek, location, neededCrits); return addSingleLocationEquipment(mek, eq, slotNumber); } else { @@ -95,9 +96,9 @@ private boolean addEquipmentMech(Mech mek, Mounted eq, int slotNumber) throws Lo private boolean addSingleLocationEquipment(Mech mek, Mounted eq, int slotNumber) throws LocationFullException { int neededCrits = UnitUtil.getCritsUsed(eq); - BMUtils.removeFMU(mek, location, slotNumber, neededCrits); + MekUtil.removeFMU(mek, location, slotNumber, neededCrits); if ((eq.getType() instanceof WeaponType) && eq.getType().hasFlag(WeaponType.F_VGL)) { - boolean success = BMUtils.addVGL(mek, eq, location, slotNumber); + boolean success = MekUtil.addVGL(mek, eq, location, slotNumber); doRefresh(); return success; } else { @@ -112,13 +113,13 @@ private boolean addSplitLocationEquipment(Mech mek, Mounted eq, int slotNumber) return false; // TM p.57 } int neededTotalSlots = UnitUtil.getCritsUsed(eq); - int freePrimarySlots = BMUtils.availableContiguousCrits(mek, location, slotNumber, true); + int freePrimarySlots = MekUtil.availableContiguousCrits(mek, location, slotNumber, true); // It's obvious that the equipment can't be placed on an occupied slot, so in that case // a good free slot can be chosen in the location if (freePrimarySlots == 0) { - int maxSpace = BMUtils.getMaxContiguousNumOfCrits(mek, location, true); - slotNumber = BMUtils.findSlotWithContiguousNumOfCrits(mek, location, maxSpace); - freePrimarySlots = BMUtils.availableContiguousCrits(mek, location, slotNumber, true); + int maxSpace = MekUtil.getMaxContiguousNumOfCrits(mek, location, true); + slotNumber = MekUtil.findSlotWithContiguousNumOfCrits(mek, location, maxSpace); + freePrimarySlots = MekUtil.availableContiguousCrits(mek, location, slotNumber, true); if (freePrimarySlots == 0) { // This location is full return false; @@ -152,7 +153,7 @@ private boolean addSplitLocationEquipment(Mech mek, Mounted eq, int slotNumber) secondLocationSet.removeIf(loc -> loc == Entity.LOC_DESTROYED); secondLocationSet.removeIf(loc -> !UnitUtil.isValidLocation(mek, eq.getType(), loc)); secondLocationSet.removeIf(loc -> - BMUtils.getMaxContiguousNumOfCrits(mek, loc, true) < neededSecondarySlots); + MekUtil.getMaxContiguousNumOfCrits(mek, loc, true) < neededSecondarySlots); List secondLocationsList = new ArrayList<>(secondLocationSet); if (secondLocationsList.isEmpty()) { @@ -176,12 +177,12 @@ private boolean addSplitLocationEquipment(Mech mek, Mounted eq, int slotNumber) } } - BMUtils.removeFMU(mek, location, slotNumber, freePrimarySlots); + MekUtil.removeFMU(mek, location, slotNumber, freePrimarySlots); for (int slot = slotNumber; slot < slotNumber + neededPrimarySlots; slot++) { mek.addEquipment(eq, location, false, slot); } - int secondSlotNumber = BMUtils.findSlotWithContiguousNumOfCrits(mek, secondLocation, neededSecondarySlots); - BMUtils.removeFMU(mek, secondLocation, secondSlotNumber, neededSecondarySlots); + int secondSlotNumber = MekUtil.findSlotWithContiguousNumOfCrits(mek, secondLocation, neededSecondarySlots); + MekUtil.removeFMU(mek, secondLocation, secondSlotNumber, neededSecondarySlots); for (int slot = secondSlotNumber; slot < secondSlotNumber + neededSecondarySlots; slot++) { mek.addEquipment(eq, secondLocation, false, slot); } diff --git a/megameklab/src/megameklab/ui/mek/BMEquipmentDatabaseView.java b/megameklab/src/megameklab/ui/mek/BMEquipmentDatabaseView.java index 38a07c74f..78665c192 100644 --- a/megameklab/src/megameklab/ui/mek/BMEquipmentDatabaseView.java +++ b/megameklab/src/megameklab/ui/mek/BMEquipmentDatabaseView.java @@ -16,6 +16,7 @@ import megamek.common.*; import megameklab.ui.EntitySource; import megameklab.ui.util.AbstractEquipmentDatabaseView; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import java.util.Collection; @@ -48,7 +49,7 @@ protected void addEquipment(EquipmentType equip, int count) { UnitUtil.updateTC(getMech(), equip); } } else if (isMisc && UnitUtil.isFixedLocationSpreadEquipment(equip)) { - UnitUtil.createSpreadMounts(getMech(), equip); + MekUtil.createSpreadMounts(getMech(), equip); } else { try { mount = new Mounted(getMech(), equip); diff --git a/megameklab/src/megameklab/ui/mek/BMMainUI.java b/megameklab/src/megameklab/ui/mek/BMMainUI.java index 1858be618..e0a56ec51 100644 --- a/megameklab/src/megameklab/ui/mek/BMMainUI.java +++ b/megameklab/src/megameklab/ui/mek/BMMainUI.java @@ -23,7 +23,7 @@ import megameklab.ui.generalUnit.PreviewTab; import megameklab.ui.generalUnit.QuirksTab; import megameklab.ui.util.TabScrollPane; -import megameklab.util.UnitUtil; +import megameklab.util.MekUtil; import javax.swing.*; import java.awt.*; @@ -115,7 +115,7 @@ public void createNewUnit(long entityType, boolean isPrimitive, boolean isIndust } else if (entityType == Entity.ETYPE_QUADVEE) { setEntity(new QuadVee(Mech.GYRO_STANDARD, QuadVee.MOTIVE_TRACK)); getEntity().setTechLevel(TechConstants.T_CLAN_ADVANCED); - UnitUtil.createSpreadMounts((Mech)getEntity(), EquipmentType.get(EquipmentTypeLookup.MECH_TRACKS)); + MekUtil.createSpreadMounts((Mech)getEntity(), EquipmentType.get(EquipmentTypeLookup.MECH_TRACKS)); getEntity().setManualBV(-1); } else { // type == 0 setEntity(new BipedMech(Mech.GYRO_STANDARD, cockpit)); @@ -125,7 +125,7 @@ public void createNewUnit(long entityType, boolean isPrimitive, boolean isIndust getEntity().setWeight(25); if (entityType == Entity.ETYPE_LAND_AIR_MECH) { mech.setEngine(new Engine(75, Engine.NORMAL_ENGINE, 0)); - UnitUtil.updateJumpJets(((Mech)getEntity()), 3, Mech.JUMP_STANDARD); + MekUtil.updateJumpJets(((Mech)getEntity()), 3, Mech.JUMP_STANDARD); } else { mech.setEngine(new Engine(25, Engine.NORMAL_ENGINE, 0)); } @@ -144,7 +144,7 @@ public void createNewUnit(long entityType, boolean isPrimitive, boolean isIndust } else { mech.addCockpit(); } - UnitUtil.updateHeatSinks(mech, 10, "Single"); + MekUtil.updateHeatSinks(mech, 10, "Single"); getEntity().autoSetInternal(); for (int loc = 0; loc < getEntity().locations(); loc++) { diff --git a/megameklab/src/megameklab/ui/mek/BMStatusBar.java b/megameklab/src/megameklab/ui/mek/BMStatusBar.java index f7524e533..5c54e1d51 100644 --- a/megameklab/src/megameklab/ui/mek/BMStatusBar.java +++ b/megameklab/src/megameklab/ui/mek/BMStatusBar.java @@ -17,7 +17,7 @@ import megamek.client.ui.swing.GUIPreferences; import megameklab.ui.generalUnit.StatusBar; -import megameklab.util.UnitUtil; +import megameklab.util.MekUtil; import javax.swing.*; @@ -43,7 +43,7 @@ protected void additionalRefresh() { public void refreshSlots() { int maxCrits = getTestEntity().totalCritSlotCount(); - int currentSlots = UnitUtil.countUsedCriticals(getMech()); + int currentSlots = MekUtil.countUsedCriticals(getMech()); slots.setText(String.format(SLOTS_LABEL, maxCrits - currentSlots, maxCrits)); slots.setForeground(currentSlots > maxCrits ? GUIPreferences.getInstance().getWarningColor() : null); } diff --git a/megameklab/src/megameklab/ui/mek/BMStructureTab.java b/megameklab/src/megameklab/ui/mek/BMStructureTab.java index 76f75b04a..793966f7d 100644 --- a/megameklab/src/megameklab/ui/mek/BMStructureTab.java +++ b/megameklab/src/megameklab/ui/mek/BMStructureTab.java @@ -25,6 +25,7 @@ import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -323,7 +324,7 @@ && getMech().getCritical(Mech.LOC_RT, i).getType() == CriticalSlot.TYPE_EQUIPMEN if ((mount.getLocation() == Entity.LOC_NONE) && UnitUtil.isFixedLocationSpreadEquipment(mount.getType())) { UnitUtil.removeMounted(getMech(), mount); - UnitUtil.createSpreadMounts(getMech(), mount.getType()); + MekUtil.createSpreadMounts(getMech(), mount.getType()); } } refresh.refreshBuild(); @@ -497,7 +498,7 @@ private boolean recalculateEngineRating(int walkMP, double tonnage) { engine.setBaseChassisHeatSinks(getMech().getEngine() .getBaseChassisHeatSinks(getMech().hasCompactHeatSinks())); getMech().setEngine(engine); - UnitUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); + MekUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); resetSystemCrits(); } } @@ -538,7 +539,7 @@ private void createArmorMountsAndSetArmorType(int at, int aTechLevel) { } // auto-place stealth crits if (getMech().getArmorType(0) == EquipmentType.T_ARMOR_STEALTH) { - Mounted mount = UnitUtil.createSpreadMounts( + Mounted mount = MekUtil.createSpreadMounts( getMech(), EquipmentType.get(EquipmentType.getArmorTypeName( getMech().getArmorType(0), false))); @@ -729,7 +730,7 @@ public void omniChanged(boolean omni) { getMech().getEngine().setBaseChassisHeatSinks( omni? Math.max(0, panHeat.getBaseCount()) : -1); panHeat.setFromMech(getMech()); - UnitUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); + MekUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); refresh.refreshPreview(); } @@ -775,11 +776,11 @@ public void typeChanged(int baseType, int motiveType, long etype) { if (motiveType == QuadVee.MOTIVE_WHEEL) { ((QuadVee)getMech()).setMotiveType(QuadVee.MOTIVE_WHEEL); - UnitUtil.createSpreadMounts(getMech(), + MekUtil.createSpreadMounts(getMech(), EquipmentType.get(EquipmentTypeLookup.QUADVEE_WHEELS)); } else { ((QuadVee)getMech()).setMotiveType(QuadVee.MOTIVE_TRACK); - UnitUtil.createSpreadMounts(getMech(), + MekUtil.createSpreadMounts(getMech(), EquipmentType.get(EquipmentTypeLookup.MECH_TRACKS)); } } @@ -828,9 +829,9 @@ public void engineChanged(Engine engine) { // If the new engine has more weight-free heat sinks than are currently installed, add the extras. int newHS = engine.getWeightFreeEngineHeatSinks() - getMech().heatSinks(); if (newHS > 0) { - UnitUtil.addHeatSinkMounts(getMech(), newHS, panHeat.getHeatSinkType()); + MekUtil.addHeatSinkMounts(getMech(), newHS, panHeat.getHeatSinkType()); } - UnitUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); + MekUtil.updateAutoSinks(getMech(), getMech().hasCompactHeatSinks()); getMech().resetSinks(); panMovement.setFromEntity(getMech()); panHeat.setFromMech(getMech()); @@ -884,7 +885,7 @@ public void cockpitChanged(int cockpitType) { @Override public void enhancementChanged(EquipmentType enhancement) { - UnitUtil.removeEnhancements(getMech()); + MekUtil.removeEnhancements(getMech()); if (null != enhancement) { if (enhancement.hasFlag(MiscType.F_MASC)) { Mounted mount = new Mounted(getMech(), enhancement); @@ -894,7 +895,7 @@ public void enhancementChanged(EquipmentType enhancement) { // this can't happen, we add to Entity.LOC_NONE } } else { - UnitUtil.createSpreadMounts(getMech(), enhancement); + MekUtil.createSpreadMounts(getMech(), enhancement); } } refresh.refreshBuild(); @@ -917,17 +918,17 @@ public void resetChassis() { public void heatSinksChanged(EquipmentType hsType, int count) { // if we have the same type of heat sink, then we should not remove the // existing heat sinks - int currentSinks = UnitUtil.countActualHeatSinks(getMech()); + int currentSinks = MekUtil.countActualHeatSinks(getMech()); if (getMech().hasWorkingMisc(hsType.getInternalName())) { if (count < currentSinks) { - UnitUtil.removeHeatSinks(getMech(), currentSinks - count); + MekUtil.removeHeatSinks(getMech(), currentSinks - count); } else if (count > currentSinks) { - UnitUtil.addHeatSinkMounts(getMech(), count - currentSinks, + MekUtil.addHeatSinkMounts(getMech(), count - currentSinks, hsType); } } else { - UnitUtil.removeHeatSinks(getMech(), count); - UnitUtil.addHeatSinkMounts(getMech(), count, hsType); + MekUtil.removeHeatSinks(getMech(), count); + MekUtil.addHeatSinkMounts(getMech(), count, hsType); // If we're switching to prototype doubles, start with the assumption that the integrated sinks are singles, // with a minimum of one double if (hsType.hasFlag(MiscType.F_IS_DOUBLE_HEAT_SINK_PROTOTYPE)) { @@ -946,7 +947,7 @@ public void heatSinksChanged(EquipmentType hsType, int count) { public void heatSinkBaseCountChanged(int count) { getMech().getEngine().setBaseChassisHeatSinks( Math.max(0, count)); - UnitUtil.updateAutoSinks(getMech(), panHeat.getHeatSinkType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)); + MekUtil.updateAutoSinks(getMech(), panHeat.getHeatSinkType().hasFlag(MiscType.F_COMPACT_HEAT_SINK)); refresh.refreshBuild(); refresh.refreshStatus(); refresh.refreshPreview(); @@ -967,7 +968,7 @@ public void redistributePrototypeHS(int prototype) { } UnitUtil.removeMounted(getMech(), doubles.get(i)); } - UnitUtil.addHeatSinkMounts(getMech(), -netChange, EquipmentType.get(EquipmentTypeLookup.SINGLE_HS)); + MekUtil.addHeatSinkMounts(getMech(), -netChange, EquipmentType.get(EquipmentTypeLookup.SINGLE_HS)); } else if (netChange > 0) { // Find all the single heat sinks, and prioritize the ones that are already assigned critical slots List singles = getMech().getMisc().stream() @@ -981,9 +982,9 @@ public void redistributePrototypeHS(int prototype) { } UnitUtil.removeMounted(getMech(), singles.get(i)); } - UnitUtil.addHeatSinkMounts(getMech(), netChange, panHeat.getHeatSinkType()); + MekUtil.addHeatSinkMounts(getMech(), netChange, panHeat.getHeatSinkType()); } - UnitUtil.updateAutoSinks(getMech(), false); + MekUtil.updateAutoSinks(getMech(), false); panSummary.refresh(); refresh.refreshStatus(); refresh.refreshSummary(); @@ -1090,7 +1091,7 @@ public void jumpChanged(int jumpMP, @Nullable EquipmentType jumpJet) { .collect(Collectors.toList()); if (jumpJet.hasFlag(MiscType.F_JUMP_BOOSTER)) { if (!getMech().hasWorkingMisc(MiscType.F_JUMP_BOOSTER)) { - UnitUtil.createSpreadMounts(getMech(), jumpJet); + MekUtil.createSpreadMounts(getMech(), jumpJet); } } else { while (jjs.size() > jumpMP) { diff --git a/megameklab/src/megameklab/ui/mek/BMSummaryView.java b/megameklab/src/megameklab/ui/mek/BMSummaryView.java index 8adfd3b3d..ff8e5cd42 100644 --- a/megameklab/src/megameklab/ui/mek/BMSummaryView.java +++ b/megameklab/src/megameklab/ui/mek/BMSummaryView.java @@ -20,6 +20,7 @@ import megamek.common.verifier.TestMech; import megameklab.ui.EntitySource; import megameklab.ui.util.IView; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import javax.swing.*; @@ -279,10 +280,10 @@ public void refresh() { runThroughEquipment(testMech); - int numberSinks = UnitUtil.countActualHeatSinks(getMech()); + int numberSinks = MekUtil.countActualHeatSinks(getMech()); numberSinks = Math.max(0, numberSinks - UnitUtil.getCriticalFreeHeatSinks(getMech(), getMech().hasCompactHeatSinks())); int critSinks = numberSinks; - if (UnitUtil.hasClanDoubleHeatSinks(getMech())) { + if (MekUtil.hasClanDoubleHeatSinks(getMech())) { critSinks = numberSinks * 2; } else if (getMech().hasDoubleHeatSinks()) { critSinks = numberSinks * 3; diff --git a/megameklab/src/megameklab/ui/mek/BMUtils.java b/megameklab/src/megameklab/ui/mek/BMUtils.java deleted file mode 100644 index d850ad6f6..000000000 --- a/megameklab/src/megameklab/ui/mek/BMUtils.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MegaMekLab. - * - * MegaMek 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. - * - * MegaMek 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 MegaMek. If not, see . - */ -package megameklab.ui.mek; - -import megamek.common.*; -import megameklab.util.UnitUtil; -import org.apache.logging.log4j.LogManager; - -import javax.swing.*; -import java.util.*; - -import static java.util.stream.Collectors.toSet; -import static megameklab.util.UnitUtil.*; - -/** - * Utility methods that are likely only applicable to Meks - * - * @author Simon (Juliez) - */ -public final class BMUtils { - - /** - * Compacts the crit slots in all locations of the given Mek, moving Empty slots to the bottom. - */ - public static void compactCriticals(Mech mek) { - for (int loc = 0; loc < mek.locations(); loc++) { - compactCriticals(mek, loc); - } - } - - /** - * Compacts the crit slots in the given location of the given Mek, moving Empty slots to the bottom. - */ - public static void compactCriticals(Mech mek, int location) { - List presentGear = extricateCritSlots(mek, location); - refillCritSlots(mek, location, presentGear); - } - - /** - * Clears all links of the given equipment to other equipment and unallocates - * it (assigns to LOC_NONE). Note: Does not clear the equipment's crit slots from its - * former location. For this, use {@link UnitUtil#removeCriticals(Entity, Mounted)} - */ - public static void clearMountedLocationAndLinked(Mounted equipment) { - if ((Entity.LOC_NONE != equipment.getLocation()) && !equipment.isOneShot()) { - if (equipment.getLinked() != null) { - equipment.getLinked().setLinkedBy(null); - equipment.setLinked(null); - } - if (equipment.getLinkedBy() != null) { - equipment.getLinkedBy().setLinked(null); - equipment.setLinkedBy(null); - } - } - equipment.setLocation(Entity.LOC_NONE, false); - equipment.setSecondLocation(Entity.LOC_NONE, false); - equipment.setSplit(false); - } - - /** - * Moves all equipment that is freely movable and unhittable (e.g. Endo Steel and - * Ferro-Fibrous but not CASE) ("FMU") that is currently unallocated (LOC_NONE) to free - * locations on the Mek as long as there are any. - */ - public static void fillInFMU(Mech mek) { - // Work with a copy because the equipment list may be modified. - for (Mounted mount : new ArrayList<>(mek.getEquipment())) { - if (!BMUtils.isFMU(mount) || (mount.getLocation() != Entity.LOC_NONE)) { - continue; - } - for (int location = 0; location < mek.locations(); location++) { - if (!isValidLocation(mek, mount.getType(), location) - || (getMaxContiguousNumOfCrits(mek, location, false) < getCritsUsed(mount))) { - continue; - } - try { - addMounted(mek, mount, location, false); - changeMountStatus(mek, mount, location, Entity.LOC_NONE, false); - break; - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - } - - /** - * Removes all equipment that is freely movable and unhittable (e.g. Endo Steel and - * Ferro-Fibrous but not CASE) ("FMU") from the given location, affecting numOfSlots - * slots beginning at startingSlot. - */ - public static void removeFMU(Entity mech, int location, int startingSlot, int numOfSlots) { - for (int slot = startingSlot; slot < startingSlot + numOfSlots; slot++) { - CriticalSlot critSlot = mech.getCritical(location, slot); - if ((critSlot != null) && BMUtils.isFMU(critSlot.getMount())) { - Mounted mounted = critSlot.getMount(); - UnitUtil.removeCriticals(mech, mounted); - UnitUtil.changeMountStatus(mech, mounted, Entity.LOC_NONE, Entity.LOC_NONE, false); - } - } - } - - /** - * Moves all equipment that is currently unallocated (LOC_NONE) to free - * locations on the Mek as long as there are any. - */ - public static void fillInAllEquipment(Mech mek) { - int externalEngineHS = UnitUtil.getCriticalFreeHeatSinks(mek, mek.hasCompactHeatSinks()); - for (Mounted mount : mek.getEquipment()) { - if ((mount.getLocation() != Entity.LOC_NONE) - || (UnitUtil.isHeatSink(mount) && (externalEngineHS-- > 0))) { - continue; - } - for (int location = Mech.LOC_HEAD; location < mek.locations(); location++) { - if (!UnitUtil.isValidLocation(mek, mount.getType(), location)) { - continue; - } - int critsUsed = UnitUtil.getCritsUsed(mount); - if (critsUsed > UnitUtil.getHighestContinuousNumberOfCrits(mek, location)) { - continue; - } - try { - if (mount.getType().isSpreadable() || (mount.isSplitable() && (critsUsed > 1))) { - for (int count = 0; count < critsUsed; count++) { - UnitUtil.addMounted(mek, mount, location, false); - } - } else { - UnitUtil.addMounted(mek, mount, location, false); - } - UnitUtil.changeMountStatus(mek, mount, location, Entity.LOC_NONE, false); - break; - } catch (Exception ex) { - LogManager.getLogger().error("", ex); - } - } - } - } - - /** - * Returns true when a slot's equipment is unhittable and freely movable ("FMU"), such - * as Endo Steel and Ferro-Fibrous Armor but not CASE (which is unhittable but not - * freely movable as its location is important). - */ - public static boolean isFMU(Mounted equipment) { - return (equipment != null) - && !equipment.getType().isHittable() - && (equipment.getType() instanceof MiscType) - && !equipment.getType().hasFlag(MiscType.F_CASE) - && !equipment.getType().hasFlag(MiscType.F_CASEP) - && !equipment.getType().hasFlag(MiscType.F_CASEII); - } - - /** - * Sorts the allocated equipment on all locations (except HD) of the Mek using - * the officially used sort order. - */ - public static void sortCrits(Mech mek) { - for (int location = 0; location < mek.locations(); location++) { - if (location != Mech.LOC_HEAD) { - sortCritSlots(mek, location); - } - } - } - - /** - * Sorts the crits within the given location. This extricates all non-system - * crits from the location, sorts them and then refills the location. - */ - public static void sortCritSlots(Mech mek, int location) { - List presentGear = extricateCritSlots(mek, location); - presentGear.sort(new MekCritSlotSorter(mek)); - presentGear = reOrderLinkedEquipment(presentGear); - refillCritSlots(mek, location, presentGear); - } - - /** - * Removes all crit slots from the given location except for system crit slots - * (e.g. engine) and returns them as a list. - */ - private static List extricateCritSlots(Mech mek, int location) { - List presentGear = new ArrayList<>(); - for (int slot = 0; slot < mek.getNumberOfCriticals(location); slot++) { - CriticalSlot critSlot = mek.getCritical(location, slot); - if ((critSlot != null) && (critSlot.getType() == CriticalSlot.TYPE_EQUIPMENT)) { - presentGear.add(critSlot); - mek.setCritical(location, slot, null); - } - } - return presentGear; - } - - /** - * Fills the given list of crit slots into the given location. This does not check - * or change the respective mounteds' locations, so care must be taken that all - * mounteds are indeed allocated to this location or that the crit slots have been - * taken from this location, e.g. with {@link #extricateCritSlots(Mech, int)}. - */ - private static void refillCritSlots(Mech mek, int location, List critList) { - //TODO: If they somehow dont fit, unallocate the mounted and remove all its critslots - critList.forEach(critSlot -> mek.addCritical(location, critSlot)); - } - - /** - * Returns a reordered version of the given presentGear list of critslots wherein - * LinkedBy mounteds such as Artemis and PPC Capacitors are placed directly behind - * their weapon. - */ - public static List reOrderLinkedEquipment(List presentGear) { - List resortedList = new ArrayList<>(); - Set presentMounteds = presentGear.stream().map(CriticalSlot::getMount).collect(toSet()); - // Assemble all the linked gear that is not ammo (ammo is sorted differently) - Set linkedMounteds = presentMounteds.stream() - .map(Mounted::getLinkedBy) - .filter(Objects::nonNull) - .filter(linked -> linked.getType() instanceof MiscType) - .filter(presentMounteds::contains) - .collect(toSet()); - - // Now rebuild the list by adding the linkedMounteds behind their weapon - Mounted lastMounted = null; - for (CriticalSlot critSlot : presentGear) { - Mounted currentMounted = critSlot.getMount(); - // after one mounted is fully added, see if there's a linkedMounted to add below it - if ((lastMounted != null) - && (currentMounted != lastMounted) - && (lastMounted.getLinkedBy() != null) - && (linkedMounteds.contains(lastMounted.getLinkedBy()))) { - for (CriticalSlot linkedSlot : presentGear) { - if (linkedSlot.getMount() == lastMounted.getLinkedBy()) { - resortedList.add(linkedSlot); - } - } - } - // Add the current crit slot but exclude the linkedMounteds as they are added behind their weapon - if (!linkedMounteds.contains(critSlot.getMount())) { - resortedList.add(critSlot); - } - lastMounted = currentMounted; - } - return resortedList; - } - - /** - * A location CriticalSlot sorter using the official sort order (mostly) - */ - public static class MekCritSlotSorter implements Comparator { - - private final MekMountedSorter mountedSorter; - - public MekCritSlotSorter(Mech mek) { - mountedSorter = new MekMountedSorter(mek); - } - - @Override - public int compare(CriticalSlot critA, CriticalSlot critB) { - return mountedSorter.compare(critA.getMount(), critB.getMount()); - } - } - - /** - * A Mounted sorter using the official sort order (mostly) - */ - public static class MekMountedSorter implements Comparator { - - private final Mech mek; - - public MekMountedSorter(Mech mek) { - this.mek = mek; - } - - @Override - public int compare(Mounted mountedA, Mounted mountedB) { - int coarseOrderA = getCoarseOrdering(mek, mountedA); - int coarseOrderB = getCoarseOrdering(mek, mountedB); - if ((coarseOrderA == 4) && (coarseOrderB == 4)) { - // compare average damage; using Aero damage here - double dmgA = 0; - double dmgB = 0; - if (mountedA.getType() instanceof WeaponType) { - dmgA = ((WeaponType) mountedA.getType()).getShortAV(); - } - if (mountedB.getType() instanceof WeaponType) { - dmgB = ((WeaponType) mountedB.getType()).getShortAV(); - } - if (dmgA != dmgB) { - return (dmgA > dmgB) ? -1 : 1; - } else { - // equal damage, compare crits - int critsA = mountedA.getCriticals(); - int critsB = mountedB.getCriticals(); - if (critsA != critsB) { - return (critsA > critsB) ? -1 : 1; - } else { - // equal crits, compare weight - double weightA = mountedA.getType().getTonnage(mek); - double weightB = mountedB.getType().getTonnage(mek); - return Double.compare(weightB, weightA); - } - } - } else if ((coarseOrderA == 5) && (coarseOrderB == 5)) { - AmmoType ammoA = (AmmoType) mountedA.getType(); - AmmoType ammoB = (AmmoType) mountedB.getType(); - int dmgA = ammoA.getRackSize() * ammoA.getDamagePerShot(); - int dmgB = ammoB.getRackSize() * ammoB.getDamagePerShot(); - return Integer.compare(dmgB, dmgA); - } else { - return Integer.compare(coarseOrderA, coarseOrderB); - } - } - } - - /** - * Returns a number indicating the order in which equipment should be sorted - * within a location according to the official crit slot sorting. Weapons and - * ammo require further internal sorting and linked equipment such as Artemis and PPC - * Capacitors also require extra treatment to be placed behind their weapon. - */ - public static int getCoarseOrdering(Mech mek, Mounted mounted) { - if (isPartialWing(mounted)) { - return 1; - } else if (UnitUtil.isHeatSink(mounted)) { - return 2; - } else if (UnitUtil.isJumpJet(mounted)) { - return 3; - } else if (UnitUtil.isMechWeapon(mounted.getType(), mek)) { - return 4; - } else if (mounted.getType() instanceof AmmoType) { - return 5; - } else if (mounted.getType().isHittable()) { - return 6; - } else if (isCASE(mounted)) { - return 7; - } else if (EquipmentType.isStructureType(mounted.getType())) { - return 8; - } else if (EquipmentType.isArmorType(mounted.getType())) { - return 9; - } else { - return 10; - } - } - - public static boolean isPartialWing(Mounted mounted) { - return (mounted.getType() instanceof MiscType) - && mounted.getType().hasFlag(MiscType.F_PARTIAL_WING); - } - - public static boolean isCASE(Mounted mounted) { - return (mounted.getType() instanceof MiscType) - && (mounted.getType().hasFlag(MiscType.F_CASE) - || mounted.getType().hasFlag(MiscType.F_CASEP) - || mounted.getType().hasFlag(MiscType.F_CASEII)); - } - - /** - * Returns the highest number of contiguous free crit slots available in the given location. - * When ignoreFMU is true, slots that contain unhittable and freely moveable (FMU) equipment - * such as Endo Steel are counted as being free. - */ - public static int getMaxContiguousNumOfCrits(Mech mek, int location, boolean ignoreFMU) { - if ((location == Entity.LOC_DESTROYED) || (location == Entity.LOC_NONE)) { - return 0; - } - int maxNumOfCrits = 0; - for (int slot = 0; slot < mek.getNumberOfCriticals(location); slot++) { - maxNumOfCrits = Math.max(availableContiguousCrits(mek, location, slot, ignoreFMU), maxNumOfCrits); - } - return maxNumOfCrits; - } - - /** - * Returns the first slot in the location that together with following slots - * forms a contiguous block of the given length as size where all slots - * are either empty of contain freely movable crits such as Endo Steel. - * Returns -1 if there is no such slot. - */ - public static int findSlotWithContiguousNumOfCrits(Entity mech, int location, int length) { - for (int slot = 0; slot < mech.getNumberOfCriticals(location); slot++) { - if (canFreeContiguousCrits(mech, location, slot, length)) { - return slot; - } - } - return -1; - } - - /** - * Returns true when numOfSlots contiguous slots starting from startingSlot are either free or - * can be freed by removing unhittable and movable equipment such as Endo Steel. - */ - public static boolean canFreeContiguousCrits(Entity mek, int location, int startingSlot, int numOfSlots) { - return availableContiguousCrits(mek, location, startingSlot, true) >= numOfSlots; - } - - /** - * Returns the number of contiguous slots starting from startingSlot that are either free or - * can be freed by removing unhittable and movable (FMU) equipment such as Endo Steel. - * When ignoreFMU is true, slots that contain unhittable and freely moveable (FMU) equipment - * such as Endo Steel are counted as being free. - */ - public static int availableContiguousCrits(Entity mek, int location, int startingSlot, boolean ignoreFMU) { - for (int slot = startingSlot; slot < mek.getNumberOfCriticals(location); slot++) { - CriticalSlot critSlot = mek.getCritical(location, slot); - if ((critSlot != null) && !(ignoreFMU && BMUtils.isFMU(critSlot.getMount()))) { - return slot - startingSlot; - } - } - return mek.getNumberOfCriticals(location) - startingSlot; - } - - /** Add a vehicular grenade launcher, asking the user for the facing. */ - public static boolean addVGL(Mech mek, Mounted vgl, int location, int slotNumber) - throws LocationFullException { - String[] facings; - if (location == Mech.LOC_LT) { - facings = new String[4]; - facings[0] = "Front"; - facings[1] = "Front-Left"; - facings[2] = "Rear-Left"; - facings[3] = "Rear"; - } else if (location == Mech.LOC_RT) { - facings = new String[4]; - facings[0] = "Front"; - facings[1] = "Front-Right"; - facings[2] = "Rear-Right"; - facings[3] = "Rear"; - } else if (location == Mech.LOC_CT) { - facings = new String[2]; - facings[0] = "Front"; - facings[1] = "Rear"; - } else { - JOptionPane.showMessageDialog(null, - "VGL must be placed in torso location!", - "Invalid location", - JOptionPane.WARNING_MESSAGE); - return false; - } - String facing = (String)JOptionPane.showInputDialog(null, - "Please choose the facing of the VGL", - "Choose Facing", JOptionPane.QUESTION_MESSAGE, - null, facings, facings[0]); - if (facing == null) { - return false; - } - mek.addEquipment(vgl, location, false, slotNumber); - UnitUtil.changeMountStatus(mek, vgl, location, -1, false); - if (facing.equals("Front-Left")) { - vgl.setFacing(5); - } else if (facing.equals("Front-Right")) { - vgl.setFacing(1); - } else if (facing.equals("Rear-Right")) { - vgl.setFacing(2); - } else if (facing.equals("Rear-Left")) { - vgl.setFacing(4); - } else if (facing.equals("Rear")) { - vgl.setFacing(3); - UnitUtil.changeMountStatus(mek, vgl, location, -1, true); - } - return true; - } - - /** - * For the given Mek, adds Clan CASE in every location that has potentially - * explosive equipment (this includes PPC Capacitors) and removes it from all - * other locations. - * Calls {@link Mech#addClanCase()}. This method does not check if other - * CASE types are already present on a location. - * - * @param mek the mek to update - */ - public static void updateClanCasePlacement(Mech mek) { - if (mek.isClan()) { - removeAllMounteds(mek, EquipmentType.get(EquipmentTypeLookup.CLAN_CASE)); - mek.addClanCase(); - } - } -} diff --git a/megameklab/src/megameklab/ui/protoMek/PMBuildTab.java b/megameklab/src/megameklab/ui/protoMek/PMBuildTab.java index 4ddf13278..fc7767d5a 100644 --- a/megameklab/src/megameklab/ui/protoMek/PMBuildTab.java +++ b/megameklab/src/megameklab/ui/protoMek/PMBuildTab.java @@ -20,6 +20,7 @@ import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; import megameklab.ui.util.SpringLayoutHelper; +import megameklab.util.ProtoMekUtil; import megameklab.util.UnitUtil; import javax.swing.*; @@ -112,7 +113,7 @@ public void actionPerformed(ActionEvent evt) { private void autoFillCrits() { for (Mounted mount : buildView.getTableModel().getCrits()) { for (int location = 0; location < getProtomech().locations(); location++) { - if (UnitUtil.protomechHasRoom(getProtomech(), location, mount)) { + if (ProtoMekUtil.protomechHasRoom(getProtomech(), location, mount)) { UnitUtil.changeMountStatus(getProtomech(), mount, location, Entity.LOC_NONE, false); } } diff --git a/megameklab/src/megameklab/ui/protoMek/PMBuildView.java b/megameklab/src/megameklab/ui/protoMek/PMBuildView.java index be41c37b6..92ce4b20b 100644 --- a/megameklab/src/megameklab/ui/protoMek/PMBuildView.java +++ b/megameklab/src/megameklab/ui/protoMek/PMBuildView.java @@ -23,6 +23,7 @@ import megameklab.ui.util.CriticalTransferHandler; import megameklab.ui.util.IView; import megameklab.ui.util.RefreshListener; +import megameklab.util.ProtoMekUtil; import megameklab.util.StringUtils; import megameklab.util.UnitUtil; @@ -195,7 +196,7 @@ public void mousePressed(MouseEvent evt) { Mounted mount = (Mounted)equipmentTable.getModel().getValueAt(selectedRow, CriticalTableModel.EQUIPMENT); for (int location = 0; location < getProtoMek().locations(); location++) { - if (UnitUtil.protomechHasRoom(getProtoMek(), location, mount)) { + if (ProtoMekUtil.protomechHasRoom(getProtoMek(), location, mount)) { item = new JMenuItem("Add to " + locations[location]); final int loc = location; item.addActionListener(ev -> addToLocation(loc, mount)); diff --git a/megameklab/src/megameklab/ui/protoMek/PMStructureTab.java b/megameklab/src/megameklab/ui/protoMek/PMStructureTab.java index 4f519119c..47de250f1 100644 --- a/megameklab/src/megameklab/ui/protoMek/PMStructureTab.java +++ b/megameklab/src/megameklab/ui/protoMek/PMStructureTab.java @@ -45,6 +45,7 @@ import megameklab.ui.listeners.ProtomekBuildListener; import megameklab.ui.util.ITab; import megameklab.ui.util.RefreshListener; +import megameklab.util.ProtoMekUtil; import megameklab.util.UnitUtil; /** @@ -422,7 +423,7 @@ public void typeChanged(int motiveType) { } } List toRemove = getProtomech().getMisc().stream() - .filter(m -> !UnitUtil.isProtomechEquipment(m.getType(), getProtomech(), true)) + .filter(m -> !ProtoMekUtil.isProtomechEquipment(m.getType(), getProtomech(), true)) .collect(Collectors.toList()); toRemove.forEach(m -> UnitUtil.removeMounted(getProtomech(), m)); panMovement.setFromEntity(getProtomech()); diff --git a/megameklab/src/megameklab/ui/util/AbstractEquipmentDatabaseView.java b/megameklab/src/megameklab/ui/util/AbstractEquipmentDatabaseView.java index 12c120b0b..80df698d5 100644 --- a/megameklab/src/megameklab/ui/util/AbstractEquipmentDatabaseView.java +++ b/megameklab/src/megameklab/ui/util/AbstractEquipmentDatabaseView.java @@ -24,7 +24,9 @@ import megamek.common.Mech; import megamek.common.annotations.Nullable; import megameklab.ui.EntitySource; +import megameklab.util.BattleArmorUtil; import megameklab.util.CConfig; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -561,13 +563,13 @@ private boolean isEquipmentForEntity(EquipmentType equipment) { if (getEntity() instanceof Mech) { // FIXME : This is handled strangely in UnitUtil: MekEquipment does not include weapons - return UnitUtil.isMechEquipment(equipment, (Mech) getEntity()) - || UnitUtil.isMechWeapon(equipment, getEntity()) + return MekUtil.isMechEquipment(equipment, (Mech) getEntity()) + || MekUtil.isMechWeapon(equipment, getEntity()) || UnitUtil.isPhysicalWeapon(equipment); } else if (getEntity() instanceof BattleArmor) { // FIXME : This is handled strangely in UnitUtil: BAAPWeapons are not BAEquipment - return UnitUtil.isBAEquipment(equipment, getBattleArmor()) - || UnitUtil.isBattleArmorAPWeapon(equipment); + return BattleArmorUtil.isBAEquipment(equipment, getBattleArmor()) + || BattleArmorUtil.isBattleArmorAPWeapon(equipment); } else { return UnitUtil.isEntityEquipment(equipment, getEntity()); } diff --git a/megameklab/src/megameklab/ui/util/BAASBMDropTargetCriticalList.java b/megameklab/src/megameklab/ui/util/BAASBMDropTargetCriticalList.java index 1f38dcc63..b41a4ef76 100644 --- a/megameklab/src/megameklab/ui/util/BAASBMDropTargetCriticalList.java +++ b/megameklab/src/megameklab/ui/util/BAASBMDropTargetCriticalList.java @@ -25,6 +25,7 @@ import megameklab.ui.EntitySource; import megameklab.ui.mek.BMCriticalTransferHandler; import megameklab.ui.mek.BMCriticalView; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -584,7 +585,7 @@ private void addHand(int location) { private void removeHand(int location) { if (getUnit() instanceof BipedMech || getUnit() instanceof TripodMech) { - UnitUtil.removeHand((Mech) getUnit(), location); + MekUtil.removeHand((Mech) getUnit(), location); if (refresh != null) { refresh.scheduleRefresh(); } @@ -593,7 +594,7 @@ private void removeHand(int location) { private void removeArm(int location) { if (getUnit() instanceof BipedMech || getUnit() instanceof TripodMech) { - UnitUtil.removeArm((Mech)getUnit(),location); + MekUtil.removeArm((Mech)getUnit(),location); if (refresh != null) { refresh.scheduleRefresh(); } diff --git a/megameklab/src/megameklab/ui/util/CritCellUtil.java b/megameklab/src/megameklab/ui/util/CritCellUtil.java index 52b252d7e..0ffd5866f 100644 --- a/megameklab/src/megameklab/ui/util/CritCellUtil.java +++ b/megameklab/src/megameklab/ui/util/CritCellUtil.java @@ -2,6 +2,7 @@ import megamek.common.*; import megamek.common.annotations.Nullable; +import megameklab.ui.EquipmentToolTip; import megameklab.util.CConfig; import megameklab.util.UnitUtil; @@ -114,7 +115,7 @@ public static void formatCell(JLabel cell, @Nullable Mounted mounted, boolean us cell.setText(" " + name); - String toolTipText = UnitUtil.getToolTipInfo(entity, mounted); + String toolTipText = EquipmentToolTip.getToolTipInfo(entity, mounted); // distinguish tooltips of equal adjacent one-slot equipment (e.g. ammo) to make the tip renew itself // when crossing from one such slot to the next (avoids them feeling like a single equipment) if (mounted.getCriticals() == 1) { diff --git a/megameklab/src/megameklab/ui/util/CriticalTableModel.java b/megameklab/src/megameklab/ui/util/CriticalTableModel.java index c9d41914b..ffe0279b5 100644 --- a/megameklab/src/megameklab/ui/util/CriticalTableModel.java +++ b/megameklab/src/megameklab/ui/util/CriticalTableModel.java @@ -18,6 +18,7 @@ import megamek.common.verifier.TestEntity; import megamek.common.verifier.TestProtomech; import megamek.common.weapons.infantry.InfantryWeapon; +import megameklab.ui.EquipmentToolTip; import megameklab.util.CConfig; import megameklab.util.UnitUtil; @@ -298,7 +299,7 @@ public Component getTableCellRendererComponent(JTable table, && (mount.getType() instanceof AmmoType)) { c.setText(c.getText() + " (" + mount.getBaseShotsLeft() + ")"); } - c.setToolTipText(UnitUtil.getToolTipInfo(unit, mount)); + c.setToolTipText(EquipmentToolTip.getToolTipInfo(unit, mount)); c.setHorizontalAlignment(getAlignment(column)); if (isSelected) { diff --git a/megameklab/src/megameklab/ui/util/CriticalTransferHandler.java b/megameklab/src/megameklab/ui/util/CriticalTransferHandler.java index 28835b168..d54127e14 100644 --- a/megameklab/src/megameklab/ui/util/CriticalTransferHandler.java +++ b/megameklab/src/megameklab/ui/util/CriticalTransferHandler.java @@ -19,6 +19,7 @@ import megameklab.ui.EntitySource; import megameklab.ui.PopupMessages; import megameklab.ui.mek.BMCriticalView; +import megameklab.util.ProtoMekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -89,7 +90,7 @@ public boolean importData(TransferSupport info) { return false; } - if (!UnitUtil.protomechHasRoom(list.getProtomech(), location, mount)) { + if (!ProtoMekUtil.protomechHasRoom(list.getProtomech(), location, mount)) { PopupMessages.showLocationFullError(null, mount.getName()); } else { changeMountStatus(mount, location, false); diff --git a/megameklab/src/megameklab/ui/util/EquipmentDatabaseCategory.java b/megameklab/src/megameklab/ui/util/EquipmentDatabaseCategory.java index 585c413fe..c0b6eda9c 100644 --- a/megameklab/src/megameklab/ui/util/EquipmentDatabaseCategory.java +++ b/megameklab/src/megameklab/ui/util/EquipmentDatabaseCategory.java @@ -16,6 +16,7 @@ import megamek.common.*; import megamek.common.weapons.tag.TAGWeapon; +import megameklab.util.BattleArmorUtil; import megameklab.util.UnitUtil; import java.util.Collections; @@ -94,7 +95,7 @@ public enum EquipmentDatabaseCategory { || eq.hasFlag(F_AMS)), AP ("Anti-Personnel", - (eq, en) -> UnitUtil.isBattleArmorAPWeapon(eq), + (eq, en) -> BattleArmorUtil.isBattleArmorAPWeapon(eq), e -> e instanceof BattleArmor), PROTOTYPE ("Prototype", diff --git a/megameklab/src/megameklab/ui/util/EquipmentTableModel.java b/megameklab/src/megameklab/ui/util/EquipmentTableModel.java index c2fbdd325..60c85d64b 100644 --- a/megameklab/src/megameklab/ui/util/EquipmentTableModel.java +++ b/megameklab/src/megameklab/ui/util/EquipmentTableModel.java @@ -27,7 +27,7 @@ import megamek.common.weapons.missiles.ThunderBoltWeapon; import megamek.common.weapons.mortars.MekMortarWeapon; import megameklab.util.CConfig; -import megameklab.util.UnitUtil; +import megameklab.util.InfantryUtil; import javax.swing.*; import javax.swing.table.AbstractTableModel; @@ -553,7 +553,7 @@ public Component getTableCellRendererComponent(JTable table, EquipmentType etype = ((EquipmentTableModel) table.getModel()).getType(actualRow); if (column == COL_NAME) { // Reinstate the real name, as the value will be the sorting-optimized name - value = UnitUtil.trimInfantryWeaponNames(etype.getName()); + value = InfantryUtil.trimInfantryWeaponNames(etype.getName()); } super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); diff --git a/megameklab/src/megameklab/ui/util/ProtomekMountList.java b/megameklab/src/megameklab/ui/util/ProtomekMountList.java index eedd9858d..ca57637fd 100644 --- a/megameklab/src/megameklab/ui/util/ProtomekMountList.java +++ b/megameklab/src/megameklab/ui/util/ProtomekMountList.java @@ -16,6 +16,7 @@ import megamek.common.*; import megamek.common.annotations.Nullable; import megameklab.ui.EntitySource; +import megameklab.util.ProtoMekUtil; import megameklab.util.UnitUtil; import org.apache.logging.log4j.LogManager; @@ -123,7 +124,7 @@ public void mouseReleased(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { if (e.isControlDown() && (mounted.getType() instanceof AmmoType)) { try { - UnitUtil.addProtoMechAmmo(getProtomech(), mounted.getType(), 1); + ProtoMekUtil.addProtoMechAmmo(getProtomech(), mounted.getType(), 1); } catch (LocationFullException ex) { LogManager.getLogger().error("", ex); } @@ -139,7 +140,7 @@ public void mouseReleased(MouseEvent e) { } if (e.isControlDown()) { if ((mounted.getType() instanceof AmmoType)) { - UnitUtil.reduceProtoMechAmmo(getProtomech(), mounted.getType(), 1); + ProtoMekUtil.reduceProtoMechAmmo(getProtomech(), mounted.getType(), 1); } else { removeMount(mounted); } diff --git a/megameklab/src/megameklab/ui/util/WeaponListCellRenderer.java b/megameklab/src/megameklab/ui/util/WeaponListCellRenderer.java index 1b19aef5d..a06373e99 100644 --- a/megameklab/src/megameklab/ui/util/WeaponListCellRenderer.java +++ b/megameklab/src/megameklab/ui/util/WeaponListCellRenderer.java @@ -24,6 +24,7 @@ import megamek.common.Entity; import megamek.common.EquipmentType; import megamek.common.Mounted; +import megameklab.ui.EquipmentToolTip; import megameklab.util.UnitUtil; public class WeaponListCellRenderer extends DefaultListCellRenderer { @@ -47,7 +48,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i label.setText(UnitUtil.getCritName(unit, eq)); label.setName(value.toString()); - label.setToolTipText(UnitUtil.getToolTipInfo(unit, new Mounted(unit, eq))); + label.setToolTipText(EquipmentToolTip.getToolTipInfo(unit, new Mounted(unit, eq))); return label; } diff --git a/megameklab/src/megameklab/util/UnitPrintManager.java b/megameklab/src/megameklab/util/UnitPrintManager.java index 6c7f9dbb1..58de92de6 100644 --- a/megameklab/src/megameklab/util/UnitPrintManager.java +++ b/megameklab/src/megameklab/util/UnitPrintManager.java @@ -148,7 +148,7 @@ private static List createSheets(List entities, boolea for (Entity unit : entities) { if (unit instanceof Mech) { UnitUtil.removeOneShotAmmo(unit); - UnitUtil.expandUnitMounts((Mech) unit); + MekUtil.expandUnitMounts((Mech) unit); sheets.add(new PrintMech((Mech) unit, pageCount++, options)); } else if ((unit instanceof Tank) && unit.getMovementMode().isMarine()) { sheets.add(new PrintTank((Tank) unit, pageCount++, options)); From 56e954fbc0a6d4491a4d48a252f019cb83208500 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 7 Jan 2024 23:39:46 +0100 Subject: [PATCH 3/5] misc --- megameklab/src/megameklab/util/AeroUtil.java | 6 +++--- megameklab/src/megameklab/util/BattleArmorUtil.java | 4 ++-- megameklab/src/megameklab/util/InfantryUtil.java | 4 ++-- megameklab/src/megameklab/util/ProtoMekUtil.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/megameklab/src/megameklab/util/AeroUtil.java b/megameklab/src/megameklab/util/AeroUtil.java index 0a2588f55..0e9fa7289 100644 --- a/megameklab/src/megameklab/util/AeroUtil.java +++ b/megameklab/src/megameklab/util/AeroUtil.java @@ -260,8 +260,6 @@ public static void autoAssignQuarters(Aero aero) { assignQuarters(aero, officer + firstClass, standardCrew, secondClass, steerageCrew + steeragePsgr); } - private AeroUtil() { } - public static void updateLoadedAero(Aero unit) { if (unit.hasETypeFlag(Entity.ETYPE_SMALL_CRAFT)) { if (unit.getArmorType(Aero.LOC_NOSE) == EquipmentType.T_ARMOR_STANDARD) { @@ -310,4 +308,6 @@ public static void updateLoadedAero(Aero unit) { UnitUtil.removeMounted(unit, group); } } -} \ No newline at end of file + + private AeroUtil() { } +} diff --git a/megameklab/src/megameklab/util/BattleArmorUtil.java b/megameklab/src/megameklab/util/BattleArmorUtil.java index 265f923f0..e79091beb 100644 --- a/megameklab/src/megameklab/util/BattleArmorUtil.java +++ b/megameklab/src/megameklab/util/BattleArmorUtil.java @@ -118,10 +118,10 @@ public static boolean canLegAttack(BattleArmor ba) { return false; } - private BattleArmorUtil() { } - public static boolean isBAMultiMount(EquipmentType equip) { return (equip instanceof WeaponType) && (equip.hasFlag(WeaponType.F_TASER) || (((WeaponType) equip).getAmmoType() == AmmoType.T_NARC)); } + + private BattleArmorUtil() { } } \ No newline at end of file diff --git a/megameklab/src/megameklab/util/InfantryUtil.java b/megameklab/src/megameklab/util/InfantryUtil.java index 8b4550514..b6555ec51 100644 --- a/megameklab/src/megameklab/util/InfantryUtil.java +++ b/megameklab/src/megameklab/util/InfantryUtil.java @@ -123,10 +123,10 @@ public static void resetInfantryArmor(Infantry unit) { unit.setArmorDamageDivisor(1.0); } - private InfantryUtil() { } - public static boolean isInfantryEquipment(EquipmentType eq, Entity unit) { // TODO: adjust for field guns and artillery return eq instanceof InfantryWeapon; } + + private InfantryUtil() { } } \ No newline at end of file diff --git a/megameklab/src/megameklab/util/ProtoMekUtil.java b/megameklab/src/megameklab/util/ProtoMekUtil.java index 494e56287..a9cbb9b42 100644 --- a/megameklab/src/megameklab/util/ProtoMekUtil.java +++ b/megameklab/src/megameklab/util/ProtoMekUtil.java @@ -76,8 +76,6 @@ public static void reduceProtoMechAmmo(Protomech entity, EquipmentType ammo, int } } - private ProtoMekUtil() { } - /** * Checks whether the space has room for the equipment within the slot and weight limits. * @@ -106,4 +104,6 @@ public static boolean protomechHasRoom(Protomech proto, int location, Mounted mo } return true; } + + private ProtoMekUtil() { } } From a09615414b151064c6b5f27fb0b52dc81ee55877 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 7 Jan 2024 23:42:53 +0100 Subject: [PATCH 4/5] merge adaptation --- .../ui/generalUnit/summary/HeatsinkSummaryItem.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/megameklab/src/megameklab/ui/generalUnit/summary/HeatsinkSummaryItem.java b/megameklab/src/megameklab/ui/generalUnit/summary/HeatsinkSummaryItem.java index bf52627ee..c9394b894 100644 --- a/megameklab/src/megameklab/ui/generalUnit/summary/HeatsinkSummaryItem.java +++ b/megameklab/src/megameklab/ui/generalUnit/summary/HeatsinkSummaryItem.java @@ -22,6 +22,7 @@ import megamek.common.annotations.Nullable; import megamek.common.verifier.TestEntity; import megamek.common.verifier.TestMech; +import megameklab.util.MekUtil; import megameklab.util.UnitUtil; public class HeatsinkSummaryItem extends AbstractSummaryItem { @@ -35,10 +36,10 @@ public void refresh(Entity entity) { if (entity instanceof Mech) { TestMech testMech = (TestMech) UnitUtil.getEntityVerifier(entity); Mech mek = (Mech) entity; - int numberSinks = UnitUtil.countActualHeatSinks(mek); + int numberSinks = MekUtil.countActualHeatSinks(mek); numberSinks = Math.max(0, numberSinks - UnitUtil.getCriticalFreeHeatSinks(mek, mek.hasCompactHeatSinks())); int critSinks = numberSinks; - if (UnitUtil.hasClanDoubleHeatSinks(mek)) { + if (MekUtil.hasClanDoubleHeatSinks(mek)) { critSinks = numberSinks * 2; } else if (mek.hasDoubleHeatSinks()) { critSinks = numberSinks * 3; From 4aacc8bd34de13db268e9d12afbded7d15b0b7e4 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 7 Jan 2024 23:54:29 +0100 Subject: [PATCH 5/5] misc code changes --- .../src/megameklab/printing/PrintUtil.java | 4 +- megameklab/src/megameklab/util/AeroUtil.java | 8 +-- megameklab/src/megameklab/util/MekUtil.java | 51 +---------------- megameklab/src/megameklab/util/TankUtil.java | 56 +------------------ megameklab/src/megameklab/util/UnitUtil.java | 47 ++++++++++++++++ 5 files changed, 56 insertions(+), 110 deletions(-) diff --git a/megameklab/src/megameklab/printing/PrintUtil.java b/megameklab/src/megameklab/printing/PrintUtil.java index edb2bb47c..4732a1298 100644 --- a/megameklab/src/megameklab/printing/PrintUtil.java +++ b/megameklab/src/megameklab/printing/PrintUtil.java @@ -106,8 +106,8 @@ private PrintUtil() { } * simple method to let us know if eq should be printed on the weapons and * equipment section of the Record sheet. * - * @param eq - * @return + * @param eq The equipment to test + * @return True when it should appear on the record sheet */ public static boolean isPrintableBAEquipment(EquipmentType eq) { if (UnitUtil.isArmorOrStructure(eq)) { diff --git a/megameklab/src/megameklab/util/AeroUtil.java b/megameklab/src/megameklab/util/AeroUtil.java index 0e9fa7289..055506010 100644 --- a/megameklab/src/megameklab/util/AeroUtil.java +++ b/megameklab/src/megameklab/util/AeroUtil.java @@ -112,11 +112,9 @@ public static boolean isAeroWeapon(EquipmentType eq, Aero unit) { || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon .getAmmoType() == AmmoType.T_PLASMA))) { - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } + return !weapon.hasFlag(WeaponType.F_ENERGY) + || !weapon.hasFlag(WeaponType.F_PLASMA) + || (weapon.getAmmoType() != AmmoType.T_NA); } return true; } diff --git a/megameklab/src/megameklab/util/MekUtil.java b/megameklab/src/megameklab/util/MekUtil.java index 6b54a2007..1ef376e52 100644 --- a/megameklab/src/megameklab/util/MekUtil.java +++ b/megameklab/src/megameklab/util/MekUtil.java @@ -22,13 +22,7 @@ import megamek.common.weapons.c3.ISC3M; import megamek.common.weapons.c3.ISC3MBS; import megamek.common.weapons.infantry.InfantryWeapon; -import megamek.common.weapons.lrms.LRMWeapon; -import megamek.common.weapons.lrms.LRTWeapon; -import megamek.common.weapons.missiles.MRMWeapon; -import megamek.common.weapons.missiles.RLWeapon; import megamek.common.weapons.other.*; -import megamek.common.weapons.srms.SRMWeapon; -import megamek.common.weapons.srms.SRTWeapon; import megamek.common.weapons.tag.CLLightTAG; import megamek.common.weapons.tag.CLTAG; import megamek.common.weapons.tag.ISTAG; @@ -1313,53 +1307,10 @@ public static boolean isMechWeapon(EquipmentType eq, Entity unit) { } if (eq instanceof WeaponType) { - WeaponType weapon = (WeaponType) eq; - - if (!weapon.hasFlag(WeaponType.F_MECH_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (weapon.isCapital() || weapon.isSubCapital()) { - return false; - } - - if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) - && (weapon.getRackSize() != 5) - && (weapon.getRackSize() != 10) - && (weapon.getRackSize() != 15) - && (weapon.getRackSize() != 20)) { + if (!weapon.hasFlag(WeaponType.F_MECH_WEAPON) || isNonMekOrTankWeapon(unit, weapon)) { return false; } - if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) - && (weapon.getRackSize() != 2) - && (weapon.getRackSize() != 4) - && (weapon.getRackSize() != 6)) { - return false; - } - if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon - .getAmmoType() == AmmoType.T_PLASMA))) { - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } - } - if ((unit instanceof LandAirMech) && (weapon.getAmmoType() == AmmoType.T_GAUSS_HEAVY || weapon.getAmmoType() == AmmoType.T_IGAUSS_HEAVY)) { diff --git a/megameklab/src/megameklab/util/TankUtil.java b/megameklab/src/megameklab/util/TankUtil.java index 32d721dd4..a945f8025 100644 --- a/megameklab/src/megameklab/util/TankUtil.java +++ b/megameklab/src/megameklab/util/TankUtil.java @@ -23,12 +23,6 @@ import megamek.common.weapons.c3.ISC3M; import megamek.common.weapons.c3.ISC3MBS; import megamek.common.weapons.infantry.InfantryWeapon; -import megamek.common.weapons.lrms.LRMWeapon; -import megamek.common.weapons.lrms.LRTWeapon; -import megamek.common.weapons.missiles.MRMWeapon; -import megamek.common.weapons.missiles.RLWeapon; -import megamek.common.weapons.srms.SRMWeapon; -import megamek.common.weapons.srms.SRTWeapon; import megamek.common.weapons.tag.CLLightTAG; import megamek.common.weapons.tag.CLTAG; import megamek.common.weapons.tag.ISTAG; @@ -45,52 +39,10 @@ public static boolean isTankWeapon(EquipmentType eq, Entity unit) { } if (eq instanceof WeaponType) { - WeaponType weapon = (WeaponType) eq; - - if (!weapon.hasFlag(WeaponType.F_TANK_WEAPON)) { - return false; - } - - if (weapon.getTonnage(unit) <= 0) { - return false; - } - - if (weapon.isCapital() || weapon.isSubCapital()) { - return false; - } - - if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) - && (weapon.getRackSize() != 5) - && (weapon.getRackSize() != 10) - && (weapon.getRackSize() != 15) - && (weapon.getRackSize() != 20)) { + if (!weapon.hasFlag(WeaponType.F_TANK_WEAPON) || UnitUtil.isNonMekOrTankWeapon(unit, weapon)) { return false; } - if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) - && (weapon.getRackSize() != 2) - && (weapon.getRackSize() != 4) - && (weapon.getRackSize() != 6)) { - return false; - } - if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { - return false; - } - - if (weapon.hasFlag(WeaponType.F_ENERGY) - || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon.getAmmoType() == AmmoType.T_PLASMA))) { - - if (weapon.hasFlag(WeaponType.F_ENERGY) - && weapon.hasFlag(WeaponType.F_PLASMA) - && (weapon.getAmmoType() == AmmoType.T_NA)) { - return false; - } - } - return TestTank.legalForMotiveType(weapon, unit.getMovementMode(), unit.isSupportVehicle()); } return false; @@ -120,13 +72,11 @@ public static boolean isTankMiscEquipment(EquipmentType eq, Entity tank) { } // Display AMS as equipment (even though it's a weapon) - if (eq.hasFlag(WeaponType.F_AMS) - && eq.hasFlag(WeaponType.F_TANK_WEAPON)) { + if (eq.hasFlag(WeaponType.F_AMS) && eq.hasFlag(WeaponType.F_TANK_WEAPON)) { return true; } - if ((eq instanceof CLTAG) || (eq instanceof ISC3M) - || (eq instanceof ISC3MBS) + if ((eq instanceof CLTAG) || (eq instanceof ISC3M) || (eq instanceof ISC3MBS) || (eq instanceof ISTAG) || (eq instanceof CLLightTAG)) { return true; } diff --git a/megameklab/src/megameklab/util/UnitUtil.java b/megameklab/src/megameklab/util/UnitUtil.java index dcfd1b3d0..8c1cef531 100644 --- a/megameklab/src/megameklab/util/UnitUtil.java +++ b/megameklab/src/megameklab/util/UnitUtil.java @@ -33,11 +33,17 @@ import megamek.common.weapons.gaussrifles.GaussWeapon; import megamek.common.weapons.infantry.InfantryWeapon; import megamek.common.weapons.lasers.CLChemicalLaserWeapon; +import megamek.common.weapons.lrms.LRMWeapon; +import megamek.common.weapons.lrms.LRTWeapon; import megamek.common.weapons.lrms.StreakLRMWeapon; import megamek.common.weapons.mgs.MGWeapon; +import megamek.common.weapons.missiles.MRMWeapon; +import megamek.common.weapons.missiles.RLWeapon; import megamek.common.weapons.missiles.ThunderBoltWeapon; import megamek.common.weapons.ppc.CLPlasmaCannon; import megamek.common.weapons.ppc.ISPlasmaRifle; +import megamek.common.weapons.srms.SRMWeapon; +import megamek.common.weapons.srms.SRTWeapon; import megamek.common.weapons.srms.StreakSRMWeapon; import megameklab.ui.PopupMessages; import org.apache.logging.log4j.LogManager; @@ -2022,4 +2028,45 @@ public static void setVariableSizeMiscTypeMinimumSize(Mounted mounted) { } private UnitUtil() { } + + static boolean isNonMekOrTankWeapon(Entity unit, WeaponType weapon) { + if (weapon.getTonnage(unit) <= 0) { + return true; + } + + if (weapon.isCapital() || weapon.isSubCapital()) { + return true; + } + + if (((weapon instanceof LRMWeapon) || (weapon instanceof LRTWeapon)) + && (weapon.getRackSize() != 5) + && (weapon.getRackSize() != 10) + && (weapon.getRackSize() != 15) + && (weapon.getRackSize() != 20)) { + return true; + } + if (((weapon instanceof SRMWeapon) || (weapon instanceof SRTWeapon)) + && (weapon.getRackSize() != 2) + && (weapon.getRackSize() != 4) + && (weapon.getRackSize() != 6)) { + return true; + } + if ((weapon instanceof MRMWeapon) && (weapon.getRackSize() < 10)) { + return true; + } + + if ((weapon instanceof RLWeapon) && (weapon.getRackSize() < 10)) { + return true; + } + + if (weapon.hasFlag(WeaponType.F_ENERGY) + || (weapon.hasFlag(WeaponType.F_PLASMA) && (weapon + .getAmmoType() == AmmoType.T_PLASMA))) { + + return weapon.hasFlag(WeaponType.F_ENERGY) + && weapon.hasFlag(WeaponType.F_PLASMA) + && (weapon.getAmmoType() == AmmoType.T_NA); + } + return false; + } } \ No newline at end of file