Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renamed 'Lances' to 'Strategic Formations', Expanded Functionality #5250

Merged
merged 8 commits into from
Nov 29, 2024
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())));
Dismissed Show dismissed Hide dismissed
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() {
Dismissed Show dismissed Hide dismissed
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