Skip to content

Commit

Permalink
Merge pull request #5900 from IllianiCBT/contractPayBug
Browse files Browse the repository at this point in the history
Fixed Negative Contract Base Pay
  • Loading branch information
IllianiCBT authored Jan 28, 2025
2 parents d52c827 + 486070e commit b249603
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
import java.util.ArrayList;
import java.util.Set;

import static java.lang.Math.floor;
import static megamek.codeUtilities.MathUtility.clamp;
import static mekhq.campaign.mission.AtBContract.getEffectiveNumUnits;

/**
* Contract offers that are generated monthly under AtB rules.
*
Expand Down Expand Up @@ -451,12 +455,16 @@ private void addFollowup(Campaign campaign,

@Override
public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract) {
int unitRatingMod = campaign.getAtBUnitRatingMod();
double multiplier = 1.0;
// IntOps reputation factor then Dragoons rating

// Operations tempo
multiplier *= contract.getContractType().getOperationsTempoMultiplier();

// Reputation multiplier
if (campaign.getCampaignOptions().getUnitRatingMethod().isCampaignOperations()) {
multiplier *= (unitRatingMod * 0.2) + 0.5;
multiplier *= (campaign.getReputation().getReputationRating() * 0.2) + 0.5;
} else {
int unitRatingMod = campaign.getAtBUnitRatingMod();
if (unitRatingMod >= IUnitRating.DRAGOON_A) {
multiplier *= 2.0;
} else if (unitRatingMod == IUnitRating.DRAGOON_B) {
Expand All @@ -468,8 +476,7 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract
}
}

multiplier *= contract.getContractType().getOperationsTempoMultiplier();

// Employer multiplier
final Faction employer = Factions.getInstance().getFaction(contract.getEmployerCode());
final Faction enemy = contract.getEnemy();
if (employer.isISMajorOrSuperPower() || employer.isClan()) {
Expand All @@ -484,28 +491,43 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract
multiplier *= 1.1;
}

// Unofficial modifiers
double unofficialMultiplier = getUnofficialMultiplier(campaign, contract);

if (unofficialMultiplier > 0) {
multiplier *= (1.0 + unofficialMultiplier);
} else if (unofficialMultiplier < 0) {
multiplier *= (1.0 - unofficialMultiplier);
}

return multiplier;
}

private static double getUnofficialMultiplier(Campaign campaign, AtBContract contract) {
double modifier = 0; // we apply these modifiers all together to avoid spiking the final pay

// Adjust pay based on the percentage of the players' forces required by the contract
int maximumLanceCount = campaign.getAllCombatTeams().size();
int reserveLanceCount = (int) floor(maximumLanceCount / COMBAT_FORCE_DIVIDER);
int requiredCombatTeams = contract.getRequiredCombatTeams();
double totalCombatTeams = campaign.getAllCombatTeams().size();
totalCombatTeams /= COMBAT_FORCE_DIVIDER;

if (totalCombatTeams > 0) {
multiplier *= (double) requiredCombatTeams / totalCombatTeams;
if (reserveLanceCount > 0) { // Ensure we don't divide by zero
double reservesDifference = ((requiredCombatTeams - reserveLanceCount) / (double) reserveLanceCount);

modifier += reservesDifference;
}

// Adjust pay based on difficulty if FG3 is enabled
if (campaign.getCampaignOptions().isUseGenericBattleValue()) {
double skulls = contract.calculateContractDifficulty(campaign);
skulls -= 5; // 5 skulls (or 2.5) is equivalent to the player force, so no modifier.
int difficulty = clamp(contract.calculateContractDifficulty(campaign), 0, 10);
int baseDifficulty = 5; // 2.5 skulls

if (skulls != 0) {
skulls *= 0.05; // each half-skull is a 5% pay change
multiplier *= (1 + skulls);
}
}
double difficultyDifference = ((difficulty - baseDifficulty) / (double) baseDifficulty);

modifier += difficultyDifference;
}

return multiplier;
return modifier;
}

@Override
Expand Down Expand Up @@ -552,7 +574,7 @@ private void setContractClauses(AtBContract contract, int unitRatingMod, Campaig
if (campaign.getCampaignOptions().isMercSizeLimited() &&
campaign.getFaction().isMercenary()) {
int max = (unitRatingMod + 1) * 12;
int numMods = (AtBContract.getEffectiveNumUnits(campaign) - max) / 2;
int numMods = (getEffectiveNumUnits(campaign) - max) / 2;
while (numMods > 0) {
mods.mods[Compute.randomInt(4)]--;
numMods--;
Expand Down
32 changes: 29 additions & 3 deletions MekHQ/src/mekhq/campaign/mission/AtBContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -1944,10 +1944,36 @@ public JPanel getContractDifficultySkulls(Campaign campaign) {
}

/**
* Calculates the contract difficulty based on the given campaign and parameters.
* Calculates the difficulty of a contract based on the relative power of enemy forces,
* player forces, and any allied forces involved in the campaign.
*
* <p>The method evaluates the enemy's estimated power against the player's strengths
* and considers allied contributions depending on the assigned command rights.
* The result is a difficulty level mapped between 1 and 10, where higher values
* represent more challenging contracts.</p>
*
* @param campaign The {@link Campaign} object representing the current game state.
* Used to extract information about the player's forces, enemy forces,
* and allied forces.
*
* @return An integer representing the difficulty of the contract:
* <ul>
* <li>1 = very easy</li>
* <li>10 = extremely difficult</li>
* </ul>
* <p>
* <b>WARNING: </b>Returns `-99` (defined as `ERROR`) if the enemy's power cannot be calculated.
* </p>
* <p><b>Mapped Result Explanation:</b></p>
* The method divides the absolute percentage difference between enemy and player forces by 20
* (rounding up), then adjusts the difficulty accordingly:
* <ul>
* <li>If the player's forces are stronger, the difficulty is adjusted downward from a baseline of 5.</li>
* <li>If the enemy's forces are stronger, the difficulty is adjusted upward from a baseline of 5.</li>
* <li>If an error is encountered, the difficulty is returned as -99</li>
* </ul>
* The result is clamped to fit between the valid range of 1 and 10. Or -99 if an error is encounterd.
*
* @param campaign The campaign object containing the necessary data.
* @return The contract difficulty as an integer value.
*/
public int calculateContractDifficulty(Campaign campaign) {
final int ERROR = -99;
Expand Down

0 comments on commit b249603

Please sign in to comment.