diff --git a/MekHQ/src/mekhq/AtBGameThread.java b/MekHQ/src/mekhq/AtBGameThread.java index b9a6d0ed79..a7e6103dec 100644 --- a/MekHQ/src/mekhq/AtBGameThread.java +++ b/MekHQ/src/mekhq/AtBGameThread.java @@ -32,7 +32,7 @@ import megamek.common.planetaryconditions.PlanetaryConditions; import megamek.logging.MMLogger; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.*; import mekhq.campaign.personnel.Person; import mekhq.campaign.unit.Unit; @@ -266,8 +266,8 @@ public void run() { // Set scenario type-specific delay deploymentRound = Math.max(entity.getDeployRound(), scenario.getDeploymentDelay() - speed); // Lances deployed in scout roles always deploy units in 6-walking speed turns - if (scenario.getLanceRole().isScouting() && (scenario.getLance(campaign) != null) - && (scenario.getLance(campaign).getForceId() == scenario.getLanceForceId()) + if (scenario.getLanceRole().isScouting() && (scenario.getStrategicFormation(campaign) != null) + && (scenario.getStrategicFormation(campaign).getForceId() == scenario.getStrategicFormationId()) && !useDropship) { deploymentRound = Math.max(deploymentRound, 6 - speed); } @@ -335,7 +335,7 @@ public void run() { } deploymentRound = Math.max(entity.getDeployRound(), scenario.getDeploymentDelay() - speed); if (!useDropship && scenario.getLanceRole().isScouting() - && (scenario.getLance(campaign).getForceId() == scenario.getLanceForceId())) { + && (scenario.getStrategicFormation(campaign).getForceId() == scenario.getStrategicFormationId())) { deploymentRound = Math.max(deploymentRound, 6 - speed); } } @@ -602,12 +602,12 @@ protected List setupBotEntities(BotClient botClient, BotForce botForce, int lanceSize; if (botForce.getTeam() == 2) { - lanceSize = Lance.getStdLanceSize(contract.getEnemy()); + lanceSize = StrategicFormation.getStdLanceSize(contract.getEnemy()); } else { - lanceSize = Lance.getStdLanceSize(contract.getEmployerFaction()); + lanceSize = StrategicFormation.getStdLanceSize(contract.getEmployerFaction()); } - Comparator comp = Comparator.comparing(((Entity e) -> e.getEntityMajorTypeName(e.getEntityType()))); + Comparator comp = Comparator.comparing(((Entity e) -> Entity.getEntityMajorTypeName(e.getEntityType()))); comp = comp.thenComparing(((Entity e) -> e.getRunMP()), Comparator.reverseOrder()); comp = comp.thenComparing(((Entity e) -> e.getRole().toString())); entitiesSorted.sort(comp); @@ -618,13 +618,13 @@ protected List setupBotEntities(BotClient botClient, BotForce botForce, } if ((i != 0) - && !lastType.equals(entity.getEntityMajorTypeName(entity.getEntityType()))) { + && !lastType.equals(Entity.getEntityMajorTypeName(entity.getEntityType()))) { forceIdLance++; lanceName = RCG.generate(); i = forceIdLance * lanceSize; } - lastType = entity.getEntityMajorTypeName(entity.getEntityType()); + lastType = Entity.getEntityMajorTypeName(entity.getEntityType()); entity.setOwner(botClient.getLocalPlayer()); String fName = String.format(forceName, lanceName, forceIdLance); entity.setForceString(fName); diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index 58eb15e5ee..89310fffbc 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -53,7 +53,7 @@ import mekhq.campaign.finances.*; import mekhq.campaign.finances.enums.TransactionType; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.icons.StandardForceIcon; import mekhq.campaign.icons.UnitIcon; import mekhq.campaign.log.HistoricalLogEntry; @@ -201,7 +201,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; @@ -314,7 +314,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; @@ -454,16 +454,16 @@ public List getAllForces() { return new ArrayList<>(forceIds.values()); } - public void importLance(Lance l) { - lances.put(l.getForceId(), l); + public void importLance(StrategicFormation l) { + strategicFormations.put(l.getForceId(), l); } - public Hashtable getLances() { - return lances; + public Hashtable getStrategicFormations() { + return strategicFormations; } - public ArrayList getLanceList() { - return lances.values().stream() + public ArrayList getStrategicFormationList() { + return strategicFormations.values().stream() .filter(l -> forceIds.containsKey(l.getForceId())) .collect(Collectors.toCollection(ArrayList::new)); } @@ -910,8 +910,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 Lance(force.getId(), this)); + if (null == strategicFormations.get(id)) { + strategicFormations.put(id, new StrategicFormation(force.getId(), this)); } } @@ -1009,11 +1009,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 Lance(force.getId(), this)); + if ((null == strategicFormations.get(id)) && (null != force)) { + strategicFormations.put(id, new StrategicFormation(force.getId(), this)); } } } @@ -1021,10 +1021,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 Lance(force.getId(), this)); + if (force.isStrategicFormation()) { + strategicFormations.put(force.getId(), new StrategicFormation(force.getId(), this)); } for (Force f : force.getSubForces()) { addAllLances(f); @@ -3634,7 +3633,7 @@ public int getDeploymentDeficit(AtBContract contract) { int role = -Math.max(1, contract.getRequiredLances() / 2); final AtBLanceRole requiredLanceRole = contract.getContractType().getRequiredLanceRole(); - for (Lance l : lances.values()) { + for (StrategicFormation l : strategicFormations.values()) { if (!l.getRole().isUnassigned() && (l.getMissionId() == contract.getId())) { total++; if (l.getRole() == requiredLanceRole) { @@ -3733,8 +3732,8 @@ && getLocation().getJumpPath().getLastSystem().getId().equals(contract.getSystem // If there is a standard battle set for today, deploy the lance. for (final AtBScenario s : contract.getCurrentAtBScenarios()) { if ((s.getDate() != null) && s.getDate().equals(getLocalDate())) { - int forceId = s.getLanceForceId(); - if ((lances.get(forceId) != null) && !forceIds.get(forceId).isDeployed()) { + int forceId = s.getStrategicFormationId(); + 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; @@ -3792,11 +3791,11 @@ private void processNewDayATB() { if (getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY) { processShipSearch(); - // Training Experience - Award to eligible training lances on active contracts - getLances().values().stream() - .filter(lance -> lance.getRole().isTraining() - && (lance.getContract(this) != null) && lance.isEligible(this) - && lance.getContract(this).isActiveOn(getLocalDate(), true)) + // Training Experience - Award to eligible training Strategic Formations on active contracts + getStrategicFormations().values().stream() + .filter(strategicFormation -> strategicFormation.getRole().isTraining() + && (strategicFormation.getContract(this) != null) && strategicFormation.isEligible(this) + && strategicFormation.getContract(this).isActiveOn(getLocalDate(), true)) .forEach(this::awardTrainingXP); } @@ -4872,9 +4871,9 @@ public void removePerson(final @Nullable Person person, final boolean log) { * commanding officer and * the minimum experience level of the unit's members. * - * @param l The {@link Lance} to calculate XP to award for training. + * @param l The {@link StrategicFormation} to calculate XP to award for training. */ - private void awardTrainingXP(final Lance l) { + private void awardTrainingXP(final StrategicFormation l) { for (UUID trainerId : forceIds.get(l.getForceId()).getAllUnits(true)) { Unit trainerUnit = getHangar().getUnit(trainerId); @@ -4998,7 +4997,7 @@ public void removeForce(Force force) { } if (campaignOptions.isUseAtB()) { - lances.remove(fid); + strategicFormations.remove(fid); } if (null != force.getParentForce()) { @@ -5051,7 +5050,7 @@ public void removeUnitFromForce(Unit u) { } if (campaignOptions.isUseAtB() && force.getUnits().isEmpty()) { - lances.remove(force.getId()); + strategicFormations.remove(force.getId()); } } } @@ -5626,14 +5625,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 (Lance 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); @@ -6659,8 +6658,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 ce602f978f..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; } @@ -221,6 +245,34 @@ public boolean isDeployed() { return parentForce; } + /** + * This method generates a list of all parent forces for the current force object in the + * hierarchy. It repeatedly fetches the parent force of the current force and adds it to a list + * until no more parent forces can be found (i.e., until the top of the force hierarchy is reached). + * + * @return A list of {@link Force} objects representing all the parent forces of the current + * force object in the hierarchy. The list will be empty if there are no parent forces. + */ + public List getAllParents() { + List parentForces = new ArrayList<>(); + + Force parentFormation = parentForce; + + if (parentForce != null) { + parentForces.add(parentForce); + } + + while (parentFormation != null) { + parentFormation = parentFormation.getParentForce(); + + if (parentFormation != null) { + parentForces.add(parentFormation); + } + } + + return parentForces; + } + public void setParentForce(final @Nullable Force parent) { this.parentForce = parent; } @@ -229,6 +281,29 @@ public Vector getSubForces() { return subForces; } + /** + * Returns a list of all of this forces' descendant forces. + * This includes direct child forces and their descendents recursively. + *

+ * This method works by first adding all direct child forces to the list, and + * then recursively adding their descendants by calling this method on each child + * force. + * + * @return A list of {@link Force} objects representing all descendant forces. + * If there are no descendant forces, this method will return an empty list. + */ + public List getAllSubForces() { + List allSubForces = new ArrayList<>(); + + for (Force subForce : subForces) { + allSubForces.add(subForce); + + allSubForces.addAll(subForce.getAllSubForces()); + } + + return allSubForces; + } + public boolean isAncestorOf(Force otherForce) { Force pForce = otherForce.getParentForce(); while (pForce != null) { @@ -608,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); @@ -655,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/Lance.java b/MekHQ/src/mekhq/campaign/force/StrategicFormation.java similarity index 56% rename from MekHQ/src/mekhq/campaign/force/Lance.java rename to MekHQ/src/mekhq/campaign/force/StrategicFormation.java index c22758c257..8efcd7df7c 100644 --- a/MekHQ/src/mekhq/campaign/force/Lance.java +++ b/MekHQ/src/mekhq/campaign/force/StrategicFormation.java @@ -39,19 +39,23 @@ import java.io.PrintWriter; import java.time.LocalDate; +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 to track additional information about each force - * on the TO&E that has at least one unit assigned. Extra info includes - * whether - * the force counts as a lance (or star or level II) eligible for assignment - * to a mission role and what the assignment is on which contract. + * 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 + * the force counts as a Strategic Formation eligible for assignment to a scenario role + * and what the assignment is on which contract. * * @author Neoancient */ -public class Lance { - private static final MMLogger logger = MMLogger.create(Lance.class); +public class StrategicFormation { + private static final MMLogger logger = MMLogger.create(StrategicFormation.class); public static final int STR_IS = 4; public static final int STR_CLAN = 5; @@ -68,29 +72,39 @@ public class Lance { private AtBLanceRole role; private UUID commanderId; - public static int getStdLanceSize(Faction f) { - if (f.isClan()) { + /** + * Determines the standard size for a given faction. The size varies depending on whether the + * faction is a Clan, ComStar/WoB, or others (Inner Sphere). + * + * @param faction The {@link Faction} object for which the standard force size is to be calculated. + * @return The standard force size for the given faction. It returns {@code STR_CLAN} if the + * faction is a Clan, {@code STR_CS} if the faction is ComStar or WoB, and {@code STR_IS} otherwise. + */ + public static int getStdLanceSize(Faction faction) { + if (faction.isClan()) { return STR_CLAN; - } else if (f.getShortName().equals("CS") || f.getShortName().equals("WOB")) { + } else if (faction.isComStarOrWoB()) { return STR_CS; } else { return STR_IS; } } - public Lance() { - } + /** + * Default constructor + */ + public StrategicFormation() {} - public Lance(int fid, Campaign c) { - forceId = fid; + public StrategicFormation(int forceId, Campaign campaign) { + this.forceId = forceId; role = AtBLanceRole.UNASSIGNED; missionId = -1; - for (AtBContract contract : c.getActiveAtBContracts()) { + for (AtBContract contract : campaign.getActiveAtBContracts()) { missionId = ((contract.getParentContract() == null) ? contract : contract.getParentContract()).getId(); } - commanderId = findCommander(forceId, c); + commanderId = findCommander(this.forceId, campaign); } public int getForceId() { @@ -101,15 +115,15 @@ public int getMissionId() { return missionId; } - public AtBContract getContract(Campaign c) { - return (AtBContract) c.getMission(missionId); + public AtBContract getContract(Campaign campaign) { + return (AtBContract) campaign.getMission(missionId); } - public void setContract(AtBContract c) { - if (null == c) { + public void setContract(AtBContract atBContract) { + if (null == atBContract) { missionId = NO_MISSION; } else { - missionId = c.getId(); + missionId = atBContract.getId(); } } @@ -125,8 +139,8 @@ public UUID getCommanderId() { return commanderId; } - public Person getCommander(Campaign c) { - return c.getPerson(commanderId); + public Person getCommander(Campaign campaign) { + return campaign.getPerson(commanderId); } public void setCommander(UUID id) { @@ -137,22 +151,22 @@ public void setCommander(Person p) { commanderId = p.getId(); } - public void refreshCommander(Campaign c) { - commanderId = findCommander(forceId, c); + public void refreshCommander(Campaign campaign) { + commanderId = findCommander(forceId, campaign); } - public int getSize(Campaign c) { - if (c.getFaction().isClan()) { - return (int) Math.ceil(getEffectivePoints(c)); + public int getSize(Campaign campaign) { + if (campaign.getFaction().isClan()) { + return (int) Math.ceil(getEffectivePoints(campaign)); } - if (c.getForce(forceId) != null) { - return c.getForce(forceId).getUnits().size(); + if (campaign.getForce(forceId) != null) { + return campaign.getForce(forceId).getUnits().size(); } else { return 0; } } - public double getEffectivePoints(Campaign c) { + public double getEffectivePoints(Campaign campaign) { /* * Used to check against force size limits; for this purpose we * consider a 'Mek and a Point of BA to be a single Point so that @@ -163,8 +177,8 @@ public double getEffectivePoints(Campaign c) { double armor = 0.0; double infantry = 0.0; double other = 0.0; - for (UUID id : c.getForce(forceId).getUnits()) { - Unit unit = c.getUnit(id); + for (UUID id : campaign.getForce(forceId).getUnits()) { + Unit unit = campaign.getUnit(id); if (null != unit) { Entity entity = unit.getEntity(); if (null != entity) { @@ -185,7 +199,7 @@ public double getEffectivePoints(Campaign c) { return Math.max(armor, infantry) + other; } - public int getWeightClass(Campaign c) { + public int getWeightClass(Campaign campaign) { /* * Clan units only count half the weight of ASF and vehicles * (2/Point). IS units only count half the weight of vehicles @@ -193,11 +207,32 @@ public int getWeightClass(Campaign c) { * weight class and decreasing the enemy force against vehicle/combined * lances. */ - double weight = calculateTotalWeight(c, forceId); + 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()); - weight = weight * 4.0 / getStdLanceSize(c.getFaction()); + 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; @@ -214,10 +249,16 @@ public int getWeightClass(Campaign c) { return EntityWeightClass.WEIGHT_SUPER_HEAVY; } - public boolean isEligible(Campaign c) { + public boolean isEligible(Campaign campaign) { // ensure the lance is marked as a combat force - final Force force = c.getForce(forceId); - if ((force == null) || !force.isCombatForce()) { + final Force force = campaign.getForce(forceId); + + if (force == null) { + return false; + } + + if (!force.isCombatForce()) { + force.setStrategicFormation(false); return false; } @@ -225,26 +266,30 @@ public boolean isEligible(Campaign c) { * Check that the number of units and weight are within the limits * and that the force contains at least one ground unit. */ - if (c.getCampaignOptions().isLimitLanceNumUnits()) { - int size = getSize(c); - if (size < getStdLanceSize(c.getFaction()) - 1 || - size > getStdLanceSize(c.getFaction()) + 2) { + if (campaign.getCampaignOptions().isLimitLanceNumUnits()) { + int size = getSize(campaign); + if (size < getStdLanceSize(campaign.getFaction()) - 1 || + size > getStdLanceSize(campaign.getFaction()) + 2) { + force.setStrategicFormation(false); return false; } } - if (c.getCampaignOptions().isLimitLanceWeight() && - getWeightClass(c) > EntityWeightClass.WEIGHT_ASSAULT) { + if (campaign.getCampaignOptions().isLimitLanceWeight() && + getWeightClass(campaign) > EntityWeightClass.WEIGHT_ASSAULT) { + force.setStrategicFormation(false); return false; } boolean hasGround = false; for (UUID id : force.getUnits()) { - Unit unit = c.getUnit(id); - if (null != unit) { + Unit unit = campaign.getUnit(id); + if (unit != null) { Entity entity = unit.getEntity(); - if (null != entity) { + + if (entity != null) { if (entity.getUnitType() >= UnitType.JUMPSHIP) { + force.setStrategicFormation(false); return false; } if ((entity.getEntityType() & ETYPE_GROUND) != 0) { @@ -254,37 +299,65 @@ size > getStdLanceSize(c.getFaction()) + 2) { } } + 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 (Force associatedForce : associatedForces) { + associatedForce.setStrategicFormation(false); + } + + return overrideState; + } + + if (hasGround) { + List childForces = force.getAllSubForces(); + + for (Force childForce : childForces) { + if (childForce.isStrategicFormation()) { + force.setStrategicFormation(false); + return false; + } + } + } + + force.setStrategicFormation(hasGround); + return hasGround; } /* Code to find unit commander from ForceViewPanel */ - public static UUID findCommander(int forceId, Campaign c) { - return c.getForce(forceId).getForceCommanderID(); + public static UUID findCommander(int forceId, Campaign campaign) { + return campaign.getForce(forceId).getForceCommanderID(); } public static LocalDate getBattleDate(LocalDate today) { return today.plusDays(Compute.randomInt(7)); } - public AtBScenario checkForBattle(Campaign c) { + public AtBScenario checkForBattle(Campaign campaign) { // Make sure there is a battle first - if ((c.getCampaignOptions().getAtBBattleChance(role) == 0) - || (Compute.randomInt(100) > c.getCampaignOptions().getAtBBattleChance(role))) { + if ((campaign.getCampaignOptions().getAtBBattleChance(role) == 0) + || (Compute.randomInt(100) > campaign.getCampaignOptions().getAtBBattleChance(role))) { // No battle return null; } // if we are using StratCon, don't *also* generate legacy scenarios - if (c.getCampaignOptions().isUseStratCon() && - (getContract(c).getStratconCampaignState() != null)) { + if (campaign.getCampaignOptions().isUseStratCon() && + (getContract(campaign).getStratconCampaignState() != null)) { return null; } int roll; // thresholds are coded from charts with 1-100 range, so we add 1 to mod to // adjust 0-based random int - int battleTypeMod = 1 + (AtBMoraleLevel.STALEMATE.ordinal() - getContract(c).getMoraleLevel().ordinal()) * 5; - battleTypeMod += getContract(c).getBattleTypeMod(); + int battleTypeMod = 1 + (AtBMoraleLevel.STALEMATE.ordinal() - getContract(campaign).getMoraleLevel().ordinal()) * 5; + battleTypeMod += getContract(campaign).getBattleTypeMod(); // debugging code that will allow you to force the generation of a particular // scenario. @@ -294,8 +367,8 @@ public AtBScenario checkForBattle(Campaign c) { /* * if (true) { - * AtBScenario scenario = AtBScenarioFactory.createScenario(c, this, - * AtBScenario.BASEATTACK, true, getBattleDate(c.getLocalDate())); + * AtBScenario scenario = AtBScenarioFactory.createScenario(campaign, this, + * AtBScenario.BASEATTACK, true, getBattleDate(campaign.getLocalDate())); * scenario.setMissionId(this.getMissionId()); * return scenario; * } @@ -305,144 +378,144 @@ public AtBScenario checkForBattle(Campaign c) { case FIGHTING: { roll = Compute.randomInt(40) + battleTypeMod; if (roll < 1) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BASEATTACK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 9) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BREAKTHROUGH, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 17) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.STANDUP, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 25) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.STANDUP, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 33) { - if (c.getCampaignOptions().isGenerateChases()) { - return AtBScenarioFactory.createScenario(c, this, + if (campaign.getCampaignOptions().isGenerateChases()) { + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.CHASE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HOLDTHELINE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } else if (roll < 41) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HOLDTHELINE, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BASEATTACK, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } case SCOUTING: { roll = Compute.randomInt(60) + battleTypeMod; if (roll < 1) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BASEATTACK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 11) { - if (c.getCampaignOptions().isGenerateChases()) { - return AtBScenarioFactory.createScenario(c, this, + if (campaign.getCampaignOptions().isGenerateChases()) { + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.CHASE, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HIDEANDSEEK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } else if (roll < 21) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HIDEANDSEEK, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 31) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.PROBE, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 41) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.PROBE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 51) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.EXTRACTION, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.RECONRAID, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } case DEFENCE: { roll = Compute.randomInt(20) + battleTypeMod; if (roll < 1) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BASEATTACK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 5) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HOLDTHELINE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 9) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.RECONRAID, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 13) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.EXTRACTION, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 17) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HIDEANDSEEK, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BREAKTHROUGH, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } case TRAINING: { roll = Compute.randomInt(10) + battleTypeMod; if (roll < 1) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BASEATTACK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 3) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HOLDTHELINE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 5) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BREAKTHROUGH, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else if (roll < 7) { - if (c.getCampaignOptions().isGenerateChases()) { - return AtBScenarioFactory.createScenario(c, this, + if (campaign.getCampaignOptions().isGenerateChases()) { + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.CHASE, true, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.BREAKTHROUGH, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } else if (roll < 9) { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HIDEANDSEEK, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - if (c.getCampaignOptions().isGenerateChases()) { - return AtBScenarioFactory.createScenario(c, this, + if (campaign.getCampaignOptions().isGenerateChases()) { + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.CHASE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } else { - return AtBScenarioFactory.createScenario(c, this, + return AtBScenarioFactory.createScenario(campaign, this, AtBScenario.HOLDTHELINE, false, - getBattleDate(c.getLocalDate())); + getBattleDate(campaign.getLocalDate())); } } } @@ -461,13 +534,13 @@ public void writeToXML(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "lance"); } - public static Lance generateInstanceFromXML(Node wn) { - Lance retVal = null; + public static StrategicFormation generateInstanceFromXML(Node wn) { + StrategicFormation retVal = null; NamedNodeMap attrs = wn.getAttributes(); Node classNameNode = attrs.getNamedItem("type"); String className = classNameNode.getTextContent(); try { - retVal = (Lance) Class.forName(className).newInstance(); + retVal = (StrategicFormation) Class.forName(className).newInstance(); NodeList nl = wn.getChildNodes(); for (int x = 0; x < nl.getLength(); x++) { @@ -492,15 +565,15 @@ public static Lance generateInstanceFromXML(Node wn) { /** * Worker function that calculates the total weight of a force with the given ID * - * @param c Campaign in which the force resides + * @param campaign Campaign in which the force resides * @param forceId Force for which to calculate weight * @return Total force weight */ - public static double calculateTotalWeight(Campaign c, int forceId) { + public static double calculateTotalWeight(Campaign campaign, int forceId) { double weight = 0.0; - for (UUID id : c.getForce(forceId).getUnits()) { - Unit unit = c.getUnit(id); + for (UUID id : campaign.getForce(forceId).getUnits()) { + Unit unit = campaign.getUnit(id); if (null != unit) { Entity entity = unit.getEntity(); if (null != entity) { @@ -509,13 +582,13 @@ public static double calculateTotalWeight(Campaign c, int forceId) { (entity.getEntityType() & Entity.ETYPE_INFANTRY) != 0) { weight += entity.getWeight(); } else if ((entity.getEntityType() & Entity.ETYPE_TANK) != 0) { - if (c.getFaction().isClan() || c.getCampaignOptions().isAdjustPlayerVehicles()) { + if (campaign.getFaction().isClan() || campaign.getCampaignOptions().isAdjustPlayerVehicles()) { weight += entity.getWeight() * 0.5; } else { weight += entity.getWeight(); } } else if ((entity.getEntityType() & Entity.ETYPE_AEROSPACEFIGHTER) != 0) { - if (c.getFaction().isClan()) { + if (campaign.getFaction().isClan()) { weight += entity.getWeight() * 0.5; } else { weight += entity.getWeight(); diff --git a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java index bad449ed3a..add1059288 100644 --- a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java +++ b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java @@ -36,7 +36,7 @@ import mekhq.campaign.againstTheBot.AtBConfiguration; import mekhq.campaign.finances.Finances; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.icons.UnitIcon; import mekhq.campaign.market.PersonnelMarket; import mekhq.campaign.market.ShoppingList; @@ -283,8 +283,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)); @@ -354,10 +354,10 @@ public Campaign parse() throws CampaignXmlParseException, NullEntityException { // determine if we've missed any lances and add those back into the campaign if (options.isUseAtB()) { - Hashtable lances = retVal.getLances(); + Hashtable lances = retVal.getStrategicFormations(); for (Force f : retVal.getAllForces()) { if (!f.getUnits().isEmpty() && (null == lances.get(f.getId()))) { - lances.put(f.getId(), new Lance(f.getId(), retVal)); + lances.put(f.getId(), new StrategicFormation(f.getId(), retVal)); logger.warn(String.format("Added missing Lance %s to AtB list", f.getName())); } } @@ -770,29 +770,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; } - Lance l = Lance.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/mission/AtBDynamicScenario.java b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenario.java index 0e761eda07..f651f572f7 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenario.java @@ -23,7 +23,7 @@ import megamek.common.annotations.Nullable; import megamek.common.enums.SkillLevel; import mekhq.campaign.Campaign; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.ScenarioForceTemplate.ForceGenerationMethod; import mekhq.campaign.mission.atb.AtBScenarioModifier; import mekhq.campaign.personnel.Person; @@ -371,11 +371,11 @@ public Person getLanceCommander(Campaign campaign) { return null; // if we don't have forces, just a bunch of units, then get the highest-ranked? } - Lance lance = campaign.getLances().get(getForceIDs().get(0)); + StrategicFormation strategicFormation = campaign.getStrategicFormations().get(getForceIDs().get(0)); - if (lance != null) { - lance.refreshCommander(campaign); - return lance.getCommander(campaign); + if (strategicFormation != null) { + strategicFormation.refreshCommander(campaign); + return strategicFormation.getCommander(campaign); } else { return null; } diff --git a/MekHQ/src/mekhq/campaign/mission/AtBScenario.java b/MekHQ/src/mekhq/campaign/mission/AtBScenario.java index d8ccf140f5..556c53c1fc 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBScenario.java @@ -21,34 +21,19 @@ */ package mekhq.campaign.mission; -import java.io.PrintWriter; -import java.text.ParseException; -import java.time.LocalDate; -import java.util.*; - -import megamek.common.*; -import megamek.common.util.fileUtils.MegaMekFile; -import megamek.utilities.BoardClassifier; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - import megamek.Version; import megamek.client.generator.TeamLoadOutGenerator; import megamek.codeUtilities.ObjectUtility; +import megamek.common.*; import megamek.common.annotations.Nullable; import megamek.common.enums.SkillLevel; import megamek.common.icons.Camouflage; import megamek.common.options.OptionsConstants; import megamek.common.planetaryconditions.Atmosphere; -import megamek.common.planetaryconditions.BlowingSand; -import megamek.common.planetaryconditions.EMI; -import megamek.common.planetaryconditions.Fog; -import megamek.common.planetaryconditions.Light; -import megamek.common.planetaryconditions.PlanetaryConditions; -import megamek.common.planetaryconditions.Weather; -import megamek.common.planetaryconditions.Wind; +import megamek.common.planetaryconditions.*; +import megamek.common.util.fileUtils.MegaMekFile; import megamek.logging.MMLogger; +import megamek.utilities.BoardClassifier; import mekhq.MHQConstants; import mekhq.MekHQ; import mekhq.Utilities; @@ -56,7 +41,7 @@ import mekhq.campaign.againstTheBot.AtBConfiguration; import mekhq.campaign.againstTheBot.AtBStaticWeightGenerator; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.ObjectiveEffect.ObjectiveEffectType; import mekhq.campaign.mission.ScenarioObjective.ObjectiveCriterion; import mekhq.campaign.mission.atb.IAtBScenario; @@ -66,12 +51,16 @@ import mekhq.campaign.stratcon.StratconBiomeManifest; import mekhq.campaign.stratcon.StratconBiomeManifest.MapTypeList; import mekhq.campaign.unit.Unit; -import mekhq.campaign.universe.Faction; -import mekhq.campaign.universe.Factions; -import mekhq.campaign.universe.Planet; -import mekhq.campaign.universe.PlanetarySystem; -import mekhq.campaign.universe.Systems; +import mekhq.campaign.universe.*; import mekhq.utilities.MHQXMLUtility; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.PrintWriter; +import java.text.ParseException; +import java.time.LocalDate; +import java.util.*; /** * @author Neoancient @@ -154,7 +143,7 @@ public abstract class AtBScenario extends Scenario implements IAtBScenario { public static final int NO_LANCE = -1; private boolean attacker; - private int lanceForceId; // -1 if scenario is not generated for a specific lance (special scenario, big + private int strategicFormationId; // -1 if scenario is not generated for a specific lance (special scenario, big // battle) private AtBLanceRole lanceRole; /* * set when scenario is created in case it is changed for the next week before @@ -218,7 +207,7 @@ public abstract class AtBScenario extends Scenario implements IAtBScenario { public AtBScenario() { super(); - lanceForceId = -1; + strategicFormationId = -1; lanceRole = AtBLanceRole.UNASSIGNED; alliesPlayer = new ArrayList<>(); alliesPlayerStub = new ArrayList<>(); @@ -235,7 +224,7 @@ public AtBScenario() { SB = StratconBiomeManifest.getInstance(); } - public void initialize(Campaign c, Lance lance, boolean attacker, LocalDate date) { + public void initialize(Campaign c, StrategicFormation lance, boolean attacker, LocalDate date) { setAttacker(attacker); alliesPlayer = new ArrayList<>(); @@ -247,10 +236,10 @@ public void initialize(Campaign c, Lance lance, boolean attacker, LocalDate date entityIds = new HashMap<>(); if (null == lance) { - lanceForceId = -1; + strategicFormationId = -1; lanceRole = AtBLanceRole.UNASSIGNED; } else { - this.lanceForceId = lance.getForceId(); + this.strategicFormationId = lance.getForceId(); lanceRole = lance.getRole(); setMissionId(lance.getMissionId()); @@ -337,10 +326,10 @@ private void initBattle(Campaign campaign) { lanceCount = 2; } - if (null != getLance(campaign)) { - getLance(campaign).refreshCommander(campaign); - if (null != getLance(campaign).getCommander(campaign).getSkill(SkillType.S_TACTICS)) { - rerollsRemaining = getLance(campaign).getCommander(campaign).getSkill(SkillType.S_TACTICS).getLevel(); + if (null != getStrategicFormation(campaign)) { + getStrategicFormation(campaign).refreshCommander(campaign); + if (null != getStrategicFormation(campaign).getCommander(campaign).getSkill(SkillType.S_TACTICS)) { + rerollsRemaining = getStrategicFormation(campaign).getCommander(campaign).getSkill(SkillType.S_TACTICS).getLevel(); } } } @@ -899,7 +888,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyHome, enemyHome, enemyEntities), campaign); } @@ -1651,7 +1640,7 @@ protected void setObjectives(Campaign c, AtBContract contract) { @Override protected void writeToXMLEnd(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "attacker", isAttacker()); - MHQXMLUtility.writeSimpleXMLTag(pw, indent, "lanceForceId", lanceForceId); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "lanceForceId", strategicFormationId); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "lanceRole", lanceRole.name()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "deploymentDelay", deploymentDelay); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "lanceCount", lanceCount); @@ -1745,7 +1734,7 @@ protected void loadFieldsFromXmlNode(final Node wn, final Version version, final if (wn2.getNodeName().equalsIgnoreCase("attacker")) { setAttacker(Boolean.parseBoolean(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("lanceForceId")) { - lanceForceId = Integer.parseInt(wn2.getTextContent()); + strategicFormationId = Integer.parseInt(wn2.getTextContent()); } else if (wn2.getNodeName().equalsIgnoreCase("lanceRole")) { lanceRole = AtBLanceRole.parseFromString(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("deploymentDelay")) { @@ -1973,20 +1962,20 @@ public List filterUntransportedUnits(List entities) { return retVal; } - public int getLanceForceId() { - return lanceForceId; + public int getStrategicFormationId() { + return strategicFormationId; } public AtBLanceRole getLanceRole() { return lanceRole; } - public Lance getLance(Campaign c) { - return c.getLances().get(lanceForceId); + public StrategicFormation getStrategicFormation(Campaign campaign) { + return campaign.getStrategicFormations().get(strategicFormationId); } - public void setLance(Lance l) { - lanceForceId = l.getForceId(); + public void setLance(StrategicFormation strategicFormation) { + strategicFormationId = strategicFormation.getForceId(); } /** diff --git a/MekHQ/src/mekhq/campaign/mission/CommonObjectiveFactory.java b/MekHQ/src/mekhq/campaign/mission/CommonObjectiveFactory.java index a9e15a7c77..bdb8938f83 100644 --- a/MekHQ/src/mekhq/campaign/mission/CommonObjectiveFactory.java +++ b/MekHQ/src/mekhq/campaign/mission/CommonObjectiveFactory.java @@ -37,7 +37,7 @@ * */ public class CommonObjectiveFactory { - private static final transient ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.AtBScenarioBuiltIn", + private static final ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.AtBScenarioBuiltIn", MekHQ.getMHQOptions().getLocale()); /** @@ -77,7 +77,7 @@ public static ScenarioObjective getPreserveSpecificFriendlies(String forceName, keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, "")); keepFriendliesAlive.setFixedAmount(number); } else { - keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, "%")); + keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, '%')); keepFriendliesAlive.setPercentage(number); } keepFriendliesAlive.setObjectiveCriterion(ObjectiveCriterion.Preserve); @@ -108,7 +108,7 @@ public static ScenarioObjective getKeepFriendliesAlive(Campaign campaign, AtBCon keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, "")); keepFriendliesAlive.setFixedAmount(number); } else { - keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, "%")); + keepFriendliesAlive.setDescription(String.format(resourceMap.getString("commonObjectives.preserveFriendlyUnits.text"), number, '%')); keepFriendliesAlive.setPercentage(number); } @@ -228,8 +228,8 @@ private static void addAssignedPlayerUnitsToObjective(AtBScenario scenario, Camp // some scenarios have a lance assigned // some scenarios have individual units assigned - if (scenario.getLanceForceId() != AtBScenario.NO_LANCE) { - objective.addForce(campaign.getForce(scenario.getLanceForceId()).getName()); + if (scenario.getStrategicFormationId() != AtBScenario.NO_LANCE) { + objective.addForce(campaign.getForce(scenario.getStrategicFormationId()).getName()); } else { int unitCount = 0; diff --git a/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioFactory.java b/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioFactory.java index cb63e6ff0b..540468ad61 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioFactory.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioFactory.java @@ -21,7 +21,7 @@ import megamek.codeUtilities.ObjectUtility; import megamek.logging.MMLogger; import mekhq.campaign.Campaign; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.AtBScenario; import mekhq.campaign.mission.atb.scenario.*; @@ -67,7 +67,7 @@ public static List> getScenarios(int type) { return scenarioMap.get(type); } - public static AtBScenario createScenario(Campaign c, Lance lance, int type, boolean attacker, LocalDate date) { + public static AtBScenario createScenario(Campaign c, StrategicFormation lance, int type, boolean attacker, LocalDate date) { List> classList = getScenarios(type); Class selectedClass; @@ -117,16 +117,16 @@ public static void registerScenario(IAtBScenario scenario) { * * Note that this handles having multiple active contracts at the same time * - * @param c the campaign for which to generate scenarios + * @param campaign the campaign for which to generate scenarios */ - public static void createScenariosForNewWeek(Campaign c) { + public static void createScenariosForNewWeek(Campaign campaign) { // First, we only want to generate if we have an active contract - if (!c.hasActiveContract()) { + if (!campaign.hasActiveContract()) { return; } // If we have an active contract, then we can progress with generation - Hashtable lances = c.getLances(); + Hashtable strategicFormations = campaign.getStrategicFormations(); List sList; List assignedLances = new ArrayList<>(); @@ -135,7 +135,7 @@ public static void createScenariosForNewWeek(Campaign c) { boolean hasBaseAttackAttacker; // We only need to process active AtB contracts that haven't hit their end date - for (final AtBContract contract : c.getActiveAtBContracts()) { + for (final AtBContract contract : campaign.getActiveAtBContracts()) { // region Value Initialization sList = new ArrayList<>(); dontGenerateForces = new ArrayList<>(); @@ -151,8 +151,8 @@ public static void createScenariosForNewWeek(Campaign c) { // the generation rules are followed for all active scenarios not just new // scenarios for (final AtBScenario scenario : contract.getCurrentAtBScenarios()) { - // Add any currently assigned lances to the assignedLances - assignedLances.add(scenario.getLanceForceId()); + // Add any currently assigned strategicFormations to the assignedLances + assignedLances.add(scenario.getStrategicFormationId()); // Remove any active scenarios from the contract, and add them to the current // scenarios list instead @@ -174,14 +174,14 @@ public static void createScenariosForNewWeek(Campaign c) { // endregion Current Scenarios // region Generate Scenarios - // Generate scenarios for lances based on their current situation + // Generate scenarios for strategicFormations based on their current situation if (!hasBaseAttackAttacker) { - for (Lance lance : lances.values()) { - // Don't generate scenarios for any lances already assigned, those assigned to a - // different contract, those not assigned to a contract, or for illegible lances - if (assignedLances.contains(lance.getForceId()) || (lance.getContract(c) == null) - || !lance.isEligible(c) || (lance.getMissionId() != contract.getId()) - || !lance.getContract(c).isActiveOn(c.getLocalDate(), true)) { + for (StrategicFormation strategicFormation : strategicFormations.values()) { + // Don't generate scenarios for any strategicFormations already assigned, those assigned to a + // different contract, those not assigned to a contract, or for illegible strategicFormations + if (assignedLances.contains(strategicFormation.getForceId()) || (strategicFormation.getContract(campaign) == null) + || !strategicFormation.isEligible(campaign) || (strategicFormation.getMissionId() != contract.getId()) + || !strategicFormation.getContract(campaign).isActiveOn(campaign.getLocalDate(), true)) { continue; } @@ -191,13 +191,13 @@ public static void createScenariosForNewWeek(Campaign c) { continue; } - // Attempt to generate a scenario for the lance - AtBScenario scenario = lance.checkForBattle(c); + // Attempt to generate a scenario for the strategicFormation + AtBScenario scenario = strategicFormation.checkForBattle(campaign); // If one is generated, then add it to the scenario list if (scenario != null) { sList.add(scenario); - assignedLances.add(lance.getForceId()); + assignedLances.add(strategicFormation.getForceId()); // We care if the scenario is a Base Attack, as one must be generated if the // current contract's morale is Unbreakable @@ -219,45 +219,46 @@ public static void createScenariosForNewWeek(Campaign c) { // region Overwhelming Morale Missions // Make sure Overwhelming morale missions have a base attack scenario generated - if (!c.getCampaignOptions().isUseStratCon()) { + if (!campaign.getCampaignOptions().isUseStratCon()) { if (!hasBaseAttack && contract.getMoraleLevel().isOverwhelming()) { /* * find a lance to act as defender, giving preference * first to those assigned to the same contract, * then to those assigned to defense roles */ - List lList = new ArrayList<>(); - for (Lance l : lances.values()) { - if ((l.getMissionId() == contract.getId()) && l.getRole().isDefence() && l.isEligible(c)) { - lList.add(l); + List lList = new ArrayList<>(); + for (StrategicFormation strategicFormation : strategicFormations.values()) { + if ((strategicFormation.getMissionId() == contract.getId()) + && strategicFormation.getRole().isDefence() && strategicFormation.isEligible(campaign)) { + lList.add(strategicFormation); } } if (lList.isEmpty()) { - for (Lance l : lances.values()) { - if ((l.getMissionId() == contract.getId()) && l.isEligible(c)) { - lList.add(l); + for (StrategicFormation strategicFormation : strategicFormations.values()) { + if ((strategicFormation.getMissionId() == contract.getId()) && strategicFormation.isEligible(campaign)) { + lList.add(strategicFormation); } } } if (lList.isEmpty()) { - for (Lance l : lances.values()) { - if (l.isEligible(c)) { - lList.add(l); + for (StrategicFormation strategicFormation : strategicFormations.values()) { + if (strategicFormation.isEligible(campaign)) { + lList.add(strategicFormation); } } } if (!lList.isEmpty()) { - Lance lance = ObjectUtility.getRandomItem(lList); - AtBScenario atbScenario = AtBScenarioFactory.createScenario(c, lance, - AtBScenario.BASEATTACK, false, Lance.getBattleDate(c.getLocalDate())); + StrategicFormation strategicFormation = ObjectUtility.getRandomItem(lList); + AtBScenario atbScenario = AtBScenarioFactory.createScenario(campaign, strategicFormation, + AtBScenario.BASEATTACK, false, StrategicFormation.getBattleDate(campaign.getLocalDate())); if (atbScenario != null) { - if ((lance.getMissionId() == atbScenario.getMissionId()) - || (lance.getMissionId() == Lance.NO_MISSION)) { + if ((strategicFormation.getMissionId() == atbScenario.getMissionId()) + || (strategicFormation.getMissionId() == StrategicFormation.NO_MISSION)) { for (int i = 0; i < sList.size(); i++) { - if (sList.get(i).getLanceForceId() == lance.getForceId()) { + if (sList.get(i).getStrategicFormationId() == strategicFormation.getForceId()) { if (dontGenerateForces.contains(atbScenario.getId())) { dontGenerateForces.remove(atbScenario.getId()); } @@ -266,23 +267,23 @@ public static void createScenariosForNewWeek(Campaign c) { } } } else { - // edge case: lance assigned to another mission gets assigned the scenario, + // edge case: strategicFormation assigned to another mission gets assigned the scenario, // we need to remove any scenario they are assigned to already - c.getMission(lance.getMissionId()).getScenarios() + campaign.getMission(strategicFormation.getMissionId()).getScenarios() .removeIf(scenario -> (scenario instanceof AtBScenario) - && (((AtBScenario) scenario).getLanceForceId() == lance.getForceId())); + && (((AtBScenario) scenario).getStrategicFormationId() == strategicFormation.getForceId())); } if (!sList.contains(atbScenario)) { sList.add(atbScenario); } - if (!assignedLances.contains(lance.getForceId())) { - assignedLances.add(lance.getForceId()); + if (!assignedLances.contains(strategicFormation.getForceId())) { + assignedLances.add(strategicFormation.getForceId()); } } else { logger.error("Unable to generate Base Attack scenario."); } } else { - logger.warn("No lances assigned to mission " + contract.getName() + logger.warn("No strategicFormations assigned to mission " + contract.getName() + ". Can't generate an Unbreakable Morale base defense mission for this force."); } } @@ -305,9 +306,9 @@ public static void createScenariosForNewWeek(Campaign c) { // for the scenario if required sList.sort((s1, s2) -> ObjectUtility.compareNullable(s1.getDate(), s2.getDate(), LocalDate::compareTo)); for (AtBScenario atbScenario : sList) { - c.addScenario(atbScenario, contract); + campaign.addScenario(atbScenario, contract); if (!dontGenerateForces.contains(atbScenario.getId())) { - atbScenario.setForces(c); + atbScenario.setForces(campaign); } } // endregion Add to Campaign diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/BaseAttackBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/BaseAttackBuiltInScenario.java index aba45e9a29..62286ce795 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/BaseAttackBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/BaseAttackBuiltInScenario.java @@ -18,23 +18,18 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - import megamek.client.bot.princess.BehaviorSettingsFactory; import megamek.common.Board; import megamek.common.Compute; import megamek.common.Entity; import megamek.common.EntityWeightClass; import mekhq.campaign.Campaign; -import mekhq.campaign.mission.enums.AtBLanceRole; -import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.mission.AtBScenario; -import mekhq.campaign.mission.BotForce; -import mekhq.campaign.mission.CommonObjectiveFactory; -import mekhq.campaign.mission.ObjectiveEffect; -import mekhq.campaign.mission.ScenarioObjective; +import mekhq.campaign.mission.*; import mekhq.campaign.mission.ObjectiveEffect.ObjectiveEffectType; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import mekhq.campaign.mission.enums.AtBLanceRole; + +import java.util.ArrayList; @AtBScenarioEnabled public class BaseAttackBuiltInScenario extends AtBScenario { @@ -103,7 +98,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti * Ally deploys 2 lances of a lighter weight class than the player, * minimum light */ - int allyForceWeight = Math.max(getLance(campaign).getWeightClass(campaign) - 1, EntityWeightClass.WEIGHT_LIGHT); + int allyForceWeight = Math.max(getStrategicFormation(campaign).getWeightClass(campaign) - 1, EntityWeightClass.WEIGHT_LIGHT); addLance(allyEntities, getContract(campaign).getEmployerCode(), getContract(campaign).getAllySkill(), getContract(campaign).getAllyQuality(), allyForceWeight, campaign); addLance(allyEntities, getContract(campaign).getEmployerCode(), getContract(campaign).getAllySkill(), @@ -143,14 +138,14 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(new BotForce(BASE_TURRET_FORCE_ID, isAttacker() ? 2 : 1, defenderStart, defenderHome, turretForce), campaign); /* Roll 2x on bot lances roll */ - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities), campaign); // the "second" enemy force will either flee in the same direction as // the first enemy force in case of the player being the attacker // or where it came from in case of player being defender ArrayList secondBotEntities = new ArrayList<>(); - addEnemyForce(secondBotEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(secondBotEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); BotForce secondBotForce = getEnemyBotForce(getContract(campaign), isAttacker() ? enemyStart : secondAttackerForceStart, isAttacker() ? getEnemyHome() : secondAttackerForceStart, secondBotEntities); diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/BreakthroughBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/BreakthroughBuiltInScenario.java index 501354caec..38ef0705fb 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/BreakthroughBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/BreakthroughBuiltInScenario.java @@ -18,8 +18,6 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - import megamek.client.bot.princess.BehaviorSettingsFactory; import megamek.common.Board; import megamek.common.Compute; @@ -27,14 +25,11 @@ import megamek.common.OffBoardDirection; import megamek.logging.MMLogger; import mekhq.campaign.Campaign; -import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.mission.AtBDynamicScenarioFactory; -import mekhq.campaign.mission.AtBScenario; -import mekhq.campaign.mission.BotForce; -import mekhq.campaign.mission.CommonObjectiveFactory; -import mekhq.campaign.mission.ScenarioObjective; +import mekhq.campaign.mission.*; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; + @AtBScenarioEnabled public class BreakthroughBuiltInScenario extends AtBScenario { private static final MMLogger logger = MMLogger.create(BreakthroughBuiltInScenario.class); @@ -97,7 +92,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(allyEntitiesForce, campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); BotForce botForce = getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities); try { diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ChaseBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ChaseBuiltInScenario.java index 3bc4250aca..a52b493173 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ChaseBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ChaseBuiltInScenario.java @@ -18,25 +18,16 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - import megamek.client.bot.princess.BehaviorSettingsFactory; import megamek.client.bot.princess.PrincessException; -import megamek.common.Board; -import megamek.common.Compute; -import megamek.common.Entity; -import megamek.common.EntityWeightClass; -import megamek.common.OffBoardDirection; +import megamek.common.*; import megamek.logging.MMLogger; import mekhq.campaign.Campaign; -import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.mission.AtBDynamicScenarioFactory; -import mekhq.campaign.mission.AtBScenario; -import mekhq.campaign.mission.BotForce; -import mekhq.campaign.mission.CommonObjectiveFactory; -import mekhq.campaign.mission.ScenarioObjective; +import mekhq.campaign.mission.*; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; + @AtBScenarioEnabled public class ChaseBuiltInScenario extends AtBScenario { private static final MMLogger logger = MMLogger.create(ChaseBuiltInScenario.class); @@ -89,9 +80,9 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(allyEntitiesForce, campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, 0, + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, 0, -1, campaign); - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, 0, + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, 0, -1, campaign); BotForce botForce = getEnemyBotForce(getContract(campaign), startEdge, getEnemyHome(), enemyEntities); @@ -121,7 +112,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti int speed = en.getWalkMP(); if (en.getJumpMP() > 0) { - if (en instanceof megamek.common.Infantry) { + if (en instanceof Infantry) { speed = en.getJumpMP(); } else { speed++; @@ -135,7 +126,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti int speed = en.getWalkMP(); if (en.getJumpMP() > 0) { - if (en instanceof megamek.common.Infantry) { + if (en instanceof Infantry) { speed = en.getJumpMP(); } else { speed++; diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ExtractionBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ExtractionBuiltInScenario.java index 0da9a9c6de..d81a7b29d2 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ExtractionBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ExtractionBuiltInScenario.java @@ -18,9 +18,6 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; -import java.util.UUID; - import megamek.client.bot.princess.BehaviorSettingsFactory; import megamek.client.bot.princess.PrincessException; import megamek.common.Board; @@ -28,17 +25,15 @@ import megamek.common.Entity; import megamek.logging.MMLogger; import mekhq.campaign.Campaign; -import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.mission.AtBScenario; -import mekhq.campaign.mission.BotForce; -import mekhq.campaign.mission.CommonObjectiveFactory; -import mekhq.campaign.mission.ObjectiveEffect; +import mekhq.campaign.mission.*; import mekhq.campaign.mission.ObjectiveEffect.EffectScalingType; import mekhq.campaign.mission.ObjectiveEffect.ObjectiveEffectType; -import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.ScenarioObjective.TimeLimitType; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; +import java.util.UUID; + @AtBScenarioEnabled public class ExtractionBuiltInScenario extends AtBScenario { private static final MMLogger logger = MMLogger.create(ExtractionBuiltInScenario.class); @@ -103,7 +98,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities), campaign); ArrayList otherForce = new ArrayList<>(); diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/HideAndSeekBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/HideAndSeekBuiltInScenario.java index c0ff5c8ace..9f593f1c5a 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/HideAndSeekBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/HideAndSeekBuiltInScenario.java @@ -29,6 +29,7 @@ import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.atb.AtBScenarioEnabled; import mekhq.campaign.stratcon.StratconBiomeManifest; +import mekhq.campaign.stratcon.StratconBiomeManifest.MapTypeList; import java.util.ArrayList; import java.util.List; @@ -54,7 +55,7 @@ public String getResourceKey() { @Override public void setTerrain() { - Map mapTypes = StratconBiomeManifest.getInstance().getBiomeMapTypes(); + Map mapTypes = StratconBiomeManifest.getInstance().getBiomeMapTypes(); List keys = mapTypes.keySet().stream().sorted().collect(Collectors.toList()); do { setTerrainType(keys.get(Compute.randomInt(keys.size()))); @@ -107,10 +108,10 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti } if (isAttacker()) { - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, 2, 0, campaign); } else { - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_HEAVY, 0, 0, campaign); } diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/HoldTheLineBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/HoldTheLineBuiltInScenario.java index 0b73a4c068..36bde06255 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/HoldTheLineBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/HoldTheLineBuiltInScenario.java @@ -18,8 +18,6 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - import megamek.common.Board; import megamek.common.Compute; import megamek.common.Entity; @@ -31,6 +29,8 @@ import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; + @AtBScenarioEnabled public class HoldTheLineBuiltInScenario extends AtBScenario { @Override @@ -79,7 +79,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_ASSAULT, isAttacker() ? 0 : 4, 0, campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities), campaign); diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ProbeBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ProbeBuiltInScenario.java index 4a9a41ae9e..a18f653bb8 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ProbeBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ProbeBuiltInScenario.java @@ -18,11 +18,6 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import megamek.common.Compute; import megamek.common.Entity; import megamek.common.EntityWeightClass; @@ -33,6 +28,12 @@ import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.atb.AtBScenarioEnabled; import mekhq.campaign.stratcon.StratconBiomeManifest; +import mekhq.campaign.stratcon.StratconBiomeManifest.MapTypeList; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @AtBScenarioEnabled public class ProbeBuiltInScenario extends AtBScenario { @@ -53,7 +54,7 @@ public String getResourceKey() { @Override public void setTerrain() { - Map mapTypes = StratconBiomeManifest.getInstance().getBiomeMapTypes(); + Map mapTypes = StratconBiomeManifest.getInstance().getBiomeMapTypes(); List keys = mapTypes.keySet().stream().sorted().collect(Collectors.toList()); do { setTerrainType(keys.get(Compute.randomInt(keys.size()))); @@ -78,7 +79,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_MEDIUM, 0, 0, + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), EntityWeightClass.WEIGHT_MEDIUM, 0, 0, campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities), campaign); diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ReconRaidBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ReconRaidBuiltInScenario.java index 9033a63e68..f547848e72 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/ReconRaidBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/ReconRaidBuiltInScenario.java @@ -18,25 +18,16 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - -import megamek.common.Board; -import megamek.common.Compute; -import megamek.common.Entity; -import megamek.common.EntityWeightClass; -import megamek.common.OffBoardDirection; +import megamek.common.*; import mekhq.campaign.Campaign; -import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.mission.AtBDynamicScenarioFactory; -import mekhq.campaign.mission.AtBScenario; -import mekhq.campaign.mission.CommonObjectiveFactory; -import mekhq.campaign.mission.ObjectiveEffect; +import mekhq.campaign.mission.*; import mekhq.campaign.mission.ObjectiveEffect.ObjectiveEffectType; -import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.ScenarioObjective.ObjectiveCriterion; import mekhq.campaign.mission.ScenarioObjective.TimeLimitType; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; + @AtBScenarioEnabled public class ReconRaidBuiltInScenario extends AtBScenario { @Override @@ -85,7 +76,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), isAttacker() ? EntityWeightClass.WEIGHT_ASSAULT : EntityWeightClass.WEIGHT_MEDIUM, 0, 0, campaign); addBotForce(getEnemyBotForce(getContract(campaign), enemyStart, getEnemyHome(), enemyEntities), campaign); diff --git a/MekHQ/src/mekhq/campaign/mission/atb/scenario/StandUpBuiltInScenario.java b/MekHQ/src/mekhq/campaign/mission/atb/scenario/StandUpBuiltInScenario.java index 1a01d05207..8e1ecb0dc7 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/scenario/StandUpBuiltInScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/scenario/StandUpBuiltInScenario.java @@ -18,8 +18,6 @@ */ package mekhq.campaign.mission.atb.scenario; -import java.util.ArrayList; - import megamek.common.Compute; import megamek.common.Entity; import mekhq.campaign.Campaign; @@ -29,6 +27,8 @@ import mekhq.campaign.mission.ScenarioObjective; import mekhq.campaign.mission.atb.AtBScenarioEnabled; +import java.util.ArrayList; + @AtBScenarioEnabled public class StandUpBuiltInScenario extends AtBScenario { @Override @@ -64,7 +64,7 @@ public void setExtraScenarioForces(Campaign campaign, ArrayList allyEnti addBotForce(getAllyBotForce(getContract(campaign), getStartingPos(), playerHome, allyEntities), campaign); } - addEnemyForce(enemyEntities, getLance(campaign).getWeightClass(campaign), campaign); + addEnemyForce(enemyEntities, getStrategicFormation(campaign).getWeightClass(campaign), campaign); addBotForce(getEnemyBotForce(getContract(campaign), getEnemyHome(), getEnemyHome(), enemyEntities), campaign); } diff --git a/MekHQ/src/mekhq/campaign/personnel/autoAwards/MiscAwards.java b/MekHQ/src/mekhq/campaign/personnel/autoAwards/MiscAwards.java index 6dcac12bec..db09548a5d 100644 --- a/MekHQ/src/mekhq/campaign/personnel/autoAwards/MiscAwards.java +++ b/MekHQ/src/mekhq/campaign/personnel/autoAwards/MiscAwards.java @@ -279,7 +279,7 @@ private static boolean prisonerOfWar(Campaign campaign, Award award, UUID person */ private static boolean drillInstructor(Campaign campaign, Award award, UUID person) { if (award.canBeAwarded(campaign.getPerson(person))) { - return campaign.getLanceList().stream() + return campaign.getStrategicFormationList().stream() .anyMatch(lance -> (lance.getRole().isTraining()) && (lance.getCommanderId().equals(person))); } diff --git a/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java b/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java index 65ad62de22..47a4e44edd 100644 --- a/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java +++ b/MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java @@ -33,7 +33,7 @@ import mekhq.campaign.event.ScenarioChangedEvent; import mekhq.campaign.event.StratconDeploymentEvent; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.*; import mekhq.campaign.mission.ScenarioForceTemplate.ForceAlignment; import mekhq.campaign.mission.ScenarioForceTemplate.ForceGenerationMethod; @@ -833,7 +833,7 @@ public static void processForceDeployment(StratconCoords coords, int forceID, Ca MekHQ.triggerEvent(new ScenarioChangedEvent(scenario.getBackingScenario())); } - if (campaign.getLances().get(forceID).getRole().isScouting()) { + if (campaign.getStrategicFormations().get(forceID).getRole().isScouting()) { for (int direction = 0; direction < 6; direction++) { StratconCoords checkCoords = coords.translate(direction); @@ -1043,7 +1043,7 @@ private static boolean commanderLanceHasDefensiveAssignment(AtBDynamicScenario s if (lanceCommander != null){ Unit commanderUnit = lanceCommander.getUnit(); if (commanderUnit != null) { - Lance lance = campaign.getLances().get(commanderUnit.getForceId()); + StrategicFormation lance = campaign.getStrategicFormations().get(commanderUnit.getForceId()); return (lance != null) && lance.getRole().isDefence(); } @@ -1415,7 +1415,7 @@ public static List getAvailableForceIDs(Campaign campaign) { // that are // deployed to a scenario and not in a track already - return campaign.getLances().keySet().stream() + return campaign.getStrategicFormations().keySet().stream() .mapToInt(key -> key) .mapToObj(campaign::getForce).filter(force -> (force != null) && !force.isDeployed() @@ -1427,46 +1427,49 @@ 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.getLances().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; } int primaryUnitType = force.getPrimaryUnitType(campaign); - boolean noReinforcementRestriction = !reinforcements || (reinforcements - && (getReinforcementType(force.getId(), currentTrack, campaign, - campaignState) != ReinforcementEligibilityType.None)); - if ((force.getScenarioId() <= 0) && !force.getUnits().isEmpty() - && !forcesInTracks.contains(force.getId()) - && forceCompositionMatchesDeclaredUnitType(primaryUnitType, unitType, reinforcements) - && noReinforcementRestriction - && !subElementsOrSelfDeployed(force, campaign)) { + boolean noReinforcementRestriction = !reinforcements || + (getReinforcementType(force.getId(), currentTrack, campaign, campaignState) != ReinforcementEligibilityType.None); + + if ((force.getScenarioId() <= 0) + && !force.getAllUnits(true).isEmpty() + && !forcesInTracks.contains(force.getId()) + && forceCompositionMatchesDeclaredUnitType(primaryUnitType, unitType, reinforcements) + && noReinforcementRestriction + && !subElementsOrSelfDeployed(force, campaign)) { + retVal.add(force.getId()); } } @@ -1672,8 +1675,8 @@ public static ReinforcementEligibilityType getReinforcementType(int forceID, Str // if the force is in 'fight' stance, it'll be able to deploy using 'fight // lance' rules - if (campaign.getLances().containsKey(forceID) - && (campaign.getLances().get(forceID).getRole().isFighting())) { + if (campaign.getStrategicFormations().containsKey(forceID) + && (campaign.getStrategicFormations().get(forceID).getRole().isFighting())) { return ReinforcementEligibilityType.FightLance; } diff --git a/MekHQ/src/mekhq/gui/BriefingTab.java b/MekHQ/src/mekhq/gui/BriefingTab.java index ca96aadcc8..5e3690ba1b 100644 --- a/MekHQ/src/mekhq/gui/BriefingTab.java +++ b/MekHQ/src/mekhq/gui/BriefingTab.java @@ -39,7 +39,7 @@ import mekhq.campaign.event.*; import mekhq.campaign.finances.Money; import mekhq.campaign.finances.enums.TransactionType; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.*; import mekhq.campaign.mission.atb.AtBScenarioFactory; import mekhq.campaign.mission.enums.MissionStatus; @@ -909,11 +909,11 @@ private void startScenario(BehaviorSettings autoResolveBehaviorSettings) { // code to support deployment of reinforcements for legacy ATB scenarios. if ((scenario instanceof AtBScenario) && !(scenario instanceof AtBDynamicScenario)) { - Lance assignedLance = ((AtBScenario) scenario).getLance(getCampaign()); + StrategicFormation assignedLance = ((AtBScenario) scenario).getStrategicFormation(getCampaign()); if (assignedLance != null) { int assignedForceId = assignedLance.getForceId(); int cmdrStrategy = 0; - Person commander = getCampaign().getPerson(Lance.findCommander(assignedForceId, getCampaign())); + Person commander = getCampaign().getPerson(StrategicFormation.findCommander(assignedForceId, getCampaign())); if ((null != commander) && (null != commander.getSkill(SkillType.S_STRATEGY))) { cmdrStrategy = commander.getSkill(SkillType.S_STRATEGY).getLevel(); } diff --git a/MekHQ/src/mekhq/gui/ForceRenderer.java b/MekHQ/src/mekhq/gui/ForceRenderer.java index 236d718440..acecca9f71 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,12 @@ import mekhq.campaign.unit.Unit; import mekhq.utilities.ReportingUtilities; +import javax.swing.*; +import javax.swing.tree.DefaultTreeCellRenderer; +import java.awt.*; + +import static mekhq.campaign.force.Force.STRATEGIC_FORMATION_OVERRIDE_NONE; + public class ForceRenderer extends DefaultTreeCellRenderer { private static final MMLogger logger = MMLogger.create(ForceRenderer.class); @@ -51,7 +50,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 +58,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 +140,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 +148,17 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean setBackground(MekHQ.getMHQOptions().getDeployedBackground()); setOpaque(true); } + + String format; + if (force.isStrategicFormation()) { + format = (force.getOverrideStrategicFormation() != STRATEGIC_FORMATION_OVERRIDE_NONE) ? + "%s" : "%s"; + } else { + format = (force.getOverrideStrategicFormation() != STRATEGIC_FORMATION_OVERRIDE_NONE) ? + "%s" : "%s"; + } + + setText(String.format(format, 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..c1602fabc3 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,32 @@ public void actionPerformed(ActionEvent action) { } gui.undeployForces(forces); gui.getTOETab().refreshForceView(); + + for (Force formation : gui.getCampaign().getAllForces()) { + MekHQ.triggerEvent(new OrganizationChangedEvent(formation)); + } + } else if (command.contains(CHANGE_STRATEGIC_FORCE_OVERRIDE)) { + if (singleForce == null) { + return; + } + + boolean formationState = singleForce.isStrategicFormation(); + singleForce.setStrategicFormation(!formationState); + singleForce.setOverrideStrategicFormation(!formationState ? 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 +1052,18 @@ protected Optional createPopupMenu() { menuItem.addActionListener(this); popup.add(menuItem); + JMenuItem optionStrategicForceOverride = new JMenuItem((force.isStrategicFormation() ? + "Never" : "Always") + " Consider Force a 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/stratcon/ScenarioWizardLanceRenderer.java b/MekHQ/src/mekhq/gui/stratcon/ScenarioWizardLanceRenderer.java index 56f4ce110a..e9b8747f8f 100644 --- a/MekHQ/src/mekhq/gui/stratcon/ScenarioWizardLanceRenderer.java +++ b/MekHQ/src/mekhq/gui/stratcon/ScenarioWizardLanceRenderer.java @@ -20,7 +20,7 @@ import mekhq.campaign.Campaign; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import javax.swing.*; import java.awt.*; @@ -50,7 +50,7 @@ public Component getListCellRendererComponent(final JList list, setForeground(foreground); setBackground(background); - Lance lance = campaign.getLances().get(value.getId()); + StrategicFormation lance = campaign.getStrategicFormations().get(value.getId()); String roleString = ""; if (lance != null) { roleString = lance.getRole().toString() + ", "; diff --git a/MekHQ/src/mekhq/gui/view/AtBScenarioViewPanel.java b/MekHQ/src/mekhq/gui/view/AtBScenarioViewPanel.java index 50fd9de1e8..ebee91f81a 100644 --- a/MekHQ/src/mekhq/gui/view/AtBScenarioViewPanel.java +++ b/MekHQ/src/mekhq/gui/view/AtBScenarioViewPanel.java @@ -292,8 +292,8 @@ private void fillStats() { gridBagConstraints.gridwidth = 1; panStats.add(lblForce, gridBagConstraints); - if (null != scenario.getLance(campaign)) { - lblForceDesc.setText(campaign.getForce(scenario.getLanceForceId()).getFullName()); + if (null != scenario.getStrategicFormation(campaign)) { + lblForceDesc.setText(campaign.getForce(scenario.getStrategicFormationId()).getFullName()); } else if (scenario instanceof AtBDynamicScenario) { StringBuilder forceBuilder = new StringBuilder(); forceBuilder.append(""); @@ -376,12 +376,12 @@ private void fillStats() { for (ScenarioObjective objective : scenario.getScenarioObjectives()) { objectiveBuilder.append(objective.getDescription()); - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); for (String forceName : objective.getAssociatedForceNames()) { - objectiveBuilder.append("\t"); + objectiveBuilder.append('\t'); objectiveBuilder.append(forceName); - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); } for (String associatedUnitID : objective.getAssociatedUnitIDs()) { @@ -399,22 +399,22 @@ private void fillStats() { if (associatedUnitName.isBlank()) { continue; } - objectiveBuilder.append("\t"); + objectiveBuilder.append('\t'); objectiveBuilder.append(associatedUnitName); - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); } - objectiveBuilder.append("\t"); + objectiveBuilder.append('\t'); objectiveBuilder.append(objective.getTimeLimitString()); - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); for (String detail : objective.getDetails()) { - objectiveBuilder.append("\t"); + objectiveBuilder.append('\t'); objectiveBuilder.append(detail); - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); } - objectiveBuilder.append("\n"); + objectiveBuilder.append('\n'); } objectiveBuilder.append(scenario.getBattlefieldControlDescription()); diff --git a/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java b/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java index 64f8cd8f22..32f05ff63c 100644 --- a/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java +++ b/MekHQ/src/mekhq/gui/view/LanceAssignmentView.java @@ -25,7 +25,7 @@ import mekhq.MekHQ; import mekhq.campaign.Campaign; import mekhq.campaign.force.Force; -import mekhq.campaign.force.Lance; +import mekhq.campaign.force.StrategicFormation; import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.enums.AtBLanceRole; import mekhq.campaign.personnel.SkillType; @@ -169,8 +169,8 @@ public Component getTableCellRendererComponent(JTable table, Object value, RowFilter laFilter = new RowFilter<>() { @Override public boolean include(Entry entry) { - Lance l = entry.getModel().getRow(entry.getIdentifier()); - return l.isEligible(campaign); + StrategicFormation strategicFormation = entry.getModel().getRow(entry.getIdentifier()); + return strategicFormation.isEligible(campaign); } }; final NaturalOrderComparator noc = new NaturalOrderComparator(); @@ -223,14 +223,14 @@ public void refresh() { cbContract.addItem(contract); } AtBContract defaultContract = activeContracts.isEmpty() ? null : activeContracts.get(0); - for (Lance l : campaign.getLances().values()) { - if ((l.getContract(campaign) == null) - || !l.getContract(campaign).isActiveOn(campaign.getLocalDate(), true)) { - l.setContract(defaultContract); + for (StrategicFormation strategicFormation : campaign.getStrategicFormations().values()) { + if ((strategicFormation.getContract(campaign) == null) + || !strategicFormation.getContract(campaign).isActiveOn(campaign.getLocalDate(), true)) { + strategicFormation.setContract(defaultContract); } } ((DataTableModel) tblRequiredLances.getModel()).setData(activeContracts); - ((DataTableModel) tblAssignments.getModel()).setData(campaign.getLanceList()); + ((DataTableModel) tblAssignments.getModel()).setData(campaign.getStrategicFormationList()); panRequiredLances.setVisible(tblRequiredLances.getRowCount() > 0); } @@ -341,14 +341,13 @@ public Object getValueAt(int row, int column) { if (COL_CONTRACT == column) { return ((AtBContract) data.get(row)).getName(); } - if (data.get(row) instanceof AtBContract) { - AtBContract contract = (AtBContract) data.get(row); + if (data.get(row) instanceof AtBContract contract) { if (column == COL_TOTAL) { int t = 0; - for (Lance l : campaign.getLanceList()) { - if (data.get(row).equals(l.getContract(campaign)) - && (l.getRole() != AtBLanceRole.UNASSIGNED) - && l.isEligible(campaign)) { + for (StrategicFormation strategicFormation : campaign.getStrategicFormationList()) { + if (data.get(row).equals(strategicFormation.getContract(campaign)) + && (strategicFormation.getRole() != AtBLanceRole.UNASSIGNED) + && strategicFormation.isEligible(campaign)) { t++; } } @@ -358,10 +357,10 @@ public Object getValueAt(int row, int column) { return Integer.toString(contract.getRequiredLances()); } else if (contract.getContractType().getRequiredLanceRole().ordinal() == column - 2) { int t = 0; - for (Lance l : campaign.getLanceList()) { - if (data.get(row).equals(l.getContract(campaign)) - && (l.getRole() == l.getContract(campaign).getContractType().getRequiredLanceRole()) - && l.isEligible(campaign)) { + for (StrategicFormation strategicFormation : campaign.getStrategicFormationList()) { + if (data.get(row).equals(strategicFormation.getContract(campaign)) + && (strategicFormation.getRole() == strategicFormation.getContract(campaign).getContractType().getRequiredLanceRole()) + && strategicFormation.isEligible(campaign)) { t++; } } @@ -388,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 @@ -402,29 +401,21 @@ public String getColumnName(int column) { } public int getColumnWidth(int col) { - switch (col) { - case COL_FORCE: - case COL_CONTRACT: - return 100; - case COL_WEIGHT_CLASS: - return 5; - default: - return 50; - } + return switch (col) { + case COL_FORCE, COL_CONTRACT -> 100; + case COL_WEIGHT_CLASS -> 5; + default -> 50; + }; } @Override public Class getColumnClass(int c) { - switch (c) { - case COL_FORCE: - return Force.class; - case COL_CONTRACT: - return AtBContract.class; - case COL_ROLE: - return AtBLanceRole.class; - default: - return String.class; - } + return switch (c) { + case COL_FORCE -> Force.class; + case COL_CONTRACT -> AtBContract.class; + case COL_ROLE -> AtBLanceRole.class; + default -> String.class; + }; } @Override @@ -432,38 +423,33 @@ public boolean isCellEditable(int row, int col) { return col > COL_WEIGHT_CLASS; } - public Lance getRow(int row) { - return (Lance) data.get(row); + public StrategicFormation getRow(int row) { + return (StrategicFormation) data.get(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 ""; } - switch (column) { - case COL_FORCE: - return campaign.getForce(((Lance) data.get(row)).getForceId()); - case COL_WEIGHT_CLASS: - return WEIGHT_CODES[((Lance) data.get(row)).getWeightClass(campaign)]; - case COL_CONTRACT: - return campaign.getMission(((Lance) data.get(row)).getMissionId()); - case COL_ROLE: - return ((Lance) data.get(row)).getRole(); - default: - return "?"; - } + return switch (column) { + case COL_FORCE -> campaign.getForce(((StrategicFormation) data.get(row)).getForceId()); + case COL_WEIGHT_CLASS -> WEIGHT_CODES[((StrategicFormation) data.get(row)).getWeightClass(campaign)]; + case COL_CONTRACT -> campaign.getMission(((StrategicFormation) data.get(row)).getMissionId()); + case COL_ROLE -> ((StrategicFormation) data.get(row)).getRole(); + default -> "?"; + }; } @Override public void setValueAt(Object value, int row, int col) { if (col == COL_CONTRACT) { - ((Lance) data.get(row)).setContract((AtBContract) value); + ((StrategicFormation) data.get(row)).setContract((AtBContract) value); } else if (col == COL_ROLE) { if (value instanceof AtBLanceRole) { - ((Lance) data.get(row)).setRole((AtBLanceRole) value); + ((StrategicFormation) data.get(row)).setRole((AtBLanceRole) value); } } fireTableDataChanged();