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

Linked StratCon OpFor Generation to AtB Difficulty Options, Added OpFor Generation Balance Checks #4029

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedASFAce01.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied ASF Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedASFAceHvy.mul</fixedMul>
<fixedMul>AlliedASFAceHvy.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedCavLance.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Cavalry Lance</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedCavLance.mul</fixedMul>
<fixedMul>AlliedCavLance.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedHorseCav.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Light Brigade Horse Cavalry</forceName>
<generationMethod>5</generationMethod>
<fixedMul>MercThe600.mul</fixedMul>
<fixedMul>MercThe600.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedMechAceCRD.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedCRDAce.mul</fixedMul>
<fixedMul>AlliedCRDAce.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedMechAceGLT.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedGLTAce.mul</fixedMul>
<fixedMul>AlliedGLTAce.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedMechAceGOL.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedGOLAce.mul</fixedMul>
<fixedMul>AlliedGOLAce.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedMechAceOTT.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedOTTAce.mul</fixedMul>
<fixedMul>AlliedOTTAce.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/AlliedMechAceTBT.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<fixedUnitCount>4</fixedUnitCount>
<forceName>Allied Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>AlliedTBTAce.mul</fixedMul>
<fixedMul>AlliedTBTAce.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>0</retreatThreshold>
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/data/scenariomodifiers/ArmednArmored.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
<eventTiming>PreForceGeneration</eventTiming>
<eventRecipient>Opposing</eventRecipient>
<qualityAdjustment>1</qualityAdjustment>
<bvBudgetAdditiveMultiplier>-1</bvBudgetAdditiveMultiplier>
<bvBudgetAdditiveMultiplier>-1</bvBudgetAdditiveMultiplier>
</AtBScenarioModifier>
4 changes: 2 additions & 2 deletions MekHQ/data/scenariomodifiers/EnemyAceMechARC2R.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
<forceAlignment>2</forceAlignment>
<forceName>Enemy Mech Ace</forceName>
<generationMethod>5</generationMethod>
<fixedMul>aceARC2R.mul</fixedMul>
<fixedMul>aceARC2R.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>75</retreatThreshold>
<startingAltitude>0</startingAltitude>
<objectiveLinkedForces>
Expand Down
4 changes: 2 additions & 2 deletions MekHQ/data/scenariomodifiers/EnemyFieldArtyOffboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
<forceAlignment>2</forceAlignment>
<forceName>Enemy Offboard Field Arty</forceName>
<generationMethod>5</generationMethod>
<fixedMul>EnemyOffFieldArty.mul</fixedMul>
<fixedMul>EnemyOffFieldArty.mul</fixedMul>
<generationOrder>1</generationOrder>
<maxWeightClass>4</maxWeightClass>
<maxWeightClass>4</maxWeightClass>
<retreatThreshold>75</retreatThreshold>
<startingAltitude>0</startingAltitude>
<objectiveLinkedForces>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>2</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Opfor Aerospace Reinforcements</forceName>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>2</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Opfor Ground Reinforcements</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PiratesIncomingAir.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>3</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Unidentified Hostiles</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PiratesIncomingGround.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>3</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Unidentified Hostiles</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PiratesPresentAir.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>3</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Unidentified Hostiles</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PiratesPresentGround.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</deploymentZones>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>3</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Unidentified Hostiles</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PrimaryAlliesAir.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<deploymentZones/>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>1</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Allied Force</forceName>
Expand Down
1 change: 1 addition & 0 deletions MekHQ/data/scenariomodifiers/PrimaryAlliesGround.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<deploymentZones/>
<destinationZone>5</destinationZone>
<fixedUnitCount>-1</fixedUnitCount>
<overrideBvCap>true</overrideBvCap>
<forceAlignment>1</forceAlignment>
<forceMultiplier>1.0</forceMultiplier>
<forceName>Allied Force</forceName>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,13 @@ chkUseStratCon.text=Use StratCon campaign rules
chkUseStratCon.toolTipText=An update of the AtB ruleset. Highly experimental.
lblSkillLevel.text=Skill Level
lblSkillLevel.toolTipText=<html>This is the difficulty level for generated scenarios. <br>Values above Elite are not recommended.</html>
lblScenarioMod.text=Random Scenario Modifiers
lblScenarioModMax.text=Maximum:
lblScenarioModMax.toolTipText=This is the maximum number of random scenario mods that can spawn on for a single Scenario. Excludes fixed modifiers.
lblScenarioModChance.text=Chance
lblScenarioModChance.toolTipText=This is the percentage chance for a random scenario mod to appear for a Scenario.
lblScenarioModBV.text=BV Cap
lblScenarioModBV.toolTipText=This is the percentage of total BV that can be used for each scenario mods. This affects fixed modifiers, but can be overridden by certain modifiers
chkUseShareSystem.text=Use share system
chkUseShareSystem.toolTipText=All personnel have a stake in the unit. This system lowers profits but can increase retention.
chkSharesExcludeLargeCraft.text=Exclude large craft from share value
Expand Down
39 changes: 39 additions & 0 deletions MekHQ/src/mekhq/campaign/CampaignOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,9 @@ public static String getTransitUnitName(final int unit) {
private boolean usePlanetaryConditions;
private int fixedMapChance;
private int spaUpgradeIntensity;
private int scenarioModMax;
private int scenarioModChance;
private int scenarioModBV;
//endregion Against the Bot Tab
//endregion Variable Declarations

Expand Down Expand Up @@ -1094,6 +1097,9 @@ public CampaignOptions() {
useWeatherConditions = true;
useLightConditions = true;
usePlanetaryConditions = false;
setScenarioModMax(3);
setScenarioModChance(25);
setScenarioModBV(50);
//endregion Against the Bot Tab
}
//endregion Constructors
Expand Down Expand Up @@ -4007,6 +4013,30 @@ public void setSpaUpgradeIntensity(final int spaUpgradeIntensity) {
this.spaUpgradeIntensity = spaUpgradeIntensity;
}

public int getScenarioModMax() {
return scenarioModMax;
}

public void setScenarioModMax(final int scenarioModMax) {
this.scenarioModMax = scenarioModMax;
}

public int getScenarioModChance() {
return scenarioModChance;
}

public void setScenarioModChance(final int scenarioModChance) {
this.scenarioModChance = scenarioModChance;
}

public int getScenarioModBV() {
return scenarioModBV;
}

public void setScenarioModBV(final int scenarioModBV) {
this.scenarioModBV = scenarioModBV;
}

//region File IO
public void writeToXml(final PrintWriter pw, int indent) {
MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "campaignOptions");
Expand Down Expand Up @@ -4451,6 +4481,9 @@ public void writeToXml(final PrintWriter pw, int indent) {
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "opForLocalUnitChance", getOpForLocalUnitChance());
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "fixedMapChance", fixedMapChance);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "spaUpgradeIntensity", spaUpgradeIntensity);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "scenarioModMax", scenarioModMax);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "scenarioModChance", scenarioModChance);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "scenarioModBV", scenarioModBV);

MHQXMLUtility.writeSimpleXMLTag(pw, indent, "planetTechAcquisitionBonus", planetTechAcquisitionBonus);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "planetIndustryAcquisitionBonus", planetIndustryAcquisitionBonus);
Expand Down Expand Up @@ -5389,6 +5422,12 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve
retVal.fixedMapChance = Integer.parseInt(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("spaUpgradeIntensity")) {
retVal.setSpaUpgradeIntensity(Integer.parseInt(wn2.getTextContent().trim()));
} else if (wn2.getNodeName().equalsIgnoreCase("scenarioModMax")) {
retVal.setScenarioModMax(Integer.parseInt(wn2.getTextContent().trim()));
} else if (wn2.getNodeName().equalsIgnoreCase("scenarioModChance")) {
retVal.setScenarioModChance(Integer.parseInt(wn2.getTextContent().trim()));
} else if (wn2.getNodeName().equalsIgnoreCase("scenarioModBV")) {
retVal.setScenarioModBV(Integer.parseInt(wn2.getTextContent().trim()));

//region Legacy
// Removed in 0.49.*
Expand Down
74 changes: 53 additions & 21 deletions MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
import megamek.codeUtilities.StringUtility;
import megamek.common.*;
import megamek.common.annotations.Nullable;
import megamek.common.planetaryconditions.Atmosphere;
import megamek.common.enums.Gender;
import megamek.common.enums.SkillLevel;
import megamek.common.icons.Camouflage;
import megamek.common.planetaryconditions.Atmosphere;
import megamek.common.util.fileUtils.MegaMekFile;
import megamek.utilities.BoardClassifier;
import mekhq.MHQConstants;
Expand Down Expand Up @@ -82,7 +82,7 @@ public class AtBDynamicScenarioFactory {
BombType.B_LG, BombType.B_ARROW, BombType.B_HOMING, BombType.B_TAG };
private static final int[] validBotAABombs = { BombType.B_RL, BombType.B_LAA, BombType.B_AAA };

private static final int[] minimumBVPercentage = { 50, 60, 70, 80, 90, 100 };
private static final int[] minimumBVPercentage = { 50, 55, 60, 70, 75, 80 };
// target number for 2d6 roll of infantry being upgraded to battle armor, indexed by dragoons rating
private static final int[] infantryToBAUpgradeTNs = { 12, 10, 8, 6, 4, 2 };

Expand Down Expand Up @@ -256,7 +256,7 @@ private static int generateForces(AtBDynamicScenario scenario, AtBContract contr
generatedLanceCount += generateFixedForce(scenario, contract, campaign, forceTemplate);
} else {
generatedLanceCount += generateForce(scenario, contract, campaign,
effectiveBV, effectiveUnitCount, weightClass, forceTemplate);
effectiveBV, effectiveUnitCount, weightClass, forceTemplate, false);
}
}
}
Expand Down Expand Up @@ -314,10 +314,12 @@ public static int generateFixedForce(AtBDynamicScenario scenario, AtBContract co
* @param effectiveUnitCount The effective unit count, up to this point, of player and allied units
* @param weightClass The maximum weight class of the units to generate (ignored )
* @param forceTemplate The force template to use to generate the force
* @param isScenarioModifier true if the source of generateForce() was a scenario modifier
* @return How many "lances" or other individual units were generated.
*/
public static int generateForce(AtBDynamicScenario scenario, AtBContract contract, Campaign campaign,
int effectiveBV, int effectiveUnitCount, int weightClass, ScenarioForceTemplate forceTemplate) {
int effectiveBV, int effectiveUnitCount, int weightClass,
ScenarioForceTemplate forceTemplate, boolean isScenarioModifier) {
// don't generate forces flagged as player-supplied
if (forceTemplate.getGenerationMethod() == ForceGenerationMethod.PlayerSupplied.ordinal()) {
return 0;
Expand Down Expand Up @@ -370,8 +372,19 @@ public static int generateForce(AtBDynamicScenario scenario, AtBContract contrac

// determine generation parameters
int forceBV = 0;

double forceMultiplier = getDifficultyMultiplier(campaign);
forceTemplate.setForceMultiplier(forceMultiplier);

int forceBVBudget = (int) (effectiveBV * forceTemplate.getForceMultiplier());

if ((isScenarioModifier) && (forceTemplate.getOverrideBvCap())) {
LogManager.getLogger().info("{} is overriding the BV Cap", forceTemplate);
forceBVBudget = forceBVBudget * campaign.getCampaignOptions().getScenarioModBV();
}

int forceUnitBudget = 0;

if (forceTemplate.getGenerationMethod() == ForceGenerationMethod.UnitCountScaled.ordinal()) {
forceUnitBudget = (int) (effectiveUnitCount * forceTemplate.getForceMultiplier());
} else if ((forceTemplate.getGenerationMethod() == ForceGenerationMethod.FixedUnitCount.ordinal()) ||
Expand Down Expand Up @@ -500,10 +513,22 @@ public static int generateForce(AtBDynamicScenario scenario, AtBContract contrac
}

// chop out random units until we drop down to our unit count budget
while (forceUnitBudget > 0 && generatedEntities.size() > forceUnitBudget) {
while ((forceUnitBudget > 0) && (generatedEntities.size() > forceUnitBudget)) {
generatedEntities.remove(Compute.randomInt(generatedEntities.size()));
}

if (forceTemplate.getGenerationMethod() == ForceGenerationMethod.BVScaled.ordinal()) {
// remove random units until forceBV is below 125% of forceBVBudget
while ((generatedEntities.size() > 1) && (((double) forceBV / forceBVBudget)) > 1.25) {
generatedEntities.remove(Compute.randomInt(generatedEntities.size()));

// update forceBV
forceBV += generatedEntities.stream()
.mapToInt(Entity::calculateBattleValue)
.sum();
}
}

// "flavor" feature - fill up APCs with infantry
List<Entity> transportedEntities = fillTransports(scenario, generatedEntities, factionCode, skill, quality, campaign);
generatedEntities.addAll(transportedEntities);
Expand Down Expand Up @@ -890,26 +915,33 @@ private static void setScenarioMap(AtBDynamicScenario scenario, int mapChance) {
*
* @param scenario
*/
public static void setScenarioModifiers(AtBDynamicScenario scenario) {
// this is hardcoded for now, but the eventual plan is to let the user configure how many modifiers
// they want applied
int numModsRoll = Compute.d6(2);
public static void setScenarioModifiers(Campaign campaign, AtBDynamicScenario scenario) {
int numMods = 0;
if (numModsRoll >= 11) {
numMods = 3;
} else if (numModsRoll >= 9) {
numMods = 2;
} else if (numModsRoll >= 7) {
numMods = 1;
}
boolean addMods = true;
int modMax = campaign.getCampaignOptions().getScenarioModMax();
int modChance = campaign.getCampaignOptions().getScenarioModChance() - 1;

for (int x = 0; x < numMods; x++) {
AtBScenarioModifier scenarioMod = AtBScenarioModifier.getRandomBattleModifier(scenario.getTemplate().mapParameters.getMapLocation());
if (modMax != 0) {
while (addMods) {
if (Compute.randomInt(100) >= modChance) {
numMods++;

scenario.addScenarioModifier(scenarioMod);
if (numMods >= modMax) {
addMods = false;
}
} else {
addMods = false;
}
}

if (scenarioMod.getBlockFurtherEvents()) {
break;
for (int x = 0; x < numMods; x++) {
AtBScenarioModifier scenarioMod = AtBScenarioModifier.getRandomBattleModifier(scenario.getTemplate().mapParameters.getMapLocation());

scenario.addScenarioModifier(scenarioMod);

if (scenarioMod.getBlockFurtherEvents()) {
break;
}
}
}
}
Expand Down
Loading
Loading