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

Refactored Morale Calculations and Logging #5266

Merged
merged 1 commit into from
Dec 2, 2024
Merged
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
33 changes: 26 additions & 7 deletions MekHQ/src/mekhq/campaign/mission/AtBContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,9 @@ public void checkMorale(Campaign campaign, LocalDate today) {
}

TargetRoll targetNumber = new TargetRoll();
logger.info("Making Morale Check");
logger.info(String.format("Current Morale: %s (%s)",
getMoraleLevel().toString(), getMoraleLevel().ordinal()));

// Confidence:
int enemySkillRating = getEnemySkill().getAdjustedValue() - 2;
Expand All @@ -485,6 +488,7 @@ public void checkMorale(Campaign campaign, LocalDate today) {

int confidence = enemySkillRating - allySkillRating;
targetNumber.addModifier(confidence, "confidence");
logger.info(String.format("Confidence: %s", confidence >= 0 ? "+" + confidence : confidence));

// Reliability:
int reliability = getEnemyQuality();
Expand Down Expand Up @@ -531,6 +535,7 @@ public void checkMorale(Campaign campaign, LocalDate today) {
}

targetNumber.addModifier(reliability, "reliability");
logger.info(String.format("Reliability: %s", reliability >= 0 ? "+" + reliability : reliability));

// Force Type (unimplemented)
// TODO once we have force types defined on the StratCon map, we should handle modifiers here.
Expand Down Expand Up @@ -566,32 +571,46 @@ public void checkMorale(Campaign campaign, LocalDate today) {

int performanceModifier = 0;

if (victories >= (defeats * 2)) {
performanceModifier -= 4;
} else if (victories > defeats) {
performanceModifier -= 2;
} else if (defeats >= (victories * 2)) {
performanceModifier += 4;
if (victories > defeats) {
if (victories >= (defeats * 2)) {
performanceModifier -= 4;
} else {
performanceModifier -= 2;
}
} else if (defeats > victories) {
performanceModifier += 2;
if (defeats >= (victories * 2)) {
performanceModifier += 4;
} else {
performanceModifier += 2;
}
}

targetNumber.addModifier(performanceModifier, "performanceModifier");
logger.info(String.format("Performance: %s", performanceModifier >= 0 ?
"+" + performanceModifier : performanceModifier));

// Total morale modifier calculation
int roll = Compute.d6(2) + targetNumber.getValue();
logger.info(String.format("Total Modifier: %s", targetNumber.getValue()));
logger.info(String.format("Roll: %s", roll));

// Morale level determination based on roll value
final AtBMoraleLevel[] moraleLevels = AtBMoraleLevel.values();

if (roll < 2) {
setMoraleLevel(moraleLevels[Math.max(getMoraleLevel().ordinal() - 2, 0)]);
logger.info("Result: Morale Level -2");
} else if (roll < 5) {
setMoraleLevel(moraleLevels[Math.max(getMoraleLevel().ordinal() - 1, 0)]);
logger.info("Result: Morale Level -1");
} else if ((roll > 12)) {
setMoraleLevel(moraleLevels[Math.min(getMoraleLevel().ordinal() + 2, moraleLevels.length - 1)]);
logger.info("Result: Morale Level +1");
} else if ((roll > 9)) {
setMoraleLevel(moraleLevels[Math.min(getMoraleLevel().ordinal() + 1, moraleLevels.length - 1)]);
logger.info("Result: Morale Level +2");
} else {
logger.info("Result: Morale Unchanged");
}

// Additional morale updates if morale level is set to 'Routed' and contract type is a garrison type
Expand Down
30 changes: 23 additions & 7 deletions MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import mekhq.campaign.mission.ScenarioMapParameters.MapLocation;
import mekhq.campaign.mission.atb.AtBScenarioModifier;
import mekhq.campaign.mission.atb.AtBScenarioModifier.EventTiming;
import mekhq.campaign.mission.enums.AtBMoraleLevel;
import mekhq.campaign.personnel.Person;
import mekhq.campaign.personnel.SkillType;
import mekhq.campaign.personnel.turnoverAndRetention.Fatigue;
Expand All @@ -52,6 +53,7 @@
import java.util.*;
import java.util.stream.Collectors;

import static java.lang.Math.round;
import static mekhq.campaign.force.Force.FORCE_NONE;
import static mekhq.campaign.mission.ScenarioMapParameters.MapLocation.AllGroundTerrain;
import static mekhq.campaign.mission.ScenarioMapParameters.MapLocation.LowAtmosphere;
Expand Down Expand Up @@ -115,18 +117,30 @@
// multiplies the BV budget of all
int scenarioRolls = track.getRequiredLanceCount();

if (contract.getMoraleLevel().isDominating()) {
scenarioRolls++;
} else if (contract.getMoraleLevel().isOverwhelming()) {
scenarioRolls += 2;
if (!autoAssignLances) {
AtBMoraleLevel moraleLevel = contract.getMoraleLevel();

switch (moraleLevel) {
Dismissed Show dismissed Hide dismissed
case STALEMATE -> scenarioRolls = (int) round(scenarioRolls * 1.25);
case ADVANCING -> scenarioRolls = (int) round(scenarioRolls * 1.5);
case DOMINATING -> scenarioRolls = scenarioRolls * 2;
case OVERWHELMING -> scenarioRolls = scenarioRolls * 3;
}
}

for (int scenarioIndex = 0; scenarioIndex < scenarioRolls; scenarioIndex++) {
if (autoAssignLances && availableForceIDs.isEmpty()) {
break;
}

int targetNum = calculateScenarioOdds(track, contract, false);
int roll = Compute.randomInt(100);

logger.info(String.format("StratCon Weekly Scenario Roll: %s vs. %s", roll, targetNum));

// if we haven't already used all the player forces and are required to randomly
// generate a scenario
if (!availableForceIDs.isEmpty() && (Compute.randomInt(100) < targetNum)) {
if (roll < targetNum) {
// pick random coordinates and force to drive the scenario
StratconCoords scenarioCoords = getUnoccupiedCoords(track, true);

Expand All @@ -151,9 +165,11 @@
int randomForceIndex = Compute.randomInt(availableForceIDs.size());
int randomForceID = availableForceIDs.get(randomForceIndex);

// remove the force from the available lists so we don't designate it as primary
// remove the force from the available lists, so we don't designate it as primary
// twice
availableForceIDs.remove(randomForceIndex);
if (autoAssignLances) {
availableForceIDs.remove(randomForceIndex);
}

// we want to remove the actual int with the value, not the value at the index
sortedAvailableForceIDs.get(AllGroundTerrain).remove((Integer) randomForceID);
Expand Down