diff --git a/megamek/src/megamek/common/MiscType.java b/megamek/src/megamek/common/MiscType.java index 262c70e46cb..2701466236c 100644 --- a/megamek/src/megamek/common/MiscType.java +++ b/megamek/src/megamek/common/MiscType.java @@ -387,6 +387,10 @@ public class MiscType extends EquipmentType { public static final long S_MARITIME_ESCAPE_POD = 1L << 1; public static final long S_ATMOSPHERIC_LIFEBOAT = 1L << 2; + // Secondary flags for various robotic/drone control systems to distinguish between the base unit and extra capacity + public static final long S_DRONE_BASE_UNIT = 1L; + public static final long S_DRONE_EXTRA = 1L << 1; + // New stuff for shields protected int baseDamageAbsorptionRate = 0; protected int baseDamageCapacity = 0; @@ -807,12 +811,12 @@ public double getTonnage(Entity entity, int location, RoundWeight defaultRoundin return defaultRounding.round(entity.getWeight() * pct, entity); } } else if (hasFlag(MiscType.F_ATAC)) { - //TODO Neo - pg IO 146 Each drone that it can control adds 150 ton to weight. + // includes capacity for one drone double tWeight = defaultRounding.round(entity.getWeight() * 0.02, entity); - return Math.min(tWeight, 50000); + return Math.min(tWeight, 50000) + 150.0; } else if (hasFlag(MiscType.F_DTAC)) { - //TODO Neo - pg IO 146 Each drone that it can control adds 150 ton to weight. - return defaultRounding.round(entity.getWeight() * 0.03, entity); + // includes capacity for one drone + return defaultRounding.round(entity.getWeight() * 0.03, entity) + 150.0; } else if (hasFlag(MiscType.F_SDS_DESTRUCT)) { return Math.min(RoundWeight.nextTon(entity.getWeight() * 0.1), 10000); } else if (hasFlag(MiscType.F_MAGNETIC_CLAMP) && hasFlag(MiscType.F_PROTOMECH_EQUIPMENT)) { @@ -1801,8 +1805,10 @@ public static void initializeTypes() { EquipmentType.addType(MiscType.createCasparIIDroneControlSystem()); EquipmentType.addType(MiscType.createImprovedCasparIIDroneControlSystem()); EquipmentType.addType(MiscType.createAutoTacticalAnalysisComputer()); + EquipmentType.addType(MiscType.createATACExtraDrone()); EquipmentType.addType(MiscType.createAdvRoboticTransportSystem()); EquipmentType.addType(MiscType.createDirectTacticalAnalysisSystem()); + EquipmentType.addType(MiscType.createDTACExtraDrone()); EquipmentType.addType(MiscType.createSDSSelfDestructSystem()); EquipmentType.addType(MiscType.createSDSJammerSystem()); @@ -5517,12 +5523,9 @@ public static MiscType createISDroneCarrierControlSystem() { .or(F_FIGHTER_EQUIPMENT).or(F_DS_EQUIPMENT).or(F_JS_EQUIPMENT).or(F_SS_EQUIPMENT) .or(F_SUPPORT_TANK_EQUIPMENT); misc.rulesRefs = "305,TO"; - misc.techAdvancement.setTechBase(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false) + misc.techAdvancement.setTechBase(TECH_BASE_ALL) .setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_F, RATING_E) - .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) - .setISApproximate(false, false, false, false, false) - .setClanAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) - .setClanApproximate(false, false, false, false, false) + .setAdvancement(DATE_ES, DATE_ES) .setStaticTechLevel(SimpleTechLevel.ADVANCED); return misc; } @@ -5579,7 +5582,7 @@ public static MiscType createISDroneExtra() { // TODO: add game rules for this (these are actually the Drones // themselves) MiscType misc = new MiscType(); - misc.name = "Drones (as Extra Equipment)"; + misc.name = "DCCS Extra Drone"; misc.setInternalName("ISDroneExtra"); misc.addLookupName("CLDroneExtra"); misc.tonnage = 0; @@ -5588,10 +5591,10 @@ public static MiscType createISDroneExtra() { misc.flags = misc.flags.or(F_DRONE_EXTRA).or(F_TANK_EQUIPMENT).or(F_FIGHTER_EQUIPMENT) .or(F_FIGHTER_EQUIPMENT).or(F_DS_EQUIPMENT).or(F_JS_EQUIPMENT).or(F_SS_EQUIPMENT) .or(F_SUPPORT_TANK_EQUIPMENT); ; - misc.techAdvancement.setTechBase(TECH_BASE_IS); - misc.techAdvancement.setISAdvancement(DATE_NONE, 2000, DATE_NONE); - misc.techAdvancement.setTechRating(RATING_C); - misc.techAdvancement.setAvailability(new int[] { RATING_E, RATING_F, RATING_F, RATING_X }); + misc.techAdvancement.setTechBase(TECH_BASE_ALL) + .setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_F, RATING_E) + .setAdvancement(DATE_ES, DATE_ES) + .setStaticTechLevel(SimpleTechLevel.ADVANCED); return misc; } @@ -5783,11 +5786,13 @@ public static MiscType createAutoTacticalAnalysisComputer() { // TODO Game Rules. MiscType misc = new MiscType(); misc.name = "Autonomous Tactical Analysis Computer (ATAC)"; + misc.shortName = "ATAC"; misc.setInternalName("AutoTacticalAnalysisComputer"); misc.tonnage = TONNAGE_VARIABLE; misc.criticals = 0; misc.cost = COST_VARIABLE; misc.flags = misc.flags.or(F_ATAC).or(F_DS_EQUIPMENT).or(F_WS_EQUIPMENT).or(F_SS_EQUIPMENT); + misc.subType = S_DRONE_BASE_UNIT; misc.rulesRefs = "145,IO"; misc.techAdvancement.setTechBase(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false) .setTechRating(RATING_E).setAvailability(RATING_F, RATING_X, RATING_F, RATING_F) @@ -5799,6 +5804,27 @@ public static MiscType createAutoTacticalAnalysisComputer() { return misc; } + public static MiscType createATACExtraDrone() { + // TODO Game Rules. + MiscType misc = new MiscType(); + misc.name = "ATAC Additional Drone"; + misc.shortName = "ATAC Drone"; + misc.setInternalName("ATACExtraDrone"); + misc.tonnage = 150.0; + misc.criticals = 0; + misc.cost = COST_VARIABLE; + misc.flags = misc.flags.or(F_ATAC).or(F_DS_EQUIPMENT).or(F_WS_EQUIPMENT).or(F_SS_EQUIPMENT); + misc.subType = S_DRONE_EXTRA; + misc.rulesRefs = "145,IO"; + misc.techAdvancement.setTechBase(TECH_BASE_ALL) + .setTechRating(RATING_E).setAvailability(RATING_F, RATING_X, RATING_F, RATING_F) + .setISAdvancement(2705, DATE_NONE, DATE_NONE, 2780, DATE_NONE) + .setClanAdvancement(2705, DATE_NONE, DATE_NONE, DATE_NONE, DATE_NONE) + .setPrototypeFactions(F_TH); + + return misc; + } + public static MiscType createAdvRoboticTransportSystem() { // TODO Game Rules. MiscType misc = new MiscType(); @@ -5823,11 +5849,13 @@ public static MiscType createDirectTacticalAnalysisSystem() { // TODO Game Rules. MiscType misc = new MiscType(); misc.name = "Direct Tactical Analysis Control (DTAC) System"; + misc.shortName = "DTAC"; misc.setInternalName("DirectTacticalAnalysisSystem"); - misc.tonnage = TONNAGE_VARIABLE;; + misc.tonnage = TONNAGE_VARIABLE; misc.criticals = 0; - misc.cost = COST_VARIABLE;; + misc.cost = COST_VARIABLE; misc.flags = misc.flags.or(F_DTAC).or(F_DS_EQUIPMENT).or(F_WS_EQUIPMENT).or(F_SS_EQUIPMENT); + misc.subType = S_DRONE_BASE_UNIT; misc.rulesRefs = "146,IO"; misc.techAdvancement.setTechBase(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) @@ -5838,6 +5866,27 @@ public static MiscType createDirectTacticalAnalysisSystem() { return misc; } + public static MiscType createDTACExtraDrone() { + // TODO Game Rules. + MiscType misc = new MiscType(); + misc.name = "DTAC Extra Drone"; + misc.shortName = "Extra Drone"; + misc.setInternalName("DTACExtraDrone"); + misc.tonnage = 150.0; + misc.criticals = 0; + misc.cost = COST_VARIABLE; + misc.flags = misc.flags.or(F_DTAC).or(F_DS_EQUIPMENT).or(F_WS_EQUIPMENT).or(F_SS_EQUIPMENT); + misc.subType = S_DRONE_EXTRA; + misc.rulesRefs = "146,IO"; + misc.techAdvancement.setTechBase(TECH_BASE_IS).setTechRating(RATING_F) + .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) + .setISAdvancement(3072, DATE_NONE, DATE_NONE, 3078, 3082) + .setISApproximate(true, false, false, false, false).setPrototypeFactions(F_WB) + .setReintroductionFactions(F_RS); + + return misc; + } + public static MiscType createSDSSelfDestructSystem() { // TODO Game Rules. MiscType misc = new MiscType(); diff --git a/megamek/src/megamek/common/templates/CapitalShipTROView.java b/megamek/src/megamek/common/templates/CapitalShipTROView.java index bf039a5bfc8..885414133fc 100644 --- a/megamek/src/megamek/common/templates/CapitalShipTROView.java +++ b/megamek/src/megamek/common/templates/CapitalShipTROView.java @@ -3,18 +3,10 @@ */ package megamek.common.templates; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; -import megamek.common.Aero; -import megamek.common.Entity; -import megamek.common.Jumpship; -import megamek.common.Messages; -import megamek.common.Mounted; -import megamek.common.Warship; +import megamek.common.*; import megamek.common.verifier.EntityVerifier; import megamek.common.verifier.TestAdvancedAerospace; @@ -84,10 +76,51 @@ protected void initModel(EntityVerifier verifier) { if (aero.hasLF()) { misc.add(Messages.getString("TROView.lfbattery")); } - final Map miscCount = aero.getMisc().stream() - .filter(m -> (m.getLinked() == null) && (m.getLinkedBy() == null)) - .collect(Collectors.groupingBy(m -> m.getType().getName(), Collectors.summingInt(m -> 1))); - miscCount.forEach((k, v) -> misc.add(String.format("%d %s", v, k))); + int mashTheaters = 0; + int drones = 0; + int atac = 0; + int dtac = 0; + final Map eqCount = new HashMap<>(); + for (Mounted mount : aero.getMisc()) { + // MASH and DCC use an additional MiscType to expand their capacity. + // Present them as a single piece of equipment and show size. + if (mount.getType().hasFlag(MiscType.F_MASH) || mount.getType().hasFlag(MiscType.F_MASH_EXTRA)) { + mashTheaters++; + } else if (mount.getType().hasFlag(MiscType.F_DRONE_CARRIER_CONTROL) + || mount.getType().hasFlag(MiscType.F_DRONE_EXTRA)) { + drones++; + } else if (mount.getType().hasFlag(MiscType.F_ATAC)) { + atac++; + } else if (mount.getType().hasFlag(MiscType.F_DTAC)) { + dtac++; + } else { + eqCount.merge(mount.getType().getShortName(), 1, Integer::sum); + } + } + for (String eq : eqCount.keySet()) { + if (eqCount.get(eq) > 1) { + misc.add(eqCount.get(eq) + "x" + eq); + } else { + misc.add(eq); + } + } + if (mashTheaters > 1) { + misc.add("MASH (" + mashTheaters + " theaters)"); + } else if (mashTheaters == 1) { + misc.add("MASH"); + } + if (drones > 0) { + misc.add("Drone Carrier Control System (" + drones + + ((drones > 1) ? " drones)" : " drone)")); + } + if (atac > 0) { + misc.add("ATAC (" + atac + + ((atac > 1) ? " drones)" : " drone)")); + } + if (dtac > 0) { + misc.add("DTAC (" + dtac + + ((dtac > 1) ? " drones)" : " drone)")); + } setModelData("miscEquipment", misc); setModelData("lfBattery", aero.hasLF()); diff --git a/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java b/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java index 86206714723..5714e8f555f 100644 --- a/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java +++ b/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java @@ -366,10 +366,17 @@ public static int minimumBaseCrew(Jumpship vessel) { } else { crew = 6 + (int) Math.ceil(vessel.getWeight() / 20000); } + int atac = 0; for (Mounted m : vessel.getMisc()) { crew += equipmentCrewRequirements(m.getType()); + // DTAC requires 1 crew / drone, ATAC 1 crew / 3 drones + if (m.getType().hasFlag(MiscType.F_ATAC)) { + atac++; + } else if (m.getType().hasFlag(MiscType.F_DTAC)) { + crew++; + } } - return crew; + return crew + (int) Math.ceil(atac / 3.0); } /**