diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index c1faced120..49952e3221 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -199,7 +199,7 @@ public class Campaign implements ITechManager { // hierarchically structured Force object to define TO&E private Force forces; - private final Hashtable lances; // AtB + private final Hashtable strategicFormations; // AtB private Faction faction; private int techFactionCode; @@ -309,7 +309,7 @@ public Campaign() { setRankSystemDirect(Ranks.getRankSystemFromCode(Ranks.DEFAULT_SYSTEM_CODE)); forces = new Force(name); forceIds.put(0, forces); - lances = new Hashtable<>(); + strategicFormations = new Hashtable<>(); finances = new Finances(); astechPool = 0; medicPool = 0; @@ -449,15 +449,15 @@ public List getAllForces() { } public void importLance(StrategicFormation l) { - lances.put(l.getForceId(), l); + strategicFormations.put(l.getForceId(), l); } public Hashtable getStrategicFormations() { - return lances; + return strategicFormations; } public ArrayList getStrategicFormationList() { - return lances.values().stream() + return strategicFormations.values().stream() .filter(l -> forceIds.containsKey(l.getForceId())) .collect(Collectors.toCollection(ArrayList::new)); } @@ -904,8 +904,8 @@ public void addForce(Force force, Force superForce) { lastForceId = id; if (campaignOptions.isUseAtB() && !force.getUnits().isEmpty()) { - if (null == lances.get(id)) { - lances.put(id, new StrategicFormation(force.getId(), this)); + if (null == strategicFormations.get(id)) { + strategicFormations.put(id, new StrategicFormation(force.getId(), this)); } } @@ -1003,11 +1003,11 @@ public void addUnitToForce(@Nullable Unit u, int id) { if (campaignOptions.isUseAtB()) { if ((null != prevForce) && prevForce.getUnits().isEmpty()) { - lances.remove(prevForce.getId()); + strategicFormations.remove(prevForce.getId()); } - if ((null == lances.get(id)) && (null != force)) { - lances.put(id, new StrategicFormation(force.getId(), this)); + if ((null == strategicFormations.get(id)) && (null != force)) { + strategicFormations.put(id, new StrategicFormation(force.getId(), this)); } } } @@ -1015,10 +1015,9 @@ public void addUnitToForce(@Nullable Unit u, int id) { /** * Adds force and all its subforces to the AtB lance table */ - private void addAllLances(Force force) { - if (!force.getUnits().isEmpty()) { - lances.put(force.getId(), new StrategicFormation(force.getId(), this)); + if (force.isStrategicFormation()) { + strategicFormations.put(force.getId(), new StrategicFormation(force.getId(), this)); } for (Force f : force.getSubForces()) { addAllLances(f); @@ -3618,7 +3617,7 @@ public int getDeploymentDeficit(AtBContract contract) { int role = -Math.max(1, contract.getRequiredLances() / 2); final AtBLanceRole requiredLanceRole = contract.getContractType().getRequiredLanceRole(); - for (StrategicFormation l : lances.values()) { + for (StrategicFormation l : strategicFormations.values()) { if (!l.getRole().isUnassigned() && (l.getMissionId() == contract.getId())) { total++; if (l.getRole() == requiredLanceRole) { @@ -3718,7 +3717,7 @@ && getLocation().getJumpPath().getLastSystem().getId().equals(contract.getSystem for (final AtBScenario s : contract.getCurrentAtBScenarios()) { if ((s.getDate() != null) && s.getDate().equals(getLocalDate())) { int forceId = s.getStrategicFormationId(); - if ((lances.get(forceId) != null) && !forceIds.get(forceId).isDeployed()) { + if ((strategicFormations.get(forceId) != null) && !forceIds.get(forceId).isDeployed()) { // If any unit in the force is under repair, don't deploy the force // Merely removing the unit from deployment would break with user expectation boolean forceUnderRepair = false; @@ -4967,7 +4966,7 @@ public void removeForce(Force force) { } if (campaignOptions.isUseAtB()) { - lances.remove(fid); + strategicFormations.remove(fid); } if (null != force.getParentForce()) { @@ -5020,7 +5019,7 @@ public void removeUnitFromForce(Unit u) { } if (campaignOptions.isUseAtB() && force.getUnits().isEmpty()) { - lances.remove(force.getId()); + strategicFormations.remove(force.getId()); } } } @@ -5595,14 +5594,14 @@ public void writeToXML(final PrintWriter pw) { // CAW: implicit DEPENDS-ON to the node, do not move this above it contractMarket.writeToXML(pw, indent); - if (!lances.isEmpty()) { - MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "lances"); - for (StrategicFormation l : lances.values()) { + if (!strategicFormations.isEmpty()) { + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "strategicFormations"); + for (StrategicFormation l : strategicFormations.values()) { if (forceIds.containsKey(l.getForceId())) { l.writeToXML(pw, indent); } } - MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "lances"); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "strategicFormations"); } MHQXMLUtility.writeSimpleXMLTag(pw, indent, "shipSearchStart", getShipSearchStart()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "shipSearchType", shipSearchType); @@ -6627,8 +6626,8 @@ public TargetRoll getTargetForAcquisition(final IAcquisitionWork acquisition, } public @Nullable AtBContract getAttachedAtBContract(Unit unit) { - if (null != unit && null != lances.get(unit.getForceId())) { - return lances.get(unit.getForceId()).getContract(this); + if (null != unit && null != strategicFormations.get(unit.getForceId())) { + return strategicFormations.get(unit.getForceId()).getContract(this); } return null; } diff --git a/MekHQ/src/mekhq/campaign/force/Force.java b/MekHQ/src/mekhq/campaign/force/Force.java index 8008ab8914..8524b4edf3 100644 --- a/MekHQ/src/mekhq/campaign/force/Force.java +++ b/MekHQ/src/mekhq/campaign/force/Force.java @@ -68,11 +68,17 @@ public class Force { // pathway to force icon public static final int FORCE_NONE = -1; + public static final int STRATEGIC_FORMATION_OVERRIDE_NONE = -1; + public static final int STRATEGIC_FORMATION_OVERRIDE_FALSE = 0; + public static final int STRATEGIC_FORMATION_OVERRIDE_TRUE = 1; + private String name; private StandardForceIcon forceIcon; private Camouflage camouflage; private String desc; private boolean combatForce; + private boolean isStrategicFormation; + private int overrideStrategicFormation; private FormationLevel formationLevel; private FormationLevel overrideFormationLevel; private Force parentForce; @@ -94,6 +100,8 @@ public Force(String name) { setCamouflage(new Camouflage()); setDescription(""); this.combatForce = true; + this.isStrategicFormation = false; + this.overrideStrategicFormation = STRATEGIC_FORMATION_OVERRIDE_NONE; this.formationLevel = FormationLevel.NONE; this.overrideFormationLevel = FormationLevel.NONE; this.parentForce = null; @@ -163,6 +171,22 @@ public void setCombatForce(boolean combatForce, boolean setForSubForces) { } } + public boolean isStrategicFormation() { + return isStrategicFormation; + } + + public void setStrategicFormation(final boolean isStrategicFormation) { + this.isStrategicFormation = isStrategicFormation; + } + + public int getOverrideStrategicFormation() { + return overrideStrategicFormation; + } + + public void setOverrideStrategicFormation(final int overrideStrategicFormation) { + this.overrideStrategicFormation = overrideStrategicFormation; + } + public FormationLevel getFormationLevel() { return formationLevel; } @@ -232,12 +256,18 @@ public boolean isDeployed() { public List getAllParents() { List parentForces = new ArrayList<>(); - Force parentForce = getParentForce(); + Force parentFormation = parentForce; - while (parentForce.getParentForce() != null) { - parentForces.add(parentForce.getParentForce()); + if (parentForce != null) { + parentForces.add(parentForce); + } + + while (parentFormation != null) { + parentFormation = parentFormation.getParentForce(); - parentForce = parentForce.getParentForce(); + if (parentFormation != null) { + parentForces.add(parentFormation); + } } return parentForces; @@ -653,6 +683,7 @@ public void writeToXML(PrintWriter pw1, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "desc", desc); } MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "combatForce", combatForce); + MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "overrideStrategicFormation", overrideStrategicFormation); MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "formationLevel", formationLevel.toString()); MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "populateOriginNode", overrideFormationLevel.toString()); MHQXMLUtility.writeSimpleXMLTag(pw1, indent, "scenarioId", scenarioId); @@ -700,6 +731,8 @@ public void writeToXML(PrintWriter pw1, int indent) { retVal.setDescription(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("combatForce")) { retVal.setCombatForce(Boolean.parseBoolean(wn2.getTextContent().trim()), false); + } else if (wn2.getNodeName().equalsIgnoreCase("overrideStrategicFormation")) { + retVal.setOverrideStrategicFormation(Integer.parseInt(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("formationLevel")) { retVal.setFormationLevel(FormationLevel.parseFromString(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("populateOriginNode")) { diff --git a/MekHQ/src/mekhq/campaign/force/StrategicFormation.java b/MekHQ/src/mekhq/campaign/force/StrategicFormation.java index 3b2c485f47..f1825c1071 100644 --- a/MekHQ/src/mekhq/campaign/force/StrategicFormation.java +++ b/MekHQ/src/mekhq/campaign/force/StrategicFormation.java @@ -39,10 +39,13 @@ import java.io.PrintWriter; import java.time.LocalDate; -import java.util.ArrayList; import java.util.List; import java.util.UUID; +import static megamek.common.EntityWeightClass.WEIGHT_ULTRA_LIGHT; +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_NONE; +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_TRUE; + /** * Used by Against the Bot & StratCon to track additional information about each force * on the TO&E that has at least one unit assigned. Extra info includes whether @@ -206,9 +209,30 @@ public int getWeightClass(Campaign campaign) { */ double weight = calculateTotalWeight(campaign, forceId); + Force originForce = campaign.getForce(forceId); + + if (originForce == null) { + return WEIGHT_ULTRA_LIGHT; + } + + List subForces = originForce.getSubForces(); + int subForcesCount = subForces.size(); + + for (Force childForce : subForces) { + double childForceWeight = calculateTotalWeight(campaign, childForce.getId()); + + if (childForceWeight > 0) { + weight += childForceWeight; + } else { + subForcesCount--; + } + } + + weight = weight / subForcesCount; + weight = weight * 4.0 / getStdLanceSize(campaign.getFaction()); if (weight < 40) { - return EntityWeightClass.WEIGHT_ULTRA_LIGHT; + return WEIGHT_ULTRA_LIGHT; } if (weight <= 130) { return EntityWeightClass.WEIGHT_LIGHT; @@ -229,7 +253,12 @@ public boolean isEligible(Campaign campaign) { // ensure the lance is marked as a combat force final Force force = campaign.getForce(forceId); - if ((force == null) || !force.isCombatForce()) { + if (force == null) { + return false; + } + + if (!force.isCombatForce()) { + force.setStrategicFormation(false); return false; } @@ -241,12 +270,14 @@ public boolean isEligible(Campaign campaign) { int size = getSize(campaign); if (size < getStdLanceSize(campaign.getFaction()) - 1 || size > getStdLanceSize(campaign.getFaction()) + 2) { + force.setStrategicFormation(false); return false; } } if (campaign.getCampaignOptions().isLimitLanceWeight() && getWeightClass(campaign) > EntityWeightClass.WEIGHT_ASSAULT) { + force.setStrategicFormation(false); return false; } @@ -258,6 +289,7 @@ size > getStdLanceSize(campaign.getFaction()) + 2) { if (entity != null) { if (entity.getUnitType() >= UnitType.JUMPSHIP) { + force.setStrategicFormation(false); return false; } if ((entity.getEntityType() & ETYPE_GROUND) != 0) { @@ -267,19 +299,28 @@ size > getStdLanceSize(campaign.getFaction()) + 2) { } } - if (hasGround) { - ArrayList strategicFormations = campaign.getStrategicFormationList(); - List allLanceForceIds = new ArrayList<>(); + int isOverridden = force.getOverrideStrategicFormation(); + if (isOverridden != STRATEGIC_FORMATION_OVERRIDE_NONE) { + boolean overrideState = isOverridden == STRATEGIC_FORMATION_OVERRIDE_TRUE; + force.setStrategicFormation(overrideState); + + List associatedForces = force.getAllParents(); + associatedForces.addAll(force.getAllSubForces()); - for (StrategicFormation strategicFormation : strategicFormations) { - allLanceForceIds.add(strategicFormation.getForceId()); + for (Force associatedForce : associatedForces) { + associatedForce.setStrategicFormation(false); } + return overrideState; + } + + if (hasGround) { // Parent Forces List parentForces = force.getAllParents(); for (Force parentForce : parentForces) { - if (allLanceForceIds.contains(parentForce.getId())) { + if (parentForce.isStrategicFormation()) { + force.setStrategicFormation(false); return false; } } @@ -288,12 +329,15 @@ size > getStdLanceSize(campaign.getFaction()) + 2) { List childForces = force.getAllSubForces(); for (Force childForce : childForces) { - if (allLanceForceIds.contains(childForce.getId())) { + if (childForce.isStrategicFormation()) { + force.setStrategicFormation(false); return false; } } } + force.setStrategicFormation(hasGround); + return hasGround; } diff --git a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java index fdd374c545..65ae61482f 100644 --- a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java +++ b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java @@ -279,8 +279,8 @@ public Campaign parse() throws CampaignXmlParseException, NullEntityException { retVal.setUnitMarket(retVal.getCampaignOptions().getUnitMarketMethod().getUnitMarket()); retVal.getUnitMarket().fillFromXML(wn, retVal, version); foundUnitMarket = true; - } else if (xn.equalsIgnoreCase("lances")) { - processLanceNodes(retVal, wn); + } else if (xn.equalsIgnoreCase("lances") || xn.equalsIgnoreCase("strategicFormations")) { + processStrategicFormationNodes(retVal, wn); } else if (xn.equalsIgnoreCase("retirementDefectionTracker")) { retVal.setRetirementDefectionTracker( RetirementDefectionTracker.generateInstanceFromXML(wn, retVal)); @@ -759,29 +759,30 @@ private static void processInfoNode(Campaign retVal, Node wni, Version version) retVal.setNewReports(newReports); } - private static void processLanceNodes(Campaign retVal, Node wn) { - NodeList wList = wn.getChildNodes(); + private static void processStrategicFormationNodes(Campaign campaign, Node workingNode) { + NodeList workingNodes = workingNode.getChildNodes(); - // Okay, lets iterate through the children, eh? - for (int x = 0; x < wList.getLength(); x++) { - Node wn2 = wList.item(x); + // Okay, let's iterate through the children, eh? + for (int x = 0; x < workingNodes.getLength(); x++) { + Node wn2 = workingNodes.item(x); // If it's not an element node, we ignore it. if (wn2.getNodeType() != Node.ELEMENT_NODE) { continue; } - if (!wn2.getNodeName().equalsIgnoreCase("lance")) { + if (!wn2.getNodeName().equalsIgnoreCase("lance") + && !wn2.getNodeName().equalsIgnoreCase("strategicFormations")) { // Error condition of sorts! // Errr, what should we do here? - logger.error("Unknown node type not loaded in Lance nodes: " + wn2.getNodeName()); + logger.error("Unknown node type not loaded in strategicFormations nodes: " + wn2.getNodeName()); continue; } - StrategicFormation l = StrategicFormation.generateInstanceFromXML(wn2); + StrategicFormation strategicFormation = StrategicFormation.generateInstanceFromXML(wn2); - if (l != null) { - retVal.importLance(l); + if (strategicFormation != null) { + campaign.importLance(strategicFormation); } } } diff --git a/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java b/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java index 7d63ffb606..2d2393b148 100644 --- a/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java +++ b/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java @@ -1427,48 +1427,52 @@ public static List getAvailableForceIDs(Campaign campaign) { /** * This is a list of all force IDs for forces that can be deployed to a scenario - * in the given force - * template a) have not been assigned to a track b) are combat-capable c) are - * not deployed to a - * scenario d) if attempting to deploy as reinforcements, haven't already failed + * in the given force template a) have not been assigned to a track b) are combat-capable c) are + * not deployed to a scenario d) if attempting to deploy as reinforcements, haven't already failed * to deploy */ public static List getAvailableForceIDs(int unitType, Campaign campaign, StratconTrackState currentTrack, boolean reinforcements, @Nullable StratconScenario currentScenario, StratconCampaignState campaignState) { List retVal = new ArrayList<>(); - // assemble a set of all force IDs that are currently assigned to tracks that - // are not this one + // assemble a set of all force IDs that are currently assigned to tracks that are not this one Set forcesInTracks = campaign.getActiveAtBContracts().stream() .flatMap(contract -> contract.getStratconCampaignState().getTracks().stream()) .filter(track -> (track != currentTrack) || !reinforcements) .flatMap(track -> track.getAssignedForceCoords().keySet().stream()) .collect(Collectors.toSet()); - // if there's an existing scenario and we're doing reinforcements, + // if there's an existing scenario, and we're doing reinforcements, // prevent forces that failed to deploy from trying to deploy again if (reinforcements && (currentScenario != null)) { forcesInTracks.addAll(currentScenario.getFailedReinforcements()); } - for (int key : campaign.getStrategicFormations().keySet()) { - Force force = campaign.getForce(key); + for (StrategicFormation formation : campaign.getStrategicFormations().values()) { + if (!formation.isEligible(campaign)) { + continue; + } + + Force force = campaign.getForce(formation.getForceId()); if (force == null) { continue; } + logger.info(force.getName()); + int primaryUnitType = force.getPrimaryUnitType(campaign); boolean noReinforcementRestriction = !reinforcements || (reinforcements && (getReinforcementType(force.getId(), currentTrack, campaign, campaignState) != ReinforcementEligibilityType.None)); - if ((force.getScenarioId() <= 0) && !force.getUnits().isEmpty() + if ((force.getScenarioId() <= 0) && !force.getAllUnits(true).isEmpty() && !forcesInTracks.contains(force.getId()) && forceCompositionMatchesDeclaredUnitType(primaryUnitType, unitType, reinforcements) && noReinforcementRestriction && !subElementsOrSelfDeployed(force, campaign)) { retVal.add(force.getId()); } + retVal.add(force.getId()); } return retVal; diff --git a/MekHQ/src/mekhq/gui/ForceRenderer.java b/MekHQ/src/mekhq/gui/ForceRenderer.java index 236d718440..4e0e86ba07 100644 --- a/MekHQ/src/mekhq/gui/ForceRenderer.java +++ b/MekHQ/src/mekhq/gui/ForceRenderer.java @@ -18,13 +18,6 @@ */ package mekhq.gui; -import java.awt.Component; - -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JTree; -import javax.swing.tree.DefaultTreeCellRenderer; - import megamek.client.ui.Messages; import megamek.common.Entity; import megamek.common.GunEmplacement; @@ -35,6 +28,10 @@ import mekhq.campaign.unit.Unit; import mekhq.utilities.ReportingUtilities; +import javax.swing.*; +import javax.swing.tree.DefaultTreeCellRenderer; +import java.awt.*; + public class ForceRenderer extends DefaultTreeCellRenderer { private static final MMLogger logger = MMLogger.create(ForceRenderer.class); @@ -51,7 +48,7 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); setOpaque(false); - if (value instanceof Unit) { + if (value instanceof Unit unit) { String name = ReportingUtilities.messageSurroundedBySpanWithColor( MekHQ.getMHQOptions().getFontColorNegativeHexColor(), "No Crew"); if (((Unit) value).getEntity() instanceof GunEmplacement) { @@ -59,7 +56,6 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean } String c3network = ""; StringBuilder transport = new StringBuilder(); - Unit unit = (Unit) value; Person person = unit.getCommander(); if (person != null) { name = person.getFullTitle(); @@ -142,8 +138,7 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean setBackground(MekHQ.getMHQOptions().getDeployedBackground()); setOpaque(true); } - } else if (value instanceof Force) { - Force force = (Force) value; + } else if (value instanceof Force force) { getAccessibleContext().setAccessibleName(( force.isDeployed() ? "Deployed Force: " : "Force: ") + force.getFullName()); if (!sel && force.isDeployed()) { @@ -151,6 +146,10 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean setBackground(MekHQ.getMHQOptions().getDeployedBackground()); setOpaque(true); } + + if (force.isStrategicFormation()) { + setText("" + force.getName() + ""); + } } else { logger.error("Attempted to render node with unknown node class of " + ((value != null) ? value.getClass() : "null")); diff --git a/MekHQ/src/mekhq/gui/adapter/TOEMouseAdapter.java b/MekHQ/src/mekhq/gui/adapter/TOEMouseAdapter.java index fae28bb097..3a55420aed 100644 --- a/MekHQ/src/mekhq/gui/adapter/TOEMouseAdapter.java +++ b/MekHQ/src/mekhq/gui/adapter/TOEMouseAdapter.java @@ -18,24 +18,6 @@ */ package mekhq.gui.adapter; -import java.awt.event.ActionEvent; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.StringJoiner; -import java.util.StringTokenizer; -import java.util.UUID; -import java.util.Vector; - -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPopupMenu; -import javax.swing.JTree; -import javax.swing.tree.TreePath; - import megamek.client.ui.dialogs.CamoChooserDialog; import megamek.common.EntityWeightClass; import megamek.common.GunEmplacement; @@ -68,6 +50,15 @@ import mekhq.gui.utilities.JMenuHelpers; import mekhq.gui.utilities.StaticChecks; +import javax.swing.*; +import javax.swing.tree.TreePath; +import java.awt.event.ActionEvent; +import java.util.*; + +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_FALSE; +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_NONE; +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_TRUE; + public class TOEMouseAdapter extends JPopupMenuAdapter { private static final MMLogger logger = MMLogger.create(TOEMouseAdapter.class); @@ -136,6 +127,8 @@ public static void connect(CampaignGUI gui, JTree tree) { private static final String CHANGE_NAME = "CHANGE_NAME"; private static final String CHANGE_COMBAT_STATUS = "CHANGE_COMBAT_STATUS"; private static final String CHANGE_COMBAT_STATUSES = "CHANGE_COMBAT_STATUSES"; + private static final String CHANGE_STRATEGIC_FORCE_OVERRIDE = "CHANGE_STRATEGIC_FORCE_OVERRIDE"; + private static final String REMOVE_STRATEGIC_FORCE_OVERRIDE = "REMOVE_STRATEGIC_FORCE_OVERRIDE"; private static final String COMMAND_CHANGE_FORCE_CAMO = "CHANGE_CAMO|FORCE|empty|"; private static final String COMMAND_CHANGE_FORCE_DESC = "CHANGE_DESC|FORCE|empty|"; @@ -146,6 +139,8 @@ public static void connect(CampaignGUI gui, JTree tree) { private static final String COMMAND_CHANGE_FORCE_NAME = "CHANGE_NAME|FORCE|empty|"; private static final String COMMAND_CHANGE_FORCE_COMBAT_STATUS = "CHANGE_COMBAT_STATUS|FORCE|empty|"; private static final String COMMAND_CHANGE_FORCE_COMBAT_STATUSES = "CHANGE_COMBAT_STATUSES|FORCE|empty|"; + private static final String COMMAND_CHANGE_STRATEGIC_FORCE_OVERRIDE = "CHANGE_STRATEGIC_FORCE_OVERRIDE|FORCE|empty|"; + private static final String COMMAND_REMOVE_STRATEGIC_FORCE_OVERRIDE = "REMOVE_STRATEGIC_FORCE_OVERRIDE|FORCE|empty|"; private static final String COMMAND_OVERRIDE_FORCE_FORMATION_LEVEL = "OVERRIDE_FORMATION_LEVEL|FORCE|FORMATION_LEVEL|"; @@ -443,6 +438,28 @@ public void actionPerformed(ActionEvent action) { } gui.undeployForces(forces); gui.getTOETab().refreshForceView(); + } else if (command.contains(CHANGE_STRATEGIC_FORCE_OVERRIDE)) { + if (singleForce == null) { + return; + } + + boolean overrideState = singleForce.getOverrideStrategicFormation() == STRATEGIC_FORMATION_OVERRIDE_TRUE; + singleForce.setStrategicFormation(!overrideState); + singleForce.setOverrideStrategicFormation(!overrideState ? STRATEGIC_FORMATION_OVERRIDE_TRUE : STRATEGIC_FORMATION_OVERRIDE_FALSE); + + for (Force formation : gui.getCampaign().getAllForces()) { + MekHQ.triggerEvent(new OrganizationChangedEvent(formation)); + } + } else if (command.contains(REMOVE_STRATEGIC_FORCE_OVERRIDE)) { + if (singleForce == null) { + return; + } + + singleForce.setOverrideStrategicFormation(STRATEGIC_FORMATION_OVERRIDE_NONE); + + for (Force formation : gui.getCampaign().getAllForces()) { + MekHQ.triggerEvent(new OrganizationChangedEvent(formation)); + } } else if (command.contains(TOEMouseAdapter.REMOVE_FORCE)) { for (Force force : forces) { if (null != force && null != force.getParentForce()) { @@ -1031,6 +1048,18 @@ protected Optional createPopupMenu() { menuItem.addActionListener(this); popup.add(menuItem); + JMenuItem optionStrategicForceOverride = new JMenuItem(force.isStrategicFormation() ? + "Remove Strategic Formation Assignment" : "Assign as Strategic Formation"); + optionStrategicForceOverride.setActionCommand(COMMAND_CHANGE_STRATEGIC_FORCE_OVERRIDE + forceIds); + optionStrategicForceOverride.addActionListener(this); + popup.add(optionStrategicForceOverride); + + JMenuItem optionRemoveStrategicForceOverride = new JMenuItem("Remove Strategic Force Override"); + optionRemoveStrategicForceOverride.setActionCommand(COMMAND_REMOVE_STRATEGIC_FORCE_OVERRIDE + forceIds); + optionRemoveStrategicForceOverride.addActionListener(this); + optionRemoveStrategicForceOverride.setVisible(force.getOverrideStrategicFormation() != STRATEGIC_FORMATION_OVERRIDE_NONE); + popup.add(optionRemoveStrategicForceOverride); + if (StaticChecks.areAllForcesUndeployed(gui.getCampaign(), forces) && StaticChecks.areAllCombatForces(forces)) { menu = new JMenu("Deploy Force"); diff --git a/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java b/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java index 42b94a2299..32f05ff63c 100644 --- a/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java +++ b/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java @@ -387,7 +387,7 @@ class LanceAssignmentTableModel extends DataTableModel { public LanceAssignmentTableModel(Campaign campaign) { this.campaign = campaign; data = new ArrayList<>(); - columnNames = new String[]{"Force", "Wt", "Mission", "Role"}; + columnNames = new String[]{"Force", "Weight Class", "Mission", "Role"}; } @Override @@ -429,7 +429,7 @@ public StrategicFormation getRow(int row) { @Override public Object getValueAt(int row, int column) { - final String[] WEIGHT_CODES = {"UL", "L", "M", "H", "A", "SH"}; + final String[] WEIGHT_CODES = {"Ultra-Light", "Light", "Medium", "Heavy", "Assault", "Super Heavy"}; if (row >= getRowCount()) { return "";