Skip to content

Commit

Permalink
Merge pull request MegaMek#5250 from IllianiCBT/strategicFormations
Browse files Browse the repository at this point in the history
Renamed 'Lances' to 'Strategic Formations', Expanded Functionality
  • Loading branch information
HammerGS authored Nov 29, 2024
2 parents b3308d0 + d1b53f6 commit 05578be
Show file tree
Hide file tree
Showing 26 changed files with 632 additions and 492 deletions.
18 changes: 9 additions & 9 deletions MekHQ/src/mekhq/AtBGameThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -602,12 +602,12 @@ protected List<Entity> 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<Entity> comp = Comparator.comparing(((Entity e) -> e.getEntityMajorTypeName(e.getEntityType())));
Comparator<Entity> 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);
Expand All @@ -618,13 +618,13 @@ protected List<Entity> 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);
Expand Down
69 changes: 34 additions & 35 deletions MekHQ/src/mekhq/campaign/Campaign.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -201,7 +201,7 @@ public class Campaign implements ITechManager {

// hierarchically structured Force object to define TO&E
private Force forces;
private final Hashtable<Integer, Lance> lances; // AtB
private final Hashtable<Integer, StrategicFormation> strategicFormations; // AtB

private Faction faction;
private int techFactionCode;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -454,16 +454,16 @@ public List<Force> 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<Integer, Lance> getLances() {
return lances;
public Hashtable<Integer, StrategicFormation> getStrategicFormations() {
return strategicFormations;
}

public ArrayList<Lance> getLanceList() {
return lances.values().stream()
public ArrayList<StrategicFormation> getStrategicFormationList() {
return strategicFormations.values().stream()
.filter(l -> forceIds.containsKey(l.getForceId()))
.collect(Collectors.toCollection(ArrayList::new));
}
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -1009,22 +1009,21 @@ 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));
}
}
}

/**
* 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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -4998,7 +4997,7 @@ public void removeForce(Force force) {
}

if (campaignOptions.isUseAtB()) {
lances.remove(fid);
strategicFormations.remove(fid);
}

if (null != force.getParentForce()) {
Expand Down Expand Up @@ -5051,7 +5050,7 @@ public void removeUnitFromForce(Unit u) {
}

if (campaignOptions.isUseAtB() && force.getUnits().isEmpty()) {
lances.remove(force.getId());
strategicFormations.remove(force.getId());
}
}
}
Expand Down Expand Up @@ -5626,14 +5625,14 @@ public void writeToXML(final PrintWriter pw) {
// CAW: implicit DEPENDS-ON to the <missions> 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);
Expand Down Expand Up @@ -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;
}
Expand Down
78 changes: 78 additions & 0 deletions MekHQ/src/mekhq/campaign/force/Force.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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<Force> getAllParents() {
List<Force> 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;
}
Expand All @@ -229,6 +281,29 @@ public Vector<Force> getSubForces() {
return subForces;
}

/**
* Returns a list of all of this forces' descendant forces.
* This includes direct child forces and their descendents recursively.
* <p>
* 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<Force> getAllSubForces() {
List<Force> 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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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")) {
Expand Down
Loading

0 comments on commit 05578be

Please sign in to comment.