Skip to content

Commit f04ce8d

Browse files
authored
Merge pull request #6076 from IllianiCBT/campaignOptionsPaymentIssues
Added Reputation Sanity Options to Campaign Settings
2 parents fc8d47d + fcc41bf commit f04ce8d

File tree

9 files changed

+152
-12
lines changed

9 files changed

+152
-12
lines changed

MekHQ/mmconf/campaignPresets/CampaignOperations.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<gm>true</gm>
88
<campaignOptions>
99
<manualUnitRatingModifier>0</manualUnitRatingModifier>
10+
<clampReputationPayMultiplier>false</clampReputationPayMultiplier>
11+
<reduceReputationPerformanceModifier>false</reduceReputationPerformanceModifier>
12+
<reputationPerformanceModifierCutOff>false</reputationPerformanceModifierCutOff>
1013
<logMaintenance>false</logMaintenance>
1114
<defaultMaintenanceTime>4</defaultMaintenanceTime>
1215
<mrmsUseRepair>true</mrmsUseRepair>

MekHQ/mmconf/campaignPresets/CampaignOperationsStratCon.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<gm>true</gm>
88
<campaignOptions>
99
<manualUnitRatingModifier>0</manualUnitRatingModifier>
10+
<clampReputationPayMultiplier>false</clampReputationPayMultiplier>
11+
<reduceReputationPerformanceModifier>false</reduceReputationPerformanceModifier>
12+
<reputationPerformanceModifierCutOff>false</reputationPerformanceModifierCutOff>
1013
<logMaintenance>false</logMaintenance>
1114
<defaultMaintenanceTime>4</defaultMaintenanceTime>
1215
<mrmsUseRepair>true</mrmsUseRepair>

MekHQ/mmconf/campaignPresets/NewPilotProgram.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<gm>false</gm>
88
<campaignOptions>
99
<manualUnitRatingModifier>0</manualUnitRatingModifier>
10+
<clampReputationPayMultiplier>true</clampReputationPayMultiplier>
11+
<reduceReputationPerformanceModifier>true</reduceReputationPerformanceModifier>
12+
<reputationPerformanceModifierCutOff>true</reputationPerformanceModifierCutOff>
1013
<logMaintenance>false</logMaintenance>
1114
<defaultMaintenanceTime>4</defaultMaintenanceTime>
1215
<mrmsUseRepair>true</mrmsUseRepair>

MekHQ/mmconf/campaignPresets/TheCompleteExperience.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
<gm>false</gm>
99
<campaignOptions>
1010
<manualUnitRatingModifier>0</manualUnitRatingModifier>
11+
<clampReputationPayMultiplier>true</clampReputationPayMultiplier>
12+
<reduceReputationPerformanceModifier>true</reduceReputationPerformanceModifier>
13+
<reputationPerformanceModifierCutOff>true</reputationPerformanceModifierCutOff>
1114
<logMaintenance>false</logMaintenance>
1215
<defaultMaintenanceTime>4</defaultMaintenanceTime>
1316
<mrmsUseRepair>true</mrmsUseRepair>

MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,35 @@ lblReputation.tooltip=Which reputation method should your campaign be graded aga
5757
<br><b>Recommended:</b> Campaign Operations
5858
lblManualUnitRatingModifier.text=Manual Modifier
5959
lblManualUnitRatingModifier.tooltip=This allows you to manually adjust your reputation rating.
60+
lblClampReputationPayMultiplier.text=Clamp Reputation Pay Multiplier \u26A0 \u2714
61+
lblClampReputationPayMultiplier.tooltip=When using CamOps Reputation your unit's reputation score\
62+
\ affects contract pay. This option clamps the reputation-based multiplier between 50 and 200%.\
63+
<br>\
64+
<br><b>Warning:</b> As CamOps Reputation has no maximum or minimum value disabling this option\
65+
\ will result in contract pay becoming increasingly inflated as the campaign progresses. This is\
66+
\ particularly a problem for generational campaigns expected to last decades or longer.\
67+
<br>\
68+
<br><b>Recommended</b>: Leave enabled.
69+
lblReduceReputationPerformanceModifier.text=Reduce Mission Performance Score \u26A0 \u2714
70+
lblReduceReputationPerformanceModifier.tooltip=When using CamOps Reputation your unit's past\
71+
\ contract performance affects contract pay. This option reduces the impact of successes,\
72+
\ failures, and breaches by 80%.\
73+
<br>\
74+
<br><b>Warning:</b> CamOps was never designed for the kind of contract tempo we can achieve\
75+
\ through MekHQ. Resulting in longer campaigns reaching astronomical heights in terms of\
76+
\ Reputation. This has knock-on effects whenever Reputation is used to influence a system.\
77+
<br>\
78+
<br><b>Recommended</b>: This option helps slow growth to more sane levels. Leave enabled.
79+
lblReputationPerformanceModifierCutOff.text=Ignore Old Missions \u26A0 \u2714
80+
lblReputationPerformanceModifierCutOff.tooltip=When using CamOps Reputation all past contracts\
81+
\ affect future contract pay. This option tells MekHQ to ignore any contracts that were completed\
82+
\ over a decade ago. Only Legacy AtB and StratCon contracts are affected.\
83+
<br>\
84+
<br><b>Warning:</b> CamOps was never designed for campaigns lasting as long as those enjoyed by\
85+
\ many users of MekHQ. This results in progressive Reputation bloat over a long enough period.\
86+
<br>\
87+
<br><b>Recommended</b>: This option helps ensure reputation doesn't spiral out of control. Leave\
88+
\ enabled.
6089
lblDate.text=Start Date
6190
lblDate.tooltip=When should the campaign begin?
6291
lblCamo.text=Unit Camouflage

MekHQ/src/mekhq/campaign/CampaignOptions.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ public class CampaignOptions {
7979
public static final double MAXIMUM_JUMPSHIP_EQUIPMENT_PERCENT = 1.0;
8080
public static final double MAXIMUM_WARSHIP_EQUIPMENT_PERCENT = 1.0;
8181

82+
public static final int REPUTATION_PERFORMANCE_CUT_OFF_YEARS = 10;
83+
8284
public static String getTechLevelName(final int techLevel) {
8385
return switch (techLevel) {
8486
case TECH_INTRO -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_INTRO];
@@ -95,6 +97,9 @@ public static String getTechLevelName(final int techLevel) {
9597
// region General Tab
9698
private UnitRatingMethod unitRatingMethod;
9799
private int manualUnitRatingModifier;
100+
private boolean clampReputationPayMultiplier;
101+
private boolean reduceReputationPerformanceModifier;
102+
private boolean reputationPerformanceModifierCutOff;
98103
// endregion General Tab
99104

100105
// region Repair and Maintenance Tab
@@ -599,6 +604,9 @@ public CampaignOptions() {
599604
// region General Tab
600605
unitRatingMethod = UnitRatingMethod.CAMPAIGN_OPS;
601606
manualUnitRatingModifier = 0;
607+
clampReputationPayMultiplier = false;
608+
reduceReputationPerformanceModifier = false;
609+
reputationPerformanceModifierCutOff = false;
602610
// endregion General Tab
603611

604612
// region Repair and Maintenance Tab
@@ -1217,6 +1225,30 @@ public int getManualUnitRatingModifier() {
12171225
public void setManualUnitRatingModifier(final int manualUnitRatingModifier) {
12181226
this.manualUnitRatingModifier = manualUnitRatingModifier;
12191227
}
1228+
1229+
public boolean isClampReputationPayMultiplier() {
1230+
return clampReputationPayMultiplier;
1231+
}
1232+
1233+
public void setClampReputationPayMultiplier(final boolean clampReputationPayMultiplier) {
1234+
this.clampReputationPayMultiplier = clampReputationPayMultiplier;
1235+
}
1236+
1237+
public boolean isReduceReputationPerformanceModifier() {
1238+
return reduceReputationPerformanceModifier;
1239+
}
1240+
1241+
public void setReduceReputationPerformanceModifier(final boolean reduceReputationPerformanceModifier) {
1242+
this.reduceReputationPerformanceModifier = reduceReputationPerformanceModifier;
1243+
}
1244+
1245+
public boolean isReputationPerformanceModifierCutOff() {
1246+
return reputationPerformanceModifierCutOff;
1247+
}
1248+
1249+
public void setReputationPerformanceModifierCutOff(final boolean reputationPerformanceModifierCutOff) {
1250+
this.reputationPerformanceModifierCutOff = reputationPerformanceModifierCutOff;
1251+
}
12201252
// endregion General Tab
12211253

12221254
// region Repair and Maintenance Tab
@@ -4539,6 +4571,9 @@ public void writeToXml(final PrintWriter pw, int indent) {
45394571
MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "campaignOptions");
45404572
// region General Tab
45414573
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "manualUnitRatingModifier", getManualUnitRatingModifier());
4574+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "clampReputationPayMultiplier", isClampReputationPayMultiplier());
4575+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "reduceReputationPerformanceModifier", isReduceReputationPerformanceModifier());
4576+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "reputationPerformanceModifierCutOff", isReputationPerformanceModifierCutOff());
45424577
// endregion General Tab
45434578

45444579
// region Repair and Maintenance Tab
@@ -5265,6 +5300,12 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve
52655300
retVal.setUnitRatingMethod(UnitRatingMethod.parseFromString(wn2.getTextContent().trim()));
52665301
} else if (wn2.getNodeName().equalsIgnoreCase("manualUnitRatingModifier")) {
52675302
retVal.setManualUnitRatingModifier(Integer.parseInt(wn2.getTextContent()));
5303+
} else if (wn2.getNodeName().equalsIgnoreCase("clampReputationPayMultiplier")) {
5304+
retVal.setClampReputationPayMultiplier(Boolean.parseBoolean(wn2.getTextContent()));
5305+
} else if (wn2.getNodeName().equalsIgnoreCase("reduceReputationPerformanceModifier")) {
5306+
retVal.setReduceReputationPerformanceModifier(Boolean.parseBoolean(wn2.getTextContent()));
5307+
} else if (wn2.getNodeName().equalsIgnoreCase("reputationPerformanceModifierCutOff")) {
5308+
retVal.setReputationPerformanceModifierCutOff(Boolean.parseBoolean(wn2.getTextContent()));
52685309
} else if (wn2.getNodeName().equalsIgnoreCase("usePortraitForType")) {
52695310
String[] values = wn2.getTextContent().split(",");
52705311
for (int i = 0; i < values.length; i++) {

MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import megamek.logging.MMLogger;
2828
import mekhq.MekHQ;
2929
import mekhq.campaign.Campaign;
30+
import mekhq.campaign.CampaignOptions;
3031
import mekhq.campaign.JumpPath;
3132
import mekhq.campaign.market.enums.ContractMarketMethod;
3233
import mekhq.campaign.mission.AtBContract;
@@ -43,9 +44,9 @@
4344
import java.util.Set;
4445

4546
import static java.lang.Math.floor;
46-
import static mekhq.campaign.mission.AtBContract.getEffectiveNumUnits;
47-
47+
import static megamek.codeUtilities.MathUtility.clamp;
4848
import static megamek.common.Compute.d6;
49+
import static mekhq.campaign.mission.AtBContract.getEffectiveNumUnits;
4950
import static mekhq.campaign.randomEvents.GrayMonday.isGrayMonday;
5051

5152
/**
@@ -495,6 +496,7 @@ private void addFollowup(Campaign campaign,
495496

496497
@Override
497498
public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract) {
499+
CampaignOptions campaignOptions = campaign.getCampaignOptions();
498500
double multiplier = 1.0;
499501

500502
// Operations tempo
@@ -512,8 +514,14 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract
512514
}
513515

514516
// Reputation multiplier
515-
if (campaign.getCampaignOptions().getUnitRatingMethod().isCampaignOperations()) {
516-
multiplier *= (campaign.getReputation().getReputationModifier() * 0.2) + 0.5;
517+
if (campaignOptions.getUnitRatingMethod().isCampaignOperations()) {
518+
double reputationFactor = campaign.getReputation().getReputationFactor();
519+
520+
if (campaignOptions.isClampReputationPayMultiplier()) {
521+
reputationFactor = clamp(reputationFactor, 0.5, 2.0);
522+
}
523+
524+
multiplier *= reputationFactor;
517525
} else {
518526
int unitRatingMod = campaign.getAtBUnitRatingMod();
519527
if (unitRatingMod >= IUnitRating.DRAGOON_A) {

MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CombatRecordRating.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@
1818
*/
1919
package mekhq.campaign.rating.CamOpsReputation;
2020

21+
import megamek.logging.MMLogger;
22+
import mekhq.campaign.Campaign;
23+
import mekhq.campaign.mission.AtBContract;
24+
import mekhq.campaign.mission.Mission;
25+
import mekhq.campaign.mission.enums.MissionStatus;
26+
27+
import java.time.LocalDate;
2128
import java.time.temporal.ChronoUnit;
2229
import java.util.HashMap;
2330
import java.util.Map;
2431
import java.util.stream.Collectors;
2532

26-
import megamek.logging.MMLogger;
27-
import mekhq.campaign.Campaign;
28-
import mekhq.campaign.mission.Mission;
29-
import mekhq.campaign.mission.enums.MissionStatus;
33+
import static mekhq.campaign.CampaignOptions.REPUTATION_PERFORMANCE_CUT_OFF_YEARS;
3034

3135
public class CombatRecordRating {
3236
private static final MMLogger logger = MMLogger.create(CombatRecordRating.class);
@@ -65,9 +69,25 @@ protected static Map<String, Integer> calculateCombatRecordRating(Campaign campa
6569
}
6670

6771
// Construct a map with mission statuses and their counts
68-
Map<MissionStatus, Long> missionCountsByStatus = campaign.getCompletedMissions().stream()
69-
.filter(mission -> mission.getStatus() != MissionStatus.ACTIVE)
70-
.collect(Collectors.groupingBy(Mission::getStatus, Collectors.counting()));
72+
boolean usePerformanceCutOff = campaign.getCampaignOptions().isReputationPerformanceModifierCutOff();
73+
LocalDate cutOffDate = campaign.getLocalDate().minusYears(REPUTATION_PERFORMANCE_CUT_OFF_YEARS);
74+
Map<MissionStatus, Long> missionCountsByStatus = new HashMap<>();
75+
for (Mission mission : campaign.getCompletedMissions()) {
76+
if (mission.getStatus() == MissionStatus.ACTIVE) {
77+
continue;
78+
}
79+
80+
if (usePerformanceCutOff) {
81+
if (mission instanceof AtBContract) {
82+
if (((AtBContract) mission).getEndingDate().isBefore(cutOffDate)) {
83+
continue;
84+
}
85+
}
86+
}
87+
88+
missionCountsByStatus.put(mission.getStatus(),
89+
missionCountsByStatus.getOrDefault(mission.getStatus(), 0L) + 1);
90+
}
7191

7292
// Assign mission counts to each category
7393
int successes = missionCountsByStatus.getOrDefault(MissionStatus.SUCCESS, 0L).intValue();
@@ -82,7 +102,14 @@ protected static Map<String, Integer> calculateCombatRecordRating(Campaign campa
82102
combatRecord.put("contractsBreached", contractBreaches);
83103

84104
// Calculate combat record rating
85-
int combatRecordRating = (successes * 5) - (failures * 10) - (contractBreaches * 25);
105+
boolean usePerformanceModifierReduction = campaign.getCampaignOptions().isReduceReputationPerformanceModifier();
106+
int successMultiplier = usePerformanceModifierReduction ? 1 : 5;
107+
int failureMultiplier = usePerformanceModifierReduction ? 2 : 10;
108+
int breachMultiplier = usePerformanceModifierReduction ? 5 : 25;
109+
110+
int combatRecordRating = (successes * successMultiplier)
111+
- (failures * failureMultiplier)
112+
- (contractBreaches * breachMultiplier);
86113

87114
// if the campaign has a retainer, check retainer duration
88115
if (campaign.getRetainerStartDate() != null) {

MekHQ/src/mekhq/gui/campaignOptions/contents/GeneralTab.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ public class GeneralTab {
8080
private MMComboBox<UnitRatingMethod> unitRatingMethodCombo;
8181
private JLabel lblManualUnitRatingModifier;
8282
private JSpinner manualUnitRatingModifier;
83+
private JCheckBox chkClampReputationPayMultiplier;
84+
private JCheckBox chkReduceReputationPerformanceModifier;
85+
private JCheckBox chkReputationPerformanceModifierCutOff;
8386
private JLabel lblDate;
8487
private JButton btnDate;
8588
private LocalDate date;
@@ -149,6 +152,9 @@ public AbstractMHQScrollablePanel createGeneralTab() {
149152
lblManualUnitRatingModifier = new CampaignOptionsLabel("ManualUnitRatingModifier");
150153
manualUnitRatingModifier = new CampaignOptionsSpinner("ManualUnitRatingModifier",
151154
0, -200, 200, 1);
155+
chkClampReputationPayMultiplier = new CampaignOptionsCheckBox("ClampReputationPayMultiplier");
156+
chkReduceReputationPerformanceModifier = new CampaignOptionsCheckBox("ReduceReputationPerformanceModifier");
157+
chkReputationPerformanceModifierCutOff = new CampaignOptionsCheckBox("ReputationPerformanceModifierCutOff");
152158

153159
// Date
154160
lblDate = new CampaignOptionsLabel("Date");
@@ -213,6 +219,13 @@ public AbstractMHQScrollablePanel createGeneralTab() {
213219
layout.gridy++;
214220
panel.add(lblManualUnitRatingModifier, layout);
215221
panel.add(manualUnitRatingModifier, layout);
222+
layout.gridy++;
223+
layout.gridwidth = 3;
224+
panel.add(chkClampReputationPayMultiplier, layout);
225+
layout.gridy++;
226+
panel.add(chkReduceReputationPerformanceModifier, layout);
227+
layout.gridy++;
228+
panel.add(chkReputationPerformanceModifierCutOff, layout);
216229

217230
layout.gridy++;
218231
layout.gridwidth = 5;
@@ -302,6 +315,10 @@ private void initialize() {
302315
lblManualUnitRatingModifier = new JLabel();
303316
manualUnitRatingModifier = new JSpinner();
304317

318+
chkClampReputationPayMultiplier = new JCheckBox();
319+
chkReduceReputationPerformanceModifier = new JCheckBox();
320+
chkReputationPerformanceModifierCutOff = new JCheckBox();
321+
305322
lblDate = new JLabel();
306323
btnDate = new JButton();
307324

@@ -498,6 +515,9 @@ public void loadValuesFromCampaignOptions(@Nullable CampaignOptions presetCampai
498515

499516
unitRatingMethodCombo.setSelectedItem(options.getUnitRatingMethod());
500517
manualUnitRatingModifier.setValue(options.getManualUnitRatingModifier());
518+
chkClampReputationPayMultiplier.setSelected(options.isClampReputationPayMultiplier());
519+
chkReduceReputationPerformanceModifier.setSelected(options.isReduceReputationPerformanceModifier());
520+
chkReputationPerformanceModifierCutOff.setSelected(options.isReputationPerformanceModifierCutOff());
501521

502522
date = campaign.getLocalDate();
503523
if (presetDate != null) {
@@ -554,5 +574,8 @@ public void applyCampaignOptionsToCampaign(@Nullable CampaignOptions presetCampa
554574

555575
options.setUnitRatingMethod(unitRatingMethodCombo.getSelectedItem());
556576
options.setManualUnitRatingModifier((int) manualUnitRatingModifier.getValue());
577+
options.setClampReputationPayMultiplier(chkClampReputationPayMultiplier.isSelected());
578+
options.setReduceReputationPerformanceModifier(chkReduceReputationPerformanceModifier.isSelected());
579+
options.setReputationPerformanceModifierCutOff(chkReputationPerformanceModifierCutOff.isSelected());
557580
}
558581
}

0 commit comments

Comments
 (0)