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

Added Automatic Bonus Parts Exchange at Contract End, Added Bonus Parts Display to Mission Stats Panel #4149

Merged
merged 6 commits into from
Jun 8, 2024
4 changes: 3 additions & 1 deletion MekHQ/resources/mekhq/resources/CampaignGUI.properties
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,6 @@ lblFacilityCapacities.text=<html><nobr><b>Facility Capacities:</b></nobr></html>
panLog.title=Daily Activity Log

dialogCheckDueScenarios.text=You must complete scenarios with a date of today or earlier before advancing the day.
dialogCheckDueScenarios.title=Scenarios Must Be Completed
dialogCheckDueScenarios.title=Scenarios Must Be Completed

spareBonusPartExchange.text=Bonus Part Exchange Program
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,10 @@ chkGenerateChases.text=Generate Chase Scenarios
chkGenerateChases.toolTipText=If selected, AtB chase scenarios will be generated. Otherwise, they will be replaced with other scenarios formats depending on the lance role in question.
chkRestrictPartsByMission.text=Restrict parts by mission
chkRestrictPartsByMission.toolTipText=The availability of parts is limited based on the mission type of the current contract.
lblBonusPartExchangeValue.text=Bonus Part Exchange Value
lblBonusPartExchangeValue.toolTipText=At the end of an AtB Contract, any remaining Bonus Parts are converted into c-bills. This setting sets the value of each Bonus Part. Set to 0 to disable Bonus Part exchange.
lblBonusPartMaxExchangeCount.text=Bonus Part Maximum Exchange Count
lblBonusPartMaxExchangeCount.toolTipText=What is the maximum number of Bonus Parts that can be exchanged for c-bills at the end of an AtB Contract? Any Bonus Parts beyond this are lost. Set to 0 to apply no limit.
chkRegionalMechVariations.text=Varied weight distributions by faction
chkRegionalMechVariations.toolTipText=Use alternate weight class distributions for some factions.
chkAttachedPlayerCamouflage.text=Player-controlled allied units use player's camouflage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ lblAllyRating.text=<html><nobr><b>Ally Rating:</b></nobr></html>
lblEnemyRating.text=<html><nobr><b>Enemy Rating:</b></nobr></html>
lblMorale.text=<html><nobr><b>Enemy Morale:</b></nobr></html>
lblScore.text=<html><nobr><b>Contract Score:</b></nobr></html>
lblBonusParts.text=<html><nobr><b>Bonus Parts:</b></nobr></html>
lblDistance.text=<html><nobr><b>Days (Jumps) to Location:</b></nobr></html>
lblOverhead.text=<html><nobr><b>Overhead Compensation:</b></nobr></html>
lblSupport.text=<html><nobr><b>StraightSupport:</b></nobr></html>
Expand Down
2 changes: 2 additions & 0 deletions MekHQ/resources/mekhq/resources/Finances.properties
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ TransactionType.UNIT_PURCHASE.text=Unit Purchase(s)
TransactionType.UNIT_PURCHASE.toolTipText=A financial transaction where a unit was or multiple units were purchased.
TransactionType.UNIT_SALE.text=Unit Sale(s)
TransactionType.UNIT_SALE.toolTipText=A financial transaction where a unit was or multiple units were sold.
TransactionType.BONUS_EXCHANGE.text=Bonus Exchange
TransactionType.BONUS_EXCHANGE.toolTipText=A financial transaction where Bonus Parts were exchanged for c-bills.

## Finances Files
# Peacetime Operating Costs
Expand Down
6 changes: 5 additions & 1 deletion MekHQ/src/mekhq/campaign/Campaign.java
Original file line number Diff line number Diff line change
Expand Up @@ -658,12 +658,14 @@ public void purchaseShipSearchResult() {
}

MechFileParser mechFileParser;

try {
mechFileParser = new MechFileParser(ms.getSourceFile(), ms.getEntryName());
} catch (Exception ex) {
LogManager.getLogger().error("Unable to load unit: " + ms.getEntryName(), ex);
LogManager.getLogger().error("Unable to load unit: {}", ms.getEntryName(), ex);
return;
}

Entity en = mechFileParser.getEntity();

int transitDays = getCampaignOptions().isInstantUnitMarketDelivery() ? 0
Expand Down Expand Up @@ -1229,6 +1231,7 @@ public Unit addNewUnit(Entity en, boolean allowNewPilots, int days, int quality)
if (!unit.isRepairable()) {
unit.setSalvage(true);
}

unit.setDaysToArrival(days);

if (allowNewPilots) {
Expand All @@ -1237,6 +1240,7 @@ public Unit addNewUnit(Entity en, boolean allowNewPilots, int days, int quality)
newCrew.forEach((type, personnel) ->
personnel.forEach(p -> type.getAddMethod().accept(unit, p)));
}

unit.resetPilotAndEntity();

unit.setQuality(quality);
Expand Down
26 changes: 26 additions & 0 deletions MekHQ/src/mekhq/campaign/CampaignOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,8 @@ public static String getTransitUnitName(final int unit) {
// Contract Operations
private boolean mercSizeLimited;
private boolean restrictPartsByMission;
private int bonusPartExchangeValue = 500000;
private int bonusPartMaxExchangeCount = 10;
private boolean limitLanceWeight;
private boolean limitLanceNumUnits;
private boolean useStrategy;
Expand Down Expand Up @@ -1162,6 +1164,8 @@ public CampaignOptions() {
// Contract Operations
mercSizeLimited = false;
restrictPartsByMission = true;
bonusPartExchangeValue = 500000;
bonusPartMaxExchangeCount = 10;
limitLanceWeight = true;
limitLanceNumUnits = true;
useStrategy = true;
Expand Down Expand Up @@ -4353,6 +4357,22 @@ public void setRestrictPartsByMission(final boolean restrictPartsByMission) {
this.restrictPartsByMission = restrictPartsByMission;
}

public int getBonusPartExchangeValue() {
return bonusPartExchangeValue;
}

public void setBonusPartExchangeValue(final int bonusPartExchangeValue) {
this.bonusPartExchangeValue = bonusPartExchangeValue;
}

public int getBonusPartMaxExchangeCount() {
return bonusPartMaxExchangeCount;
}

public void setBonusPartMaxExchangeCount(final int bonusPartMaxExchangeCount) {
this.bonusPartMaxExchangeCount = bonusPartMaxExchangeCount;
}

public boolean isLimitLanceWeight() {
return limitLanceWeight;
}
Expand Down Expand Up @@ -4903,6 +4923,8 @@ public void writeToXml(final PrintWriter pw, int indent) {
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "additionalStrategyDeployment", additionalStrategyDeployment);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "adjustPaymentForStrategy", adjustPaymentForStrategy);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "restrictPartsByMission", restrictPartsByMission);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "bonusPartExchangeValue", bonusPartExchangeValue);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "bonusPartMaxExchangeCount", bonusPartMaxExchangeCount);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "limitLanceWeight", limitLanceWeight);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "limitLanceNumUnits", limitLanceNumUnits);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "assignPortraitOnRoleChange", assignPortraitOnRoleChange);
Expand Down Expand Up @@ -5921,6 +5943,10 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve
retVal.adjustPaymentForStrategy = Boolean.parseBoolean(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("restrictPartsByMission")) {
retVal.restrictPartsByMission = Boolean.parseBoolean(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("bonusPartExchangeValue")) {
retVal.bonusPartExchangeValue = Integer.parseInt(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("bonusPartMaxExchangeCount")) {
retVal.bonusPartMaxExchangeCount = Integer.parseInt(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("limitLanceWeight")) {
retVal.limitLanceWeight = Boolean.parseBoolean(wn2.getTextContent().trim());
} else if (wn2.getNodeName().equalsIgnoreCase("limitLanceNumUnits")) {
Expand Down
4 changes: 2 additions & 2 deletions MekHQ/src/mekhq/campaign/Quartermaster.java
Original file line number Diff line number Diff line change
Expand Up @@ -470,13 +470,13 @@ public boolean buyUnit(Entity en, int days) {
Money cost = new Unit(en, getCampaign()).getBuyCost();
if (getCampaign().getFinances().debit(TransactionType.UNIT_PURCHASE, getCampaign().getLocalDate(),
cost, "Purchased " + en.getShortName())) {
getCampaign().addNewUnit(en, false, days);
getCampaign().addNewUnit(en, false, days, 3);
return true;
} else {
return false;
}
} else {
getCampaign().addNewUnit(en, false, days);
getCampaign().addNewUnit(en, false, days, 3);
return true;
}
}
Expand Down
9 changes: 8 additions & 1 deletion MekHQ/src/mekhq/campaign/finances/enums/TransactionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public enum TransactionType {
THEFT("TransactionType.THEFT.text", "TransactionType.THEFT.toolTipText"),
TRANSPORTATION("TransactionType.TRANSPORTATION.text", "TransactionType.TRANSPORTATION.toolTipText"),
UNIT_PURCHASE("TransactionType.UNIT_PURCHASE.text", "TransactionType.UNIT_PURCHASE.toolTipText"),
UNIT_SALE("TransactionType.UNIT_SALE.text", "TransactionType.UNIT_SALE.toolTipText");
UNIT_SALE("TransactionType.UNIT_SALE.text", "TransactionType.UNIT_SALE.toolTipText"),
BONUS_EXCHANGE("TransactionType.BONUS_EXCHANGE.text", "TransactionType.BONUS_EXCHANGE.toolTipText");
//endregion Enum Declarations

//region Variable Declarations
Expand Down Expand Up @@ -187,6 +188,10 @@ public boolean isUnitPurchase() {
public boolean isUnitSale() {
return this == UNIT_SALE;
}

public boolean isBonusExchange() {
return this == BONUS_EXCHANGE;
}
//endregion Boolean Comparison Methods

//region File I/O
Expand Down Expand Up @@ -246,6 +251,8 @@ public static TransactionType parseFromString(final String text) {
return PAYOUT;
case 20:
return TAXES;
case 21:
return BONUS_EXCHANGE;
default:
break;
}
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/campaign/mission/AtBContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ public void doBonusRoll(Campaign c) {
}

if (null != en) {
c.addNewUnit(en, false, 0);
c.addNewUnit(en, false, 0, 3);
} else {
c.addReport("<html><font color='" + MekHQ.getMHQOptions().getFontColorNegativeHexColor() + "'>Could not load unit</font></html>");
}
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/campaign/mission/Loot.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public void get(Campaign campaign, Scenario s) {
}

for (Entity e : units) {
campaign.addNewUnit(e, false, 0);
campaign.addNewUnit(e, false, 0, 3);
}

for (Part p : parts) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ protected void execute() {
return;
}
Entity en = mechFileParser.getEntity();
getCampaign().addNewUnit(en, false, 0);
getCampaign().addNewUnit(en, false, 0, 3);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ private List<Unit> createUnits(final Campaign campaign,
continue;
}

final Unit unit = campaign.addNewUnit(tracker.getEntity(), false, 0);
final Unit unit = campaign.addNewUnit(tracker.getEntity(), false, 0, 3);
unit.addPilotOrSoldier(tracker.getPerson());
if (getOptions().isGenerateUnitsAsAttached()) {
tracker.getPerson().setOriginalUnit(unit);
Expand Down Expand Up @@ -1287,7 +1287,7 @@ public List<Entity> generateMothballedEntities(final Campaign campaign,
private List<Unit> createMothballedSpareUnits(final Campaign campaign,
final List<Entity> mothballedEntities) {
final List<Unit> mothballedUnits = mothballedEntities.stream()
.map(entity -> campaign.addNewUnit(entity, false, 0))
.map(entity -> campaign.addNewUnit(entity, false, 0, 3))
.collect(Collectors.toList());
mothballedUnits.forEach(Unit::completeMothball);
return mothballedUnits;
Expand Down
34 changes: 34 additions & 0 deletions MekHQ/src/mekhq/gui/BriefingTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import mekhq.MekHQ;
import mekhq.campaign.ResolveScenarioTracker;
import mekhq.campaign.event.*;
import mekhq.campaign.finances.Money;
import mekhq.campaign.finances.enums.TransactionType;
import mekhq.campaign.force.Lance;
import mekhq.campaign.mission.*;
import mekhq.campaign.mission.atb.AtBScenarioFactory;
Expand Down Expand Up @@ -398,6 +400,8 @@ && getCampaign().getFinances().getBalance().isGreaterOrEqualThan(rdd.totalPayout
((AtBContract) mission).checkForFollowup(getCampaign());
}

bonusPartExchange((AtBContract) mission);

if (getCampaign().getCampaignOptions().isEnableAutoAwards()) {
AutoAwardsController autoAwardsController = new AutoAwardsController();

Expand All @@ -410,6 +414,36 @@ && getCampaign().getFinances().getBalance().isGreaterOrEqualThan(rdd.totalPayout
comboMission.setSelectedItem(missions.isEmpty() ? null : missions.get(0));
}

/**
* Credits the campaign finances with additional funds based on campaign settings and remaining Bonus Parts.
*
* @param mission the mission just concluded
*/
private void bonusPartExchange(AtBContract mission) {
final ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.CampaignGUI",
MekHQ.getMHQOptions().getLocale());

double bonusPartExchangeValue = getCampaign().getCampaignOptions().getBonusPartExchangeValue();

if (bonusPartExchangeValue != 0.0) {
int bonusPartMaxExchangeCount = getCampaign().getCampaignOptions().getBonusPartMaxExchangeCount();

int spareBonusParts = mission.getNumBonusParts();

if (bonusPartMaxExchangeCount != 0) {
spareBonusParts = Math.min(bonusPartMaxExchangeCount, spareBonusParts);
}

bonusPartExchangeValue *= spareBonusParts;

getCampaign().getFinances().credit(
TransactionType.BONUS_EXCHANGE,
getCampaign().getLocalDate(),
Money.of(bonusPartExchangeValue),
resourceMap.getString("spareBonusPartExchange.text"));
}
}

private void deleteMission() {
final Mission mission = comboMission.getSelectedItem();
if (mission == null) {
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/gui/CampaignGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -1896,7 +1896,7 @@ protected void loadListFile(final boolean allowNewPilots) {
if (unitFile != null) {
try {
for (Entity entity : new MULParser(unitFile, getCampaign().getGameOptions()).getEntities()) {
getCampaign().addNewUnit(entity, allowNewPilots, 0);
getCampaign().addNewUnit(entity, allowNewPilots, 0, 3);
}
} catch (Exception e) {
LogManager.getLogger().error("", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ private void addOneItem(final IAcquisitionWork acquisition) {
if (equipment instanceof Part) {
gui.getCampaign().getQuartermaster().addPart((Part) equipment, 0);
} else if (equipment instanceof Entity) {
gui.getCampaign().addNewUnit((Entity) equipment, false, 0);
gui.getCampaign().addNewUnit((Entity) equipment, false, 0, 3);
} else {
LogManager.getLogger().error("Attempted to add unknown equipment of " + acquisition.getAcquisitionName());
return;
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@ private void addRATRolledUnit() {
}

if (getLastRolledUnit() != null) {
final Unit unit = getGUI().getCampaign().addNewUnit(getLastRolledUnit(), false, 0);
final Unit unit = getGUI().getCampaign().addNewUnit(getLastRolledUnit(), false, 0, 3);
if ((getPerson() != null) && (getPerson().getUnit() == null)) {
unit.addPilotOrSoldier(getPerson());
getPerson().setOriginalUnit(unit);
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/gui/dialog/MekHQUnitSelectorDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected JPanel createButtonsPanel() {
protected void select(boolean isGM) {
if (getSelectedEntity() != null) {
if (isGM) {
campaign.addNewUnit(selectedUnit.getEntity(), false, 0);
campaign.addNewUnit(selectedUnit.getEntity(), false, 0, 3);
} else {
campaign.getShoppingList().addShoppingItem(selectedUnit, 1, campaign);
}
Expand Down
2 changes: 1 addition & 1 deletion MekHQ/src/mekhq/gui/dialog/PersonnelMarketDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ private void addUnit(Entity en, boolean pay) {
unitCost, "Purchased " + en.getShortName())) {
return;
}
Unit unit = campaign.addNewUnit(en, false, 0);
Unit unit = campaign.addNewUnit(en, false, 0, 3);
if (unit == null) {
// No such unit matching the entity.
return;
Expand Down
Loading
Loading