From 8dd21a20755659ac9f2487208062af3bed2d3a14 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 10:51:12 -0400 Subject: [PATCH 01/28] use new reputationcontroller.getReputationModifier() --- .../contractMarket/CamOpsContractMarket.java | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 3132a5adfa..6abf1f92c4 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -5,7 +5,6 @@ import megamek.logging.MMLogger; import mekhq.MekHQ; import mekhq.campaign.Campaign; -import mekhq.campaign.againstTheBot.AtBConfiguration; import mekhq.campaign.market.enums.ContractMarketMethod; import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.enums.AtBContractType; @@ -39,7 +38,8 @@ public AtBContract addAtBContract(Campaign campaign) { if (contractMods == null) { contractMods = generateContractModifiers(campaign); } - Optional c = generateContract(campaign); + int ratingMod = campaign.getReputation().getReputationModifier(); + Optional c = generateContract(campaign, ratingMod); if (c.isPresent()) { AtBContract atbContract = c.get(); contracts.add(atbContract); @@ -60,7 +60,7 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { //} // TODO: CamopsMarket: allow players to choose negotiators and send them out, removing them // from other tasks they're doing. For now just use the highest negotiation skill on the force. - int ratingMod = getReputationModifier(campaign); + int ratingMod = campaign.getReputation().getReputationModifier(); contractMods = generateContractModifiers(campaign); int negotiationSkill = findNegotiationSkill(campaign); int numOffers = getNumberOfOffers( @@ -128,17 +128,17 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign) { + private Optional generateContract(Campaign campaign, int ratingMod) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); contractIds.put(lastId, contract); - Faction employer = determineEmployer(campaign); + Faction employer = determineEmployer(campaign, ratingMod); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); } - contract.setContractType(determineMission(campaign, employer)); + contract.setContractType(determineMission(campaign, employer, ratingMod)); setEnemyCode(contract); setIsRiotDuty(contract); setAttacker(contract); @@ -168,20 +168,16 @@ private Optional generateContract(Campaign campaign) { return Optional.of(contract); } - private int getReputationModifier(Campaign campaign) { - return getReputationScore(campaign) / 10; - } - private int getReputationScore(Campaign campaign) { return campaign.getReputation().getReputationRating(); } - private Faction determineEmployer(Campaign campaign) { + private Faction determineEmployer(Campaign campaign, int ratingMod) { Collection employerTags; - int roll = Compute.d6(2) + getReputationModifier(campaign) + contractMods.employersMod; + int roll = Compute.d6(2) + ratingMod + contractMods.employersMod; if (roll < 6) { // Roll again on the independent employers column - roll = Compute.d6(2) + getReputationModifier(campaign) + contractMods.employersMod; + roll = Compute.d6(2) + ratingMod + contractMods.employersMod; employerTags = getEmployerTags(campaign, roll, true); } else { employerTags = getEmployerTags(campaign, roll, false); @@ -253,7 +249,7 @@ private Collection getEmployerTags(Campaign campaign, int roll, boolean ind return tags; } - private AtBContractType determineMission(Campaign campaign, Faction employer) { + private AtBContractType determineMission(Campaign campaign, Faction employer, int ratingMod) { int roll = Compute.d6(2); if (campaign.getFaction().isPirate()) { if (roll < 6) { @@ -262,7 +258,7 @@ private AtBContractType determineMission(Campaign campaign, Faction employer) { return AtBContractType.OBJECTIVE_RAID; } } - return findMissionType(getReputationModifier(campaign), employer.isISMajorOrSuperPower()); + return findMissionType(ratingMod, employer.isISMajorOrSuperPower()); } private void setContractClauses(AtBContract contract, Campaign campaign) { From 419e0b4777c546b7430938fc0b67cef5e72e4632 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 11:12:44 -0400 Subject: [PATCH 02/28] remove unnecessary reputation score method --- .../campaign/market/contractMarket/CamOpsContractMarket.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 6abf1f92c4..b86ddd9e6e 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -168,10 +168,6 @@ private Optional generateContract(Campaign campaign, int ratingMod) return Optional.of(contract); } - private int getReputationScore(Campaign campaign) { - return campaign.getReputation().getReputationRating(); - } - private Faction determineEmployer(Campaign campaign, int ratingMod) { Collection employerTags; int roll = Compute.d6(2) + ratingMod + contractMods.employersMod; From c3fadadfac02ed740701cdef96a33d630a5b2052 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 11:20:57 -0400 Subject: [PATCH 03/28] add isGovernment() to check if force is a non-clan government unit --- MekHQ/src/mekhq/campaign/universe/Faction.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/universe/Faction.java b/MekHQ/src/mekhq/campaign/universe/Faction.java index 374369c506..c63af30b16 100644 --- a/MekHQ/src/mekhq/campaign/universe/Faction.java +++ b/MekHQ/src/mekhq/campaign/universe/Faction.java @@ -247,6 +247,11 @@ public boolean isRebelOrPirate() { return isRebel() || isPirate(); } + public boolean isGovernment() { + return !isClan() && (isComStar() || isISMajorOrSuperPower() || isMinorPower() + || isPlanetaryGovt() || isIndependent()); + } + public boolean isComStar() { return "CS".equals(getShortName()); } From 6d94daaf0c3b89f86870cd59eba72b1b2469e1d1 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 11:31:58 -0400 Subject: [PATCH 04/28] add method to get hiring hall to simplify dependencies in calling methods --- MekHQ/src/mekhq/campaign/Campaign.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index 3a8831b2d6..2282a44c40 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -107,6 +107,7 @@ import mekhq.campaign.universe.*; import mekhq.campaign.universe.Planet.PlanetaryEvent; import mekhq.campaign.universe.PlanetarySystem.PlanetarySystemEvent; +import mekhq.campaign.universe.enums.HiringHallLevel; import mekhq.campaign.universe.eras.Era; import mekhq.campaign.universe.eras.Eras; import mekhq.campaign.universe.fameAndInfamy.BatchallFactions; @@ -417,6 +418,16 @@ public PlanetarySystem getCurrentSystem() { return location.getCurrentSystem(); } + /** + * Returns the Hiring Hall level from the force's current system on the current date. If there + * is no hiring hall present, the level is HiringHallLevel.NONE. + * + * @return The Hiring Hall level of the current system at the present date. + */ + public HiringHallLevel getSystemHiringHallLevel() { + return getCurrentSystem().getHiringHallLevel(getLocalDate()); + } + public Money getFunds() { return finances.getBalance(); } From e36160f86dfe0f1e45baa4202d91074b70a153f9 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 11:34:33 -0400 Subject: [PATCH 05/28] make contract modifiers static instead of a class instance --- .../contractMarket/CamOpsContractMarket.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index b86ddd9e6e..43599b8ec9 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -27,19 +27,15 @@ public class CamOpsContractMarket extends AbstractContractMarket { private static int BASE_NEGOTIATION_TARGET = 8; private static int EMPLOYER_NEGOTIATION_SKILL_LEVEL = 5; - private ContractModifiers contractMods = null; - public CamOpsContractMarket() { super(ContractMarketMethod.CAM_OPS); } @Override public AtBContract addAtBContract(Campaign campaign) { - if (contractMods == null) { - contractMods = generateContractModifiers(campaign); - } + ContractModifiers contractMods = getContractModifiers(campaign); int ratingMod = campaign.getReputation().getReputationModifier(); - Optional c = generateContract(campaign, ratingMod); + Optional c = generateContract(campaign, ratingMod, contractMods); if (c.isPresent()) { AtBContract atbContract = c.get(); contracts.add(atbContract); @@ -61,7 +57,7 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { // TODO: CamopsMarket: allow players to choose negotiators and send them out, removing them // from other tasks they're doing. For now just use the highest negotiation skill on the force. int ratingMod = campaign.getReputation().getReputationModifier(); - contractMods = generateContractModifiers(campaign); + ContractModifiers contractMods = getContractModifiers(campaign); int negotiationSkill = findNegotiationSkill(campaign); int numOffers = getNumberOfOffers( rollNegotiation(negotiationSkill, ratingMod + contractMods.offersMod) - BASE_NEGOTIATION_TARGET); @@ -83,14 +79,16 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract return 1.0; } - private ContractModifiers generateContractModifiers(Campaign campaign) { + private ContractModifiers getContractModifiers(Campaign campaign) { + ContractModifiers modifiers; if (campaign.getFaction().isMercenary()) { - return new ContractModifiers(campaign.getCurrentSystem().getHiringHallLevel(campaign.getLocalDate())); - } else if (campaign.getFaction().isRebelOrPirate()) { - return new ContractModifiers(HiringHallLevel.NONE); + modifiers = new ContractModifiers(campaign.getSystemHiringHallLevel()); + } else if (campaign.getFaction().isGovernment()) { + modifiers = new ContractModifiers(HiringHallLevel.GREAT); } else { - return new ContractModifiers(HiringHallLevel.GREAT); + modifiers = new ContractModifiers(HiringHallLevel.NONE); } + return modifiers; } private int findNegotiationSkill(Campaign campaign) { @@ -128,12 +126,12 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign, int ratingMod) { + private Optional generateContract(Campaign campaign, int ratingMod, ContractModifiers contractMods) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); contractIds.put(lastId, contract); - Faction employer = determineEmployer(campaign, ratingMod); + Faction employer = determineEmployer(campaign, ratingMod, contractMods); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); @@ -168,7 +166,7 @@ private Optional generateContract(Campaign campaign, int ratingMod) return Optional.of(contract); } - private Faction determineEmployer(Campaign campaign, int ratingMod) { + private Faction determineEmployer(Campaign campaign, int ratingMod, ContractModifiers contractMods) { Collection employerTags; int roll = Compute.d6(2) + ratingMod + contractMods.employersMod; if (roll < 6) { @@ -261,7 +259,7 @@ private void setContractClauses(AtBContract contract, Campaign campaign) { // TODO: add logic to determine initial contract clauses from CamOps 4th printing. } - private class ContractModifiers { + private static class ContractModifiers { protected int offersMod; protected int employersMod; protected int missionsMod; From cc172438819e684d014712aaffab59fa5b0fb57f Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 11:52:27 -0400 Subject: [PATCH 06/28] move followup contract generation from AtBContract to AbstractContractMarket --- .../contractMarket/AbstractContractMarket.java | 10 ++++++---- .../AtbMonthlyContractMarket.java | 17 +++++++++++++++-- .../contractMarket/CamOpsContractMarket.java | 10 +++++----- .../contractMarket/DisabledContractMarket.java | 2 +- .../src/mekhq/campaign/mission/AtBContract.java | 12 ------------ MekHQ/src/mekhq/gui/BriefingTab.java | 2 +- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/AbstractContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/AbstractContractMarket.java index 80c4ab09a1..80f929e24b 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/AbstractContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/AbstractContractMarket.java @@ -78,11 +78,13 @@ public abstract class AbstractContractMarket { abstract public void generateContractOffers(Campaign campaign, boolean newCampaign); /** - * Add a followup contract to an existing contract. - * @param campaign - * @param contract + * Generate followup contracts and add them to the market if the currently selected market type + * supports them. + * + * @param campaign The current campaign. + * @param contract The AtBContract being completed and used as a basis for followup missions */ - abstract public void addFollowup(Campaign campaign, AtBContract contract); + abstract public void checkForFollowup(Campaign campaign, AtBContract contract); /** * Calculate the total payment modifier for the contract based on the configured market method diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java index 7081e06851..4f1607207e 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java @@ -409,8 +409,7 @@ protected AtBContract generateAtBSubcontract(Campaign campaign, return contract; } - @Override - public void addFollowup(Campaign campaign, + private void addFollowup(Campaign campaign, AtBContract contract) { if (followupContracts.containsValue(contract.getId())) { return; @@ -498,6 +497,20 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract return multiplier; } + @Override + public void checkForFollowup(Campaign campaign, AtBContract contract) { + AtBContractType type = contract.getContractType(); + if (type.isDiversionaryRaid() || type.isReconRaid() + || type.isRiotDuty()) { + int roll = Compute.d6(); + if (roll == 6) { + addFollowup(campaign, contract); + campaign.addReport( + "Your employer has offered a follow-up contract (available on the contract market)."); + } + } + } + private void setContractClauses(AtBContract contract, int unitRatingMod, Campaign campaign) { ClauseMods mods = new ClauseMods(); clauseMods.put(contract.getId(), mods); diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 43599b8ec9..6f463f410c 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -68,17 +68,17 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { updateReport(campaign); } - @Override - public void addFollowup(Campaign campaign, AtBContract contract) { - //TODO: add logic if we decide followup contracts should be allow in CamOps - } - @Override public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract) { //TODO: add logic from camops 4th printing return 1.0; } + @Override + public void checkForFollowup(Campaign campaign, AtBContract contract) { + + } + private ContractModifiers getContractModifiers(Campaign campaign) { ContractModifiers modifiers; if (campaign.getFaction().isMercenary()) { diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/DisabledContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/DisabledContractMarket.java index 3a5f5117bd..5636171699 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/DisabledContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/DisabledContractMarket.java @@ -20,7 +20,7 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { } @Override - public void addFollowup(Campaign campaign, AtBContract contract) { + public void checkForFollowup(Campaign campaign, AtBContract contract) { } diff --git a/MekHQ/src/mekhq/campaign/mission/AtBContract.java b/MekHQ/src/mekhq/campaign/mission/AtBContract.java index 3b6ec15591..a444bef981 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBContract.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBContract.java @@ -965,18 +965,6 @@ public Money getMonthlyPayOut() { .dividedBy(getLength()); } - public void checkForFollowup(Campaign campaign) { - if (getContractType().isDiversionaryRaid() || getContractType().isReconRaid() - || getContractType().isRiotDuty()) { - int roll = Compute.d6(); - if (roll == 6) { - campaign.getContractMarket().addFollowup(campaign, this); - campaign.addReport( - "Your employer has offered a follow-up contract (available on the contract market)."); - } - } - } - @Override protected int writeToXMLBegin(final PrintWriter pw, int indent) { indent = super.writeToXMLBegin(pw, indent); diff --git a/MekHQ/src/mekhq/gui/BriefingTab.java b/MekHQ/src/mekhq/gui/BriefingTab.java index 92bbc3a36d..b420870c1f 100644 --- a/MekHQ/src/mekhq/gui/BriefingTab.java +++ b/MekHQ/src/mekhq/gui/BriefingTab.java @@ -473,7 +473,7 @@ && getCampaign().getFinances().getBalance().isGreaterOrEqualThan(rdd.totalPayout // resolve bonus parts exchange if (getCampaign().getCampaignOptions().isUseAtB() && (mission instanceof AtBContract)) { - ((AtBContract) mission).checkForFollowup(getCampaign()); + getCampaign().getContractMarket().checkForFollowup(getCampaign(), (AtBContract) mission); bonusPartExchange((AtBContract) mission); } From 94b8e19813f481bb01fe6c9be9e140c51c37a50b Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 12:36:50 -0400 Subject: [PATCH 07/28] add camops faction tags --- .../src/mekhq/campaign/universe/Faction.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/universe/Faction.java b/MekHQ/src/mekhq/campaign/universe/Faction.java index c63af30b16..2bc0891a12 100644 --- a/MekHQ/src/mekhq/campaign/universe/Faction.java +++ b/MekHQ/src/mekhq/campaign/universe/Faction.java @@ -332,6 +332,22 @@ public boolean isInactive() { public boolean isChaos() { return is(Tag.CHAOS); } + + public boolean isStingy() { + return is(Tag.STINGY); + } + + public boolean isGenerous() { + return is(Tag.GENEROUS); + } + + public boolean isControlling() { + return is(Tag.CONTROLLING); + } + + public boolean isLenient() { + return is(Tag.LENIENT); + } // endregion Power Checks // endregion Checks @@ -482,6 +498,14 @@ public enum Tag { /** Faction is an independent planetary government (Camops p. 39) */ PLANETARY_GOVERNMENT, /** Faction is an independent corporation (Camops p. 39) */ - CORPORATION + CORPORATION, + /** Faction is stingy and tends to pay less for contracts (Camops p. 42) */ + STINGY, + /** Faction is generous and tends to pay more for contracts (Camops p. 42) */ + GENEROUS, + /** Faction is controlling with mercenary command rights (Camops p. 42) */ + CONTROLLING, + /** Faction is lenient with mercenary command rights (Camops p. 42) */ + LENIENT } } From 07e95255f308dafedba34a11badae85d056e2538 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 12:51:29 -0400 Subject: [PATCH 08/28] rename contractmodifiers to hiringhallmodifiers --- .../contractMarket/CamOpsContractMarket.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 6f463f410c..a766e56763 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -33,9 +33,9 @@ public CamOpsContractMarket() { @Override public AtBContract addAtBContract(Campaign campaign) { - ContractModifiers contractMods = getContractModifiers(campaign); + HiringHallModifiers hiringHallModifiers = getHiringHallModifiers(campaign); int ratingMod = campaign.getReputation().getReputationModifier(); - Optional c = generateContract(campaign, ratingMod, contractMods); + Optional c = generateContract(campaign, ratingMod, hiringHallModifiers); if (c.isPresent()) { AtBContract atbContract = c.get(); contracts.add(atbContract); @@ -57,10 +57,10 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { // TODO: CamopsMarket: allow players to choose negotiators and send them out, removing them // from other tasks they're doing. For now just use the highest negotiation skill on the force. int ratingMod = campaign.getReputation().getReputationModifier(); - ContractModifiers contractMods = getContractModifiers(campaign); + HiringHallModifiers hiringHallModifiers = getHiringHallModifiers(campaign); int negotiationSkill = findNegotiationSkill(campaign); int numOffers = getNumberOfOffers( - rollNegotiation(negotiationSkill, ratingMod + contractMods.offersMod) - BASE_NEGOTIATION_TARGET); + rollNegotiation(negotiationSkill, ratingMod + hiringHallModifiers.offersMod) - BASE_NEGOTIATION_TARGET); for (int i = 0; i < numOffers; i++) { addAtBContract(campaign); @@ -79,14 +79,14 @@ public void checkForFollowup(Campaign campaign, AtBContract contract) { } - private ContractModifiers getContractModifiers(Campaign campaign) { - ContractModifiers modifiers; + private HiringHallModifiers getHiringHallModifiers(Campaign campaign) { + HiringHallModifiers modifiers; if (campaign.getFaction().isMercenary()) { - modifiers = new ContractModifiers(campaign.getSystemHiringHallLevel()); + modifiers = new HiringHallModifiers(campaign.getSystemHiringHallLevel()); } else if (campaign.getFaction().isGovernment()) { - modifiers = new ContractModifiers(HiringHallLevel.GREAT); + modifiers = new HiringHallModifiers(HiringHallLevel.GREAT); } else { - modifiers = new ContractModifiers(HiringHallLevel.NONE); + modifiers = new HiringHallModifiers(HiringHallLevel.NONE); } return modifiers; } @@ -126,12 +126,12 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign, int ratingMod, ContractModifiers contractMods) { + private Optional generateContract(Campaign campaign, int ratingMod, HiringHallModifiers hiringHallModifierss) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); contractIds.put(lastId, contract); - Faction employer = determineEmployer(campaign, ratingMod, contractMods); + Faction employer = determineEmployer(campaign, ratingMod, hiringHallModifierss); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); @@ -166,12 +166,12 @@ private Optional generateContract(Campaign campaign, int ratingMod, return Optional.of(contract); } - private Faction determineEmployer(Campaign campaign, int ratingMod, ContractModifiers contractMods) { + private Faction determineEmployer(Campaign campaign, int ratingMod, HiringHallModifiers hiringHallModifiers) { Collection employerTags; - int roll = Compute.d6(2) + ratingMod + contractMods.employersMod; + int roll = Compute.d6(2) + ratingMod + hiringHallModifiers.employersMod; if (roll < 6) { // Roll again on the independent employers column - roll = Compute.d6(2) + ratingMod + contractMods.employersMod; + roll = Compute.d6(2) + ratingMod + hiringHallModifiers.employersMod; employerTags = getEmployerTags(campaign, roll, true); } else { employerTags = getEmployerTags(campaign, roll, false); @@ -259,12 +259,12 @@ private void setContractClauses(AtBContract contract, Campaign campaign) { // TODO: add logic to determine initial contract clauses from CamOps 4th printing. } - private static class ContractModifiers { + private static class HiringHallModifiers { protected int offersMod; protected int employersMod; protected int missionsMod; - protected ContractModifiers(HiringHallLevel level) { + protected HiringHallModifiers(HiringHallLevel level) { switch (level) { case NONE -> { offersMod = -3; From 5f7e0dc06c6d0d51c4124ffdd5e86eebb7cde152 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 14:00:33 -0400 Subject: [PATCH 09/28] add employer tags --- MekHQ/data/universe/factions.xml | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/MekHQ/data/universe/factions.xml b/MekHQ/data/universe/factions.xml index 030c3ddb2a..583cd6fe97 100644 --- a/MekHQ/data/universe/factions.xml +++ b/MekHQ/data/universe/factions.xml @@ -97,7 +97,7 @@ successor - unimplemented tag describing another faction code as the specified f Terran Hegemony.png Inner Sphere/ Terran Hegemony.png - is,super,playable + is,super,playable,generous,controlling 2315 2790 @@ -137,7 +137,7 @@ successor - unimplemented tag describing another faction code as the specified f Capellan Confederation.png Inner Sphere/ Capellan Confederation.png - is,major,playable + is,major,playable,stingy,controlling 2367 @@ -152,7 +152,7 @@ successor - unimplemented tag describing another faction code as the specified f Draconis Combine.png Inner Sphere/ Draconis Combine.png - is,major,playable + is,major,playable,stingy,controlling 2319 @@ -166,7 +166,7 @@ successor - unimplemented tag describing another faction code as the specified f Federated Suns.png Inner Sphere/ Federated Suns.png - is,major,playable + is,major,playable,generous 2317 @@ -180,7 +180,7 @@ successor - unimplemented tag describing another faction code as the specified f Free Worlds League.png Inner Sphere/ Free Worlds League.png - is,major,playable + is,major,playable,generous,controlling 2271 @@ -196,7 +196,7 @@ successor - unimplemented tag describing another faction code as the specified f Lyran Commonwealth.png Inner Sphere/ Lyran Commonwealth.png - is,major,playable + is,major,playable,generous,lenient 2340 @@ -470,7 +470,7 @@ successor - unimplemented tag describing another faction code as the specified f Rim Worlds Republic.png Periphery/ Rim Worlds Republic.png - periphery,playable + periphery,playable,stingy,controlling 2250 2779 @@ -505,7 +505,7 @@ successor - unimplemented tag describing another faction code as the specified f Taurian Concordat.png Periphery/ Taurian Concordat.png - periphery,playable + periphery,playable,stingy,controlling 2335 @@ -518,7 +518,7 @@ successor - unimplemented tag describing another faction code as the specified f Magistracy of Canopus.png Periphery/ Magistracy of Canopus.png - periphery,playable + periphery,playable,generous,lenient 2530 @@ -532,7 +532,7 @@ successor - unimplemented tag describing another faction code as the specified f Outworlds Alliance.png Periphery/ Outworlds Alliance.png - periphery,playable + periphery,playable,stingy,lenient 2413 3083 RA @@ -1038,7 +1038,7 @@ successor - unimplemented tag describing another faction code as the specified f ComStar.png Inner Sphere/ ComStar.png - is,inactive,major,playable + is,inactive,major,playable,generous,controlling 2788 @@ -1054,7 +1054,7 @@ successor - unimplemented tag describing another faction code as the specified f Free Worlds League.png Inner Sphere/ Duchy of Andurien.png - is,minor + is,minor,stingy,lenient 3030 @@ -1169,7 +1169,7 @@ successor - unimplemented tag describing another faction code as the specified f Escorpion Imperio.png Clan/ Escorpion Imperio.png - clan,deep_periphery,playable + clan,deep_periphery,playable,stingy,controlling 3080 @@ -1186,7 +1186,7 @@ successor - unimplemented tag describing another faction code as the specified f Inner Sphere/ Federated Commonwealth.png 255,221,0 - is,super,playable + is,super,playable,generous 3028 3068 FS @@ -1219,7 +1219,7 @@ successor - unimplemented tag describing another faction code as the specified f Free Rasalhague Republic.png Inner Sphere/ Free Rasalhague Republic.png - is,minor,playable + is,minor,playable,generous,controlling 3034 3103 RD @@ -1272,7 +1272,7 @@ successor - unimplemented tag describing another faction code as the specified f Hanseatic League.png Periphery/ Hanseatic League.png - deep_periphery,playable + deep_periphery,playable,stingy,controlling 2891 3141 CEI @@ -1381,7 +1381,7 @@ successor - unimplemented tag describing another faction code as the specified f Marian Hegemony.png Periphery/ Marian Hegemony.png - periphery,playable + periphery,playable,stingy,controlling 2920 @@ -1486,7 +1486,7 @@ successor - unimplemented tag describing another faction code as the specified f Nueva Castile.png Periphery/ Nueva Castile.png - deep_periphery,playable + deep_periphery,playable,stingy,controlling 2392 3080 CEI @@ -1502,7 +1502,7 @@ successor - unimplemented tag describing another faction code as the specified f Oberon Confederation.png Periphery/ Oberon Confederation.png - periphery + periphery,stingy,controlling 2775 3049 @@ -1589,7 +1589,7 @@ successor - unimplemented tag describing another faction code as the specified f Ghost Bear Dominion.png Clan/ Rasalhague Dominion.png - clan,is,minor,playable + clan,is,minor,playable,generous,controlling 3103 @@ -1604,7 +1604,7 @@ successor - unimplemented tag describing another faction code as the specified f Raven Alliance.png Clan/ Raven Alliance.png - clan,periphery,playable + clan,periphery,playable,generous,controlling 3083 @@ -1763,7 +1763,7 @@ successor - unimplemented tag describing another faction code as the specified f 153,198,237 Periphery/ St. Ives Compact.png - is,minor,playable + is,minor,playable,generous,lenient 3029 3063 CC @@ -1779,7 +1779,7 @@ successor - unimplemented tag describing another faction code as the specified f Star League.png Inner Sphere/ Star League.png - is,super,playable + is,super,playable,generous,controlling 2570 2781 @@ -1878,7 +1878,7 @@ successor - unimplemented tag describing another faction code as the specified f 0,0,0,0,0,0,2 CC 255,160,122 - is,minor + is,minor,stingy,controlling 3029 3031 FS @@ -1915,7 +1915,7 @@ successor - unimplemented tag describing another faction code as the specified f Word of Blake.png Inner Sphere/ Word of Blake.png - is,minor,playable + is,minor,playable,controlling 3052 3081 @@ -2111,7 +2111,7 @@ successor - unimplemented tag describing another faction code as the specified f Umayyad Caliphate.png Periphery/ Umayyad Caliphate.png - deep_periphery + deep_periphery,stingy,controlling 2830 3080 CEI @@ -2257,7 +2257,7 @@ successor - unimplemented tag describing another faction code as the specified f Aurigan Coalition.png Periphery/ Aurigan Coalition.png - periphery,minor,playable + periphery,minor,playable,generous,lenient 2910 3028 From df60cd0285cd395064ecc7c793c3d499f3db3690 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 14:02:26 -0400 Subject: [PATCH 10/28] fix typos --- .../campaign/market/contractMarket/CamOpsContractMarket.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index a766e56763..bf7652bfb9 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -126,12 +126,12 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign, int ratingMod, HiringHallModifiers hiringHallModifierss) { + private Optional generateContract(Campaign campaign, int ratingMod, HiringHallModifiers hiringHallModifiers) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); contractIds.put(lastId, contract); - Faction employer = determineEmployer(campaign, ratingMod, hiringHallModifierss); + Faction employer = determineEmployer(campaign, ratingMod, hiringHallModifiers); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); From 15b82b9e45377361748ed4a9ead4948a14258cc8 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 14:37:54 -0400 Subject: [PATCH 11/28] rename paymentMultiplier to operationsTempoMultiplier --- .../contractMarket/AtbMonthlyContractMarket.java | 2 +- .../campaign/mission/enums/AtBContractType.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java index 4f1607207e..b07f628147 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/AtbMonthlyContractMarket.java @@ -472,7 +472,7 @@ public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract } } - multiplier *= contract.getContractType().getPaymentMultiplier(); + multiplier *= contract.getContractType().getOperationsTempoMultiplier(); final Faction employer = Factions.getInstance().getFaction(contract.getEmployerCode()); final Faction enemy = contract.getEnemy(); diff --git a/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java b/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java index 373ce15eae..8916f8c405 100644 --- a/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java +++ b/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java @@ -29,6 +29,8 @@ import mekhq.campaign.universe.enums.EraFlag; public enum AtBContractType { + // TODO: Missing Camops Mission Types: ASSASSINATION, ESPIONAGE, MOLE_HUNTING, OBSERVATION_RAID, + // RETAINER, SABOTAGE, TERRORISM, HIGH_RISK, COVERT // region Enum Declarations GARRISON_DUTY("AtBContractType.GARRISON_DUTY.text", "AtBContractType.GARRISON_DUTY.toolTipText", 18, 1.0), CADRE_DUTY("AtBContractType.CADRE_DUTY.text", "AtBContractType.CADRE_DUTY.toolTipText", 12, 0.8), @@ -51,18 +53,18 @@ public enum AtBContractType { private final String name; private final String toolTipText; private final int constantLength; - private final double paymentMultiplier; + private final double operationsTempoMultiplier; // endregion Variable Declarations // region Constructors AtBContractType(final String name, final String toolTipText, final int constantLength, - final double paymentMultiplier) { + final double operationsTempoMultiplier) { final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Mission", MekHQ.getMHQOptions().getLocale()); this.name = resources.getString(name); this.toolTipText = resources.getString(toolTipText); this.constantLength = constantLength; - this.paymentMultiplier = paymentMultiplier; + this.operationsTempoMultiplier = operationsTempoMultiplier; } // endregion Constructors @@ -75,8 +77,8 @@ public int getConstantLength() { return constantLength; } - public double getPaymentMultiplier() { - return paymentMultiplier; + public double getOperationsTempoMultiplier() { + return operationsTempoMultiplier; } // endregion Getters From 875d0499ecb7439d86cbb076b26815af5a5f02a7 Mon Sep 17 00:00:00 2001 From: algebro Date: Wed, 2 Oct 2024 16:40:25 -0400 Subject: [PATCH 12/28] add contract terms class for resolving and storing contract terms and modifiers --- .../contractMarket/CamOpsContractMarket.java | 42 ++- .../market/contractMarket/ContractTerms.java | 290 ++++++++++++++++++ 2 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index bf7652bfb9..bcff7619b4 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -137,6 +137,8 @@ private Optional generateContract(Campaign campaign, int ratingMod, contract.setMercSubcontract(true); } contract.setContractType(determineMission(campaign, employer, ratingMod)); + ContractTerms contractTerms = new ContractTerms(contract.getContractType(), + employer, ratingMod, campaign.getLocalDate()); setEnemyCode(contract); setIsRiotDuty(contract); setAttacker(contract); @@ -152,7 +154,7 @@ private Optional generateContract(Campaign campaign, int ratingMod, contract.setAllyQuality(IUnitRating.DRAGOON_F); } contract.calculateLength(campaign.getCampaignOptions().isVariableContractLength()); - setContractClauses(contract, campaign); + setContractClauses(contract, contractTerms); contract.setRequiredLances(calculateRequiredLances(campaign, contract)); contract.setMultiplier(calculatePaymentMultiplier(campaign, contract)); contract.setPartsAvailabilityLevel(contract.getContractType().calculatePartsAvailabilityLevel()); @@ -255,8 +257,42 @@ private AtBContractType determineMission(Campaign campaign, Faction employer, in return findMissionType(ratingMod, employer.isISMajorOrSuperPower()); } - private void setContractClauses(AtBContract contract, Campaign campaign) { - // TODO: add logic to determine initial contract clauses from CamOps 4th printing. + private void setContractClauses(AtBContract contract, ContractTerms terms) { + setCommandRights(contract, terms); + setSalvageRights(contract, terms); + setSupportRights(contract, terms); + setTransportRights(contract, terms); + } + + private void setCommandRights(AtBContract contract, ContractTerms terms) { + int roll = Compute.d6(2); + contract.setCommandRights(terms.getCommandRights(roll)); + } + + private void setSalvageRights(AtBContract contract, ContractTerms terms) { + int roll = Compute.d6(2); + if (terms.isSalvageExchange(roll)) { + contract.setSalvageExchange(true); + } else { + contract.setSalvageExchange(false); + contract.setSalvagePct(terms.getSalvagePercentage(roll)); + } + } + + private void setSupportRights(AtBContract contract, ContractTerms terms) { + int roll = Compute.d6(2); + if (terms.isStraightSupport(roll)) { + contract.setStraightSupport(terms.getSupportPercentage(roll)); + } else if (terms.isBattleLossComp(roll)) { + contract.setBattleLossComp(terms.getSupportPercentage(roll)); + } else { + contract.setStraightSupport(0); + } + } + + private void setTransportRights(AtBContract contract, ContractTerms terms) { + int roll = Compute.d6(2); + contract.setTransportComp(terms.getTransportTerms(roll)); } private static class HiringHallModifiers { diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java new file mode 100644 index 0000000000..fb203bbce4 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -0,0 +1,290 @@ +package mekhq.campaign.market.contractMarket; + +import mekhq.campaign.mission.enums.AtBContractType; +import mekhq.campaign.mission.enums.ContractCommandRights; +import mekhq.campaign.universe.Faction; + +import java.time.LocalDate; + +/** + * Structure that resolves and stores modifiers and contract terms as shown in the Master Contract + * Terms Table on page 42 of CamOps (4th printing). + */ +public class ContractTerms { + private double operationsTempoMultiplier; + private int baseLength; + private double employmentMultiplier; + private int commandModifier; + private int salvageModifier; + private int supportModifier; + private int transportModifier; + + public ContractTerms(AtBContractType mission, Faction employer, int reputationRating, LocalDate date) { + operationsTempoMultiplier = mission.getOperationsTempoMultiplier(); + baseLength = mission.getConstantLength(); + addMissionTypeModifiers(mission); + addEmployerModifiers(employer, date); + addUnitReputationModifiers(reputationRating); + } + + public double getOperationsTempoMultiplier() { + return operationsTempoMultiplier; + } + + public int getBaseLength() { + return baseLength; + } + + public double getEmploymentMultiplier() { + return employmentMultiplier; + } + + public ContractCommandRights getCommandRights(int roll) { + roll += commandModifier; + ContractCommandRights commandRights; + if (roll > 2 && roll < 8) { + commandRights = ContractCommandRights.HOUSE; + } else if (roll < 12) { + commandRights = ContractCommandRights.LIAISON; + } else { + commandRights = ContractCommandRights.INDEPENDENT; + } + return commandRights; + } + + public boolean isSalvageExchange(int roll) { + roll += salvageModifier; + return roll == 2 || roll == 3; + } + + public int getSalvagePercentage(int roll) { + roll += salvageModifier; + if (roll < 4) { + return 0; + } else if (roll == 4) { + return 10; + } else if (roll == 5) { + return 20; + } else if (roll == 6) { + return 30; + } else if (roll == 7) { + return 40; + } else if (roll == 8) { + return 50; + } else if (roll == 9) { + return 60; + } else if (roll == 10) { + return 70; + } else if (roll == 11) { + return 80; + } else if (roll == 12) { + return 90; + } else { + return 100; + } + } + + public int getSupportPercentage(int roll) { + roll += supportModifier; + int percentage = 0; + if (roll == 3 || roll == 9) { + percentage = 20; + } else if (roll == 4 || roll == 10) { + percentage = 40; + } else if (roll == 5 || roll == 11) { + percentage = 60; + } else if (roll == 6 || roll == 12) { + percentage = 80; + } else if (roll == 7 || roll > 12) { + percentage = 100; + } + return percentage; + } + + public boolean isStraightSupport(int roll) { + roll += supportModifier; + return roll > 2 && roll < 8; + } + + public boolean isBattleLossComp(int roll) { + roll += supportModifier; + return roll > 7; + } + + public int getTransportTerms(int roll) { + roll += transportModifier; + if (roll < 2) { + return 0; + } else if (roll == 2) { + return 20; + } else if (roll == 3) { + return 25; + } else if (roll == 4) { + return 30; + } else if (roll == 5) { + return 35; + } else if (roll == 6) { + return 45; + } else if (roll == 7) { + return 50; + } else if (roll == 8) { + return 55; + } else if (roll == 9) { + return 60; + } else { + return 100; + } + } + + private void addMissionTypeModifiers(AtBContractType mission) { + switch (mission) { + case CADRE_DUTY -> supportModifier += 1; + case DIVERSIONARY_RAID -> { + salvageModifier += 2; + supportModifier += 2; + transportModifier += 1; + } + case EXTRACTION_RAID -> { + commandModifier += -1; + salvageModifier += -1; + supportModifier += 2; + transportModifier += 1; + } + case GARRISON_DUTY -> { + commandModifier += 1; + supportModifier += 1; + } + case GUERRILLA_WARFARE -> { + commandModifier += -2; + salvageModifier += 3; + supportModifier += -2; + transportModifier += -1; + } + case OBJECTIVE_RAID -> { + commandModifier += -1; + supportModifier += 1; + transportModifier += 2; + } + case PIRATE_HUNTING -> { + commandModifier += 2; + salvageModifier += 2; + supportModifier += -1; + transportModifier += -1; + } + case PLANETARY_ASSAULT -> { + commandModifier += -2; + supportModifier += 2; + transportModifier += 3; + } + case RECON_RAID -> { + commandModifier += -1; + salvageModifier += -2; + supportModifier += 1; + transportModifier += -1; + } + case RELIEF_DUTY -> { + commandModifier += -1; + salvageModifier += 1; + supportModifier += 1; + transportModifier += 1; + } + case RIOT_DUTY -> { + commandModifier += -2; + salvageModifier += 1; + supportModifier += 2; + } + case SECURITY_DUTY -> { + commandModifier += -3; + supportModifier += 2; + transportModifier += 1; + } + } + } + + private void addEmployerModifiers(Faction employer, LocalDate date) { + if (employer.isSuperPower()) { + employmentMultiplier += 1.3; + supportModifier += 1; + transportModifier += 2; + } else if (employer.isMajorPower()) { + employmentMultiplier += 1.2; + salvageModifier += -1; + transportModifier += 1; + } else if (employer.isMinorPower()) { + employmentMultiplier += 1.1; + salvageModifier += -2; + } else if (employer.isCorporation() || employer.isMercenary()) { + employmentMultiplier += 1.1; + commandModifier += -1; + salvageModifier += 2; + supportModifier += 1; + transportModifier += 1; + } else if (employer.isIndependent() || employer.isPlanetaryGovt()) { + employmentMultiplier += 1.0; + salvageModifier += -1; + supportModifier += -1; + } + if (employer.isStingy()) { + employmentMultiplier += -0.2; + salvageModifier += -1; + supportModifier += -1; + transportModifier += -1; + } + if (employer.isGenerous()) { + employmentMultiplier += 0.2; + salvageModifier += 1; + supportModifier += 2; + transportModifier += 1; + } + if (employer.isControlling()) { + commandModifier += -2; + salvageModifier += -1; + } + if (employer.isLenient()) { + commandModifier += 1; + salvageModifier += 1; + } + if (date.getYear() < 2781 || date.getYear() > 3062) { + salvageModifier += -2; + } + } + + private void addUnitReputationModifiers(int reputationRating) { + if (reputationRating <= 0) { + commandModifier += -2; + salvageModifier += -1; + supportModifier += -1; + transportModifier += -3; + } else if (reputationRating == 1) { + commandModifier += -1; + salvageModifier += -1; + supportModifier += -1; + transportModifier += -2; + } else if (reputationRating == 2) { + commandModifier += -1; + transportModifier += -2; + } else if (reputationRating == 3) { + commandModifier += -1; + transportModifier += -1; + } else if (reputationRating == 4) { + transportModifier += -1; + } else if (reputationRating == 6 || reputationRating == 7) { + commandModifier += 1; + salvageModifier += 1; + } else if (reputationRating == 8) { + commandModifier += 1; + salvageModifier += 1; + supportModifier += 1; + } else if (reputationRating == 9) { + commandModifier += 2; + salvageModifier += 2; + supportModifier += 1; + transportModifier += 1; + } else { + commandModifier += 3; + salvageModifier += 2; + supportModifier += 2; + transportModifier += 2; + } + } +} \ No newline at end of file From 4f72f9690e8adf317764959955c162c3618c8f1e Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 10:47:32 -0400 Subject: [PATCH 13/28] remove covert from missing missions since it's just a category --- MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java b/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java index 8916f8c405..155507eb8e 100644 --- a/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java +++ b/MekHQ/src/mekhq/campaign/mission/enums/AtBContractType.java @@ -30,7 +30,7 @@ public enum AtBContractType { // TODO: Missing Camops Mission Types: ASSASSINATION, ESPIONAGE, MOLE_HUNTING, OBSERVATION_RAID, - // RETAINER, SABOTAGE, TERRORISM, HIGH_RISK, COVERT + // RETAINER, SABOTAGE, TERRORISM, HIGH_RISK // region Enum Declarations GARRISON_DUTY("AtBContractType.GARRISON_DUTY.text", "AtBContractType.GARRISON_DUTY.toolTipText", 18, 1.0), CADRE_DUTY("AtBContractType.CADRE_DUTY.text", "AtBContractType.CADRE_DUTY.toolTipText", 12, 0.8), From 5da0c45edec9c249330650a126ee3087e5bdef52 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 11:24:19 -0400 Subject: [PATCH 14/28] rename reputationFactor to reputationMod --- .../market/contractMarket/ContractTerms.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java index fb203bbce4..ef0f6c59a5 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -19,12 +19,12 @@ public class ContractTerms { private int supportModifier; private int transportModifier; - public ContractTerms(AtBContractType mission, Faction employer, int reputationRating, LocalDate date) { + public ContractTerms(AtBContractType mission, Faction employer, int reputationMod, LocalDate date) { operationsTempoMultiplier = mission.getOperationsTempoMultiplier(); baseLength = mission.getConstantLength(); addMissionTypeModifiers(mission); addEmployerModifiers(employer, date); - addUnitReputationModifiers(reputationRating); + addUnitReputationModifiers(reputationMod); } public double getOperationsTempoMultiplier() { @@ -202,25 +202,25 @@ private void addMissionTypeModifiers(AtBContractType mission) { } private void addEmployerModifiers(Faction employer, LocalDate date) { + employmentMultiplier = 1.0; if (employer.isSuperPower()) { - employmentMultiplier += 1.3; + employmentMultiplier += 0.3; supportModifier += 1; transportModifier += 2; } else if (employer.isMajorPower()) { - employmentMultiplier += 1.2; + employmentMultiplier += 0.2; salvageModifier += -1; transportModifier += 1; } else if (employer.isMinorPower()) { - employmentMultiplier += 1.1; + employmentMultiplier += 0.1; salvageModifier += -2; } else if (employer.isCorporation() || employer.isMercenary()) { - employmentMultiplier += 1.1; + employmentMultiplier += 0.1; commandModifier += -1; salvageModifier += 2; supportModifier += 1; transportModifier += 1; } else if (employer.isIndependent() || employer.isPlanetaryGovt()) { - employmentMultiplier += 1.0; salvageModifier += -1; supportModifier += -1; } @@ -249,33 +249,33 @@ private void addEmployerModifiers(Faction employer, LocalDate date) { } } - private void addUnitReputationModifiers(int reputationRating) { - if (reputationRating <= 0) { + private void addUnitReputationModifiers(int reputationMod) { + if (reputationMod <= 0) { commandModifier += -2; salvageModifier += -1; supportModifier += -1; transportModifier += -3; - } else if (reputationRating == 1) { + } else if (reputationMod == 1) { commandModifier += -1; salvageModifier += -1; supportModifier += -1; transportModifier += -2; - } else if (reputationRating == 2) { + } else if (reputationMod == 2) { commandModifier += -1; transportModifier += -2; - } else if (reputationRating == 3) { + } else if (reputationMod == 3) { commandModifier += -1; transportModifier += -1; - } else if (reputationRating == 4) { + } else if (reputationMod == 4) { transportModifier += -1; - } else if (reputationRating == 6 || reputationRating == 7) { + } else if (reputationMod == 6 || reputationMod == 7) { commandModifier += 1; salvageModifier += 1; - } else if (reputationRating == 8) { + } else if (reputationMod == 8) { commandModifier += 1; salvageModifier += 1; supportModifier += 1; - } else if (reputationRating == 9) { + } else if (reputationMod == 9) { commandModifier += 2; salvageModifier += 2; supportModifier += 1; From a498199cb8a84a3d94a5706f092d05509a95aada Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 13:39:50 -0400 Subject: [PATCH 15/28] add getReputationFactor() method --- .../market/contractMarket/ContractTerms.java | 22 +++++++++---------- .../contractMarket/MissionSelector.java | 4 ++++ .../ReputationController.java | 4 ++++ 3 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java index ef0f6c59a5..7e3bd69b05 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -19,12 +19,12 @@ public class ContractTerms { private int supportModifier; private int transportModifier; - public ContractTerms(AtBContractType mission, Faction employer, int reputationMod, LocalDate date) { + public ContractTerms(AtBContractType mission, Faction employer, int reputationFactor, LocalDate date) { operationsTempoMultiplier = mission.getOperationsTempoMultiplier(); baseLength = mission.getConstantLength(); addMissionTypeModifiers(mission); addEmployerModifiers(employer, date); - addUnitReputationModifiers(reputationMod); + addUnitReputationModifiers(reputationFactor); } public double getOperationsTempoMultiplier() { @@ -249,33 +249,33 @@ private void addEmployerModifiers(Faction employer, LocalDate date) { } } - private void addUnitReputationModifiers(int reputationMod) { - if (reputationMod <= 0) { + private void addUnitReputationModifiers(int reputationFactor) { + if (reputationFactor <= 0) { commandModifier += -2; salvageModifier += -1; supportModifier += -1; transportModifier += -3; - } else if (reputationMod == 1) { + } else if (reputationFactor == 1) { commandModifier += -1; salvageModifier += -1; supportModifier += -1; transportModifier += -2; - } else if (reputationMod == 2) { + } else if (reputationFactor == 2) { commandModifier += -1; transportModifier += -2; - } else if (reputationMod == 3) { + } else if (reputationFactor == 3) { commandModifier += -1; transportModifier += -1; - } else if (reputationMod == 4) { + } else if (reputationFactor == 4) { transportModifier += -1; - } else if (reputationMod == 6 || reputationMod == 7) { + } else if (reputationFactor == 6 || reputationFactor == 7) { commandModifier += 1; salvageModifier += 1; - } else if (reputationMod == 8) { + } else if (reputationFactor == 8) { commandModifier += 1; salvageModifier += 1; supportModifier += 1; - } else if (reputationMod == 9) { + } else if (reputationFactor == 9) { commandModifier += 2; salvageModifier += 2; supportModifier += 1; diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java new file mode 100644 index 0000000000..4c2612f22c --- /dev/null +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -0,0 +1,4 @@ +package mekhq.campaign.market.contractMarket; + +public class MissionSelector { +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java index 862ab59280..40ff6f72b1 100644 --- a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java @@ -103,6 +103,10 @@ public int getAtbModifier() { public int getReputationRating() { return this.reputationRating; } + + public int getReputationFactor() { + return (int) (getReputationModifier() * 0.2 + 0.5); + } // endregion Getters and Setters /** From 40b6b8e2ffe9ca93f71d6d03b46a6f0dd474d5a0 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 13:43:56 -0400 Subject: [PATCH 16/28] remove unused reputationFactor method --- MekHQ/src/mekhq/campaign/Campaign.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index 2282a44c40..8d80f4d67d 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -6861,19 +6861,6 @@ public int getAtBUnitRatingMod() { : reputation.getAtbModifier(); } - /** - * Retrieves the unit reputation factor based on the rating method defined in the Campaign Options. - * - * @return the reputation factor for the selected unit rating method. - */ - public int getReputationFactor() { - return switch (campaignOptions.getUnitRatingMethod()) { - case NONE -> 5; - case FLD_MAN_MERCS_REV -> getAtBUnitRatingMod() * 2; - case CAMPAIGN_OPS -> (int) (getReputation().getReputationModifier() * 0.2 + 0.5); - }; - } - /** * Returns the Strategy skill of the designated commander in the campaign. * From 62abce828d159d1c9f313da9b6428bd31b1fb417 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 13:57:43 -0400 Subject: [PATCH 17/28] add MissionSelector for determining missions --- .../contractMarket/CamOpsContractMarket.java | 34 ++++-- .../contractMarket/MissionSelector.java | 111 ++++++++++++++++++ 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index bcff7619b4..a581622845 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -10,6 +10,7 @@ import mekhq.campaign.mission.enums.AtBContractType; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.SkillType; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.universe.Faction; import mekhq.campaign.universe.Faction.Tag; @@ -34,8 +35,8 @@ public CamOpsContractMarket() { @Override public AtBContract addAtBContract(Campaign campaign) { HiringHallModifiers hiringHallModifiers = getHiringHallModifiers(campaign); - int ratingMod = campaign.getReputation().getReputationModifier(); - Optional c = generateContract(campaign, ratingMod, hiringHallModifiers); + ReputationController reputation = campaign.getReputation(); + Optional c = generateContract(campaign, reputation, hiringHallModifiers); if (c.isPresent()) { AtBContract atbContract = c.get(); contracts.add(atbContract); @@ -126,19 +127,19 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign, int ratingMod, HiringHallModifiers hiringHallModifiers) { + private Optional generateContract(Campaign campaign, ReputationController reputation, HiringHallModifiers hiringHallModifiers) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); contractIds.put(lastId, contract); - Faction employer = determineEmployer(campaign, ratingMod, hiringHallModifiers); + Faction employer = determineEmployer(campaign, reputation.getReputationModifier(), hiringHallModifiers); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); } - contract.setContractType(determineMission(campaign, employer, ratingMod)); + contract.setContractType(determineMission(campaign, employer, reputation.getReputationModifier())); ContractTerms contractTerms = new ContractTerms(contract.getContractType(), - employer, ratingMod, campaign.getLocalDate()); + employer, reputation.getReputationFactor(), campaign.getLocalDate()); setEnemyCode(contract); setIsRiotDuty(contract); setAttacker(contract); @@ -246,15 +247,22 @@ private Collection getEmployerTags(Campaign campaign, int roll, boolean ind } private AtBContractType determineMission(Campaign campaign, Faction employer, int ratingMod) { - int roll = Compute.d6(2); if (campaign.getFaction().isPirate()) { - if (roll < 6) { - return AtBContractType.RECON_RAID; - } else { - return AtBContractType.OBJECTIVE_RAID; - } + return MissionSelector.getPirateMission(Compute.d6(2), 0); + } + int margin = rollNegotiation(findNegotiationSkill(campaign), + ratingMod + getHiringHallModifiers(campaign).missionsMod) - BASE_NEGOTIATION_TARGET; + boolean isClan = campaign.getFaction().isClan(); + if (employer.isInnerSphere() || employer.isClan()) { + return MissionSelector.getInnerSphereClanMission(Compute.d6(2), margin, isClan); + } else if (employer.isIndependent() || employer.isPlanetaryGovt()) { + return MissionSelector.getIndependentMission(Compute.d6(2), margin, isClan); + } else if (employer.isCorporation()) { + return MissionSelector.getCorporationMission(Compute.d6(2), margin, isClan); + } else { + logger.warn("No matching employer on Missions table; defaulting to IS/Clan"); + return MissionSelector.getInnerSphereClanMission(Compute.d6(2), margin, isClan); } - return findMissionType(ratingMod, employer.isISMajorOrSuperPower()); } private void setContractClauses(AtBContract contract, ContractTerms terms) { diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java index 4c2612f22c..00c35ad9b4 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -1,4 +1,115 @@ package mekhq.campaign.market.contractMarket; +import megamek.common.Compute; +import mekhq.campaign.mission.enums.AtBContractType; + public class MissionSelector { + public static AtBContractType getInnerSphereClanMission(int roll, int margin, boolean isClan) { + if (isClan) { + int result = roll + margin; + if (result < 4 || result > 11) { + // Reroll on the IS/Clan column if the force is clan and the result is Covert or Special + return getInnerSphereClanMission(Compute.d6(2), margin, true); + } + } + roll += margin; + if (roll < 3) { + return getCovertMission(Compute.d6(2), margin); + } else if (roll == 3 || roll > 11) { + return getSpecialMission(Compute.d6(2), margin); + } else if (roll == 4) { + return AtBContractType.PIRATE_HUNTING; + } else if (roll == 5) { + return AtBContractType.PLANETARY_ASSAULT; + } else if (roll == 6 || roll == 7) { + return AtBContractType.RECON_RAID; + } else if (roll == 8) { + return AtBContractType.EXTRACTION_RAID; + } else if (roll == 9) { + return AtBContractType.EXTRACTION_RAID; + } else if (roll == 10) { + return AtBContractType.GARRISON_DUTY; + } else { + return AtBContractType.CADRE_DUTY; + } + } + + public static AtBContractType getIndependentMission(int roll, int margin, boolean isClan) { + if (isClan) { + int result = roll + margin; + if (result < 4 || result > 11) { + // Reroll on the IS/Clan column if the force is clan and the result is Covert or Special + return getInnerSphereClanMission(Compute.d6(2), margin, true); + } + } + roll += margin; + if (roll < 3) { + return getCovertMission(Compute.d6(2), margin); + } else if (roll == 3 || roll > 11) { + return getSpecialMission(Compute.d6(2), margin); + } else if (roll == 4) { + return AtBContractType.PLANETARY_ASSAULT; + } else if (roll == 5 || roll == 9) { + return AtBContractType.OBJECTIVE_RAID; + } else if (roll == 6) { + return AtBContractType.EXTRACTION_RAID; + } else if (roll == 7) { + return AtBContractType.PIRATE_HUNTING; + } else if (roll == 8) { + return AtBContractType.SECURITY_DUTY; + } else if (roll == 10) { + return AtBContractType.GARRISON_DUTY; + } else { + return AtBContractType.CADRE_DUTY; + } + } + + public static AtBContractType getCorporationMission(int roll, int margin, boolean isClan) { + if (isClan) { + int result = roll + margin; + if (result < 5 || result > 11) { + // Reroll on the IS/Clan column if the force is clan and the result is Covert or Special + return getInnerSphereClanMission(Compute.d6(2), margin, true); + } + } + roll += margin; + if (roll < 4) { + return getCovertMission(Compute.d6(2), margin); + } else if (roll == 4 || roll > 11) { + return getSpecialMission(Compute.d6(2), margin); + } else if (roll == 5 || roll == 8) { + return AtBContractType.OBJECTIVE_RAID; + } else if (roll == 6) { + return AtBContractType.EXTRACTION_RAID; + } else if (roll == 7) { + return AtBContractType.RECON_RAID; + } else if (roll == 9) { + return AtBContractType.SECURITY_DUTY; + } else if (roll == 10) { + return AtBContractType.GARRISON_DUTY; + } else { + // TODO: determine which is the higher paying between cadre/garrison and return that + return AtBContractType.CADRE_DUTY; + } + } + + public static AtBContractType getSpecialMission(int roll, int margin) { + roll += margin; + if (roll < 3) { + + } + } + + public static AtBContractType getCovertMission(int roll, int margin) { + roll += margin; + } + + public static AtBContractType getPirateMission(int roll, int margin) { + roll += margin; + if (roll < 6) { + return AtBContractType.RECON_RAID; + } else { + return AtBContractType.OBJECTIVE_RAID; + } + } } From 4ab7d5814fd1bb7dc027d0d631a990d9704131cc Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 14:08:18 -0400 Subject: [PATCH 18/28] finish the rest of the mission tables --- .../contractMarket/MissionSelector.java | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java index 00c35ad9b4..2bffc85595 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -93,23 +93,47 @@ public static AtBContractType getCorporationMission(int roll, int margin, boolea } } - public static AtBContractType getSpecialMission(int roll, int margin) { + public static AtBContractType getPirateMission(int roll, int margin) { roll += margin; - if (roll < 3) { - + if (roll < 6) { + return AtBContractType.RECON_RAID; + } else { + return AtBContractType.OBJECTIVE_RAID; } } - public static AtBContractType getCovertMission(int roll, int margin) { + private static AtBContractType getSpecialMission(int roll, int margin) { roll += margin; - } - - public static AtBContractType getPirateMission(int roll, int margin) { - roll += margin; - if (roll < 6) { + if (roll < 3) { + return getCovertMission(Compute.d6(2), margin); + } else if (roll < 5) { + // TODO: figure out how to offer planetary assault followup contracts + return AtBContractType.GUERRILLA_WARFARE; + } else if (roll == 5 || roll == 8) { + // TODO: figure out how to offer planetary assault followup contracts return AtBContractType.RECON_RAID; + } else if (roll == 6) { + return AtBContractType.EXTRACTION_RAID; + } else if (roll == 7) { + // TODO: change this to RETAINER if/when that is implemented + return AtBContractType.GARRISON_DUTY; + } else if (roll == 9) { + return AtBContractType.RELIEF_DUTY; + } else if (roll == 10) { + // TODO: figure out how to offer planetary assault followup contracts + return AtBContractType.DIVERSIONARY_RAID; + } else if (roll == 11) { + // // TODO: determine which is the higher paying between riot/garrison and return that + return AtBContractType.RIOT_DUTY; } else { - return AtBContractType.OBJECTIVE_RAID; + // TODO: determine which is the higher paying between cadre/garrison and return that + return AtBContractType.CADRE_DUTY; } } + + private static AtBContractType getCovertMission(int roll, int margin) { + // TODO: most of the covert mission types are not implemented in MekHQ at the time of writing, + // so just use the special missions table for now. + return getSpecialMission(Compute.d6(2), margin); + } } From 257581f98e9bb2f61c6146847ce20442db588ac1 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 14:23:15 -0400 Subject: [PATCH 19/28] add comments documenting the flow of the generateContract method --- .../market/contractMarket/CamOpsContractMarket.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index a581622845..5f23b1d662 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -132,33 +132,43 @@ private Optional generateContract(Campaign campaign, ReputationCont lastId++; contract.setId(lastId); contractIds.put(lastId, contract); + // Step 1: Determine Employer Faction employer = determineEmployer(campaign, reputation.getReputationModifier(), hiringHallModifiers); contract.setEmployerCode(employer.getShortName(), campaign.getLocalDate()); if (employer.isMercenary()) { contract.setMercSubcontract(true); } + // Step 2: Determine the mission type contract.setContractType(determineMission(campaign, employer, reputation.getReputationModifier())); ContractTerms contractTerms = new ContractTerms(contract.getContractType(), employer, reputation.getReputationFactor(), campaign.getLocalDate()); setEnemyCode(contract); - setIsRiotDuty(contract); setAttacker(contract); + // Step 3: Set the system location try { setSystemId(contract); } catch (NoContractLocationFoundException ex) { return Optional.empty(); } + // Step 4: Populate some information about enemies and allies setAllyRating(contract, campaign.getGameYear()); setEnemyRating(contract, campaign.getGameYear()); if (contract.getContractType().isCadreDuty()) { contract.setAllySkill(SkillLevel.GREEN); contract.setAllyQuality(IUnitRating.DRAGOON_F); } + // Step 5: Determine the contract length (Not CamOps RAW) contract.calculateLength(campaign.getCampaignOptions().isVariableContractLength()); + // Step 6: Determine the initial contract clauses setContractClauses(contract, contractTerms); + // Step 7: Determine the number of required lances (Not CamOps RAW) contract.setRequiredLances(calculateRequiredLances(campaign, contract)); + // Step 8: Calculate the payment contract.setMultiplier(calculatePaymentMultiplier(campaign, contract)); + // Step 9: Determine parts availability + // TODO: Rewrite this to be CamOps-compliant contract.setPartsAvailabilityLevel(contract.getContractType().calculatePartsAvailabilityLevel()); + // Step 10: Finish up contract initialization contract.initContractDetails(campaign); contract.calculateContract(campaign); contract.setName(String.format("%s - %s - %s %s", From 605977c600c0d12e971da1c4ce12ce5da9671346 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 14:37:20 -0400 Subject: [PATCH 20/28] implement payment multiplier for camops --- .../market/contractMarket/CamOpsContractMarket.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 5f23b1d662..906a0fb927 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -71,8 +71,11 @@ public void generateContractOffers(Campaign campaign, boolean newCampaign) { @Override public double calculatePaymentMultiplier(Campaign campaign, AtBContract contract) { - //TODO: add logic from camops 4th printing - return 1.0; + Faction employer = contract.getEmployerFaction(); + int reputationFactor = campaign.getReputation().getReputationFactor(); + ContractTerms terms = new ContractTerms(contract.getContractType(), employer, + reputationFactor, campaign.getLocalDate()); + return terms.getEmploymentMultiplier() * terms.getOperationsTempoMultiplier() * reputationFactor; } @Override @@ -127,7 +130,8 @@ private int getNumberOfOffers(int margin) { } } - private Optional generateContract(Campaign campaign, ReputationController reputation, HiringHallModifiers hiringHallModifiers) { + private Optional generateContract(Campaign campaign, ReputationController reputation, + HiringHallModifiers hiringHallModifiers) { AtBContract contract = new AtBContract("UnnamedContract"); lastId++; contract.setId(lastId); From f6d64c30610e9bfd928c13ab7081d812160b4c84 Mon Sep 17 00:00:00 2001 From: algebro Date: Thu, 3 Oct 2024 14:38:50 -0400 Subject: [PATCH 21/28] add class javadoc --- .../mekhq/campaign/market/contractMarket/MissionSelector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java index 2bffc85595..97c496786d 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -3,6 +3,9 @@ import megamek.common.Compute; import mekhq.campaign.mission.enums.AtBContractType; +/** + * Utility class that implements the mission tables as described in CamOps (4th printing). + */ public class MissionSelector { public static AtBContractType getInnerSphereClanMission(int roll, int margin, boolean isClan) { if (isClan) { From 8833b4c6eebf0a270a733dddded7132c0489125e Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 10:05:00 -0400 Subject: [PATCH 22/28] add legal notice --- .../universe/enums/HiringHallLevel.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/universe/enums/HiringHallLevel.java b/MekHQ/src/mekhq/campaign/universe/enums/HiringHallLevel.java index 5b8ad5704f..b4de49dd27 100644 --- a/MekHQ/src/mekhq/campaign/universe/enums/HiringHallLevel.java +++ b/MekHQ/src/mekhq/campaign/universe/enums/HiringHallLevel.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ package mekhq.campaign.universe.enums; /** From 51d97c53d9ad134c19270c7b6d167a617984c132 Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 10:12:43 -0400 Subject: [PATCH 23/28] refactor to switch blocks and add legal notice --- .../contractMarket/MissionSelector.java | 142 ++++++++---------- 1 file changed, 63 insertions(+), 79 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java index 97c496786d..bc11dcb025 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -1,5 +1,24 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ package mekhq.campaign.market.contractMarket; +import megamek.codeUtilities.MathUtility; import megamek.common.Compute; import mekhq.campaign.mission.enums.AtBContractType; @@ -15,26 +34,17 @@ public static AtBContractType getInnerSphereClanMission(int roll, int margin, bo return getInnerSphereClanMission(Compute.d6(2), margin, true); } } - roll += margin; - if (roll < 3) { - return getCovertMission(Compute.d6(2), margin); - } else if (roll == 3 || roll > 11) { - return getSpecialMission(Compute.d6(2), margin); - } else if (roll == 4) { - return AtBContractType.PIRATE_HUNTING; - } else if (roll == 5) { - return AtBContractType.PLANETARY_ASSAULT; - } else if (roll == 6 || roll == 7) { - return AtBContractType.RECON_RAID; - } else if (roll == 8) { - return AtBContractType.EXTRACTION_RAID; - } else if (roll == 9) { - return AtBContractType.EXTRACTION_RAID; - } else if (roll == 10) { - return AtBContractType.GARRISON_DUTY; - } else { - return AtBContractType.CADRE_DUTY; - } + return switch(MathUtility.clamp(roll + margin, 2, 12)) { + case 2 -> getCovertMission(Compute.d6(2), margin); + case 3, 12 -> getSpecialMission(Compute.d6(2), margin); + case 4 -> AtBContractType.PIRATE_HUNTING; + case 5 -> AtBContractType.PLANETARY_ASSAULT; + case 6, 7 -> AtBContractType.OBJECTIVE_RAID; + case 8 -> AtBContractType.EXTRACTION_RAID; + case 9 -> AtBContractType.RECON_RAID; + case 10 -> AtBContractType.GARRISON_DUTY; + default -> AtBContractType.CADRE_DUTY; + }; } public static AtBContractType getIndependentMission(int roll, int margin, boolean isClan) { @@ -45,26 +55,17 @@ public static AtBContractType getIndependentMission(int roll, int margin, boolea return getInnerSphereClanMission(Compute.d6(2), margin, true); } } - roll += margin; - if (roll < 3) { - return getCovertMission(Compute.d6(2), margin); - } else if (roll == 3 || roll > 11) { - return getSpecialMission(Compute.d6(2), margin); - } else if (roll == 4) { - return AtBContractType.PLANETARY_ASSAULT; - } else if (roll == 5 || roll == 9) { - return AtBContractType.OBJECTIVE_RAID; - } else if (roll == 6) { - return AtBContractType.EXTRACTION_RAID; - } else if (roll == 7) { - return AtBContractType.PIRATE_HUNTING; - } else if (roll == 8) { - return AtBContractType.SECURITY_DUTY; - } else if (roll == 10) { - return AtBContractType.GARRISON_DUTY; - } else { - return AtBContractType.CADRE_DUTY; - } + return switch(MathUtility.clamp(roll + margin, 2, 12)) { + case 2 -> getCovertMission(Compute.d6(2), margin); + case 3, 12 -> getSpecialMission(Compute.d6(2), margin); + case 4 -> AtBContractType.PLANETARY_ASSAULT; + case 5, 9 -> AtBContractType.OBJECTIVE_RAID; + case 6 -> AtBContractType.EXTRACTION_RAID; + case 7 -> AtBContractType.PIRATE_HUNTING; + case 8 -> AtBContractType.SECURITY_DUTY; + case 10 -> AtBContractType.GARRISON_DUTY; + default -> AtBContractType.CADRE_DUTY; + }; } public static AtBContractType getCorporationMission(int roll, int margin, boolean isClan) { @@ -75,25 +76,17 @@ public static AtBContractType getCorporationMission(int roll, int margin, boolea return getInnerSphereClanMission(Compute.d6(2), margin, true); } } - roll += margin; - if (roll < 4) { - return getCovertMission(Compute.d6(2), margin); - } else if (roll == 4 || roll > 11) { - return getSpecialMission(Compute.d6(2), margin); - } else if (roll == 5 || roll == 8) { - return AtBContractType.OBJECTIVE_RAID; - } else if (roll == 6) { - return AtBContractType.EXTRACTION_RAID; - } else if (roll == 7) { - return AtBContractType.RECON_RAID; - } else if (roll == 9) { - return AtBContractType.SECURITY_DUTY; - } else if (roll == 10) { - return AtBContractType.GARRISON_DUTY; - } else { + return switch(MathUtility.clamp(roll + margin, 2, 12)) { + case 2, 3 -> getCovertMission(Compute.d6(2), margin); + case 4, 12 -> getSpecialMission(Compute.d6(2), margin); + case 5, 8 -> AtBContractType.OBJECTIVE_RAID; + case 6 -> AtBContractType.EXTRACTION_RAID; + case 7 -> AtBContractType.RECON_RAID; + case 9 -> AtBContractType.SECURITY_DUTY; + case 10 -> AtBContractType.GARRISON_DUTY; // TODO: determine which is the higher paying between cadre/garrison and return that - return AtBContractType.CADRE_DUTY; - } + default -> AtBContractType.CADRE_DUTY; + }; } public static AtBContractType getPirateMission(int roll, int margin) { @@ -106,32 +99,23 @@ public static AtBContractType getPirateMission(int roll, int margin) { } private static AtBContractType getSpecialMission(int roll, int margin) { - roll += margin; - if (roll < 3) { - return getCovertMission(Compute.d6(2), margin); - } else if (roll < 5) { + return switch(MathUtility.clamp(roll + margin, 2, 12)) { + case 2 -> getCovertMission(Compute.d6(2), margin); // TODO: figure out how to offer planetary assault followup contracts - return AtBContractType.GUERRILLA_WARFARE; - } else if (roll == 5 || roll == 8) { + case 3, 4 -> AtBContractType.GUERRILLA_WARFARE; // TODO: figure out how to offer planetary assault followup contracts - return AtBContractType.RECON_RAID; - } else if (roll == 6) { - return AtBContractType.EXTRACTION_RAID; - } else if (roll == 7) { + case 5, 8 -> AtBContractType.RECON_RAID; + case 6 -> AtBContractType.EXTRACTION_RAID; // TODO: change this to RETAINER if/when that is implemented - return AtBContractType.GARRISON_DUTY; - } else if (roll == 9) { - return AtBContractType.RELIEF_DUTY; - } else if (roll == 10) { + case 7 -> AtBContractType.GARRISON_DUTY; + case 9 -> AtBContractType.RELIEF_DUTY; // TODO: figure out how to offer planetary assault followup contracts - return AtBContractType.DIVERSIONARY_RAID; - } else if (roll == 11) { - // // TODO: determine which is the higher paying between riot/garrison and return that - return AtBContractType.RIOT_DUTY; - } else { + case 10 -> AtBContractType.DIVERSIONARY_RAID; + // TODO: determine which is the higher paying between riot/garrison and return that + case 11 -> AtBContractType.RIOT_DUTY; // TODO: determine which is the higher paying between cadre/garrison and return that - return AtBContractType.CADRE_DUTY; - } + default -> AtBContractType.CADRE_DUTY; + }; } private static AtBContractType getCovertMission(int roll, int margin) { From e99b243579a22ad9da9e6470107b7c72ee3d4967 Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 10:30:01 -0400 Subject: [PATCH 24/28] refactor to switch blocks and add legal statement --- .../market/contractMarket/ContractTerms.java | 192 +++++++++--------- 1 file changed, 100 insertions(+), 92 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java index 7e3bd69b05..cf2886f57a 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -1,5 +1,24 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ package mekhq.campaign.market.contractMarket; +import megamek.codeUtilities.MathUtility; import mekhq.campaign.mission.enums.AtBContractType; import mekhq.campaign.mission.enums.ContractCommandRights; import mekhq.campaign.universe.Faction; @@ -59,46 +78,32 @@ public boolean isSalvageExchange(int roll) { public int getSalvagePercentage(int roll) { roll += salvageModifier; - if (roll < 4) { - return 0; - } else if (roll == 4) { - return 10; - } else if (roll == 5) { - return 20; - } else if (roll == 6) { - return 30; - } else if (roll == 7) { - return 40; - } else if (roll == 8) { - return 50; - } else if (roll == 9) { - return 60; - } else if (roll == 10) { - return 70; - } else if (roll == 11) { - return 80; - } else if (roll == 12) { - return 90; - } else { - return 100; - } + return switch (MathUtility.clamp(roll, 3, 13)) { + case 3 -> 0; + case 4 -> 10; + case 5 -> 20; + case 6 -> 30; + case 7 -> 40; + case 8 -> 50; + case 9 -> 60; + case 10 -> 70; + case 11 -> 80; + case 12 -> 90; + default -> 100; + }; } public int getSupportPercentage(int roll) { roll += supportModifier; - int percentage = 0; - if (roll == 3 || roll == 9) { - percentage = 20; - } else if (roll == 4 || roll == 10) { - percentage = 40; - } else if (roll == 5 || roll == 11) { - percentage = 60; - } else if (roll == 6 || roll == 12) { - percentage = 80; - } else if (roll == 7 || roll > 12) { - percentage = 100; - } - return percentage; + return switch(MathUtility.clamp(roll, 2, 13)) { + case 2 -> 0; + case 3, 9 -> 20; + case 4, 10 -> 40; + case 5, 11 -> 60; + case 6, 12 -> 80; + case 8 -> 10; + default -> 100; + }; } public boolean isStraightSupport(int roll) { @@ -113,27 +118,18 @@ public boolean isBattleLossComp(int roll) { public int getTransportTerms(int roll) { roll += transportModifier; - if (roll < 2) { - return 0; - } else if (roll == 2) { - return 20; - } else if (roll == 3) { - return 25; - } else if (roll == 4) { - return 30; - } else if (roll == 5) { - return 35; - } else if (roll == 6) { - return 45; - } else if (roll == 7) { - return 50; - } else if (roll == 8) { - return 55; - } else if (roll == 9) { - return 60; - } else { - return 100; - } + return switch (MathUtility.clamp(roll, 1, 10)) { + case 1 -> 0; + case 2 -> 20; + case 3 -> 25; + case 4 -> 30; + case 5 -> 35; + case 6 -> 45; + case 7 -> 50; + case 8 -> 55; + case 9 -> 60; + default -> 100; + }; } private void addMissionTypeModifiers(AtBContractType mission) { @@ -250,41 +246,53 @@ private void addEmployerModifiers(Faction employer, LocalDate date) { } private void addUnitReputationModifiers(int reputationFactor) { - if (reputationFactor <= 0) { - commandModifier += -2; - salvageModifier += -1; - supportModifier += -1; - transportModifier += -3; - } else if (reputationFactor == 1) { - commandModifier += -1; - salvageModifier += -1; - supportModifier += -1; - transportModifier += -2; - } else if (reputationFactor == 2) { - commandModifier += -1; - transportModifier += -2; - } else if (reputationFactor == 3) { - commandModifier += -1; - transportModifier += -1; - } else if (reputationFactor == 4) { - transportModifier += -1; - } else if (reputationFactor == 6 || reputationFactor == 7) { - commandModifier += 1; - salvageModifier += 1; - } else if (reputationFactor == 8) { - commandModifier += 1; - salvageModifier += 1; - supportModifier += 1; - } else if (reputationFactor == 9) { - commandModifier += 2; - salvageModifier += 2; - supportModifier += 1; - transportModifier += 1; - } else { - commandModifier += 3; - salvageModifier += 2; - supportModifier += 2; - transportModifier += 2; + switch(MathUtility.clamp(reputationFactor, 0, 10)) { + case 0: + commandModifier += -2; + salvageModifier += -1; + supportModifier += -1; + transportModifier += -3; + break; + case 1: + commandModifier += -1; + salvageModifier += -1; + supportModifier += -1; + transportModifier += -2; + break; + case 2: + commandModifier += -1; + transportModifier += -2; + break; + case 3: + commandModifier += -1; + transportModifier += -1; + break; + case 4: + transportModifier += -1; + break; + case 6: + case 7: + commandModifier += 1; + salvageModifier += 1; + break; + case 8: + commandModifier += 1; + salvageModifier += 1; + supportModifier += 1; + break; + case 9: + commandModifier += 2; + salvageModifier += 2; + supportModifier += 1; + transportModifier += 1; + break; + default: + commandModifier += 3; + salvageModifier += 2; + supportModifier += 2; + transportModifier += 2; + break; + } } } \ No newline at end of file From 51740002501bcb1a4a278a1da32a937c1f67cd62 Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 10:31:58 -0400 Subject: [PATCH 25/28] add legal notice --- .../contractMarket/CamOpsContractMarket.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java index 906a0fb927..31199c9394 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/CamOpsContractMarket.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ package mekhq.campaign.market.contractMarket; import megamek.common.Compute; From fcc0b602b522be2b24ab82f62f833d049de10f61 Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 10:33:01 -0400 Subject: [PATCH 26/28] make some employer tags mutually exclusive for modifiers --- .../mekhq/campaign/market/contractMarket/ContractTerms.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java index cf2886f57a..8ec0bfa668 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -225,8 +225,7 @@ private void addEmployerModifiers(Faction employer, LocalDate date) { salvageModifier += -1; supportModifier += -1; transportModifier += -1; - } - if (employer.isGenerous()) { + } else if (employer.isGenerous()) { employmentMultiplier += 0.2; salvageModifier += 1; supportModifier += 2; @@ -235,8 +234,7 @@ private void addEmployerModifiers(Faction employer, LocalDate date) { if (employer.isControlling()) { commandModifier += -2; salvageModifier += -1; - } - if (employer.isLenient()) { + } else if (employer.isLenient()) { commandModifier += 1; salvageModifier += 1; } From 679528f780fe499199491049cf7eaeaae1d63249 Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 16:03:34 -0400 Subject: [PATCH 27/28] add javadocs --- .../market/contractMarket/ContractTerms.java | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java index 8ec0bfa668..3220f15c27 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/ContractTerms.java @@ -27,7 +27,7 @@ /** * Structure that resolves and stores modifiers and contract terms as shown in the Master Contract - * Terms Table on page 42 of CamOps (4th printing). + * Terms Table on page 42 and Supplemental Contract Terms Table on page 43 of CamOps (4th printing). */ public class ContractTerms { private double operationsTempoMultiplier; @@ -58,9 +58,16 @@ public double getEmploymentMultiplier() { return employmentMultiplier; } + /** + * Determines the command rights based on a roll and the current CamOps command modifier. + * + * @param roll the result of a 2d6 roll + * @return the type of Command rights (Integrated, House, Liaison, or Independent) after + * all applicable modifiers + */ public ContractCommandRights getCommandRights(int roll) { roll += commandModifier; - ContractCommandRights commandRights; + ContractCommandRights commandRights; // defaults to integrated if (roll > 2 && roll < 8) { commandRights = ContractCommandRights.HOUSE; } else if (roll < 12) { @@ -71,11 +78,26 @@ public ContractCommandRights getCommandRights(int roll) { return commandRights; } + /** + * Determines whether the salvage rights being offered are Exchange based on a 2d6 roll and + * the current salvage modifier for the contract. + * + * @param roll The result of a 2d6 roll + * @return boolean representing whether the salvage type is exchange + */ public boolean isSalvageExchange(int roll) { roll += salvageModifier; return roll == 2 || roll == 3; } + /** + * Determines the percentage of salvage being offered as part of the salvage terms of a + * contract, based on the results of a 2d6 roll and the current salvage modifier for the + * contract. + * + * @param roll The result of a 2d6 roll + * @return the salvage percentage being offered + */ public int getSalvagePercentage(int roll) { roll += salvageModifier; return switch (MathUtility.clamp(roll, 3, 13)) { @@ -93,6 +115,14 @@ public int getSalvagePercentage(int roll) { }; } + /** + * Determines the support percentage being offered as part of the support terms of a + * contract, based on the results of a 2d6 roll and the current support modifier for the + * contract. + * + * @param roll The result of a 2d6 roll + * @return the support percentage being offered + */ public int getSupportPercentage(int roll) { roll += supportModifier; return switch(MathUtility.clamp(roll, 2, 13)) { @@ -106,16 +136,39 @@ public int getSupportPercentage(int roll) { }; } + /** + * Determines whether straight support is being offered based on a 2d6 roll and + * the current support modifier for the contract. + * + * @param roll The result of a 2d6 roll + * @return boolean representing whether the Straight support type is being offered + */ public boolean isStraightSupport(int roll) { roll += supportModifier; return roll > 2 && roll < 8; } + /** + * Determines whether Battle Loss Compensation is being offered based on a 2d6 roll and + * the current support modifier for the contract. + * + * @param roll The result of a 2d6 roll + * @return boolean representing whether the Battle Loss Compensation support type is + * being offered + */ public boolean isBattleLossComp(int roll) { roll += supportModifier; return roll > 7; } + /** + * Determines the transport cost percentage being offered as part of the transport terms of a + * contract, based on the results of a 2d6 roll and the current transport modifier for the + * contract. + * + * @param roll The result of a 2d6 roll + * @return the transport percentage being offered + */ public int getTransportTerms(int roll) { roll += transportModifier; return switch (MathUtility.clamp(roll, 1, 10)) { From 3814786bafd2cd78f09a95d7d44b582e241b066b Mon Sep 17 00:00:00 2001 From: algebro Date: Fri, 4 Oct 2024 16:09:37 -0400 Subject: [PATCH 28/28] add javadocs --- .../contractMarket/MissionSelector.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java index bc11dcb025..b270c681bd 100644 --- a/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java +++ b/MekHQ/src/mekhq/campaign/market/contractMarket/MissionSelector.java @@ -26,6 +26,16 @@ * Utility class that implements the mission tables as described in CamOps (4th printing). */ public class MissionSelector { + /** + * Determines the mission from the Inner Sphere/Clan column of the Missions Table on page 40 + * in CamOps, 4th printing. Certain rolls generate missions from other columns, i.e. Special + * and Covert. + * + * @param roll The result of a 2d6 roll + * @param margin The margin of success from a Negotiation check + * @param isClan Whether the player unit is a Clan faction + * @return The AtBContractType representing the type of mission for the contract + */ public static AtBContractType getInnerSphereClanMission(int roll, int margin, boolean isClan) { if (isClan) { int result = roll + margin; @@ -47,6 +57,16 @@ public static AtBContractType getInnerSphereClanMission(int roll, int margin, bo }; } + /** + * Determines the mission from the Independent column of the Missions Table on page 40 in + * CamOps, 4th printing. Certain rolls generate missions from other columns, i.e. Special + * and Covert. + * + * @param roll The result of a 2d6 roll + * @param margin The margin of success from a Negotiation check + * @param isClan Whether the player unit is a Clan faction + * @return The AtBContractType representing the type of mission for the contract + */ public static AtBContractType getIndependentMission(int roll, int margin, boolean isClan) { if (isClan) { int result = roll + margin; @@ -68,6 +88,16 @@ public static AtBContractType getIndependentMission(int roll, int margin, boolea }; } + /** + * Determines the mission from the Corporation column of the Missions Table on page 40 in + * CamOps, 4th printing. Certain rolls generate missions from other columns, i.e. Special + * and Covert. + * + * @param roll The result of a 2d6 roll + * @param margin The margin of success from a Negotiation check + * @param isClan Whether the player unit is a Clan faction + * @return The AtBContractType representing the type of mission for the contract + */ public static AtBContractType getCorporationMission(int roll, int margin, boolean isClan) { if (isClan) { int result = roll + margin; @@ -89,6 +119,14 @@ public static AtBContractType getCorporationMission(int roll, int margin, boolea }; } + /** + * Determines the mission from the Pirate column of the Missions Table on page 40 in CamOps, + * 4th printing. + * + * @param roll The result of a 2d6 roll + * @param margin The margin of success from a Negotiation check + * @return The AtBContractType representing the type of mission for the contract + */ public static AtBContractType getPirateMission(int roll, int margin) { roll += margin; if (roll < 6) {