diff --git a/MekHQ/resources/mekhq/resources/CamOpsReputation.properties b/MekHQ/resources/mekhq/resources/CamOpsReputation.properties new file mode 100644 index 0000000000..81d43476b8 --- /dev/null +++ b/MekHQ/resources/mekhq/resources/CamOpsReputation.properties @@ -0,0 +1,57 @@ +unitReputation.text=Unit Reputation: %d

+ +averageExperienceRating.text=Average Experience Rating: %s +experienceLevel.text=
     Experience Level: %s

+ +commandRating.text=Command Rating: %s +leadership.text=
     Leadership: %s +tactics.text=
     Tactics: %s +strategy.text=
     Strategy: %s +negotiation.text=
     Negotiation: %s +traits.text=
     Traits: %s Not Implemented +personality.text=
     Personality: %s + +combatRecordRating.text=Combat Record Rating: %s +successes.text=Successes +partialSuccesses.text=Partial Successes +failures.text=Failures +contractsBreached.text=Contracts Breached +retainerDuration.text=Retainer Duration +mission.text=
     %s: %d (+%d) + +transportationRating.text=Transportation Rating: %s +hasJumpShipOrWarShip.text=
     Has JumpShip or WarShip: +10 +smallCraft.text=Small Craft +fighters.text=Fighters +battleMechs.text=BattleMechs +vehicleSuperHeavy.text=Vehicles (Super Heavy) +vehicleHeavy.text=Vehicles (Heavy) +vehicleLight.text=Vehicles (Light) +protoMechs.text=ProtoMechs +battleArmor.text=Battle Armor +infantry.text=Infantry +transportString.text=
     %s: %d / %d Bays%s %s +asterisk.text=
* Lighter units will occupy spare bays
+noDropShip.text=No DropShip: -5 +dropShipString.text=
     DropShips: %d / %d Docking Collars (%s)
+ +supportRating.text=
Support Rating: %d +crewRequirements.text=
     Partially Crewed Large Craft: -5
+administrationRequirements.text=
     Administration Requirements: %d / %d (%d)
+technicianRequirements.text=
     Technician Requirements: %s
+battleMechsAndProtoMechs.text=BattleMechs & ProtoMechs +vehicles.text=Vehicles +fightersAndSmallCraft.text=Fighters & Small Craft +technicianString.text=          %s: %d / %d
+ +financialRating.text=Financial Rating: %s +hasLoanOrDebt.text=
     Has Loan or Debt: -10

+ +crimeRating.text=
Crime Rating: %s +piracy.text=
     Piracy: %s +otherCrimes.text=
     Other: %s +dateOfLastCrime.text=
     Date of Last Crime: %s
+ +otherModifiers.text=
Other Modifiers: %s +inactiveYears.text=
     Inactivity: %d +customModifier.text=
     Custom Modifier: %s diff --git a/MekHQ/resources/mekhq/resources/CampaignGUI.properties b/MekHQ/resources/mekhq/resources/CampaignGUI.properties index a81c06edda..bc14b027de 100644 --- a/MekHQ/resources/mekhq/resources/CampaignGUI.properties +++ b/MekHQ/resources/mekhq/resources/CampaignGUI.properties @@ -208,10 +208,10 @@ btnTransportReport.text=Transport Capacity btnHangarOverview.text=Hangar Breakdown btnPersonnelOverview.text=Personnel Breakdown btnCargoCapacity.text=Cargo Capacity -btnUnitRating.text=Unit Rating Details +btnUnitRating.text=Reputation Report panReports.title=Available Reports panObjectives.title=Current Objectives -lblRating.text=Unit Rating:; +lblRating.text=Reputation:; lblPersonnel.text=Personnel:; lblMorale.text=Morale:; lblAdministrativeCapacity.text=Administrative Capacity:; diff --git a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties index 3751354283..c69f7f28b1 100644 --- a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties +++ b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties @@ -12,8 +12,8 @@ CampaignOptionsDialog.title=Campaign Options ## General Tab generalPanel.title=General -unitRatingMethodLabel.text=Unit Rating Method: -manualUnitRatingModifierLabel.text=Manual Unit Rating Modifier +unitRatingMethodLabel.text=Unit Reputation Method: +manualUnitRatingModifierLabel.text=Manual Reputation Modifier lblName.text=Name: lblDate.text=Date: lblFaction.text=Faction: @@ -434,12 +434,17 @@ lifePathsPanel.title=Life Paths personnelRandomizationPanel.title=Personnel Randomization chkUseDylansRandomXP.text=Use Dylan's Random XP (Unofficial) chkUseDylansRandomXP.toolTipText=Use Dylan's optional random XP on creation of a new person (20% chance each of 0, 1, 2, 3, and randomized between 1 and 8 XP) + +# Random Histories +randomHistoriesPanel.title=Random Histories chkUseRandomPersonalities.text=Use Random Personalities chkUseRandomPersonalities.toolTipText=Personnel are generated with random personality traits, quirks and intelligence.\
\ -
Intelligence affects a characters ability to graduate from education module academies.\ +
Intelligence affects a character's ability to graduate from education module academies.\
\
While traits and quirks do not currently have a mechanical effect, they will be used by the upcoming Random Events module. +chkUseRandomPersonalityReputation.text=Personalities Influence Unit Reputation +chkUseRandomPersonalityReputation.toolTipText=if enabled, the personality of the campaign commander will impact the unit's Reputation. # Family familyPanel.title=Family (Unofficial) @@ -868,8 +873,6 @@ chkUseStratCon.text=Use StratCon campaign rules chkUseStratCon.toolTipText=An update of the AtB ruleset. lblSkillLevel.text=Skill Level lblSkillLevel.toolTipText=This is the difficulty level for generated scenarios.
Values above Elite are not recommended. -lblAtbCamOpsDivision.text=CamOps Unit Rating Modifier Divider -lblAtbCamOpsDivision.toolTipText=Many AtB systems modify rolls based on unit rating. Due to how CamOps unit rating is calculated, this can result in receiving the maximum modifier much sooner compared to using the FM:Mr unit rating. To address this, this value divides the CamOps unit rating to determine the modifier applied to AtB's systems. lblScenarioMod.text=Random Scenario Modifiers lblScenarioModMax.text=Maximum: lblScenarioModMax.toolTipText=This is the maximum number of random scenario mods that can spawn on for a single Scenario. Excludes StratCon facility modifiers. diff --git a/MekHQ/resources/mekhq/resources/GUI.properties b/MekHQ/resources/mekhq/resources/GUI.properties index f09d0bdef5..6d8671d910 100644 --- a/MekHQ/resources/mekhq/resources/GUI.properties +++ b/MekHQ/resources/mekhq/resources/GUI.properties @@ -387,7 +387,7 @@ PersonnelReportDialog.title=Personnel Report TransportReportDialog.title=Transport Capacity Report ### UnitRatingReportDialog Class -UnitRatingReportDialog.title=Unit Rating Report +UnitRatingReportDialog.title=Reputation Report #### Unspecified Dialogs ### AddOrEditPersonnelEntryDialog Class diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index 83d79e1217..dfa9dcc7d3 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -97,7 +97,7 @@ import mekhq.campaign.personnel.ranks.Ranks; import mekhq.campaign.personnel.turnoverAndRetention.Fatigue; import mekhq.campaign.personnel.turnoverAndRetention.RetirementDefectionTracker; -import mekhq.campaign.rating.CampaignOpsReputation; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; import mekhq.campaign.rating.FieldManualMercRevDragoonsRating; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.rating.UnitRatingMethod; @@ -196,6 +196,7 @@ public class Campaign implements ITechManager { private Faction faction; private int techFactionCode; private String retainerEmployerCode; // AtB + private LocalDate retainerStartDate; // AtB private RankSystem rankSystem; private final ArrayList currentReport; @@ -250,8 +251,12 @@ public class Campaign implements ITechManager { private int shipSearchType; private String shipSearchResult; //AtB private LocalDate shipSearchExpiration; //AtB - private IUnitGenerator unitGenerator; - private IUnitRating unitRating; + private IUnitGenerator unitGenerator; // deprecated + private IUnitRating unitRating; // deprecated + private ReputationController reputation; + private int crimeRating; + private int crimePirateModifier; + private LocalDate dateOfLastCrime; private final CampaignSummary campaignSummary; private final Quartermaster quartermaster; private StoryArc storyArc; @@ -283,6 +288,11 @@ public Campaign() { setFaction(Factions.getInstance().getDefaultFaction()); techFactionCode = ITechnology.F_MERC; retainerEmployerCode = null; + retainerStartDate = null; + reputation = null; + crimeRating = 0; + crimePirateModifier = 0; + dateOfLastCrime = null; setRankSystemDirect(Ranks.getRankSystemFromCode(Ranks.DEFAULT_SYSTEM_CODE)); forces = new Force(name); forceIds.put(0, forces); @@ -1341,6 +1351,17 @@ public Collection getUnits() { return getHangar().getUnits(); } + /** + * Retrieves a collection of units that are not mothballed or being salvaged. + * + * @return a collection of active units + */ + public Collection getActiveUnits() { + return getHangar().getUnits().stream() + .filter(unit -> !unit.isMothballed() && !unit.isSalvage()) + .toList(); + } + public Collection getLargeCraftAndWarShips() { return getHangar().getUnits().stream() .filter(unit -> (unit.getEntity().isLargeCraft()) || (unit.getEntity().isWarShip())) @@ -1688,12 +1709,9 @@ public void checkBloodnameAdd(Person person, boolean ignoreDice) { break; } } - // Higher rated units are more likely to have Bloodnamed + // Higher-rated units are more likely to have Bloodnamed if (getCampaignOptions().getUnitRatingMethod().isEnabled()) { - IUnitRating rating = getUnitRating(); - bloodnameTarget += IUnitRating.DRAGOON_C - (getCampaignOptions().getUnitRatingMethod().equals( - UnitRatingMethod.FLD_MAN_MERCS_REV) - ? rating.getUnitRatingAsInteger() : rating.getModifier()); + bloodnameTarget += IUnitRating.DRAGOON_C - getUnitRatingMod(); } // Reavings diminish the number of available Bloodrights in later eras @@ -3401,8 +3419,10 @@ && getCampaignOptions().getRandomDependentMethod().isAgainstTheBot() /* * First of the month; roll Morale. */ - IUnitRating rating = getUnitRating(); - rating.reInitialize(); + if (campaignOptions.getUnitRatingMethod().isFMMR()) { + IUnitRating rating = getUnitRating(); + rating.reInitialize(); + } for (AtBContract contract : getActiveAtBContracts()) { contract.checkMorale(getLocalDate(), getUnitRatingMod()); @@ -3731,6 +3751,10 @@ public boolean newDay() { processFatigueNewDay(); + if (campaignOptions.getUnitRatingMethod().isCampaignOperations()) { + updateCrimeRating(); + } + if (campaignOptions.isUseEducationModule()) { processEducationNewDay(); } @@ -3770,6 +3794,35 @@ public boolean newDay() { return true; } + /** + * Updates the campaign's crime rating based on specific conditions. + */ + private void updateCrimeRating() { + if (faction.isPirate()) { + dateOfLastCrime = currentDay; + crimePirateModifier = -100; + } + + if (currentDay.getDayOfMonth() == 1) { + if (dateOfLastCrime != null) { + long yearsBetween = ChronoUnit.YEARS.between(currentDay, dateOfLastCrime); + + int remainingCrimeChange = 2; + + if (yearsBetween >= 1) { + if (crimePirateModifier < 0) { + remainingCrimeChange = Math.max(0, 2 + crimePirateModifier); + changeCrimePirateModifier(2); // this is the amount of change specified by CamOps + } + + if (crimeRating < 0 && remainingCrimeChange > 0) { + changeCrimeRating(remainingCrimeChange); + } + } + } + } + } + /** * This method iterates through the list of personnel and deletes the records of those who have * departed the unit and who match additional checks. @@ -4359,6 +4412,75 @@ public void setRetainerEmployerCode(String code) { retainerEmployerCode = code; } + public LocalDate getRetainerStartDate() { + return retainerStartDate; + } + + public void setRetainerStartDate(LocalDate retainerStartDate) { + this.retainerStartDate = retainerStartDate; + } + + public int getRawCrimeRating() { + return crimeRating; + } + + public void setCrimeRating(int crimeRating) { + this.crimeRating = crimeRating; + } + + /** + * Updates the crime rating by the specified change. + * If improving crime rating, use a positive number, otherwise negative + * + * @param change the change to be applied to the crime rating + */ + public void changeCrimeRating(int change) { + this.crimeRating = Math.min(0, crimeRating + change); + } + + public int getCrimePirateModifier() { + return crimePirateModifier; + } + + public void setCrimePirateModifier(int crimePirateModifier) { + this.crimePirateModifier = crimePirateModifier; + } + /** + * Updates the crime pirate modifier by the specified change. + * If improving the modifier, use a positive number, otherwise negative + * + * @param change the change to be applied to the crime modifier + */ + public void changeCrimePirateModifier(int change) { + this.crimePirateModifier = Math.min(0, crimePirateModifier + change); + } + + /** + * Calculates the adjusted crime rating by adding the crime rating + * with the pirate modifier. + * + * @return The adjusted crime rating. + */ + public int getAdjustedCrimeRating() { + return crimeRating + crimePirateModifier; + } + + public LocalDate getDateOfLastCrime() { + return dateOfLastCrime; + } + + public void setDateOfLastCrime(LocalDate dateOfLastCrime) { + this.dateOfLastCrime = dateOfLastCrime; + } + + public ReputationController getReputation() { + return reputation; + } + + public void setReputation(ReputationController reputation) { + this.reputation = reputation; + } + private void addInMemoryLogHistory(LogEntry le) { if (!inMemoryLogHistory.isEmpty()) { while (ChronoUnit.DAYS.between(inMemoryLogHistory.get(0).getDate(), le.getDate()) > MHQConstants.MAX_HISTORICAL_LOG_DAYS) { @@ -4513,7 +4635,27 @@ public void writeToXML(final PrintWriter pw) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "faction", getFaction().getShortName()); if (retainerEmployerCode != null) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "retainerEmployerCode", retainerEmployerCode); + + if (retainerStartDate == null) { + // this handles <50.0 campaigns + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "retainerStartDate", currentDay); + } else { + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "retainerStartDate", retainerStartDate); + } } + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "crimeRating", crimeRating); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "crimePirateModifier", crimePirateModifier); + + // this handles <50.0 campaigns + if (dateOfLastCrime != null) { + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "dateOfLastCrime", dateOfLastCrime); + } else if (getAdjustedCrimeRating() < 0) { + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "dateOfLastCrime", currentDay); + } + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "reputation"); + reputation.writeReputationToXML(pw, indent); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "reputation"); // this handles campaigns that predate 49.20 if (campaignStartDate == null) { @@ -6054,33 +6196,49 @@ private synchronized void checkDuplicateNamesDuringDelete(Entity entity) { }); } + /** + * Returns the text representation of the unit rating based on the selected unit rating method. + * If the unit rating method is FMMR, the unit rating value is returned. + * If the unit rating method is Campaign Operations, the reputation rating and unit rating modification are combined and returned. + * If the unit rating method is neither FMMR nor Campaign Operations, "N/A" is returned. + * + * @return The text representation of the unit rating + */ public String getUnitRatingText() { - return getUnitRating().getUnitRating(); + UnitRatingMethod unitRatingMethod = campaignOptions.getUnitRatingMethod(); + + if (unitRatingMethod.isFMMR()) { + return getUnitRating().getUnitRating(); + } else if (unitRatingMethod.isCampaignOperations()) { + int reputationRating = reputation.getReputationRating(); + int unitRatingMod = getUnitRatingMod(); + + return String.format("%d (%+d)", reputationRating, unitRatingMod); + } else { + return "N/A"; + } } /** - * Against the Bot Calculates and returns dragoon rating if that is the chosen - * method; for IOps method, returns unit reputation / 10. If the player chooses - * not to use unit rating at all, use a default value of C. Note that the AtB - * system is designed for use with FMMerc dragoon rating, and use of the IOps - * Beta system may have unsatisfactory results, but we follow the options set by - * the user here. + * Retrieves the unit rating modifier based on campaign options. + * If the unit rating method is not enabled, it returns the default value of IUnitRating.DRAGOON_C. + * If the unit rating method uses FMMR, it returns the unit rating as an integer. + * Otherwise, it calculates the modifier using the getAtBModifier method. + * + * @return The unit rating modifier based on the campaign options. */ public int getUnitRatingMod() { if (!getCampaignOptions().getUnitRatingMethod().isEnabled()) { return IUnitRating.DRAGOON_C; } - IUnitRating rating = getUnitRating(); - return getCampaignOptions().getUnitRatingMethod().isFMMR() ? rating.getUnitRatingAsInteger() - : (int) MathUtility.clamp((rating.getModifier() / campaignOptions.getAtbCamOpsDivision()), IUnitRating.DRAGOON_F, IUnitRating.DRAGOON_ASTAR); + + return getCampaignOptions().getUnitRatingMethod().isFMMR() ? + getUnitRating().getUnitRatingAsInteger() : reputation.getAtbModifier(); } - /** - * This is a better method for pairing AtB with IOpts with regards to Prisoner Capture - */ + @Deprecated public int getUnitRatingAsInteger() { - return getCampaignOptions().getUnitRatingMethod().isEnabled() - ? getUnitRating().getUnitRatingAsInteger() : IUnitRating.DRAGOON_C; + return getUnitRatingMod(); } public RandomSkillPreferences getRandomSkillPreferences() { @@ -7305,6 +7463,7 @@ public void setUnitRating(IUnitRating rating) { * Returns the type of rating method as selected in the Campaign Options dialog. * Lazy-loaded for performance. Default is CampaignOpsReputation */ + @Deprecated public IUnitRating getUnitRating() { // if we switched unit rating methods, if (unitRating != null && (unitRating.getUnitRatingMethod() != getCampaignOptions().getUnitRatingMethod())) { @@ -7316,8 +7475,6 @@ public IUnitRating getUnitRating() { if (UnitRatingMethod.FLD_MAN_MERCS_REV.equals(method)) { unitRating = new FieldManualMercRevDragoonsRating(this); - } else { - unitRating = new CampaignOpsReputation(this); } } diff --git a/MekHQ/src/mekhq/campaign/CampaignOptions.java b/MekHQ/src/mekhq/campaign/CampaignOptions.java index fab77be4cb..ab0777c57e 100644 --- a/MekHQ/src/mekhq/campaign/CampaignOptions.java +++ b/MekHQ/src/mekhq/campaign/CampaignOptions.java @@ -274,8 +274,11 @@ public static String getTransitUnitName(final int unit) { //region Life Paths Tab // Personnel Randomization private boolean useDylansRandomXP; // Unofficial + + // Random Histories private RandomOriginOptions randomOriginOptions; private boolean useRandomPersonalities; + private boolean useRandomPersonalityReputation; // Retirement private boolean useRandomRetirement; @@ -830,8 +833,11 @@ public CampaignOptions() { //region Life Paths Tab // Personnel Randomization setUseDylansRandomXP(false); + + // Random Histories setRandomOriginOptions(new RandomOriginOptions(true)); setUseRandomPersonalities(false); + setUseRandomPersonalityReputation(true); // Family setFamilyDisplayLevel(FamilialRelationshipDisplayLevel.SPOUSE); @@ -1864,6 +1870,14 @@ public boolean isUseRandomPersonalities() { public void setUseRandomPersonalities(final boolean useRandomPersonalities) { this.useRandomPersonalities = useRandomPersonalities; } + + public boolean isUseRandomPersonalityReputation() { + return useRandomPersonalityReputation; + } + + public void setUseRandomPersonalityReputation(final boolean useRandomPersonalityReputation) { + this.useRandomPersonalityReputation = useRandomPersonalityReputation; + } //endregion Personnel Randomization //region Retirement @@ -4712,6 +4726,7 @@ public void writeToXml(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useDylansRandomXP", isUseDylansRandomXP()); getRandomOriginOptions().writeToXML(pw, indent); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useRandomPersonalities", isUseRandomPersonalities()); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useRandomPersonalityReputation", isUseRandomPersonalityReputation()); //endregion Personnel Randomization //region Retirement @@ -5466,6 +5481,8 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve retVal.setRandomOriginOptions(randomOriginOptions); } else if (wn2.getNodeName().equalsIgnoreCase("useRandomPersonalities")) { retVal.setUseRandomPersonalities(Boolean.parseBoolean(wn2.getTextContent().trim())); + } else if (wn2.getNodeName().equalsIgnoreCase("useRandomPersonalityReputation")) { + retVal.setUseRandomPersonalityReputation(Boolean.parseBoolean(wn2.getTextContent().trim())); //endregion Personnel Randomization //region Family diff --git a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java index c210b5b30a..ab0a97a9ca 100644 --- a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java +++ b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java @@ -56,6 +56,7 @@ import mekhq.campaign.personnel.ranks.RankSystem; import mekhq.campaign.personnel.ranks.RankValidator; import mekhq.campaign.personnel.turnoverAndRetention.RetirementDefectionTracker; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; import mekhq.campaign.storyarc.StoryArc; import mekhq.campaign.unit.Unit; import mekhq.campaign.unit.cleanup.EquipmentUnscrambler; @@ -694,6 +695,16 @@ private static void processInfoNode(Campaign retVal, Node wni, Version version) retVal.setFactionCode(wn.getTextContent()); } else if (xn.equalsIgnoreCase("retainerEmployerCode")) { retVal.setRetainerEmployerCode(wn.getTextContent()); + } else if (xn.equalsIgnoreCase("retainerStartDate")) { + retVal.setRetainerStartDate(LocalDate.parse(wn.getTextContent())); + } else if (xn.equalsIgnoreCase("crimeRating")) { + retVal.setCrimeRating(Integer.parseInt(wn.getTextContent())); + } else if (xn.equalsIgnoreCase("crimePirateModifier")) { + retVal.setCrimePirateModifier(Integer.parseInt(wn.getTextContent())); + } else if (xn.equalsIgnoreCase("dateOfLastCrime")) { + retVal.setDateOfLastCrime(LocalDate.parse(wn.getTextContent())); + } else if (xn.equalsIgnoreCase("reputation")) { + retVal.setReputation(new ReputationController().generateInstanceFromXML(wn)); } else if (xn.equalsIgnoreCase("rankSystem")) { if (!wn.hasChildNodes()) { // we need there to be child nodes to parse from continue; diff --git a/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java index 29ce00e7f0..11f600d817 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java @@ -54,6 +54,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.personnel.enums.Phenotype; import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.rating.UnitRatingMethod; import mekhq.campaign.stratcon.StratconBiomeManifest; import mekhq.campaign.stratcon.StratconContractInitializer; import mekhq.campaign.unit.Unit; @@ -713,13 +714,14 @@ public static int generateForce(AtBDynamicScenario scenario, AtBContract contrac // For BV-scaled forces, check whether to stop generating after each formation is // generated. if (forceTemplate.getGenerationMethod() == ForceGenerationMethod.BVScaled.ordinal()) { - // Check random number vs. percentage of the BV budget already generated, with the // percentage chosen based on unit rating int roll = Compute.randomInt(100); double rollTarget = ((double) forceBV / forceBVBudget) * 100; - stopGenerating = rollTarget > minimumBVPercentage[campaign.getUnitRating().getUnitRatingAsInteger()] && - roll < rollTarget; + + int unitRating = getUnitRating(campaign); + + stopGenerating = rollTarget > minimumBVPercentage[unitRating] && roll < rollTarget; } else { // For generation methods other than scaled BV, compare to the overall budget stopGenerating = generatedEntities.size() >= forceUnitBudget; @@ -763,6 +765,25 @@ public static int generateForce(AtBDynamicScenario scenario, AtBContract contrac return generatedLanceCount; } + /** + * Retrieves the unit rating from the given campaign. + * + * @param campaign the campaign from which the unit rating is to be retrieved + * @return the unit rating value as an integer + */ + private static int getUnitRating(Campaign campaign) { + final CampaignOptions campaignOptions = campaign.getCampaignOptions(); + final UnitRatingMethod unitRatingMethod = campaignOptions.getUnitRatingMethod(); + + int unitRating = IUnitRating.DRAGOON_C; + if (unitRatingMethod.isFMMR()) { + unitRating = campaign.getUnitRating().getUnitRatingAsInteger(); + } else if (unitRatingMethod.isCampaignOperations()) { + unitRating = campaign.getReputation().getAtbModifier(); + } + return unitRating; + } + /** * Generates the indicated number of civilian entities. * diff --git a/MekHQ/src/mekhq/campaign/personnel/Person.java b/MekHQ/src/mekhq/campaign/personnel/Person.java index 9fbe04bfe8..3e6286a2c0 100644 --- a/MekHQ/src/mekhq/campaign/personnel/Person.java +++ b/MekHQ/src/mekhq/campaign/personnel/Person.java @@ -3657,16 +3657,31 @@ public Skill getBestTechSkill() { } public boolean isTech() { - //type must be correct and you must be more than ultra-green in the skill - boolean isMechTech = hasSkill(SkillType.S_TECH_MECH) && getSkill(SkillType.S_TECH_MECH).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; - boolean isAeroTech = hasSkill(SkillType.S_TECH_AERO) && getSkill(SkillType.S_TECH_AERO).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; - boolean isMechanic = hasSkill(SkillType.S_TECH_MECHANIC) && getSkill(SkillType.S_TECH_MECHANIC).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; - boolean isBATech = hasSkill(SkillType.S_TECH_BA) && getSkill(SkillType.S_TECH_BA).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; - // At some point we may want to re-write things to include this - /*boolean isEngineer = hasSkill(SkillType.S_TECH_VESSEL) && getSkill(SkillType.S_TECH_VESSEL).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN - && campaign.getUnit(getUnitId()).getEngineer() != null - && campaign.getUnit(getUnitId()).getEngineer().equals(this);*/ - return (getPrimaryRole().isTech() || getSecondaryRole().isTechSecondary()) && (isMechTech || isAeroTech || isMechanic || isBATech); + return isTechMech() || isTechAero() || isTechMechanic() || isTechBA(); + } + + public boolean isTechMech() { + boolean hasSkill = hasSkill(SkillType.S_TECH_MECH) && getSkill(SkillType.S_TECH_MECH).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; + + return hasSkill && (getPrimaryRole().isMechTech() || getSecondaryRole().isMechTech()); + } + + public boolean isTechAero() { + boolean hasSkill = hasSkill(SkillType.S_TECH_AERO) && getSkill(SkillType.S_TECH_AERO).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; + + return hasSkill && (getPrimaryRole().isAeroTech() || getSecondaryRole().isAeroTech()); + } + + public boolean isTechMechanic() { + boolean hasSkill = hasSkill(SkillType.S_TECH_MECHANIC) && getSkill(SkillType.S_TECH_MECHANIC).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; + + return hasSkill && (getPrimaryRole().isMechanic() || getSecondaryRole().isMechanic()); + } + + public boolean isTechBA() { + boolean hasSkill = hasSkill(SkillType.S_TECH_BA) && getSkill(SkillType.S_TECH_BA).getExperienceLevel() > SkillType.EXP_ULTRA_GREEN; + + return hasSkill && (getPrimaryRole().isBATech() || getSecondaryRole().isBATech()); } public boolean isAdministrator() { diff --git a/MekHQ/src/mekhq/campaign/personnel/Skill.java b/MekHQ/src/mekhq/campaign/personnel/Skill.java index 8721c3659e..6fb059bcd7 100644 --- a/MekHQ/src/mekhq/campaign/personnel/Skill.java +++ b/MekHQ/src/mekhq/campaign/personnel/Skill.java @@ -20,7 +20,6 @@ */ package mekhq.campaign.personnel; -import megamek.Version; import megamek.common.Compute; import megamek.common.enums.SkillLevel; import mekhq.utilities.MHQXMLUtility; @@ -34,7 +33,7 @@ * As ov v0.1.9, we will be tracking a group of skills on the person. These skills will define * personnel rather than subtypes wrapped around pilots and teams. This will allow for considerably * more flexibility in the kinds of personnel available. - * + *

* Four important characteristics will determine how each skill works * level - this is the level of the skill. By default this will go from 0 to 10, but the max will * be customizable. These won't necessarily correspond to named levels (e.g. Green, Elite) @@ -142,6 +141,15 @@ public int getFinalSkillValue() { } } + /** + * Calculates the total skill value by summing the level and bonus. + * + * @return The total skill value. + */ + public int getTotalSkillLevel() { + return level + bonus; + } + public void improve() { if (level >= SkillType.NUM_LEVELS - 1) { // Can't improve past the max diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/AverageExperienceRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/AverageExperienceRating.java new file mode 100644 index 0000000000..e5452d327a --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/AverageExperienceRating.java @@ -0,0 +1,230 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.codeUtilities.MathUtility; +import megamek.common.*; +import megamek.common.enums.SkillLevel; +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.personnel.SkillType; +import mekhq.campaign.unit.Unit; + +import java.util.function.Consumer; + +public class AverageExperienceRating { + private static final MMLogger logger = MMLogger.create(AverageExperienceRating.class); + + /** + * Calculates the skill level based on the average experience rating of a campaign. + * + * @param campaign the campaign to calculate the average experience rating from + * @param log whether to log the calculation in mekhq.log + * @return the skill level based on the average experience rating + * @throws IllegalStateException if the experience score is not within the expected range + */ + protected static SkillLevel getSkillLevel(Campaign campaign, boolean log) { + // values below 0 are treated as 'Legendary', + // values above 7 are treated as 'wet behind the ears' which we call 'None' + int experienceScore = MathUtility.clamp( + calculateAverageExperienceRating(campaign, log), + 0, + 7 + ); + + return switch (experienceScore) { + case 7 -> SkillLevel.NONE; + case 6 -> SkillLevel.ULTRA_GREEN; + case 5 -> SkillLevel.GREEN; + case 4 -> SkillLevel.REGULAR; + case 3 -> SkillLevel.VETERAN; + case 2 -> SkillLevel.ELITE; + case 1 -> SkillLevel.HEROIC; + case 0 -> SkillLevel.LEGENDARY; + default -> throw new IllegalStateException( + "Unexpected value in mekhq/campaign/rating/CamOpsRatingV2/AverageExperienceRating.java/getSkillLevel: " + + experienceScore + ); + }; + } + + /** + * Retrieves the reputation modifier. + * + * @param averageSkillLevel the average skill level to calculate the reputation modifier for + * @return the reputation modifier for the camera operator + */ + protected static int getReputationModifier(SkillLevel averageSkillLevel) { + int modifier = switch(averageSkillLevel) { + case NONE, ULTRA_GREEN, GREEN -> 5; + case REGULAR -> 10; + case VETERAN -> 20; + case ELITE, HEROIC, LEGENDARY -> 40; + }; + + logger.debug("Reputation Rating = {}, +{}", + averageSkillLevel.toString(), + modifier); + + return modifier; + } + + /** + * Calculates a modifier for Against the Bot's various systems, based on the average skill level. + * + * @param campaign the campaign from which to calculate the ATB modifier + * @return the ATB modifier as an integer value + */ + public static int getAtBModifier(Campaign campaign) { + SkillLevel averageSkillLevel = getSkillLevel(campaign, false); + + return switch (averageSkillLevel) { + case NONE, ULTRA_GREEN -> 0; + case GREEN -> 1; + case REGULAR -> 2; + case VETERAN -> 3; + case ELITE -> 4; + case HEROIC, LEGENDARY -> 5; + }; + } + + /** + * Calculates the average experience rating of combat personnel in the given campaign. + * + * @param campaign the campaign to calculate the average experience rating for + * @param log whether to log the calculation to mekhq.log + * @return the average experience rating of personnel in the campaign + */ + private static int calculateAverageExperienceRating(Campaign campaign, boolean log) { + int personnelCount = 0; + double totalExperience = 0.0; + + for (Person person : campaign.getActivePersonnel()) { + Unit unit = person.getUnit(); + + // if the person does not belong to a unit, then skip this person + if (unit == null) { + continue; + } + + Entity entity = unit.getEntity(); + // if the unit's entity is a JumpShip, then it is not considered a combatant. + if (entity instanceof Jumpship) { + continue; + } + + // if both primary and secondary roles are support roles, skip this person + // as they are also not considered combat personnel + if (person.getPrimaryRole().isSupport() && person.getSecondaryRole().isSupport()) { + continue; + } + + Crew crew = entity.getCrew(); + + // Experience calculation varies depending on the type of entity + if (entity instanceof Infantry) { + // we only want to parse infantry units once, as CamOps treats them as an individual entity + if (!unit.isCommander(person)) { + continue; + } + + // For Infantry, average experience is calculated using a different method. + totalExperience += calculateInfantryExperience((Infantry) entity, crew); // add the average experience to the total + personnelCount++; + } else if (entity instanceof Protomech) { + // ProtoMech entities only use gunnery for calculation + if (person.hasSkill(SkillType.S_GUN_PROTO)) { + totalExperience += person.getSkill(SkillType.S_GUN_PROTO).getTotalSkillLevel(); + } + + personnelCount ++; + } else { + // For regular entities, another method calculates the average experience + if (unit.isGunner(person) || unit.isDriver(person)) { + totalExperience += calculateRegularExperience(person, entity, unit); + personnelCount ++; + } + } + } + + if (personnelCount == 0) { + return 7; + } + + // Calculate the average experience rating across all personnel. If there are no personnel, return 0 + double rawAverage = personnelCount > 0 ? (totalExperience / personnelCount) : 0; + + // CamOps wants us to round down from 0.5 and up from >0.5, so we need to do an extra step here + double fractionalPart = rawAverage - Math.floor(rawAverage); + + int averageExperienceRating = (int) (fractionalPart > 0.5 ? Math.ceil(rawAverage) : Math.floor(rawAverage)); + + // Log the details of the calculation to aid debugging, + // and so the user can easily see if there is a mistake + if (log) { + logger.debug("Average Experience Rating: {} / {} = {}", + totalExperience, + personnelCount, + averageExperienceRating); + } + + // Return the average experience rating + return averageExperienceRating; + } + + /** + * Calculates the average experience of an Infantry entity's crew. + * + * @param infantry The Infantry entity, which also includes some crew details. + * @param crew The unit crew. + * @return The average experience of the Infantry crew. + */ + private static double calculateInfantryExperience(Infantry infantry, Crew crew) { + // Average of gunnery and antiMek skill + int gunnery = crew.getGunnery(); + int antiMek = infantry.getAntiMekSkill(); + + return (double) (gunnery + antiMek) / 2; + } + + /** + * Calculates the average experience of a (non-Infantry, non-ProtoMech) crew. + * + * @param person The person in the crew. + * @param entity The entity associated with the crew. + * @param unit The unit the crew belongs to. + * @return The average experience of the crew. + */ + private static double calculateRegularExperience(Person person, Entity entity, Unit unit) { + /* + * skillData[0] represents sumOfSkillLevels + * skillData[1] represents skillCount + */ + int[] skillData = new int[2]; + + Consumer skillHandler = skillName -> { + if (person.hasSkill(skillName)) { + skillData[0] += person.getSkill(skillName).getTotalSkillLevel(); + skillData[1]++; + } + }; + + if (unit.isDriver(person)) { + skillHandler.accept(SkillType.getDrivingSkillFor(entity)); + } + + if (unit.isGunner(person)) { + skillHandler.accept(SkillType.getGunnerySkillFor(entity)); + } + + if (skillData[1] != 0) { + if (person.getPrimaryRole().isVehicleCrew() && + (person.getSecondaryRole().isCivilian() || person.getSecondaryRole().isVehicleCrew())) { + if (person.hasSkill(SkillType.S_TECH_MECHANIC)) { + return person.getSkill(SkillType.S_TECH_MECHANIC).getTotalSkillLevel(); + } + } + } + + return (skillData[0] > 0) ? (double) skillData[0] / skillData[1] : 0.0; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CombatRecordRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CombatRecordRating.java new file mode 100644 index 0000000000..cb049fc28b --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CombatRecordRating.java @@ -0,0 +1,86 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.mission.Mission; +import mekhq.campaign.mission.enums.MissionStatus; + +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class CombatRecordRating { + private static final MMLogger logger = MMLogger.create(CombatRecordRating.class); + + /** + * Calculates the combat record rating for the provided campaign. + * + * @param campaign the campaign for which to calculate the combat record rating + * @return a map containing the combat record ratings: + * - "partialSuccesses": the number of missions with status "PARTIAL" + * - "successes": the number of missions with status "SUCCESS" + * - "failures": the number of missions with status "FAILED" + * - "contractsBreached": the number of missions with status "BREACH" + * - "retainerDuration": the duration of the campaign's retainer (in years), + * zero if there is no retainer + * - "total": the total combat record rating calculated using the formula: + * (successes * 5) - (failures * 10) - (contractBreaches * 25) + */ + protected static Map calculateCombatRecordRating(Campaign campaign) { + Map combatRecord = new HashMap<>(); + + // If the faction is pirate, set all values to zero and return the map immediately, + // CamOps says pirates don't track combat record rating, but we still want these values for use elsewhere + if (campaign.getFaction().isPirate()) { + combatRecord.put("partialSuccesses", 0); + combatRecord.put("successes", 0); + combatRecord.put("failures", 0); + combatRecord.put("contractsBreached", 0); + combatRecord.put("retainerDuration", 0); + combatRecord.put("total", 0); + return combatRecord; + } + + // Construct a map with mission statuses and their counts + Map missionCountsByStatus = campaign.getCompletedMissions().stream() + .filter(mission -> mission.getStatus() != MissionStatus.ACTIVE) + .collect(Collectors.groupingBy(Mission::getStatus, Collectors.counting())); + + // Assign mission counts to each category + int successes = missionCountsByStatus.getOrDefault(MissionStatus.SUCCESS, 0L).intValue(); + int partialSuccesses = missionCountsByStatus.getOrDefault(MissionStatus.PARTIAL, 0L).intValue(); + int failures = missionCountsByStatus.getOrDefault(MissionStatus.FAILED, 0L).intValue(); + int contractBreaches = missionCountsByStatus.getOrDefault(MissionStatus.BREACH, 0L).intValue(); + + // place the values into the map + combatRecord.put("partialSuccesses", partialSuccesses); + combatRecord.put("successes", successes); + combatRecord.put("failures", failures); + combatRecord.put("contractsBreached", contractBreaches); + + // Calculate combat record rating + int combatRecordRating = (successes * 5) - (failures * 10) - (contractBreaches * 25); + + // if the campaign has a retainer, check retainer duration + if (campaign.getRetainerStartDate() != null) { + int retainerDuration = (int) ChronoUnit.YEARS.between(campaign.getRetainerStartDate(), campaign.getLocalDate()); + combatRecord.put("retainerDuration", retainerDuration); + combatRecordRating += retainerDuration * 5; + } else { + combatRecord.put("retainerDuration", 0); + } + + // add the total rating to the map + combatRecord.put("total", combatRecordRating); + + // post a log to aid debugging + logger.debug("Combat Record Rating = {}", + combatRecord.keySet().stream() + .map(key -> String.format("%s: %d", key, combatRecord.get(key))) + .collect(Collectors.joining("\n"))); + + // return the completed map + return combatRecord; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CommandRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CommandRating.java new file mode 100644 index 0000000000..58d6050625 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CommandRating.java @@ -0,0 +1,123 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.CampaignOptions; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.personnel.SkillType; +import mekhq.campaign.personnel.enums.randomEvents.personalities.Aggression; +import mekhq.campaign.personnel.enums.randomEvents.personalities.Ambition; +import mekhq.campaign.personnel.enums.randomEvents.personalities.Greed; +import mekhq.campaign.personnel.enums.randomEvents.personalities.Social; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class CommandRating { + private static final MMLogger logger = MMLogger.create(CommandRating.class); + + /** + * Calculates the rating of a commander based on their skills and personality. + * + * @param campaign the campaign the commander belongs to + * @param commander the commander to calculate the rating for + * @return a map containing the commander's rating in different areas: + * - "leadership": the commander's leadership skill value + * - "tactics": the commander's tactics skill value + * - "strategy": the commander's strategy skill value + * - "negotiation": the commander's negotiation skill value + * - "traits": the commander's traits (not currently tracked, always 0) + * - "personality": the value of the commander's personality characteristics (or 0, if disabled) + */ + protected static Map calculateCommanderRating(Campaign campaign, Person commander) { + Map commandRating = new HashMap<>(); + + commandRating.put("leadership", getSkillValue(commander, SkillType.S_LEADER)); + commandRating.put("tactics", getSkillValue(commander, SkillType.S_TACTICS)); + commandRating.put("strategy", getSkillValue(commander, SkillType.S_STRATEGY)); + commandRating.put("negotiation", getSkillValue(commander, SkillType.S_NEG)); + + // ATOW traits are not currently tracked by mhq, but when they are, this is where we'd add that data + commandRating.put("traits", 0); + + // this will return 0 if personalities are disabled + commandRating.put("personality", getPersonalityValue(campaign, commander)); + + commandRating.put("total", commandRating.values().stream().mapToInt(rating -> rating).sum()); + + logger.debug("Command Rating = {}", + commandRating.keySet().stream() + .map(key -> key + ": " + commandRating.get(key) + '\n') + .collect(Collectors.joining())); + + return commandRating; + } + + /** + * @return the final skill value for the given skill, + * or 0 if the person does not have the skill + * + * @param person the person + * @param skill the skill + */ + private static int getSkillValue(Person person, String skill) { + if (person == null) { + return 0; + } + + if (person.hasSkill(skill)) { + return person.getSkill(skill).getExperienceLevel(); + } else { + return 0; + } + } + + /** + * Calculates the total value of a person's personality characteristics. + * + * @param campaign the current campaign + * @param person the person to calculate the personality value for + * @return the total personality value of the person in the campaign + */ + private static int getPersonalityValue(Campaign campaign, Person person) { + if (person == null) { + return 0; + } + + CampaignOptions campaignOptions = campaign.getCampaignOptions(); + + if (campaignOptions.isUseRandomPersonalities() && campaignOptions.isUseRandomPersonalityReputation()) { + int personalityValue = 0; + int modifier; + + Aggression aggression = person.getAggression(); + if (!person.getAggression().isNone()) { + modifier = aggression.isTraitPositive() ? 1 : -1; + personalityValue += aggression.isTraitMajor() ? modifier * 2 : modifier; + } + + Ambition ambition = person.getAmbition(); + if (!person.getAmbition().isNone()) { + modifier = ambition.isTraitPositive() ? 1 : -1; + personalityValue += ambition.isTraitMajor() ? modifier * 2 : modifier; + } + + Greed greed = person.getGreed(); + if (!person.getGreed().isNone()) { + modifier = greed.isTraitPositive() ? 1 : -1; + personalityValue += greed.isTraitMajor() ? modifier * 2 : modifier; + } + + Social social = person.getSocial(); + if (!person.getSocial().isNone()) { + modifier = social.isTraitPositive() ? 1 : -1; + personalityValue += social.isTraitMajor() ? modifier * 2 : modifier; + } + + return personalityValue; + } else { + return 0; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CrimeRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CrimeRating.java new file mode 100644 index 0000000000..53396722e3 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CrimeRating.java @@ -0,0 +1,35 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class CrimeRating { + private static final MMLogger logger = MMLogger.create(CrimeRating.class); + + /** + * Calculates the crime rating for a given campaign. + * + * @param campaign the campaign for which to calculate the crime rating + * @return the calculated crime rating + */ + protected static Map calculateCrimeRating(Campaign campaign) { + Map crimeRating = new HashMap<>(); + + crimeRating.put("piracy", campaign.getCrimePirateModifier()); + crimeRating.put("other", campaign.getRawCrimeRating()); + + int adjustedCrimeRating = campaign.getAdjustedCrimeRating(); + crimeRating.put("total", adjustedCrimeRating); + + logger.debug("Crime Rating = {}", + crimeRating.entrySet().stream() + .map(entry -> String.format("%s: %d\n", entry.getKey(), entry.getValue())) + .collect(Collectors.joining())); + + return crimeRating; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/FinancialRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/FinancialRating.java new file mode 100644 index 0000000000..b67c085f26 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/FinancialRating.java @@ -0,0 +1,35 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.logging.MMLogger; +import mekhq.campaign.finances.Finances; + +import java.util.Map; +import java.util.stream.Collectors; + +public class FinancialRating { + private static final MMLogger logger = MMLogger.create(FinancialRating.class); + + /** + * Calculates the financial rating based on the current financial status. + * Negative financial status (having a loan or a negative balance) affects the rating negatively. + * @param finances the financial status. + * @return a map of the financial rating. + */ + protected static Map calculateFinancialRating(Finances finances) { + boolean hasLoan = finances.isInDebt(); + boolean inDebt = finances.getBalance().isNegative(); + + Map financeMap = Map.of( + "hasLoan", hasLoan ? 1 : 0, + "inDebt", inDebt ? 1 : 0, + "total", (hasLoan || inDebt) ? -10 : 0 + ); + + logger.debug("Financial Rating = {}", + financeMap.entrySet().stream() + .map(entry -> String.format("%s: %d\n", entry.getKey(), entry.getValue())) + .collect(Collectors.joining())); + + return financeMap; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/OtherModifiers.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/OtherModifiers.java new file mode 100644 index 0000000000..f5edb003bb --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/OtherModifiers.java @@ -0,0 +1,99 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.mission.AtBContract; +import mekhq.campaign.mission.enums.AtBContractType; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class OtherModifiers { + private static final MMLogger logger = MMLogger.create(OtherModifiers.class); + + /** + * Calculates the 'other modifiers' used by CamOps Reputation + * + * @param campaign The campaign for which to calculate the modifiers. + * @return A map representing the calculated modifiers. The map contains two entries: + * - "inactiveYears": The number of inactive years calculated from the campaign options. + * - "total": The total value calculated based on the number of inactive years. + */ + protected static Map calculateOtherModifiers(Campaign campaign) { + // Calculate inactive years if campaign options allow + int inactiveYears = campaign.getCampaignOptions().isUseAtB() ? getInactiveYears(campaign) : 0; + int manualModifier = campaign.getCampaignOptions().getManualUnitRatingModifier(); + + // Crime rating improvements are handled on New Day, so are not included here. + + // Create a map for modifiers with "inactive years" and "total" calculated from inactive years + Map modifierMap = Map.of( + "inactiveYears", inactiveYears, + "customModifier", manualModifier, + "total", manualModifier - (inactiveYears * 5) + ); + + // Log the calculated modifiers + logger.debug("Other Modifiers = {}", + modifierMap.entrySet().stream() + .map(entry -> String.format("%s: %d\n", entry.getKey(), entry.getValue())) + .collect(Collectors.joining())); + + // Return the calculated modifier map + return modifierMap; + } + + /** + * @return the number of years between the oldest mission date and the current date. + * + * @param campaign the current campaign + */ + private static int getInactiveYears(Campaign campaign) { + LocalDate today = campaign.getLocalDate(); + + // Build a list of completed contracts, excluding Garrison and Cadre contracts + List contracts = getSuitableContracts(campaign); + + // Decide the oldest mission date based on the earliest completion date of the contracts + // or the campaign start date if there are no completed contracts + LocalDate oldestMissionDate = contracts.isEmpty() ? campaign.getCampaignStartDate() + : contracts.stream() + .map(AtBContract::getEndingDate) + .min(LocalDate::compareTo) + .orElse(today); + + // Calculate and return the number of years between the oldest mission date and today + return Math.max(0, (int) ChronoUnit.YEARS.between(today, oldestMissionDate)); + } + + /** + * Retrieves a list of suitable AtBContracts for the given Campaign. + * + * @param campaign The Campaign to retrieve contracts from. + * @return A List of suitable AtBContracts. + */ + private static List getSuitableContracts(Campaign campaign) { + // Filter mission of type AtBContract and with completed status, check if it's suitable + return campaign.getMissions().stream() + .filter(c -> (c instanceof AtBContract) && (c.getStatus().isCompleted())) + .filter(c -> isSuitableContract((AtBContract) c)) + .map(c -> (AtBContract) c) + .toList(); + } + + /** + * Determines whether a given AtBContract is suitable. + * CamOps excludes Garrison and Cadre contracts when calculating inactivity. + * + * @param contract The AtBContract to check. + * @return true if the contract is suitable, false otherwise. + */ + private static boolean isSuitableContract(AtBContract contract) { + AtBContractType contractType = contract.getContractType(); + + return (!contractType.isGarrisonType() && !contractType.isCadreDuty()); + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java new file mode 100644 index 0000000000..f729c4566c --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/ReputationController.java @@ -0,0 +1,608 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.common.annotations.Nullable; +import megamek.common.enums.SkillLevel; +import megamek.logging.MMLogger; +import mekhq.MekHQ; +import mekhq.campaign.Campaign; +import mekhq.utilities.MHQXMLUtility; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.PrintWriter; +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Collectors; + +import static mekhq.campaign.rating.CamOpsReputation.AverageExperienceRating.getAtBModifier; +import static mekhq.campaign.rating.CamOpsReputation.AverageExperienceRating.getReputationModifier; +import static mekhq.campaign.rating.CamOpsReputation.AverageExperienceRating.getSkillLevel; +import static mekhq.campaign.rating.CamOpsReputation.CombatRecordRating.calculateCombatRecordRating; +import static mekhq.campaign.rating.CamOpsReputation.CommandRating.calculateCommanderRating; +import static mekhq.campaign.rating.CamOpsReputation.CrimeRating.calculateCrimeRating; +import static mekhq.campaign.rating.CamOpsReputation.FinancialRating.calculateFinancialRating; +import static mekhq.campaign.rating.CamOpsReputation.OtherModifiers.calculateOtherModifiers; +import static mekhq.campaign.rating.CamOpsReputation.SupportRating.calculateSupportRating; +import static mekhq.campaign.rating.CamOpsReputation.TransportationRating.calculateTransportationRating; + +public class ReputationController { + // utilities + private static final MMLogger logger = MMLogger.create(ReputationController.class); + + private final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.CamOpsReputation", + MekHQ.getMHQOptions().getLocale()); + + // average experience rating + private SkillLevel averageSkillLevel = SkillLevel.NONE; + private int averageExperienceRating = 0; + private int atbModifier = 0; + + // command rating + private Map commanderMap = new HashMap<>(); + private int commanderRating = 0; + + // combat record rating + private Map combatRecordMap = new HashMap<>(); + private int combatRecordRating = 0; + + // transportation rating + private Map transportationCapacities = new HashMap<>(); + private Map transportationRequirements = new HashMap<>(); + private Map transportationValues = new HashMap<>(); + private int transportationRating = 0; + + // support rating + private Map administrationRequirements = new HashMap<>(); + private Map crewRequirements = new HashMap<>(); + private Map> technicianRequirements = new HashMap<>(); + private int supportRating = 0; + + // financial rating + private Map financialRatingMap = new HashMap<>(); + private int financialRating = 0; + + // crime rating + private LocalDate dateOfLastCrime = null; + private Map crimeRatingMap = new HashMap<>(); + private int crimeRating = 0; + + // other modifiers + private Map otherModifiersMap = new HashMap<>(); + private int otherModifiers = 0; + + // total + private int reputationRating = 0; + + //region Getters and Setters + public SkillLevel getAverageSkillLevel() { + return this.averageSkillLevel; + } + + public int getAtbModifier() { + return this.atbModifier; + } + + public int getReputationRating() { + return this.reputationRating; + } + //endregion Getters and Setters + + /** + * Initializes the ReputationController class with default values. + */ + public ReputationController() {} + + /** + * Performs and stores all reputation calculations. + * + * @param campaign the campaign for which to initialize the reputation + */ + @SuppressWarnings(value = "unchecked") + public void initializeReputation(Campaign campaign) { + // step one: calculate average experience rating + averageSkillLevel = getSkillLevel(campaign, true); + averageExperienceRating = getReputationModifier(averageSkillLevel); + atbModifier = getAtBModifier(campaign); + + // step two: calculate command rating + commanderMap = calculateCommanderRating(campaign, campaign.getFlaggedCommander()); + commanderRating = commanderMap.get("total"); + + // step three: calculate combat record rating + combatRecordMap = calculateCombatRecordRating(campaign); + combatRecordRating = combatRecordMap.get("total"); + + // step four: calculate transportation rating + List> rawTransportationData = calculateTransportationRating(campaign); + + transportationCapacities = rawTransportationData.get(0); + transportationRequirements = rawTransportationData.get(1); + transportationValues = rawTransportationData.get(2); + + transportationRating = transportationCapacities.get("total"); + transportationCapacities.remove("total"); + + // step five: support rating + Map> rawSupportData = calculateSupportRating(campaign, transportationRequirements); + + administrationRequirements = (Map) rawSupportData.get("administrationRequirements"); + crewRequirements = (Map) rawSupportData.get("crewRequirements"); + technicianRequirements = (Map>) rawSupportData.get("technicianRequirements"); + + supportRating = (int) rawSupportData.get("total").get("total"); + + // step six: calculate financial rating + financialRatingMap = calculateFinancialRating(campaign.getFinances()); + financialRating = financialRatingMap.get("total"); + + // step seven: calculate crime rating + crimeRatingMap = calculateCrimeRating(campaign); + crimeRating = crimeRatingMap.get("total"); + dateOfLastCrime = campaign.getDateOfLastCrime(); + + // step eight: calculate other modifiers + otherModifiersMap = calculateOtherModifiers(campaign); + otherModifiers = otherModifiersMap.get("total"); + + // step nine: total everything + calculateTotalReputation(); + logger.debug("TOTAL REPUTATION = {}", reputationRating); + } + + /** + * Calculates the total reputation by adding up various ratings and modifiers. + * This method updates the reputationRating variable. + */ + private void calculateTotalReputation() { + reputationRating = averageExperienceRating; + reputationRating += commanderRating; + reputationRating += combatRecordRating; + reputationRating += transportationRating; + reputationRating += supportRating; + reputationRating += financialRating; + reputationRating += crimeRating; + reputationRating += otherModifiers; + } + + /** + * Retrieves the report text for the given campaign. + * + * @param campaign the campaign for which to generate the report + * @return the report text as a string + */ + public String getReportText(Campaign campaign) { + StringBuilder description = new StringBuilder(); + + description.append("

"); + + description.append(String.format(resources.getString("unitReputation.text"), reputationRating)); + + // AVERAGE EXPERIENCE RATING + description.append(String.format(resources.getString("averageExperienceRating.text"), averageExperienceRating)); + description.append(String.format(resources.getString("experienceLevel.text"), averageSkillLevel.toString())); + + // COMMAND RATING + description.append(String.format(resources.getString("commandRating.text"), commanderRating)); + description.append(String.format(resources.getString("leadership.text"), commanderMap.get("leadership"))); + description.append(String.format(resources.getString("tactics.text"), commanderMap.get("tactics"))); + description.append(String.format(resources.getString("strategy.text"), commanderMap.get("strategy"))); + description.append(String.format(resources.getString("negotiation.text"), commanderMap.get("negotiation"))); + description.append(String.format(resources.getString("traits.text"), commanderMap.get("traits"))); + + if (campaign.getCampaignOptions().isUseRandomPersonalities() && (campaign.getCampaignOptions().isUseRandomPersonalityReputation())) { + description.append(String.format(resources.getString("personality.text"), commanderMap.get("personality"))).append("

"); + } else { + description.append("

"); + } + + // COMBAT RECORD RATING + description.append(String.format(resources.getString("combatRecordRating.text"), combatRecordRating)); + + description.append(getMissionString("successes", resources.getString("successes.text"), 5)); + description.append(getMissionString("partialSuccesses", resources.getString("partialSuccesses.text"), 0)); + description.append(getMissionString("failures", resources.getString("failures.text"), -10)); + description.append(getMissionString("contractsBreached", resources.getString("contractsBreached.text"), -25)); + + if (campaign.getRetainerStartDate() != null) { + description.append(getMissionString("retainerDuration", resources.getString("retainerDuration.text"), 5)).append("

"); + } else { + description.append("

"); + } + + // TRANSPORTATION RATING + description.append(String.format(resources.getString("transportationRating.text"), transportationRating)); + + if (transportationCapacities.get("hasJumpShipOrWarShip") == 1) { + description.append(resources.getString("hasJumpShipOrWarShip.text")); + } + + description.append(getDropShipString()); + description.append(getTransportString("smallCraftCount", "smallCraftBays", "smallCraft", resources.getString("smallCraft.text"), true)); + description.append(getTransportString("asfCount", "asfBays", "asf", resources.getString("fighters.text"), false)); + description.append(getTransportString("mechCount", "mechBays", "mech", resources.getString("battleMechs.text"), false)); + description.append(getTransportString("superHeavyVehicleCount", "superHeavyVehicleBays", "superHeavyVehicle", resources.getString("vehicleSuperHeavy.text"), true)); + description.append(getTransportString("heavyVehicleCount", "heavyVehicleBays", "heavyVehicle", resources.getString("vehicleHeavy.text"), true)); + description.append(getTransportString("lightVehicleCount", "lightVehicleBays", "lightVehicle", resources.getString("vehicleLight.text"), false)); + description.append(getTransportString("protoMechCount", "protoMechBays", "protoMech", resources.getString("protoMechs.text"), false)); + description.append(getTransportString("battleArmorCount", "battleArmorBays", "battleArmor", resources.getString("battleArmor.text"), false)); + description.append(getTransportString("infantryCount", "infantryBays", "infantry", resources.getString("infantry.text"), false)); + description.append(resources.getString("asterisk.text")); + + // SUPPORT RATING + description.append(String.format(resources.getString("supportRating.text"), supportRating)); + + if (crewRequirements.get("crewRequirements") < 0) { + description.append(resources.getString("crewRequirements.text")); + } + + description.append(String.format(resources.getString("administrationRequirements.text"), + administrationRequirements.get("personnelCount"), + administrationRequirements.get("administratorCount"), + administrationRequirements.get("total"))); + + description.append(String.format(resources.getString("technicianRequirements.text"), technicianRequirements.get("rating").get(0))); + + description.append(getTechnicianString("mech")); + description.append(getTechnicianString("vehicle")); + description.append(getTechnicianString("aero")); + description.append(getTechnicianString("battleArmor")); + + description.append("
"); + + // FINANCIAL RATING + description.append(String.format(resources.getString("financialRating.text"), financialRating)); + + if ((financialRatingMap.get("hasLoan") + financialRatingMap.get("inDebt")) > 0) { + description.append(resources.getString("hasLoanOrDebt.text")); + } else { + description.append("
"); + } + + // CRIME RATING + description.append(String.format(resources.getString("crimeRating.text"), crimeRating)); + + if (crimeRating < 0) { + int piracy = crimeRatingMap.get("piracy"); + if (piracy < 0) { + description.append(String.format(resources.getString("piracy.text"), piracy)); + } + + int otherCrimes = crimeRatingMap.get("other"); + if (otherCrimes < 0) { + description.append(String.format(resources.getString("otherCrimes.text"), otherCrimes)); + } + + description.append(String.format(resources.getString("dateOfLastCrime.text"), dateOfLastCrime)); + } else { + description.append("
"); + } + + // OTHER MODIFIERS + description.append(String.format(resources.getString("otherModifiers.text"), otherModifiers)); + + int inactiveYears = otherModifiersMap.get("inactiveYears"); + + if (inactiveYears > 0) { + description.append(String.format(resources.getString("inactiveYears.text"), -inactiveYears * 5)); + } + + int customModifier = otherModifiersMap.get("customModifier"); + + if (customModifier != 0) { + String modifier = String.format("(%+d)", customModifier); + description.append(String.format(resources.getString("customModifier.text"), modifier)); + } + + description.append("
"); + + return description.toString(); + } + + /** + * Appends the technician requirement information for the given type. + * If the technician requirement exceeds 0, it generates an HTML formatted string + * with the technician label and the current count and maximum count of technicians. + * + * @param type the type of technician requirement (mech, vehicle, aero, battleArmor) + * @return the generated technician requirement string in HTML format, + * or an empty string if either technicianRequirement value is 0. + */ + private String getTechnicianString(String type) { + List technicianRequirement = technicianRequirements.get(type); + + if ((technicianRequirement.get(0) > 0) || (technicianRequirement.get(1) > 0)) { + String label = switch (type) { + case "mech" -> resources.getString("battleMechsAndProtoMechs.text"); + case "vehicle" -> resources.getString("vehicles.text"); + case "aero" -> resources.getString("fightersAndSmallCraft.text"); + case "battleArmor" -> resources.getString("battleArmor.text"); + default -> throw new IllegalStateException("Unexpected value in mekhq/campaign/rating/CamOpsReputation/ReputationController.java/getTechnicianString: " + + type); + }; + + return String.format(resources.getString("technicianString.text"), + label, + technicianRequirement.get(0), + technicianRequirement.get(1)); + } + + return ""; + } + + /** + * Generates the mission string with the given key, label, and multiplier. + * + * @param key the key for accessing the combat record count + * @param label the label to be displayed in the mission string + * @param multiplier the multiplier to apply to the count + * @return the generated mission string, formatted as + * "
     label: count (count * multiplier)
", or null if the count is <= 0 + */ + private String getMissionString(String key, String label, int multiplier) { + int count = combatRecordMap.get(key); + int total = count * multiplier; + + if (count > 0) { + return String.format(resources.getString("mission.text"), + label, + count, + String.format(total > 0 ? "+%d" : "%d", total)); + } else { + return ""; + } + } + + /** + * Generates DropShip string information for the unit report + * + * @return the generated string in HTML format, formatted as + * "
     DropShips: unitCount / bayCapacity Docking Collars (modifier)
" + */ + private String getDropShipString() { + int unitCount = transportationRequirements.get("dropShipCount"); + int bayCapacity = transportationCapacities.get("dockingCollars"); + String modifier = "0"; + + if (unitCount == 0) { + modifier = resources.getString("noDropShip.text"); + } else if (bayCapacity >= unitCount) { + modifier = "+5"; + } + + return String.format(resources.getString("dropShipString.text"), + unitCount, + bayCapacity, + modifier); + } + + /** + * Generates a transport string with the given unitKey, bayKey, valueKey, label, and displayAsterisk. + * + * @param unitKey the key to access the unit count in the transportationRequirements map + * @param bayKey the key to access the bay capacity in the transportationCapacities map + * @param valueKey the key to access the rating in the transportationValues map + * @param label the label to be displayed in the transport string + * @param displayAsterisk whether to display an asterisk in the transport string + * @return the generated transport string in HTML format, formatted as + * "
     label: unitCount / bayCount Bays* modifier
", or an empty string if unitCount and bayCount + * are both 0 + */ + private String getTransportString(String unitKey, String bayKey, String valueKey, String label, boolean displayAsterisk) { + int unitCount = transportationRequirements.get(unitKey); + int bayCount = transportationCapacities.get(bayKey); + int rating = transportationValues.get(valueKey); + + String asterisk = displayAsterisk ? "*" : ""; + String modifier = ""; + + if (unitCount > 0 || bayCount > 0) { + if (rating > 0) { + modifier = String.format("(+%d)", rating); + } else if (rating < 0) { + modifier = String.format("(%d)", rating); + } + + return String.format(resources.getString("transportString.text"), + label, + unitCount, + bayCount, + asterisk, + modifier); + } else { + return ""; + } + } + + /** + * Writes the reputation ratings and values to an XML file. + * + * @param pw the PrintWriter object used to write to XML + * @param indent the number of spaces to indent the XML tags + */ + public void writeReputationToXML(final PrintWriter pw, int indent) { + // average experience rating + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "averageSkillLevel", averageSkillLevel.toString()); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "averageExperienceRating", averageExperienceRating); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "atbModifier", atbModifier); + + // command rating + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "commanderMap"); + writeMapToXML(pw, indent, commanderMap); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "commanderMap"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "commanderRating", commanderRating); + + // combat record rating + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "combatRecordMap"); + writeMapToXML(pw, indent, combatRecordMap); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "combatRecordMap"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "combatRecordRating", combatRecordRating); + + // transportation rating + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "transportationCapacities"); + writeMapToXML(pw, indent, transportationCapacities); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "transportationCapacities"); + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "transportationRequirements"); + writeMapToXML(pw, indent, transportationRequirements); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "transportationRequirements"); + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "transportationValues"); + writeMapToXML(pw, indent, transportationValues); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "transportationValues"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "transportationRating", transportationRating); + + // support rating + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "administrationRequirements"); + writeMapToXML(pw, indent, administrationRequirements); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "administrationRequirements"); + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "crewRequirements"); + writeMapToXML(pw, indent, crewRequirements); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "crewRequirements"); + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "technicianRequirements"); + writeMapToXML(pw, indent, technicianRequirements); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "technicianRequirements"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "supportRating", supportRating); + + // financial rating + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "financialRatingMap"); + writeMapToXML(pw, indent, financialRatingMap); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "financialRatingMap"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "supportRating", financialRating); + + // crime rating + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "dateOfLastCrime", dateOfLastCrime); + + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "crimeRatingMap"); + writeMapToXML(pw, indent, crimeRatingMap); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "crimeRatingMap"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "crimeRating", crimeRating); + + // other modifiers + MHQXMLUtility.writeSimpleXMLOpenTag(pw, indent++, "otherModifiersMap"); + writeMapToXML(pw, indent, otherModifiersMap); + MHQXMLUtility.writeSimpleXMLCloseTag(pw, --indent, "otherModifiersMap"); + + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "otherModifiers", otherModifiers); + + // total + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "reputationRating", reputationRating); + } + + /** + * Writes a map to XML format. + * + * @param pw the PrintWriter object used to write to XML + * @param indent the number of spaces to indent the XML tags + * @param map the map to write to XML, where the keys are strings, and the values can be any type + * @param the type of the values in the map + * @return the updated value of the indent parameter after writing the map to XML + */ + private void writeMapToXML(final PrintWriter pw, final int indent, final Map map) { + for (String key : map.keySet()) { + MHQXMLUtility.writeSimpleXMLTag(pw, indent, key, map.get(key).toString()); + } + } + + public ReputationController generateInstanceFromXML(final Node wn) { + NodeList nl = wn.getChildNodes(); + + try { + for (int x = 0; x < nl.getLength(); x++) { + Node wn2 = nl.item(x); + + if (wn2.getNodeName().equalsIgnoreCase("averageSkillLevel")) { + this.averageSkillLevel = SkillLevel.valueOf(wn2.getTextContent().toUpperCase()); + } else if (wn2.getNodeName().equalsIgnoreCase("averageExperienceRating")) { + this.averageExperienceRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("atbModifier")) { + this.atbModifier = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("commanderMap")) { + this.parseSubNode(wn2, commanderMap, false); + } else if (wn2.getNodeName().equalsIgnoreCase("commanderRating")) { + this.commanderRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("combatRecordMap")) { + this.parseSubNode(wn2, combatRecordMap, false); + } else if (wn2.getNodeName().equalsIgnoreCase("combatRecordRating")) { + this.combatRecordRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("transportationCapacities")) { + this.parseSubNode(wn2, transportationCapacities, false); + } else if (wn2.getNodeName().equalsIgnoreCase("transportationRequirements")) { + this.parseSubNode(wn2, transportationRequirements, false); + } else if (wn2.getNodeName().equalsIgnoreCase("transportationValues")) { + this.parseSubNode(wn2, transportationValues, false); + } else if (wn2.getNodeName().equalsIgnoreCase("transportationRating")) { + this.transportationRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("administrationRequirements")) { + this.parseSubNode(wn2, administrationRequirements, false); + } else if (wn2.getNodeName().equalsIgnoreCase("crewRequirements")) { + this.parseSubNode(wn2, crewRequirements, false); + } else if (wn2.getNodeName().equalsIgnoreCase("technicianRequirements")) { + this.parseSubNode(wn2, null, true); + } else if (wn2.getNodeName().equalsIgnoreCase("supportRating")) { + this.supportRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("financialRatingMap")) { + this.parseSubNode(wn2, financialRatingMap, false); + } else if (wn2.getNodeName().equalsIgnoreCase("financialRating")) { + this.financialRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("dateOfLastCrime")) { + this.dateOfLastCrime = LocalDate.parse(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("crimeRatingMap")) { + this.parseSubNode(wn2, crimeRatingMap, false); + } else if (wn2.getNodeName().equalsIgnoreCase("crimeRating")) { + this.crimeRating = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("otherModifiersMap")) { + this.parseSubNode(wn2, otherModifiersMap, false); + } else if (wn2.getNodeName().equalsIgnoreCase("otherModifiers")) { + this.otherModifiers = Integer.parseInt(wn2.getTextContent()); + } else if (wn2.getNodeName().equalsIgnoreCase("reputationRating")) { + this.reputationRating = Integer.parseInt(wn2.getTextContent()); + } + } + } catch (Exception ex) { + logger.error("Could not parse Reputation: ", ex); + } + + return this; + } + + /** + * Parses the sub-nodes of a given node and populates either a map or a technicianRequirements list based on the boolean flag. + * + * @param wn2 The node whose sub-nodes need to be parsed. + * @param map The map to populate with the sub-node data (null if technicianRequirements). + * @param isTechnicianRequirements Flag indicating whether to populate a technicianRequirements list. + */ + private void parseSubNode(Node wn2, @Nullable Map map, boolean isTechnicianRequirements) { + NodeList subNodeList = wn2.getChildNodes(); + + for (int i = 0; i < subNodeList.getLength(); i++) { + Node node = subNodeList.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (isTechnicianRequirements) { + try { + String[] numbers = node.getTextContent().substring(1, node.getTextContent().length() - 1).split(",\\s*"); + List list = Arrays.stream(numbers).map(Integer::parseInt).collect(Collectors.toList()); + technicianRequirements.put(node.getNodeName(), list); + } catch (NumberFormatException ex) { + logger.error("Could not parse TechnicianRequirements: ", ex); + } + } else { + try { + map.put(node.getNodeName(), Integer.parseInt(node.getTextContent())); + } catch (Exception ex) { + logger.error("Could not parse {}: ", map, ex); + } + } + } + } + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/SupportRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/SupportRating.java new file mode 100644 index 0000000000..e54fecba0f --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/SupportRating.java @@ -0,0 +1,294 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.common.Entity; +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.unit.Unit; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class SupportRating { + private static final MMLogger logger = MMLogger.create(SupportRating.class); + private static final int VEHICLE_WEIGHT_DIVIDER = 15; + + /** + * This method calculates the support rating for a campaign. + * + * @param campaign The campaign object on which the calculation is based. + * @param transportationRequirements A map representing the transportation requirements. + * @return A map containing maps with the calculated support rating, as well as individual requirements. + */ + protected static Map> calculateSupportRating(Campaign campaign, Map transportationRequirements) { + // Create a map to store the results + Map> supportRating = new HashMap<>(); + + // Calculate the crew requirements for this campaign + Map crewRequirements = calculateCrewRequirements(campaign); + // Calculate the technician requirements for this campaign + Map> technicianRequirements = calculateTechnicianRequirements(campaign, transportationRequirements); + // Calculate the administration requirements for this campaign + Map administrationRequirements = calculateAdministratorRequirements(campaign, technicianRequirements.get("totals").get(0)); + + // Add the calculated requirements into the supportRating map + supportRating.put("administrationRequirements", administrationRequirements); + supportRating.put("crewRequirements", crewRequirements); + supportRating.put("technicianRequirements", technicianRequirements); + + // Calculate the total of requirements + int total = administrationRequirements.get("total") + + crewRequirements.get("crewRequirements") + + technicianRequirements.get("rating").get(0); + + // Add the total value into the supportRating map + supportRating.put("total", Map.of("total", total)); + + logger.debug("Support Rating = {}", total); + + // Return the final map containing the calculated values + return supportRating; + } + + /** + * Calculates the campaign's administrative requirements. + * + * @param campaign The campaign for which to calculate the administrative requirements. + * @param technicianRequirements The number of technicians required by the campaign. + * @return A map containing the following information: + * - "totalPersonnelCount": The total number of personnel in the campaign. + * - "administratorCount": The number of administrators in the campaign. + * - "personnelCount": The calculated number of non-administrator personnel required based on the campaign faction. + * - "total": A calculated value indicating the total administrative requirement, where 0 indicates + * a sufficient of non-administrator personnel compared to administrators, and -5 indicates + * a shortage. + */ + private static Map calculateAdministratorRequirements(Campaign campaign, int technicianRequirements) { + Map administrationRequirements = new HashMap<>(); + + // Get the total sums of personnel and administrators + int totalPersonnelCount = getTotalPersonnelCount(campaign, technicianRequirements); + + int administratorCount = (int) campaign.getActivePersonnel().stream() + .filter(Person::isAdministrator) + .count(); + + // Calculate personnel count based on campaign faction + int personnelCount = totalPersonnelCount - administratorCount; + double divisor = campaign.getFaction().isPirate() || campaign.getFaction().isMercenary() ? 10.0 : 5.0; + personnelCount = (int) Math.ceil(personnelCount / divisor); + + administrationRequirements.put("totalPersonnelCount", totalPersonnelCount); + administrationRequirements.put("administratorCount", administratorCount); + administrationRequirements.put("personnelCount", personnelCount); + + // Calculate final total + int total = personnelCount > administratorCount ? -5 : 0; + administrationRequirements.put("total", total); + + logger.debug("Administrator Requirements = {}", + administrationRequirements.entrySet().stream() + .map(entry -> entry.getKey() + ": " + entry.getValue() + '\n') + .collect(Collectors.joining())); + + return administrationRequirements; + } + + /** + * Calculates the total personnel count required for the campaign, taking into account technician requirements. + * + * @param campaign The campaign for which to calculate the total personnel count. + * @param technicianRequirements The number of technicians required for the campaign. + * @return The total personnel count required for the campaign. + */ + private static int getTotalPersonnelCount(Campaign campaign, int technicianRequirements) { + int totalPersonnelCount = technicianRequirements; + + // Count personnel + for (Unit unit : campaign.getActiveUnits()) { + if (unit.isMothballed()) { + continue; + } + + Entity entity = unit.getEntity(); + + if (entity.isMek() || entity.isAerospaceFighter() || entity.isConventionalFighter()) { + totalPersonnelCount++; + } else if (entity.isVehicle()) { + totalPersonnelCount += (int) Math.ceil(entity.getWeight() / VEHICLE_WEIGHT_DIVIDER); + } else { + totalPersonnelCount += unit.getFullCrewSize(); + } + } + + return totalPersonnelCount; + } + + /** + * Calculates the crew requirements for the campaign. + * If a not fully crewed LargeCraft is found, the crew requirements are set to -5. + * Otherwise, the crew requirements are set to 0. + * + * @param campaign the campaign for which to calculate the crew requirements + * @return a map containing the crew requirements, with the key "crewRequirements" and the value either -5 or 0 + */ + private static Map calculateCrewRequirements(Campaign campaign) { + int crewRequirements = 0; + + // Iterate over all units in the campaign + for (Unit unit : campaign.getActiveUnits()) { + Entity entity = unit.getEntity(); + + // Check if the unit is a LargeCraft and is not fully crewed + if (entity.isLargeCraft() && !unit.isFullyCrewed()) { + crewRequirements = -5; + break; // Exit the loop as soon as a not fully crewed LargeCraft is found + } + } + + return Map.of("crewRequirements", crewRequirements); + } + + /** + * Calculates the technician requirements based on transportation requirements. + * + * @param campaign The campaign for which to calculate the technician requirements. + * @param transportationRequirements The transportation requirements for the campaign. + * @return A map where the keys represent the technician type and the values represent a list of the technician count and the tech count. + */ + private static Map> calculateTechnicianRequirements(Campaign campaign, Map transportationRequirements) { + Map> technicianRequirements = new HashMap<>(); + + // Calculate counts for each unit type + int mechCount = transportationRequirements.get("mechCount"); + int vehicleCount = transportationRequirements.get("totalVehicleCount"); + int aeroCount = transportationRequirements.get("asfCount") + transportationRequirements.get("smallCraftCount"); + var baProtoCounts = calculateBattleArmorAndProtoMechCounts(campaign); + int battleArmorCount = Math.round(baProtoCounts.get("battleArmorCount") / 5.0f); + mechCount += Math.round(baProtoCounts.get("protoMechCount") / 5.0f); + + // Calculate tech counts + var techCounts = calculateTechCounts(campaign); + technicianRequirements.put("mech", List.of(mechCount, techCounts.get("techMechCount"))); + technicianRequirements.put("vehicle", List.of(vehicleCount, techCounts.get("techMechanicCount"))); + technicianRequirements.put("aero", List.of(aeroCount, techCounts.get("techAeroCount"))); + technicianRequirements.put("battleArmor", List.of(battleArmorCount, techCounts.get("techBattleArmorCount"))); + + // Calculate total requirements and techs + int totalRequirements = (mechCount + vehicleCount + aeroCount + battleArmorCount); + int totalTechs = techCounts.values().stream().mapToInt(Integer::intValue).sum(); + int percentage = (int) ((float) totalTechs / totalRequirements * 100); + + if (totalRequirements == 0) { + percentage = 100; + } + + technicianRequirements.put("totals", List.of(totalRequirements, totalTechs)); + technicianRequirements.put("rating", List.of(calculateTechRating(percentage))); + + logger.debug("Technician Requirements = {}", + technicianRequirements.entrySet().stream() + .map(entry -> entry.getKey() + ": " + entry.getValue() + '\n') + .collect(Collectors.joining())); + + return technicianRequirements; + } + + /** + * Calculates the total count of battle armor and proto mechs in a given campaign. + * + * @param campaign the campaign containing the units to be counted + * @return a map containing the counts of battle armor and proto mechs, with the keys "battleArmorCount" and "protoMechCount" + */ + private static Map calculateBattleArmorAndProtoMechCounts(Campaign campaign) { + Map counts = new HashMap<>(); + + int battleArmorCount = 0; + int protoMechCount = 0; + + for (Unit unit : campaign.getActiveUnits()) { + Entity entity = unit.getEntity(); + + if (entity.isBattleArmor()) { + battleArmorCount += unit.getFullCrewSize(); + } else if (entity.isProtoMek()) { + protoMechCount += unit.getFullCrewSize(); + } + } + + counts.put("battleArmorCount", battleArmorCount); + counts.put("protoMechCount", protoMechCount); + + return counts; + } + + /** + * Calculates the number of personnel with different tech roles in the given campaign. + * + * @param campaign the campaign object from which to calculate the tech counts + * @return a map that contains the counts of different tech roles. The keys are as follows: + * - "techMechCount" for personnel with the role "TechMech" + * - "techMechanicCount" for personnel with the role "TechMechanic" + * - "techAeroCount" for personnel with the role "TechAero" + * - "techBattleArmorCount" for personnel with the role "TechBA" + */ + private static Map calculateTechCounts(Campaign campaign) { + Map techCounts = new HashMap<>(); + + techCounts.put("techMechCount", 0); + techCounts.put("techMechanicCount", 0); + techCounts.put("techAeroCount", 0); + techCounts.put("techBattleArmorCount", 0); + + for (Person person : campaign.getActivePersonnel()) { + updateCount(person::isTechMech, "techMechCount", techCounts); + updateCount(person::isTechMechanic, "techMechanicCount", techCounts); + updateCount(person::isTechAero, "techAeroCount", techCounts); + updateCount(person::isTechBA, "techBattleArmorCount", techCounts); + } + + return techCounts; + } + + /** + * Updates the count in the given map based on a condition. + * If the condition is true, the count for the specified key in the map is incremented by 1. + * + * @param condition The condition to check. If true, the count will be updated. + * @param key The key in the map for which to update the count. + * @param counts The map containing the counts. + */ + private static void updateCount(Supplier condition, String key, Map counts) { + if (condition.get()) { + counts.put(key, counts.get(key) + 1); + } + } + + /** + * Calculates the technician rating based on the percentage of total technicians to total requirements. + * + * @param percentage The percentage of total technicians to total requirements. + * @return The technician rating based on the given percentage: + * - If the percentage is less than 100, returns -5. + * - If the percentage is between 100 and 150 (inclusive), returns 0. + * - If the percentage is between 151 and 175 (inclusive), returns 5. + * - If the percentage is between 176 and 200 (inclusive), returns 10. + * - If the percentage is greater than 200, returns 15. + */ + private static int calculateTechRating(int percentage) { + if (percentage < 100) { + return -5; + } else if (percentage <= 150) { + return 0; + } else if (percentage <= 175) { + return 5; + } else if (percentage <= 200) { + return 10; + } + + return 15; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/TransportationRating.java b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/TransportationRating.java new file mode 100644 index 0000000000..23f79e35dc --- /dev/null +++ b/MekHQ/src/mekhq/campaign/rating/CamOpsReputation/TransportationRating.java @@ -0,0 +1,355 @@ +package mekhq.campaign.rating.CamOpsReputation; + +import megamek.common.*; +import megamek.logging.MMLogger; +import mekhq.campaign.Campaign; +import mekhq.campaign.unit.Unit; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class TransportationRating { + private static final MMLogger logger = MMLogger.create(TransportationRating.class); + + /** + * Calculates the transportation rating for the given campaign. + * + * @param campaign The campaign for which to calculate the transportation rating. + * @return A list containing maps of transportation capacities and requirements, including the transportation rating. + */ + public static List> calculateTransportationRating(Campaign campaign) { + // Calculate transportation capacities and requirements for the campaign + Map transportationCapacities = calculateTransportationCapacities(campaign); + Map transportationRequirements = calculateTransportRequirements(campaign); + Map transportationValues = new HashMap<>(); + + int transportationRating = 0; + + // For each type of entity (denoted here as "SmallCraft", "AeroSpaceFighter", etc.) + // calculate the rating adjustment based on the capacity and requirements + + // Small Craft + int capacity = transportationCapacities.get("smallCraftBays"); // Get the capacity for the entity + int requirements = transportationRequirements.get("smallCraftCount"); // Get the requirements for the entity + + // Add the rating adjustment to the total; We do this for each following entity + int rating = calculateRating(capacity, requirements); + transportationValues.put("smallCraft", rating); + transportationRating += rating; + + // Calculate spare capacity if any. + // Some entity types can use spare bays not used by other entities + int spareCapacity = Math.max(0, capacity - requirements); + + // The above logic is repeated for the remaining entities + + // ASF + capacity = transportationCapacities.get("asfBays"); + requirements = Math.max(0, transportationRequirements.get("asfCount") - spareCapacity); + + rating = calculateRating(capacity, requirements); + transportationValues.put("asf", rating); + transportationRating += rating; + + // Mechs + capacity = transportationCapacities.get("mechBays"); + requirements = transportationRequirements.get("mechCount"); + + rating = calculateRating(capacity, requirements); + transportationValues.put("mech", rating); + transportationRating += rating; + + // Super Heavy Vehicles + capacity = transportationCapacities.get("superHeavyVehicleBays"); + requirements = transportationRequirements.get("superHeavyVehicleCount"); + + rating = calculateRating(capacity, requirements); + transportationValues.put("superHeavyVehicle", rating); + transportationRating += rating; + + spareCapacity = Math.max(0, capacity - requirements); + + // Heavy Vehicles + capacity = transportationCapacities.get("heavyVehicleBays"); + requirements = Math.max(0, transportationRequirements.get("heavyVehicleCount") - spareCapacity); + + rating = calculateRating(capacity, requirements); + transportationValues.put("heavyVehicle", rating); + transportationRating += rating; + + // as this spare capacity can also be used by light vehicles, + // we need to track the remaining spare capacity + spareCapacity -= Math.max(0, transportationRequirements.get("heavyVehicleCount")); + spareCapacity += Math.max(0, capacity - requirements); + + // Light Vehicles + capacity = transportationCapacities.get("lightVehicleBays"); + requirements = Math.max(0, transportationRequirements.get("lightVehicleCount") - spareCapacity); + + rating = calculateRating(capacity, requirements); + transportationValues.put("lightVehicle", rating); + transportationRating += rating; + + // ProtoMechs + capacity = transportationCapacities.get("protoMechBays"); + requirements = transportationRequirements.get("protoMechCount"); + + rating = calculateRating(capacity, requirements); + transportationValues.put("protoMech", rating); + transportationRating += rating; + + // Battle Armor + capacity = transportationCapacities.get("battleArmorBays"); + requirements = transportationRequirements.get("battleArmorCount"); + + rating = calculateRating(capacity, requirements); + transportationValues.put("battleArmor", rating); + transportationRating += rating; + + // Infantry + capacity = transportationCapacities.get("infantryBays"); + requirements = transportationRequirements.get("infantryCount"); + + rating = calculateRating(capacity, requirements); + transportationValues.put("infantry", rating); + transportationRating += rating; + + // Support Personnel + capacity = transportationCapacities.get("passengerCapacity"); + requirements = transportationRequirements.get("passengerCount"); + + if ((capacity > 0) && (capacity >= requirements)) { + transportationRating += 3; + transportationValues.put("passenger", 3); + logger.debug("Exceeding Support Personnel Transport Requirements: +3"); + } else if ((requirements > 0) && (transportationRating > 0)) { + transportationRating -= 3; + transportationValues.put("passenger", -3); + logger.debug("Below Support Personnel Transport Requirements: -3"); + } + + // JumpShip & WarShip Presence + if (transportationCapacities.get("hasJumpShipOrWarShip") > 0) { + transportationRating += 10; + logger.debug("Has JumpShip or WarShip: +10"); + } + + // Docking Collar Requirements + int dockingCollarCount = transportationCapacities.get("dockingCollars"); + + if ((dockingCollarCount > 0) && (dockingCollarCount >= transportationRequirements.get("dropShipCount"))) { + transportationRating += 5; + logger.debug("Exceeding docking collar requirements: +5"); + } + + if (transportationRequirements.get("dropShipCount") == 0) { + transportationRating -= 5; + logger.debug("No DropShip: -"); + } + + // Finally, the calculated transportation rating is added to the map of transportation capacities + transportationCapacities.put("total", transportationRating); + logger.debug("Transportation Rating = {}", transportationRating); + + // Return list of capacities and requirements + return List.of(transportationCapacities, transportationRequirements, transportationValues); + } + + /** + * Calculates the transportation rating adjustment based on capacity and requirements. + * + * @param capacity the transport bay capacity + * @param requirements the transport bay usage + * @return the rating calculated based on the capacity and requirements + */ + protected static int calculateRating(int capacity, int requirements) { + if (requirements > 0) { + int usage = capacity - requirements; + + if (usage < 0) { + return -5; + } else if (usage > requirements * 2) { + return 10; + } else { + return 5; + } + } + + return 0; + } + + /** + * Retrieves the transportation bays and passenger capacity for a campaign. + * + * @param campaign the campaign to retrieve the transportation bays and passenger capacity for + * @return a map containing the transportation bays and passenger capacity, where each key represents + * a bay type and its corresponding value represents the count or capacity + */ + private static Map calculateTransportationCapacities(Campaign campaign) { + int uncrewedUnits = 0; + int dockingCollars = 0; + int hasJumpShipOrWarShip = 0; + + int smallCraftBays = 0, mechBays = 0, asfBays = 0, superHeavyVehicleBays = 0, heavyVehicleBays = 0, + lightVehicleBays = 0, protoMechBays = 0, battleArmorBays = 0, infantryBays = 0, passengerCapacity = 0; + + // Iterating through each unit in the campaign + for (Unit unit : campaign.getActiveUnits()) { + Entity entity = unit.getEntity(); + + // Skip the unit if it doesn't meet the specific criteria + if (!(entity.isDropShip()) && !(entity.isJumpShip()) + && !(entity.isWarShip()) && !(entity.isSmallCraft())) { + continue; + } + + // If not fully crewed, increment the uncrewed unit count and skip this unit + if (!unit.isFullyCrewed()) { + uncrewedUnits++; + continue; + } + + // this is a binary bonus, so we only need to flip the value once + if ((hasJumpShipOrWarShip == 0) && (entity.isJumpShip() || entity.isWarShip())) { + hasJumpShipOrWarShip = 1; + } + + dockingCollars += entity.getDockingCollars().size(); + + // Iterate through each bay in entity + for (Bay bay : entity.getTransportBays()) { + if (bay instanceof SmallCraftBay) { + smallCraftBays += (int) bay.getCapacity(); + } else if (bay instanceof MechBay) { + mechBays += (int) bay.getCapacity(); + } else if (bay instanceof ASFBay) { + asfBays += (int) bay.getCapacity(); + } else if (bay instanceof SuperHeavyVehicleBay) { + superHeavyVehicleBays += (int) bay.getCapacity(); + } else if (bay instanceof HeavyVehicleBay) { + heavyVehicleBays += (int) bay.getCapacity(); + } else if (bay instanceof LightVehicleBay) { + lightVehicleBays += (int) bay.getCapacity(); + } else if (bay instanceof ProtomechBay) { + protoMechBays += (int) bay.getCapacity(); + } else if (bay instanceof BattleArmorBay) { + battleArmorBays += (int) bay.getCapacity(); + } else if (bay instanceof InfantryBay) { + infantryBays += (int) Math.floor(bay.getCapacity() / ((InfantryBay) bay).getPlatoonType().getWeight()); + } + + passengerCapacity += bay.getPersonnel(entity.isClan()); + } + } + + // Map the capacity of each bay type + Map transportationCapacities = new HashMap<>(Map.of( + "smallCraftBays", smallCraftBays, + "mechBays", mechBays, + "asfBays", asfBays, + "superHeavyVehicleBays", superHeavyVehicleBays, + "heavyVehicleBays", heavyVehicleBays, + "lightVehicleBays", lightVehicleBays, + "protoMechBays", protoMechBays, + "battleArmorBays", battleArmorBays, + "infantryBays", infantryBays, + "passengerCapacity", passengerCapacity) + ); + + // add the supplemental information to the map + transportationCapacities.put("hasJumpShipOrWarShip", hasJumpShipOrWarShip); + transportationCapacities.put("dockingCollars", dockingCollars); + transportationCapacities.put("uncrewedUnits", uncrewedUnits); + + // log the stored information to aid debugging + logger.debug("Transportation Capacities = {}", + transportationCapacities.entrySet().stream() + .map(entry -> entry.getKey() + ": " + entry.getValue() + '\n') + .collect(Collectors.joining())); + + // return the map + return transportationCapacities; + } + + /** + * Calculates the transport requirements for the given campaign. + * + * @param campaign the campaign for which to calculate the transport requirements + * @return a map containing the count for each type of entity in the campaign + */ + private static Map calculateTransportRequirements(Campaign campaign) { + // Initialize variables to store counts of different unit types + int dropShipCount = 0, smallCraftCount = 0, mechCount = 0, asfCount = 0, superHeavyVehicleCount = 0, + heavyVehicleCount = 0, lightVehicleCount = 0, protoMechCount = 0, battleArmorCount = 0, + infantryCount = 0; + + // Iterate through each unit in the campaign + for (Unit unit : campaign.getActiveUnits()) { + Entity entity = unit.getEntity(); + + // Vehicles are handled separately based on their weight + if (entity.isVehicle()) { + double weight = entity.getWeight(); + if (weight > 100) { + superHeavyVehicleCount++; + } else if (weight > 50) { + heavyVehicleCount++; + } else { + lightVehicleCount++; + } + } + // Non-vehicle entities are categorized based on the entity types + else { + if (entity.isDropShip()) { + dropShipCount++; + } else if (entity.isSmallCraft()) { + smallCraftCount++; + } else if (entity.isMek()) { + mechCount++; + } else if (entity.isAerospaceFighter() || entity.isConventionalFighter()) { + asfCount++; + } else if (entity.isProtoMek()) { + protoMechCount++; + } else if (entity.isBattleArmor()) { + battleArmorCount++; + } else if (entity.isInfantry()) { + infantryCount++; + } + } + } + + // Count the number of passengers by filtering the personnel list + int passengerCount = (int) campaign.getPersonnel().stream() + .filter(person -> !person.getStatus().isAbsent() && !person.getStatus().isDepartedUnit()) + .filter(person -> person.getUnit() == null) + .count(); + + // Map each unit count to its type + Map transportRequirements = new HashMap<>(Map.of( + "dropShipCount", dropShipCount, + "smallCraftCount", smallCraftCount, + "mechCount", mechCount, + "asfCount", asfCount, + "superHeavyVehicleCount", superHeavyVehicleCount, + "heavyVehicleCount", heavyVehicleCount, + "lightVehicleCount", lightVehicleCount, + "protoMechCount", protoMechCount, + "battleArmorCount", battleArmorCount, + "infantryCount", infantryCount) + ); + + transportRequirements.put("totalVehicleCount", (superHeavyVehicleCount + heavyVehicleCount + lightVehicleCount)); + transportRequirements.put("passengerCount", passengerCount); + + // Log the calculated transport requirements + logger.debug("Transportation Requirements = {}", + transportRequirements.entrySet().stream() + .map(entry -> entry.getKey() + ": " + entry.getValue() + '\n') + .collect(Collectors.joining())); + + // Returns a map with calculated counts for each unit type + return transportRequirements; + } +} diff --git a/MekHQ/src/mekhq/campaign/rating/CampaignOpsReputation.java b/MekHQ/src/mekhq/campaign/rating/CampaignOpsReputation.java deleted file mode 100644 index 3881821590..0000000000 --- a/MekHQ/src/mekhq/campaign/rating/CampaignOpsReputation.java +++ /dev/null @@ -1,1036 +0,0 @@ -/* - * CampaignOpsRating.java - * - * Copyright (c) 2009 Jay Lawson (jaylawson39 at yahoo.com). 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.rating; - -import megamek.common.*; -import megamek.common.enums.SkillLevel; -import mekhq.campaign.Campaign; -import mekhq.campaign.personnel.Person; -import mekhq.campaign.personnel.SkillType; -import mekhq.campaign.unit.Unit; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author Deric Page (deric (dot) page (at) usa.net) - * @since 3/12/2012 - */ -public class CampaignOpsReputation extends AbstractUnitRating { - - private int nonAdminPersonnelCount = 0; - - // Tech Support & Admins. - private int mechTechTeamsNeeded = 0; - private int mechanicTeamsNeeded = 0; - private int battleArmorTechTeamsNeeded = 0; - private int aeroTechTeamsNeeded = 0; - private int adminsNeeded = 0; - - private int totalTechTeams = 0; - private int mechTechTeams = 0; - private int aeroTechTeams = 0; - private int mechanicTeams = 0; - private int baTechTeams = 0; - private int generalTechTeams = 0; - private final List craftWithoutCrew = new ArrayList<>(); - private int technicians = 0; - - public CampaignOpsReputation(Campaign campaign) { - super(campaign); - } - - @Override - public UnitRatingMethod getUnitRatingMethod() { - return UnitRatingMethod.CAMPAIGN_OPS; - } - - int getNonAdminPersonnelCount() { - return nonAdminPersonnelCount; - } - - int getAdminsNeeded() { - return adminsNeeded; - } - - int getVeeCount() { - return getLightVeeCount() + getHeavyVeeCount(); - } - - int getMechTechTeamsNeeded() { - return mechTechTeamsNeeded; - } - - int getMechanicTeamsNeeded() { - return mechanicTeamsNeeded; - } - - int getBattleArmorTechTeamsNeeded() { - return battleArmorTechTeamsNeeded; - } - - int getAeroTechTeamsNeeded() { - return aeroTechTeamsNeeded; - } - - private void countUnits() { - // Reset counts - setTotalSkillLevels(BigDecimal.ZERO); - - for (Unit u : getCampaign().getHangar().getUnits()) { - if (u.isMothballed()) { - continue; - } - if (!u.isPresent()) { - continue; - } - - updateUnitCounts(u); - - Person p = u.getCommander(); - if (p != null) { - getCommanderList().add(p); - } - - Entity entity = u.getEntity(); - updateBayCount(entity); - int unitType = entity.getUnitType(); - if (UnitType.INFANTRY == unitType || - UnitType.BATTLE_ARMOR == unitType) { - updateTotalSkill((Infantry) entity); - } else { - updateTotalSkill(u.getEntity().getCrew(), entity.getUnitType()); - } - - // todo: Add Mobile Structure when MegaMek supports it. - switch (unitType) { - case UnitType.SPACE_STATION: - case UnitType.NAVAL: - case UnitType.DROPSHIP: - if (u.getFullCrewSize() < u.getActiveCrew().size()) { - addCraftWithoutCrew(u); - } - break; - case UnitType.WARSHIP: - case UnitType.JUMPSHIP: - updateDockingCollarCount((Jumpship) entity); - if (u.getFullCrewSize() < u.getActiveCrew().size()) { - addCraftWithoutCrew(u); - } - break; - } - // UnitType doesn't include FixedWingSupport. - if (entity instanceof FixedWingSupport) { - if (u.getFullCrewSize() < u.getActiveCrew().size()) { - addCraftWithoutCrew(u); - } - } - } - } - - private void updateTotalSkill(Infantry infantry) { - Crew crew = infantry.getCrew(); - if (null == crew) { - return; - } - - int gunnery = crew.getGunnery(); - int antiMek = infantry.getAntiMekSkill(); - if (antiMek == 0 || antiMek == 8) { - antiMek = gunnery + 1; - } - - BigDecimal skillLevel = BigDecimal.valueOf(gunnery).add(BigDecimal.valueOf(antiMek)); - - incrementSkillRatingCounts(getExperienceLevelName(skillLevel)); - setTotalSkillLevels(getTotalSkillLevels(false).add(skillLevel)); - } - - private void updateTotalSkill(Crew crew, int unitType) { - // Make sure we have a crew. - if (crew == null) { - return; - } - - boolean hasPilot = false; - int gunnery; - int piloting = 0; - - switch (unitType) { - case UnitType.MEK: - case UnitType.WARSHIP: - case UnitType.SMALL_CRAFT: - case UnitType.DROPSHIP: - case UnitType.CONV_FIGHTER: - case UnitType.AERO: - case UnitType.AEROSPACEFIGHTER: - case UnitType.VTOL: - case UnitType.TANK: - gunnery = crew.getGunnery(); - piloting = crew.getPiloting(); - hasPilot = true; - break; - case UnitType.PROTOMEK: - gunnery = crew.getGunnery(); - break; - default: - return; - } - - BigDecimal skillLevel = BigDecimal.valueOf(gunnery); - if (hasPilot) { - skillLevel = skillLevel.add(BigDecimal.valueOf(piloting)); - } else { - // Assume a piloting equal to Gunnery +1. - skillLevel = skillLevel.add(BigDecimal.valueOf(gunnery)).add(BigDecimal.ONE); - } - - incrementSkillRatingCounts(getExperienceLevelName(skillLevel)); - setTotalSkillLevels(getTotalSkillLevels(false).add(skillLevel)); - } - - @Override - protected BigDecimal getNumberUnits() { - return new BigDecimal(getTotalCombatUnits()); - } - - private int getTotalCombatUnits() { - int totalCombatUnits = getMechCount(); - totalCombatUnits += getFighterCount(); - totalCombatUnits += getProtoCount(); - totalCombatUnits += getVeeCount(); - totalCombatUnits += getNumberBaSquads(); - totalCombatUnits += getInfantryUnitCount(); - totalCombatUnits += getDropShipCount(); - totalCombatUnits += getSmallCraftCount(); - return totalCombatUnits; - } - - private int getTotalForceUnits() { - int totalGround = 0; - int totalAero = 0; - int totalInfantry = 0; - int totalBattleArmor = 0; - - // Count total units for transport - getTotalCombatUnits(); - - for (Unit u : getCampaign().getHangar().getUnits()) { - if (u == null) { - continue; - } - if (u.isMothballed() || !u.hasPilot()) { - continue; - } - - if ((u.getEntity().getEntityType() & - Entity.ETYPE_WARSHIP) == Entity.ETYPE_WARSHIP) { - totalAero++; - } else if ((u.getEntity().getEntityType() & - Entity.ETYPE_JUMPSHIP) == Entity.ETYPE_JUMPSHIP) { - //noinspection UnnecessaryContinue - continue; - } else if ((u.getEntity().getEntityType() & - Entity.ETYPE_AEROSPACEFIGHTER) == Entity.ETYPE_AEROSPACEFIGHTER) { - totalAero++; - } else if ((u.getEntity().getEntityType() & - Entity.ETYPE_DROPSHIP) == Entity.ETYPE_DROPSHIP) { - totalAero++; - } else if (((u.getEntity().getEntityType() & - Entity.ETYPE_MECH) == Entity.ETYPE_MECH) - || ((u.getEntity().getEntityType() & - Entity.ETYPE_TANK) == Entity.ETYPE_TANK)) { - totalGround++; - } else if ((u.getEntity().getEntityType() & - Entity.ETYPE_BATTLEARMOR) == Entity.ETYPE_BATTLEARMOR) { - totalBattleArmor++; - } else if ((u.getEntity().getEntityType() & - Entity.ETYPE_INFANTRY) == Entity.ETYPE_INFANTRY) { - totalInfantry++; - } - - } - - return totalGround + totalAero + totalInfantry + totalBattleArmor; - } - - @Override - protected BigDecimal calcAverageExperience() { - int totalCombatUnits = getTotalForceUnits(); - - if (totalCombatUnits == 0) { - return BigDecimal.ZERO; - } - - return getTotalSkillLevels().divide(BigDecimal.valueOf(totalCombatUnits), - 2,RoundingMode.HALF_DOWN); - } - - private void calcNeededTechs() { - int protoTeamCount = BigDecimal.valueOf(getProtoCount()) - .divide(BigDecimal.valueOf(5), 0, - RoundingMode.HALF_UP) - .intValue(); - setMechTechTeamsNeeded(getMechCount() + protoTeamCount); - setAeroTechTeamsNeeded(getFighterCount() + getSmallCraftCount()); - int infantryTeamCount = BigDecimal.valueOf(getInfantryCount()) - .divide(BigDecimal.valueOf(112), - 0, - RoundingMode.HALF_UP) - .intValue(); - setMechanicTeamsNeeded(getSuperHeavyVeeCount() + getVeeCount() + - infantryTeamCount); - setBattleArmorTechTeamsNeeded(BigDecimal.valueOf(getBattleArmorCount()) - .divide(BigDecimal.valueOf(5), - 0, - RoundingMode.HALF_UP) - .intValue()); - } - - private void updatePersonnelCounts() { - setNonAdminPersonnelCount(0); - technicians = 0; - - // We count all active personnel in the force provided they are not: - // 1) A Dependent - // 2) Administrative Personnel: Administrator, doctor, or medic (as per CO (3rd Printing) pg. 21) - // 3) A Prisoner - for (Person p : getCampaign().getActivePersonnel()) { - if (p.getPrimaryRole().isDependent() || p.isAdministrator() || p.isDoctor() - || p.getPrimaryRole().isMedic() || p.getSecondaryRole().isMedic() - || !p.getPrisonerStatus().isFree()) { - continue; - } - - if (p.isTech()) { - technicians++; - } - - setNonAdminPersonnelCount(getNonAdminPersonnelCount() + 1); - } - setNonAdminPersonnelCount(getNonAdminPersonnelCount() + getCampaign().getAstechPool()); - } - - private void calcNeededAdmins() { - int calculatedAdmin = BigDecimal.valueOf(getNonAdminPersonnelCount()) - .divide(BigDecimal.TEN, 0, RoundingMode.UP) - .intValue(); - - if (getCampaign().getFaction().isMercenary() || getCampaign().getFaction().isPirate()) { - setAdminsNeeded(calculatedAdmin); - } else { - setAdminsNeeded((int) Math.ceil(calculatedAdmin / 2d)); - } - } - - // todo Combat Personnel (up to 1/4 total) may be assigned double-duty and count as 1/3 of a tech. - // todo Combat Personnel (up to 1/4 total) may be assigned double-duty and count as 1/3 of an admin. - - @Override - protected void initValues() { - super.initValues(); - - setMechCount(0); - setProtoCount(0); - setLightVeeCount(0); - setBattleArmorCount(0); - setInfantryCount(0); - setFighterCount(0); - setDropShipCount(0); - setSmallCraftCount(0); - setJumpShipCount(0); - setDockingCollarCount(0); - clearCraftWithoutCrew(); - - countUnits(); - calcNeededTechs(); - updatePersonnelCounts(); - calcNeededAdmins(); - } - - @Override - protected int calculateUnitRatingScore() { - int totalScore = getExperienceValue(); - totalScore += getCampaign().getCampaignOptions().getManualUnitRatingModifier(); - totalScore += getCommanderValue(); - totalScore += getCombatRecordValue(); - totalScore += getTransportValue(); - totalScore += getSupportValue(); - totalScore += getFinancialValue(); - totalScore += getCrimesPenalty(); - totalScore += getIdleTimeModifier(); - - return totalScore; - } - - @Override - public SkillLevel getAverageExperience() { - if (!hasUnits()) { - return SkillLevel.NONE; - } - - switch (getExperienceValue()) { - case 5: - return SkillLevel.GREEN; - case 10: - return SkillLevel.REGULAR; - case 20: - return SkillLevel.VETERAN; - case 40: - return SkillLevel.ELITE; - default: - return SkillLevel.NONE; - } - } - - @Override - protected SkillLevel getExperienceLevelName(BigDecimal experience) { - if (!hasUnits()) { - return SkillLevel.NONE; - } - - final BigDecimal eliteThreshold = new BigDecimal("5.00"); - final BigDecimal vetThreshold = new BigDecimal("7.00"); - final BigDecimal regThreshold = new BigDecimal("9.00"); - - if (experience.compareTo(regThreshold) > 0) { - return SkillLevel.GREEN; - } else if (experience.compareTo(vetThreshold) > 0) { - return SkillLevel.REGULAR; - } else if (experience.compareTo(eliteThreshold) > 0) { - return SkillLevel.VETERAN; - } else { - return SkillLevel.ELITE; - } - } - - @Override - public int getExperienceValue() { - if (!hasUnits()) { - return 0; - } - BigDecimal averageExp = calcAverageExperience(); - SkillLevel level = getExperienceLevelName(averageExp); - switch (level) { - case NONE: - return 0; - case GREEN: - return 5; - case REGULAR: - return 10; - case VETERAN: - return 20; - default: - return 40; - } - } - - @Override - public int getCommanderValue() { - Person commander = getCommander(); - if (commander == null) { - return 0; - } - int skillTotal = getCommanderSkillLevelWithBonus(SkillType.S_LEADER); - skillTotal += getCommanderSkillLevelWithBonus(SkillType.S_TACTICS); - skillTotal += getCommanderSkillLevelWithBonus(SkillType.S_STRATEGY); - skillTotal += getCommanderSkillLevelWithBonus(SkillType.S_NEG); - - // ToDo AToW Traits. - // ToDo MHQ would need to support: Combat Sense, Connections, - // ToDo Reputation, Wealth, High CHA, - // ToDo Combat Paralysis, - // ToDo Unlucky & Low CHA. - - int commanderValue = skillTotal; // ToDo + positiveTraits - negativeTraits. - - return commanderValue > 0 ? commanderValue : 1; - } - - @Override - public String getUnitRating() { - // Campaign Operations does not use letter-grades. - return getModifier() + " (" + calculateUnitRatingScore() + ")"; - } - - @Override - public int getUnitRating(int score) { - // Campaign Operations does not use letter-grades. - return 0; - } - - @Override - public String getUnitRatingName(int rating) { - // Campaign Operations does not use letter-grades. - return ""; - } - - @Override - public int getTransportValue() { - if (!hasUnits()) { - return 0; - } - - int totalValue = 0; - - TransportCapacityIndicators tci = new TransportCapacityIndicators(); - tci.updateCapacityIndicators(getMechBayCount(), getMechCount()); - tci.updateCapacityIndicators(getProtoBayCount(), getProtoCount()); - tci.updateCapacityIndicators(getBaBayCount(), getBattleArmorCount() / 5); // battle armor bays can hold 5 suits of battle armor per bay - tci.updateCapacityIndicators(getInfantryBayCount(), calcInfantryPlatoons()); - - // Heavy vehicles can use heavy or super heavy vehicle bays and light vehicles can use light, heavy, or super heavy vehicle bays, - // while fighters can use fighter or small craft bays - // We put all possible super heavy vehicles into super heavy vehicle bays. - // If we have some super heavy vehicle bays left over, add them to the heavy vehicle bay count, and then calculate the - // number of heavy vehicle bays that are still empty. We then add these to the light vehicle bay count - // The same is done for small craft and fighters, just replace heavy vehicle with small craft and light vehicle with fighters, - // and remove references to super heavy vehicles - int excessSuperHeavyVeeBays = Math.max(getSuperHeavyVeeBayCount() - getSuperHeavyVeeCount(), 0); - int excessHeavyVeeBays = Math.max(getHeavyVeeBayCount() + excessSuperHeavyVeeBays - getHeavyVeeCount(), 0); - int excessSmallCraftBays = Math.max(getSmallCraftBayCount() - getSmallCraftCount(), 0); - - // We need to subtract any filled bays from the count. This follows the following logic: - // Assume you have 2 heavy vehicle bays, and 4 light vehicle bays, and are trying to store 1 heavy and 5 light vehicles - // You have 1 more light vehicle than light vehicle bays to store them in, so you check how many free heavy vehicle bays - // there are. Finding 1, you can store the light vehicle there, and it doesn't count as having excess - int superHeavyVeeBaysFilledByLighterVees, heavyVeeBaysFilledByLights, smallCraftBaysFilledByFighters; - int excessHeavyVees = Math.max(getHeavyVeeCount() - getHeavyVeeBayCount(), 0); - int excessLightVees = Math.max(getLightVeeCount() - getLightVeeBayCount(), 0); - int excessFighters = Math.max(getFighterCount() - getFighterBayCount(), 0); - - superHeavyVeeBaysFilledByLighterVees = Math.min(excessHeavyVees + excessLightVees, excessSuperHeavyVeeBays); - heavyVeeBaysFilledByLights = Math.min(excessLightVees, excessHeavyVeeBays); - smallCraftBaysFilledByFighters = Math.min(excessFighters, excessSmallCraftBays); - - tci.updateCapacityIndicators(getSuperHeavyVeeBayCount() - superHeavyVeeBaysFilledByLighterVees, getSuperHeavyVeeCount()); - tci.updateCapacityIndicators(getHeavyVeeBayCount() + excessSuperHeavyVeeBays - heavyVeeBaysFilledByLights, getHeavyVeeCount()); - tci.updateCapacityIndicators(getLightVeeBayCount() + excessHeavyVeeBays, getLightVeeCount()); - tci.updateCapacityIndicators(getSmallCraftBayCount() - smallCraftBaysFilledByFighters, getSmallCraftCount()); - tci.updateCapacityIndicators(getFighterBayCount() + excessSmallCraftBays, getFighterCount()); - - //Find the percentage of units that are transported. - if (tci.hasDoubleCapacity()) { - totalValue += 10; - } else if (tci.hasExcessCapacity()) { - totalValue += 5; - } else if (tci.hasSufficientCapacity()) { - totalValue += 0; - } else { - totalValue -= 5; - } - - if (getDropShipCount() < 1) { - totalValue -= 5; - } - - // TODO: Calculate transport needs and capacity for support personnel. - // According to Campaign Ops, this will require tracking bay personnel - // & passenger quarters. - - if (getJumpShipCount() > 0) { - totalValue += 10; - } - if (getWarShipCount() > 0) { - totalValue += 10; - if (getCampaign().getLocalDate().isAfter(LocalDate.of(2800, 1, 1))) { - totalValue += 5; - } - } - if ((getDropShipCount() > 0) && (getDockingCollarCount() >= getDropShipCount())) { - totalValue += 5; - } - - return totalValue; - } - - int calcTechSupportValue() { - int totalValue = 0; - setTotalTechTeams(0); - int astechTeams; - setMechTechTeams(0); - setAeroTechTeams(0); - setMechanicTeams(0); - setBaTechTeams(0); - setGeneralTechTeams(0); - - // How many astech teams do we have? - astechTeams = getCampaign().getNumberAstechs() / 6; - - for (Person tech : getCampaign().getTechs()) { - // If we're out of astech teams, the rest of the techs are - // unsupported and don't count. - if (astechTeams <= 0) { - break; - } - - if ((tech.getPrimaryRole().isMechTech() || tech.getSecondaryRole().isMechTech()) - && (tech.getSkill(SkillType.S_TECH_MECH) != null)) { - setMechTechTeams(getMechTechTeams() + 1); - astechTeams--; - } else if ((tech.getPrimaryRole().isAeroTech() || tech.getSecondaryRole().isAeroTech()) - && (tech.getSkill(SkillType.S_TECH_AERO) != null)) { - setAeroTechTeams(getAeroTechTeams() + 1); - astechTeams--; - } else if ((tech.getPrimaryRole().isMechanic() || tech.getSecondaryRole().isMechanic()) - && (tech.getSkill(SkillType.S_TECH_MECHANIC) != null)) { - setMechanicTeams(getMechanicTeams() + 1); - astechTeams--; - } else if ((tech.getPrimaryRole().isBATech() || tech.getSecondaryRole().isBATech()) - && (tech.getSkill(SkillType.S_TECH_BA) != null)) { - setBaTechTeams(getBaTechTeams() + 1); - astechTeams--; - } else { - setGeneralTechTeams(getGeneralTechTeams() + 1); - astechTeams--; - } - } - - boolean techShortage = false; - if (getMechTechTeamsNeeded() > getMechTechTeams()) { - techShortage = true; - } - if (getAeroTechTeamsNeeded() > getAeroTechTeams()) { - techShortage = true; - } - if (getMechanicTeamsNeeded() > getMechanicTeams()) { - techShortage = true; - } - if (getBattleArmorTechTeamsNeeded() > getBaTechTeams()) { - techShortage = true; - } - - setTotalTechTeams(getMechTechTeams() + getAeroTechTeams() + - getMechanicTeams() + getBaTechTeams() + - getGeneralTechTeams()); - int totalTechTeamsNeeded = getMechTechTeamsNeeded() + - getAeroTechTeamsNeeded() + - getMechanicTeamsNeeded() + - getBattleArmorTechTeamsNeeded(); - setSupportPercent(BigDecimal.ZERO); - if (totalTechTeamsNeeded != 0) { - setSupportPercent(BigDecimal.valueOf(getTotalTechTeams()) - .divide(BigDecimal.valueOf(totalTechTeamsNeeded), - 5, - RoundingMode.HALF_UP) - .multiply(HUNDRED)); - } - - if (techShortage) { - totalValue -= 5; - } else { - if (getSupportPercent().compareTo(BigDecimal.valueOf(200)) > 0) { - totalValue += 15; - } else if (getSupportPercent().compareTo(BigDecimal.valueOf(175)) > - 0) { - totalValue += 10; - } else if (getSupportPercent().compareTo(BigDecimal.valueOf(149)) > - 0) { - totalValue += 5; - } - } - - return totalValue; - } - - private int calcAdminSupportValue() { - return (getAdminsNeeded() > getTotalAdmins()) ? -5 : 0; - } - - private int calcLargeCraftSupportValue() { - Unit unit = getCampaign().getHangar().findUnit(u -> { - if (u.getEntity() instanceof SmallCraft || u.getEntity() instanceof Jumpship) { - if (u.getActiveCrew().size() < u.getFullCrewSize()) { - return true; - } - } - return false; - }); - - // if we found a unit we have a crew shortage - // on at least one vessel in our fleet - return (unit != null) ? -5 : 0; - } - - @Override - public int getSupportValue() { - int value = calcTechSupportValue(); - value += calcAdminSupportValue(); - value += calcLargeCraftSupportValue(); - return value; - } - - @Override - public BigDecimal getTransportPercent() { - // Handled under getTransportValue() - return BigDecimal.ZERO; - } - - @Override - public int getFinancialValue() { - return getCampaign().getFinances().isInDebt() ? -10 : 0; - } - - // ToDo: MekHQ doesn't currently support recording crimes. - private int getCrimesPenalty() { - return 0; - } - - // ToDo MekHQ doesn't current apply completion dates to missions. - private int getIdleTimeModifier() { - return 0; - } - - @Override - public int getModifier() { - BigDecimal reputation = new BigDecimal(calculateUnitRatingScore()); - return reputation.divide(BigDecimal.TEN, 0, - RoundingMode.DOWN).intValue(); - } - - private String getExperienceDetails() { - return String.format("%-" + HEADER_LENGTH + "s %3d", "Experience:", getExperienceValue()) - + '\n' - + String.format(" %-" + SUBHEADER_LENGTH + "s %3s", "Average Experience:", getAverageExperience()) - + '\n' - + getSkillLevelCounts() - .entrySet() - .stream() - .map(entry -> String.format(" #%-" + CATEGORY_LENGTH + "s %3d", entry.getKey().toString() + ':', entry.getValue())) - .collect(Collectors.joining("\n")); - } - - private String getCommanderDetails() { - StringBuilder out = new StringBuilder(); - String commanderName = null == getCommander() ? "" : - "(" + getCommander().getFullTitle() + ")"; - out.append(String.format("%-" + HEADER_LENGTH + "s %3d %s", - "Commander:", getCommanderValue(), - commanderName)); - - final String TEMPLATE = " %-" + SUBHEADER_LENGTH + "s %3d"; - out.append("\n").append(String.format(TEMPLATE, "Leadership:", - getCommanderSkillLevelWithBonus(SkillType.S_LEADER))); - out.append("\n").append(String.format(TEMPLATE, "Negotiation:", - getCommanderSkillLevelWithBonus(SkillType.S_NEG))); - out.append("\n").append(String.format(TEMPLATE, "Strategy:", - getCommanderSkillLevelWithBonus(SkillType.S_STRATEGY))); - out.append("\n").append(String.format(TEMPLATE, "Tactics:", - getCommanderSkillLevelWithBonus(SkillType.S_TACTICS))); - - return out.toString(); - } - - private String getCombatRecordDetails() { - final String TEMPLATE = " %-" + SUBHEADER_LENGTH + "s %3d"; - - return String.format("%-" + HEADER_LENGTH + "s %3d", "Combat Record:", - getCombatRecordValue()) + - "\n" + String.format(TEMPLATE, "Successful Missions:", - getSuccessCount()) + - "\n" + String.format(TEMPLATE, "Partial Missions:", - getPartialCount()) + - "\n" + String.format(TEMPLATE, "Failed Missions:", - getFailCount()) + - "\n" + String.format(TEMPLATE, "Contract Breaches:", - getBreachCount()); - } - - String getTransportationDetails() { - final String TEMPLATE = " %-" + CATEGORY_LENGTH + - "s %3d needed / %3d available"; - - int superHeavyVeeBayCount = getSuperHeavyVeeBayCount(); - int heavyVeeBayCount = getHeavyVeeBayCount(); - int smallCraftBayCount = getSmallCraftBayCount(); - - int excessSuperHeavyVeeBays = Math.max(superHeavyVeeBayCount - getSuperHeavyVeeCount(),0); - int excessHeavyVeeBays = Math.max(heavyVeeBayCount - getHeavyVeeCount(), 0); - int excessSmallCraftBays = Math.max(smallCraftBayCount - getSmallCraftCount(), 0); - - String out = String.format("%-" + HEADER_LENGTH + "s %3d", "Transportation:", getTransportValue()) + - "\n" + String.format(TEMPLATE, "BattleMech Bays:", getMechCount(), getMechBayCount()) + - "\n" + String.format(TEMPLATE, "Fighter Bays:", getFighterCount(), getFighterBayCount()) + - " (plus " + excessSmallCraftBays + " excess Small Craft)" + - "\n" + String.format(TEMPLATE, "Small Craft Bays:", getSmallCraftCount(), smallCraftBayCount) + - "\n" + String.format(TEMPLATE, "ProtoMech Bays:", getProtoCount(), getProtoBayCount()) + - "\n" + String.format(TEMPLATE, "Super Heavy Vehicle Bays:", getSuperHeavyVeeCount(), superHeavyVeeBayCount) + - "\n" + String.format(TEMPLATE, "Heavy Vehicle Bays:", getHeavyVeeCount(), heavyVeeBayCount) + - " (plus " + excessSuperHeavyVeeBays + " excess Super Heavy)" + - "\n" + String.format(TEMPLATE, "Light Vehicle Bays:", getLightVeeCount(), getLightVeeBayCount()) + - " (plus " + excessHeavyVeeBays + " excess Heavy and " + excessSuperHeavyVeeBays + " excess Super Heavy)" + - "\n" + String.format(TEMPLATE, "Battle Armor Bays:", getBattleArmorCount() / 5, getBaBayCount()) + - "\n" + String.format(TEMPLATE, "Infantry Bays:", calcInfantryPlatoons(), getInfantryBayCount()) + - "\n" + String.format(TEMPLATE, "Docking Collars:", getDropShipCount(), getDockingCollarCount()); - - final String TEMPLATE_2 = " %-" + CATEGORY_LENGTH + "s %3s"; - out += "\n" + String.format(TEMPLATE_2, "Has JumpShips?", getJumpShipCount() > 0 ? "Yes" : "No"); - out += "\n" + String.format(TEMPLATE_2, "Has WarShips?", getWarShipCount() > 0 ? "Yes" : "No"); - - return out; - } - - private String getSupportDetails() { - StringBuilder out = new StringBuilder(); - out.append(String.format("%-" + HEADER_LENGTH + "s %3d", - "Support:", getSupportValue())); - - final String TEMPLATE_CAT = " %-" + CATEGORY_LENGTH + - "s %4d needed / %4d available"; - out.append("\n Tech Support:"); - out.append("\n").append(String.format(TEMPLATE_CAT, "Mech Techs:", - getMechTechTeamsNeeded(), - getMechTechTeams())); - out.append("\n NOTE: ProtoMechs and BattleMechs use same techs."); - out.append("\n").append(String.format(TEMPLATE_CAT, - "Aero Techs:", - getAeroTechTeamsNeeded(), - getAeroTechTeams())); - out.append("\n").append(String.format(TEMPLATE_CAT, "Mechanics:", - getMechanicTeamsNeeded(), - getMechanicTeams())); - out.append("\n NOTE: Vehicles and Infantry use the same" + - " mechanics."); - out.append("\n").append(String.format(TEMPLATE_CAT, "Battle Armor Techs:", - getBattleArmorTechTeamsNeeded(), - getBaTechTeams())); - out.append("\n").append(String.format(TEMPLATE_CAT, "Astechs:", - technicians * 6, - getCampaign().getNumberAstechs())); - out.append("\n").append(String.format(" %-" + (CATEGORY_LENGTH + 4) + - "s %4d needed / %4d available", - "Admin Support:", - getAdminsNeeded(), - getTotalAdmins())); - out.append("\n Large Craft Crew:"); - if (getCraftWithoutCrew().size() < 1) { - out.append("\n All fully crewed."); - } else { - for (String s : getCraftWithoutCrew()) { - out.append("\n ").append(s).append(" short crew."); - } - } - - return out.toString(); - } - - private int getTotalAdmins() { - // Admins, Doctors, and Medics all fall under the Administrators based on my read of - // CO (3rd Printing) pg. 21 - return getCampaign().getAdmins().size() + getCampaign().getDoctors().size() - + getCampaign().getNumberMedics(); - } - - @Override - public String getDetails() { - final String TEMPLATE = "%-" + HEADER_LENGTH + "s %s"; - initValues(); - StringBuilder sb = new StringBuilder(); - sb.append(String.format(TEMPLATE, "Unit Reputation:", calculateUnitRatingScore())); - sb.append("\n").append(" Method: Campaign Operations\n"); - if (getCampaign().getCampaignOptions().getManualUnitRatingModifier() != 0) { - sb.append(" Manual Modifier: ") - .append(getCampaign().getCampaignOptions().getManualUnitRatingModifier()) - .append("\n"); - } - sb.append("\n"); - sb.append(getExperienceDetails()).append("\n\n"); - sb.append(getCommanderDetails()).append("\n\n"); - sb.append(getCombatRecordDetails()).append("\n\n"); - sb.append(getTransportationDetails()).append("\n\n"); - sb.append(getSupportDetails()).append("\n\n"); - - sb.append(String.format(TEMPLATE, "Financial", getFinancialValue())); - sb.append("\n").append(String.format(" %-" + SUBHEADER_LENGTH + - "s %3s", - "In Debt?", - getCampaign().getFinances() - .isInDebt() ? "Yes" : - "No")); - - sb.append("\n\n") - .append(String.format(TEMPLATE, "Criminal Activity:", 0)) - .append(" (MHQ does not currently track criminal activity.)"); - - sb.append("\n\n") - .append(String.format(TEMPLATE, "Inactivity Modifier:", 0)) - .append(" (MHQ does not track end dates for missions/contracts.)"); - - return new String(sb); - } - - @Override - public String getHelpText() { - return "Method: Campaign Ops\n" + - "An attempt to match the Campaign Ops method for calculating " + - "the Reputation as closely as possible.\n" + - "Known differences include the following:\n" + - "+ Command: Does not incorporate any positive or negative " + - "traits from AToW or BRPG3." + - "+ Transportation: Transportation needs of Support Personnel " + - "are not accounted for as MHQ does not " + - "track Bay Personnel or Passenger Quarters.\n" + - "+ Criminal Activity: MHQ does not currently track criminal " + - "activity." + - "+ Inactivity: MHQ does not track end dates for missions/" + - "contracts."; - } - - private void setNonAdminPersonnelCount(int nonAdminPersonnelCount) { - this.nonAdminPersonnelCount = nonAdminPersonnelCount; - } - - private void setMechTechTeamsNeeded(int mechTechTeamsNeeded) { - this.mechTechTeamsNeeded = mechTechTeamsNeeded; - } - - private void setMechanicTeamsNeeded(int mechanicTeamsNeeded) { - this.mechanicTeamsNeeded = mechanicTeamsNeeded; - } - - private void setBattleArmorTechTeamsNeeded(int battleArmorTechTeamsNeeded) { - this.battleArmorTechTeamsNeeded = battleArmorTechTeamsNeeded; - } - - private void setAeroTechTeamsNeeded(int aeroTechTeamsNeeded) { - this.aeroTechTeamsNeeded = aeroTechTeamsNeeded; - } - - private void setAdminsNeeded(int adminsNeeded) { - this.adminsNeeded = adminsNeeded; - } - - private int getTotalTechTeams() { - return totalTechTeams; - } - - private void setTotalTechTeams(int totalTechTeams) { - this.totalTechTeams = totalTechTeams; - } - - private int getMechTechTeams() { - return mechTechTeams; - } - - private void setMechTechTeams(int mechTechTeams) { - this.mechTechTeams = mechTechTeams; - } - - private int getAeroTechTeams() { - return aeroTechTeams; - } - - private void setAeroTechTeams(int aeroTechTeams) { - this.aeroTechTeams = aeroTechTeams; - } - - private int getMechanicTeams() { - return mechanicTeams; - } - - private void setMechanicTeams(int mechanicTeams) { - this.mechanicTeams = mechanicTeams; - } - - private int getBaTechTeams() { - return baTechTeams; - } - - private void setBaTechTeams(int baTechTeams) { - this.baTechTeams = baTechTeams; - } - - private int getGeneralTechTeams() { - return generalTechTeams; - } - - private void setGeneralTechTeams(int generalTechTeams) { - this.generalTechTeams = generalTechTeams; - } - - private List getCraftWithoutCrew() { - return new ArrayList<>(craftWithoutCrew); - } - - private void addCraftWithoutCrew(Unit u) { - craftWithoutCrew.add(u.getName()); - } - - private void clearCraftWithoutCrew() { - craftWithoutCrew.clear(); - } - - /** - * Data structure that holds transport capacity indicators - * @author NickAragua - * - */ - private static class TransportCapacityIndicators { - private boolean sufficientCapacity = true; - private boolean excessCapacity = true; - private boolean doubleCapacity = true; - - public boolean hasSufficientCapacity() { - return sufficientCapacity; - } - - public boolean hasExcessCapacity() { - return excessCapacity; - } - - public boolean hasDoubleCapacity() { - return doubleCapacity; - } - - /** - * Updates the transport capacity indicators - * @param bayCount The number of available bays - * @param unitCount The number of units using the given type of bay - */ - public void updateCapacityIndicators(int bayCount, int unitCount) { - // per CamOps, if we don't have any of a given type of unit but have bays for it - // the force doesn't count as having excess capacity for that unit type - if (unitCount == 0) { - return; - } - - // examples: - // 1 infantry platoon, 1 bay = sufficient capacity - // 1 infantry platoon, 1 tank, 1 infantry bay, 1 tank bay = excess capacity - // 1 infantry platoon, 1 tank, 2 infantry bay, 1 tank bay = double capacity - // 1 infantry platoon, no infantry bays, 1 tank, 1 tank bay = insufficient capacity - - // we have enough capacity if there are as many or more bays than units - sufficientCapacity &= (bayCount >= unitCount); - - // we have excess capacity if there are more bays than units for at least one unit type AND - // we have sufficient capacity for everything else - excessCapacity &= ((bayCount > unitCount) || sufficientCapacity); - - // we have double capacity if there are more than twice as many bays as units for every unit type - doubleCapacity &= (bayCount > (unitCount * 2)); - } - } -} diff --git a/MekHQ/src/mekhq/campaign/unit/Unit.java b/MekHQ/src/mekhq/campaign/unit/Unit.java index 64cae75d61..0e6e518867 100644 --- a/MekHQ/src/mekhq/campaign/unit/Unit.java +++ b/MekHQ/src/mekhq/campaign/unit/Unit.java @@ -4779,6 +4779,13 @@ public List getActiveCrew() { return crew; } + /** + * @return true if the unit is fully crewed, false otherwise. + */ + public boolean isFullyCrewed() { + return getActiveCrew().size() == getFullCrewSize(); + } + /** * Prototype TSM makes a unit harder to repair and maintain. * diff --git a/MekHQ/src/mekhq/gui/CampaignGUI.java b/MekHQ/src/mekhq/gui/CampaignGUI.java index cace8d9f42..6f34fc4920 100644 --- a/MekHQ/src/mekhq/gui/CampaignGUI.java +++ b/MekHQ/src/mekhq/gui/CampaignGUI.java @@ -875,8 +875,11 @@ private void initMenu() { JMenuItem miDragoonsRating = new JMenuItem(resourceMap.getString("miDragoonsRating.text")); miDragoonsRating.setMnemonic(KeyEvent.VK_U); miDragoonsRating.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_DOWN_MASK)); - miDragoonsRating - .addActionListener(evt -> new UnitRatingReportDialog(getFrame(), getCampaign()).setVisible(true)); + if (getCampaign().getCampaignOptions().getUnitRatingMethod().isFMMR()) { + miDragoonsRating.addActionListener(evt -> new UnitRatingReportDialog(getFrame(), getCampaign()).setVisible(true)); + } else { + miDragoonsRating.addActionListener(evt -> new ReputationReportDialog(getFrame(), getCampaign()).setVisible(true)); + } menuReports.add(miDragoonsRating); JMenuItem miPersonnelReport = new JMenuItem(resourceMap.getString("miPersonnelReport.text")); diff --git a/MekHQ/src/mekhq/gui/CommandCenterTab.java b/MekHQ/src/mekhq/gui/CommandCenterTab.java index 15a8a248ca..ffd7b96094 100644 --- a/MekHQ/src/mekhq/gui/CommandCenterTab.java +++ b/MekHQ/src/mekhq/gui/CommandCenterTab.java @@ -24,7 +24,12 @@ import megamek.common.event.Subscribe; import mekhq.MHQOptionsChangedEvent; import mekhq.MekHQ; +import mekhq.campaign.Campaign; +import mekhq.campaign.CampaignOptions; +import mekhq.campaign.CampaignSummary; import mekhq.campaign.event.*; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; +import mekhq.campaign.rating.UnitRatingMethod; import mekhq.campaign.report.CargoReport; import mekhq.campaign.report.HangarReport; import mekhq.campaign.report.PersonnelReport; @@ -213,7 +218,14 @@ private void initInfoPanel() { gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(1, 5, 1, 5); panInfo.add(lblExperienceHead, gridBagConstraints); - lblExperience = new JLabel(getCampaign().getUnitRating().getAverageExperience().toString()); + + lblExperience = new JLabel(); + if (getCampaign().getCampaignOptions().getUnitRatingMethod().isFMMR()) { + lblExperience.setText(getCampaign().getUnitRating().getAverageExperience().toString()); + } else { + lblExperience.setText(getCampaign().getReputation().getAverageSkillLevel().toString()); + } + lblExperienceHead.setLabelFor(lblExperience); gridBagConstraints.gridx = 1; gridBagConstraints.weightx = 1.0; @@ -512,8 +524,12 @@ private void initReportsPanel() { btnUnitRating = new JButton(resourceMap.getString("btnUnitRating.text")); btnUnitRating.setVisible(getCampaign().getCampaignOptions().getUnitRatingMethod().isEnabled()); - btnUnitRating.addActionListener(evt -> new UnitRatingReportDialog(getCampaignGui().getFrame(), - getCampaign()).setVisible(true)); + + if (getCampaign().getCampaignOptions().getUnitRatingMethod().isFMMR()) { + btnUnitRating.addActionListener(evt -> new UnitRatingReportDialog(getCampaignGui().getFrame(), getCampaign()).setVisible(true)); + } else { + btnUnitRating.addActionListener(evt -> new ReputationReportDialog(getCampaignGui().getFrame(), getCampaign()).setVisible(true)); + } panReports.add(btnUnitRating); panReports.setBorder(BorderFactory.createTitledBorder(resourceMap.getString("panReports.title"))); @@ -539,26 +555,41 @@ public void refreshAll() { * refresh the basic info panel with campaign information */ private void refreshBasicInfo() { - getCampaign().getUnitRating().reInitialize(); - getCampaign().getCampaignSummary().updateInformation(); - lblRating.setText(getCampaign().getUnitRatingText()); - lblPersonnel.setText(getCampaign().getCampaignSummary().getPersonnelReport()); - lblMissionSuccess.setText(getCampaign().getCampaignSummary().getMissionSuccessReport()); - lblExperience.setText(getCampaign().getUnitRating().getAverageExperience().toString()); - lblComposition.setText(getCampaign().getCampaignSummary().getForceCompositionReport()); - lblCargoSummary.setText(getCampaign().getCampaignSummary().getCargoCapacityReport().toString()); - lblRepairStatus.setText(getCampaign().getCampaignSummary().getForceRepairReport()); - lblTransportCapacity.setText(getCampaign().getCampaignSummary().getTransportCapacity()); - - if (getCampaign().getCampaignOptions().isUseAdministrativeStrain()) { + final Campaign campaign = getCampaign(); + final CampaignOptions campaignOptions = campaign.getCampaignOptions(); + final UnitRatingMethod unitRatingMethod = campaignOptions.getUnitRatingMethod(); + final CampaignSummary campaignSummary = campaign.getCampaignSummary(); + + if (unitRatingMethod.isFMMR()) { + campaign.getUnitRating().reInitialize(); + lblExperience.setText(campaign.getUnitRating().getAverageExperience().toString()); + } else if (unitRatingMethod.isCampaignOperations()) { + if (campaign.getReputation() == null) { + ReputationController reputationController = new ReputationController(); + reputationController.initializeReputation(campaign); + campaign.setReputation(reputationController); + } + lblExperience.setText(campaign.getReputation().getAverageSkillLevel().toString()); + } + + campaignSummary.updateInformation(); + lblRating.setText(campaign.getUnitRatingText()); + lblPersonnel.setText(campaignSummary.getPersonnelReport()); + lblMissionSuccess.setText(campaignSummary.getMissionSuccessReport()); + lblComposition.setText(campaignSummary.getForceCompositionReport()); + lblCargoSummary.setText(campaignSummary.getCargoCapacityReport().toString()); + lblRepairStatus.setText(campaignSummary.getForceRepairReport()); + lblTransportCapacity.setText(campaignSummary.getTransportCapacity()); + + if (campaignOptions.isUseAdministrativeStrain()) { try { - lblAdminstrativeCapacity.setText(getCampaign().getCampaignSummary().getAdministrativeCapacityReport(getCampaign())); + lblAdminstrativeCapacity.setText(campaignSummary.getAdministrativeCapacityReport(campaign)); } catch (Exception ignored) {} } - if (getCampaign().getCampaignOptions().isUseFatigue()) { + if (campaignOptions.isUseFatigue()) { try { - lblFacilityCapacities.setText(getCampaign().getCampaignSummary().getFacilityReport()); + lblFacilityCapacities.setText(campaignSummary.getFacilityReport()); } catch (Exception ignored) {} } } diff --git a/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java index ef9eb602d1..8e6f801a6e 100644 --- a/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java @@ -30,6 +30,7 @@ import mekhq.campaign.parts.Armor; import mekhq.campaign.parts.Part; import mekhq.campaign.personnel.autoAwards.AutoAwardsController; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; import mekhq.campaign.universe.companyGeneration.CompanyGenerationPersonTracker; @@ -151,6 +152,10 @@ protected void okAction() { AutoAwardsController autoAwardsController = new AutoAwardsController(); autoAwardsController.ManualController(campaign, false); } + + ReputationController reputationController = new ReputationController(); + reputationController.initializeReputation(campaign); + campaign.setReputation(reputationController); } @Override diff --git a/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java b/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java index ddf5214617..89ce87bd98 100644 --- a/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java @@ -320,6 +320,7 @@ public boolean isCellEditable(int row, int column) { btnEndRetainer.setVisible(null != campaign.getRetainerEmployerCode()); btnEndRetainer.addActionListener(ev -> { campaign.setRetainerEmployerCode(null); + campaign.setRetainerStartDate(null); lblCurrentRetainer.setVisible(false); lblRetainerEmployer.setVisible(false); btnEndRetainer.setVisible(false); diff --git a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java index 4844595f5a..0679a99602 100644 --- a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java @@ -38,6 +38,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.personnel.SpecialAbility; import mekhq.campaign.personnel.ranks.Ranks; +import mekhq.campaign.rating.CamOpsReputation.ReputationController; import mekhq.campaign.storyarc.StoryArc; import mekhq.campaign.storyarc.StoryArcStub; import mekhq.campaign.universe.Factions; @@ -305,6 +306,11 @@ public Campaign doInBackground() throws Exception { if (optionsDialog.showDialog().isCancelled()) { return null; } + + // initialize reputation + ReputationController reputationController = new ReputationController(); + reputationController.initializeReputation(campaign); + campaign.setReputation(reputationController); //endregion Progress 6 //region Progress 7 @@ -357,6 +363,13 @@ public Campaign doInBackground() throws Exception { setProgress(7); // Make sure campaign options event handlers get their data MekHQ.triggerEvent(new OptionsChangedEvent(campaign)); + + // this is to handle pre-50.0 campaigns + if (campaign.getReputation() == null) { + ReputationController reputationController = new ReputationController(); + reputationController.initializeReputation(campaign); + campaign.setReputation(reputationController); + } //endregion Progress 7 } campaign.setApp(getApplication()); diff --git a/MekHQ/src/mekhq/gui/dialog/NewAtBContractDialog.java b/MekHQ/src/mekhq/gui/dialog/NewAtBContractDialog.java index 7de1a7e9be..1ee94d1068 100644 --- a/MekHQ/src/mekhq/gui/dialog/NewAtBContractDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/NewAtBContractDialog.java @@ -29,7 +29,6 @@ import mekhq.campaign.finances.enums.TransactionType; import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.enums.AtBContractType; -import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.stratcon.StratconContractDefinition; import mekhq.campaign.stratcon.StratconContractInitializer; import mekhq.campaign.universe.Factions; @@ -94,8 +93,7 @@ protected void initComponents() { contract = new AtBContract("New Contract"); contract.calculateContract(campaign); ((AtBContract) contract).initContractDetails(campaign); - IUnitRating rating = campaign.getUnitRating(); - dragoonRating = rating.getUnitRatingAsInteger(); + dragoonRating = campaign.getUnitRatingMod(); super.initComponents(); updateEnemies(); diff --git a/MekHQ/src/mekhq/gui/dialog/NewLoanDialog.java b/MekHQ/src/mekhq/gui/dialog/NewLoanDialog.java index 3072bfd979..dbf9ebff53 100644 --- a/MekHQ/src/mekhq/gui/dialog/NewLoanDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/NewLoanDialog.java @@ -28,7 +28,6 @@ import mekhq.campaign.finances.Loan; import mekhq.campaign.finances.Money; import mekhq.campaign.finances.enums.FinancialTerm; -import mekhq.campaign.rating.IUnitRating; import org.apache.logging.log4j.LogManager; import javax.swing.*; @@ -99,8 +98,8 @@ public NewLoanDialog(final JFrame frame, final boolean modal, final Campaign cam this.frame = frame; this.campaign = campaign; this.numberFormatter = new NumberFormatter(NumberFormat.getInstance()); - IUnitRating unitRating = campaign.getUnitRating(); - rating = unitRating.getModifier(); + + rating = campaign.getUnitRatingMod(); loan = Loan.getBaseLoan(rating, this.campaign.getLocalDate()); maxCollateralValue = this.campaign.getFinances().getMaxCollateral(this.campaign); initComponents(); diff --git a/MekHQ/src/mekhq/gui/dialog/reportDialogs/ReputationReportDialog.java b/MekHQ/src/mekhq/gui/dialog/reportDialogs/ReputationReportDialog.java new file mode 100644 index 0000000000..5a15bc6c35 --- /dev/null +++ b/MekHQ/src/mekhq/gui/dialog/reportDialogs/ReputationReportDialog.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 - 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.gui.dialog.reportDialogs; + +import mekhq.campaign.Campaign; + +import javax.swing.*; + +public class ReputationReportDialog extends AbstractReportDialog { + //region Variable Declarations + private final Campaign campaign; + //endregion Variable Declarations + + //region Constructors + public ReputationReportDialog(final JFrame frame, final Campaign campaign) { + super(frame, "ReputationReportDialog", "UnitRatingReportDialog.title"); + this.campaign = campaign; + initialize(); + } + //endregion Constructors + + //region Getters + public Campaign getCampaign() { + return campaign; + } + + @Override + protected JTextPane createTxtReport() { + final JTextPane txtReport = new JTextPane(); + + txtReport.setContentType("text/html"); + + txtReport.setText(String.format(getCampaign().getReputation().getReportText(campaign))); + + txtReport.setName("txtReport"); + txtReport.setEditable(false); + txtReport.setCaretPosition(0); + return txtReport; + } + //endregion Getters +} diff --git a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java index 5dad33a2d5..ace0c49ebe 100644 --- a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java +++ b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java @@ -359,6 +359,7 @@ public class CampaignOptionsPane extends AbstractMHQTabbedPane { private JCheckBox chkUseDylansRandomXP; private RandomOriginOptionsPanel randomOriginOptionsPanel; private JCheckBox chkUseRandomPersonalities; + private JCheckBox chkUseRandomPersonalityReputation; // Marriage private JCheckBox chkUseManualMarriages; @@ -645,8 +646,6 @@ public class CampaignOptionsPane extends AbstractMHQTabbedPane { private JCheckBox chkUseAtB; private JCheckBox chkUseStratCon; private MMComboBox comboSkillLevel; - private JLabel lblAtbCamOpsDivision; - private JSpinner spnAtbCamOpsDivision; // unit administration private JCheckBox chkUseAero; @@ -2963,17 +2962,6 @@ private JScrollPane createAgainstTheBotTab() { gridBagConstraints.gridy++; panSubAtBAdmin.add(chkAutoconfigMunitions, gridBagConstraints); - lblAtbCamOpsDivision = new JLabel(resources.getString("lblAtbCamOpsDivision.text")); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy++; - gridBagConstraints.gridwidth = 1; - panSubAtBAdmin.add(lblAtbCamOpsDivision, gridBagConstraints); - - spnAtbCamOpsDivision = new JSpinner(new SpinnerNumberModel(2.5, 1, 10, 0.1)); - spnAtbCamOpsDivision.setToolTipText(resources.getString("lblAtbCamOpsDivision.toolTipText")); - gridBagConstraints.gridx = 1; - panSubAtBAdmin.add(spnAtbCamOpsDivision, gridBagConstraints); - chkMercSizeLimited = new JCheckBox(resources.getString("chkMercSizeLimited.text")); chkMercSizeLimited.setToolTipText(resources.getString("chkMercSizeLimited.toolTipText")); gridBagConstraints.gridx = 0; @@ -3497,15 +3485,17 @@ private JScrollPane createLifePathsPanel() { lifePathsPanel.add(createPersonnelRandomizationPanel(), gbc); gbc.gridx++; - lifePathsPanel.add(createAnniversaryPanel(), gbc); + lifePathsPanel.add(createRandomHistoriesPanel(), gbc); // gbc.gridx = 0; gbc.gridy++; - gbc.gridwidth = 2; lifePathsPanel.add(createFamilyPanel(), gbc); + gbc.gridx++; + lifePathsPanel.add(createAnniversaryPanel(), gbc); + // gbc.gridx = 0; @@ -5047,16 +5037,44 @@ private JPanel createPersonnelRandomizationPanel() { chkUseDylansRandomXP.setToolTipText(resources.getString("chkUseDylansRandomXP.toolTipText")); chkUseDylansRandomXP.setName("chkUseDylansRandomXP"); + // Layout the Panel + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("personnelRandomizationPanel.title"))); + panel.setName("personnelRandomizationPanel"); + + final GroupLayout layout = new GroupLayout(panel); + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + panel.setLayout(layout); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(chkUseDylansRandomXP) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(chkUseDylansRandomXP) + ); + + return panel; + } + + private JPanel createRandomHistoriesPanel() { randomOriginOptionsPanel = new RandomOriginOptionsPanel(getFrame(), campaign, comboFaction); chkUseRandomPersonalities = new JCheckBox(resources.getString("chkUseRandomPersonalities.text")); chkUseRandomPersonalities.setToolTipText(resources.getString("chkUseRandomPersonalities.toolTipText")); chkUseRandomPersonalities.setName("chkUseRandomPersonalities"); + chkUseRandomPersonalityReputation = new JCheckBox(resources.getString("chkUseRandomPersonalityReputation.text")); + chkUseRandomPersonalityReputation.setToolTipText(resources.getString("chkUseRandomPersonalityReputation.toolTipText")); + chkUseRandomPersonalityReputation.setName("chkUseRandomPersonalityReputation"); + // Layout the Panel final JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder(resources.getString("personnelRandomizationPanel.title"))); - panel.setName("personnelRandomizationPanel"); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("randomHistoriesPanel.title"))); + panel.setName("randomHistoriesPanel"); final GroupLayout layout = new GroupLayout(panel); layout.setAutoCreateGaps(true); @@ -5065,16 +5083,16 @@ private JPanel createPersonnelRandomizationPanel() { layout.setVerticalGroup( layout.createSequentialGroup() - .addComponent(chkUseDylansRandomXP) .addComponent(randomOriginOptionsPanel) .addComponent(chkUseRandomPersonalities) + .addComponent(chkUseRandomPersonalityReputation) ); layout.setHorizontalGroup( layout.createParallelGroup(Alignment.LEADING) - .addComponent(chkUseDylansRandomXP) .addComponent(randomOriginOptionsPanel) .addComponent(chkUseRandomPersonalities) + .addComponent(chkUseRandomPersonalityReputation) ); return panel; @@ -8299,6 +8317,7 @@ public void setOptions(@Nullable CampaignOptions options, chkUseDylansRandomXP.setSelected(options.isUseDylansRandomXP()); randomOriginOptionsPanel.setOptions(options.getRandomOriginOptions()); chkUseRandomPersonalities.setSelected(options.isUseRandomPersonalities()); + chkUseRandomPersonalityReputation.setSelected(options.isUseRandomPersonalityReputation()); // Family comboFamilyDisplayLevel.setSelectedItem(options.getFamilyDisplayLevel()); @@ -8626,7 +8645,6 @@ public void setOptions(@Nullable CampaignOptions options, chkClanVehicles.setSelected(options.isClanVehicles()); chkAutoconfigMunitions.setSelected(options.isAutoconfigMunitions()); chkMercSizeLimited.setSelected(options.isMercSizeLimited()); - spnAtbCamOpsDivision.setValue(options.getAtbCamOpsDivision()); chkRestrictPartsByMission.setSelected(options.isRestrictPartsByMission()); spnBonusPartExchangeValue.setValue(options.getBonusPartExchangeValue()); spnBonusPartMaxExchangeCount.setValue(options.getBonusPartMaxExchangeCount()); @@ -9005,6 +9023,7 @@ public void updateOptions() { options.setUseDylansRandomXP(chkUseDylansRandomXP.isSelected()); options.setRandomOriginOptions(randomOriginOptionsPanel.createOptionsFromPanel()); options.setUseRandomPersonalities(chkUseRandomPersonalities.isSelected()); + options.setUseRandomPersonalityReputation(chkUseRandomPersonalityReputation.isSelected()); // Family options.setFamilyDisplayLevel(comboFamilyDisplayLevel.getSelectedItem()); @@ -9203,7 +9222,6 @@ public void updateOptions() { } options.setGenerateChases(chkGenerateChases.isSelected()); options.setMercSizeLimited(chkMercSizeLimited.isSelected()); - options.setAtbCamOpsDivision((Double) spnAtbCamOpsDivision.getValue()); options.setRestrictPartsByMission(chkRestrictPartsByMission.isSelected()); options.setBonusPartExchangeValue((Integer) spnBonusPartExchangeValue.getValue()); options.setBonusPartMaxExchangeCount((Integer) spnBonusPartMaxExchangeCount.getValue()); diff --git a/MekHQ/unittests/mekhq/campaign/rating/CampaignOpsReputationTest.java b/MekHQ/unittests/mekhq/campaign/rating/CampaignOpsReputationTest.java deleted file mode 100644 index 3d70888cc7..0000000000 --- a/MekHQ/unittests/mekhq/campaign/rating/CampaignOpsReputationTest.java +++ /dev/null @@ -1,1541 +0,0 @@ -/* - * FieldManualMercRevMrbcRating.java - * - * Copyright (c) 2009 Jay Lawson (jaylawson39 at yahoo.com). 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.rating; - -import asserts.BigDecimalAssert; -import megamek.common.*; -import megamek.common.InfantryBay.PlatoonType; -import megamek.common.enums.SkillLevel; -import mekhq.campaign.Campaign; -import mekhq.campaign.CampaignOptions; -import mekhq.campaign.Hangar; -import mekhq.campaign.finances.Finances; -import mekhq.campaign.mission.Mission; -import mekhq.campaign.mission.enums.MissionStatus; -import mekhq.campaign.personnel.Person; -import mekhq.campaign.personnel.Skill; -import mekhq.campaign.personnel.SkillType; -import mekhq.campaign.personnel.enums.PersonnelRole; -import mekhq.campaign.personnel.enums.PersonnelStatus; -import mekhq.campaign.personnel.enums.PrisonerStatus; -import mekhq.campaign.unit.Unit; -import mekhq.campaign.universe.Faction; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.math.BigDecimal; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - -/** - * @author Deric "Netzilla" Page (deric dot page at usa dot net) - * @since 9/28/13 11:20 AM - */ -@SuppressWarnings(value = "FieldCanBeLocal") -public class CampaignOpsReputationTest { - - private Campaign mockCampaign; - private CampaignOptions mockCampaignOptions; - private Hangar mockHangar; - private List unitList; - private List personnelList; - private List activePersonnelList; - private List missionList; - private List completedMissionList; - - // Mothballed units. - private Unit mockMechMothballed; - private Unit mockAeroMothballed; - private Unit mockTankMothballed; - - // Mechs - private Skill mockMechGunnery; - private Skill mockMechPilot; - private Skill mockLeader ; - private Skill mockTactics; - private Skill mockStrategy; - private Skill mockNegotiation; - private BipedMech mockThunderbolt1; - private Unit mockThunderboltUnit1; - private Person mockThunderbolt1Pilot; - private Person mockThunderbolt1Tech; - private BipedMech mockThunderbolt2; - private Unit mockThunderboltUnit2; - private Person mockThunderbolt2Pilot; - private Person mockThunderbolt2Tech; - private BipedMech mockGrasshopper1; - private Unit mockGrasshopperUnit1; - private Person mockGrasshopper1Pilot; - private Person mockGrasshopper1Tech; - private BipedMech mockGrasshopper2; - private Unit mockGrasshopperUnit2; - private Person mockGrasshopper2Pilot; - private Person mockGrasshopper2Tech; - - // Tanks - private Skill mockTankGunnery; - private Skill mockTankPilot; - private Tank mockBulldog1; - private Unit mockBulldogUnit1; - private Person mockBulldog1Driver; - private Person mockBulldog1Gunner1; - private Person mockBulldog1Gunner2; - private Person mockBulldog1Gunner3; - private Person mockBulldog1Tech; - private Tank mockBulldog2; - private Unit mockBulldogUnit2; - private Person mockBulldog2Driver; - private Person mockBulldog2Gunner1; - private Person mockBulldog2Gunner2; - private Person mockBulldog2Gunner3; - private Person mockBulldog2Tech; - private Tank mockBulldog3; - private Unit mockBulldogUnit3; - private Person mockBulldog3Driver; - private Person mockBulldog3Gunner1; - private Person mockBulldog3Gunner2; - private Person mockBulldog3Gunner3; - private Person mockBulldog3Tech; - private Tank mockBulldog4; - private Unit mockBulldogUnit4; - private Person mockBulldog4Driver; - private Person mockBulldog4Gunner1; - private Person mockBulldog4Gunner2; - private Person mockBulldog4Gunner3; - private Person mockBulldog4Tech; - private Tank mockPackrat1; - private Unit mockPackratUnit1; - private Person mockPackrat1Driver; - private Person mockPackrat1Gunner; - private Person mockPackrat1Tech; - private Tank mockPackrat2; - private Unit mockPackratUnit2; - private Person mockPackrat2Driver; - private Person mockPackrat2Gunner; - private Person mockPackrat2Tech; - private Tank mockPackrat3; - private Unit mockPackratUnit3; - private Person mockPackrat3Driver; - private Person mockPackrat3Gunner; - private Person mockPackrat3Tech; - private Tank mockPackrat4; - private Unit mockPackratUnit4; - private Person mockPackrat4Driver; - private Person mockPackrat4Gunner; - private Person mockPackrat4Tech; - - // Infantry - private Skill mockInfantryGunnery; - private Infantry mockLaserPlatoon; - private Unit mockLaserPlatoonUnit; - private Collection infantryPersonnel; - - // Fighters - private Skill mockAeroGunnery; - private Skill mockAeroPilot; - private AeroSpaceFighter mockCorsair1; - private Unit mockCorsairUnit1; - private Person mockCorsair1Pilot; - private Person mockCorsair1Tech; - private AeroSpaceFighter mockCorsair2; - private Unit mockCorsairUnit2; - private Person mockCorsair2Pilot; - private Person mockCorsair2Tech; - - // DropShips - private Skill mockDropGunnery; - private Skill mockDropPilot; - private Dropship mockSeeker; - private Unit mockSeekerUnit; - private Collection seekerCrew; - - // JumpShips - private Skill mockJumpGunnery; - private Skill mockJumpPilot; - private Jumpship mockInvader; - private Unit mockInvaderUnit; - private Collection invaderCrew; - - // Techs - private Skill mockMechTechSkillRegular; - private Skill mockMechTechSkillElite; - private Skill mockFighterTechSkill; - private Skill mockFighterTechSkillElite; - private Skill mockVeeTechSkill; - private Collection regularAdmins; - - // Finances - private Finances mockFinances; - - private CampaignOpsReputation spyReputation; - - @BeforeEach - public void setUp() { - mockCampaign = mock(Campaign.class); - Faction mockFaction = mock(Faction.class); - when(mockFaction.is(any())).thenReturn(true); - when(mockCampaign.getFaction()).thenReturn(mockFaction); - mockHangar = mock(Hangar.class); - when(mockCampaign.getHangar()).thenReturn(mockHangar); - - mockCampaignOptions = mock(CampaignOptions.class); - when(mockCampaignOptions.getManualUnitRatingModifier()).thenReturn(0); - when(mockCampaign.getCampaignOptions()).thenReturn(mockCampaignOptions); - spyReputation = spy(new CampaignOpsReputation(mockCampaign)); - - int astechs = 0; - unitList = new ArrayList<>(); - personnelList = new ArrayList<>(); - activePersonnelList = new ArrayList<>(); - missionList = new ArrayList<>(); - completedMissionList = new ArrayList<>(); - - mockMothballed(); - mockSkills(); - astechs += mockThunderbolt1(); - astechs += mockThunderbolt2(); - astechs += mockGrasshopper1(); - astechs += mockGrasshopper2(); - astechs += mockBulldog1(); - astechs += mockBulldog2(); - astechs += mockBulldog3(); - astechs += mockBulldog4(); - astechs += mockPackrat1(); - astechs += mockPackrat2(); - astechs += mockPackrat3(); - astechs += mockPackrat4(); - mockLaserPlatoon(); - astechs += mockCorsair1(); - astechs += mockCorsair2(); - mockSeeker(); - mockInvader(); - - unitList.add(mockThunderboltUnit1); - unitList.add(mockThunderboltUnit2); - unitList.add(mockGrasshopperUnit1); - unitList.add(mockGrasshopperUnit2); - unitList.add(mockBulldogUnit1); - unitList.add(mockBulldogUnit2); - unitList.add(mockBulldogUnit3); - unitList.add(mockBulldogUnit4); - unitList.add(mockPackratUnit1); - unitList.add(mockPackratUnit2); - unitList.add(mockPackratUnit3); - unitList.add(mockPackratUnit4); - unitList.add(mockLaserPlatoonUnit); - unitList.add(mockCorsairUnit1); - unitList.add(mockCorsairUnit2); - unitList.add(mockSeekerUnit); - unitList.add(mockInvaderUnit); - - for (Unit u : unitList) { - when(u.isPresent()).thenReturn(true); - when(u.hasPilot()).thenReturn(true); - } - - regularAdmins = new HashSet<>(20); - for (int i = 0; i < 20; i++) { - Person admin = mock(Person.class); - when(admin.isAdministrator()).thenReturn(true); - when(admin.getPrimaryRole()).thenReturn(PersonnelRole.ADMINISTRATOR_COMMAND); - when(admin.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(admin).getStatus(); - regularAdmins.add(admin); - } - - personnelList.addAll(regularAdmins); - - for (Person p : personnelList) { - if (p.getStatus().isActive()) { - activePersonnelList.add(p); - } - } - - mockFinances = mock(Finances.class); - when(mockFinances.isInDebt()).thenReturn(false); - - when(mockHangar.getUnits()).thenReturn(unitList); - doReturn(personnelList).when(mockCampaign).getPersonnel(); - doReturn(activePersonnelList).when(mockCampaign).getActivePersonnel(); - doReturn(astechs).when(mockCampaign).getAstechPool(); - doCallRealMethod().when(mockCampaign).getNumberAstechs(); - doCallRealMethod().when(mockCampaign).getNumberPrimaryAstechs(); - doCallRealMethod().when(mockCampaign).getNumberSecondaryAstechs(); - doCallRealMethod().when(mockCampaign).getTechs(); - doCallRealMethod().when(mockCampaign).getDoctors(); - doCallRealMethod().when(mockCampaign).getAdmins(); - doReturn(mockGrasshopper2Pilot).when(mockCampaign).getFlaggedCommander(); - doReturn(missionList).when(mockCampaign).getMissions(); - doReturn(completedMissionList).when(mockCampaign).getCompletedMissions(); - doReturn(mockFinances).when(mockCampaign).getFinances(); - } - - @Test - public void testCalculateSupportNeeds() { - // Test the example company. - BigDecimal expectedTotalSkill = new BigDecimal("144.00"); - BigDecimal expectedAverageSkill = new BigDecimal("9.00"); - spyReputation.initValues(); - assertEquals(4, spyReputation.getMechCount()); - assertEquals(2, spyReputation.getFighterCount()); - assertEquals(0, spyReputation.getProtoCount()); - assertEquals(8, spyReputation.getVeeCount()); - assertEquals(0, spyReputation.getBattleArmorCount()); - assertEquals(28, spyReputation.getInfantryCount()); - assertEquals(200, spyReputation.getNonAdminPersonnelCount()); - assertEquals(1, spyReputation.getDropShipCount()); - BigDecimalAssert.assertEquals(expectedTotalSkill, spyReputation.getTotalSkillLevels(), 2); - assertEquals(4, spyReputation.getMechTechTeamsNeeded()); - assertEquals(2, spyReputation.getAeroTechTeamsNeeded()); - assertEquals(8, spyReputation.getMechanicTeamsNeeded()); - assertEquals(0, spyReputation.getBattleArmorTechTeamsNeeded()); - assertEquals(10, spyReputation.getAdminsNeeded()); - assertEquals(expectedAverageSkill, spyReputation.calcAverageExperience()); - assertEquals(10, spyReputation.getExperienceValue()); - - // Add a couple of mothballed units. - unitList.add(mockMechMothballed); - unitList.add(mockTankMothballed); - unitList.add(mockAeroMothballed); - assertEquals(4, spyReputation.getMechCount()); - assertEquals(2, spyReputation.getFighterCount()); - assertEquals(0, spyReputation.getProtoCount()); - assertEquals(8, spyReputation.getVeeCount()); - assertEquals(0, spyReputation.getBattleArmorCount()); - assertEquals(28, spyReputation.getInfantryCount()); - assertEquals(200, spyReputation.getNonAdminPersonnelCount()); - assertEquals(1, spyReputation.getDropShipCount()); - BigDecimalAssert.assertEquals(expectedTotalSkill, spyReputation.getTotalSkillLevels(), 2); - assertEquals(4, spyReputation.getMechTechTeamsNeeded()); - assertEquals(2, spyReputation.getAeroTechTeamsNeeded()); - assertEquals(8, spyReputation.getMechanicTeamsNeeded()); - assertEquals(0, spyReputation.getBattleArmorTechTeamsNeeded()); - assertEquals(10, spyReputation.getAdminsNeeded()); - assertEquals(expectedAverageSkill, spyReputation.calcAverageExperience()); - assertEquals(10, spyReputation.getExperienceValue()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getMechCount()); - assertEquals(0, spyReputation.getFighterCount()); - assertEquals(0, spyReputation.getProtoCount()); - assertEquals(0, spyReputation.getVeeCount()); - assertEquals(0, spyReputation.getBattleArmorCount()); - assertEquals(0, spyReputation.getInfantryCount()); - assertEquals(0, spyReputation.getNonAdminPersonnelCount()); - assertEquals(0, spyReputation.getDropShipCount()); - BigDecimalAssert.assertEquals(BigDecimal.ZERO, spyReputation.getTotalSkillLevels(), 2); - assertEquals(0, spyReputation.getMechTechTeamsNeeded()); - assertEquals(0, spyReputation.getAeroTechTeamsNeeded()); - assertEquals(0, spyReputation.getMechanicTeamsNeeded()); - assertEquals(0, spyReputation.getBattleArmorTechTeamsNeeded()); - assertEquals(0, spyReputation.getAdminsNeeded()); - assertEquals(BigDecimal.ZERO, spyReputation.calcAverageExperience()); - assertEquals(0, spyReputation.getExperienceValue()); - } - - private void buildFreshCampaign() { - when(mockHangar.getUnits()).thenReturn(Collections.emptyList()); - doReturn(new ArrayList(0)).when(mockCampaign).getPersonnel(); - doReturn(new ArrayList(0)).when(mockCampaign).getActivePersonnel(); - doReturn(new ArrayList(0)).when(mockCampaign).getAdmins(); - doReturn(new ArrayList(0)).when(mockCampaign).getTechs(); - doReturn(new ArrayList(0)).when(mockCampaign).getDoctors(); - doReturn(0).when(mockCampaign).getAstechPool(); - doReturn(0).when(mockCampaign).getNumberAstechs(); - doReturn(null).when(mockCampaign).getFlaggedCommander(); - } - - @Test - public void testGetCommanderValue() { - spyReputation.initValues(); - assertEquals(13, spyReputation.getCommanderValue()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getCommanderValue()); - } - - @Test - public void testGetCombatRecordValue() { - // New company with no record. - spyReputation.initValues(); - assertEquals(0, spyReputation.getCombatRecordValue()); - - // Add a few missions. - Mission winOne = mock(Mission.class); - when(winOne.getStatus()).thenReturn(MissionStatus.SUCCESS); - missionList.add(winOne); - completedMissionList.add(winOne); - Mission winTwo = mock(Mission.class); - when(winTwo.getStatus()).thenReturn(MissionStatus.SUCCESS); - missionList.add(winTwo); - completedMissionList.add(winTwo); - Mission winThree = mock(Mission.class); - when(winThree.getStatus()).thenReturn(MissionStatus.SUCCESS); - missionList.add(winThree); - completedMissionList.add(winThree); - Mission lossOne = mock(Mission.class); - when(lossOne.getStatus()).thenReturn(MissionStatus.FAILED); - missionList.add(lossOne); - completedMissionList.add(lossOne); - Mission active = mock(Mission.class); - when(active.getStatus()).thenReturn(MissionStatus.ACTIVE); - missionList.add(active); - assertEquals(5, spyReputation.getCombatRecordValue()); - } - - @Test - public void testGetTransportValue() { - spyReputation.initValues(); - assertEquals(20, spyReputation.getTransportValue()); - - // Test not having any DropShips (though we still have a JumpShip). - doReturn(0).when(spyReputation).getDropShipCount(); - doReturn(0).when(spyReputation).getMechBayCount(); - doReturn(0).when(spyReputation).getInfantryBayCount(); - doReturn(0).when(spyReputation).getLightVeeBayCount(); - doReturn(0).when(spyReputation).getHeavyVeeBayCount(); - doReturn(0).when(spyReputation).getBaBayCount(); - doReturn(0).when(spyReputation).getFighterBayCount(); - doReturn(0).when(spyReputation).getProtoBayCount(); - doReturn(0).when(spyReputation).getSmallCraftBayCount(); - assertEquals(0, spyReputation.getTransportValue()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getTransportValue()); - } - - @Test - public void testGetSupportValue() { - spyReputation.initValues(); - assertEquals(-5, spyReputation.getSupportValue()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getSupportValue()); - } - - @Test - public void testGetFinancialValue() { - spyReputation.initValues(); - assertEquals(0, spyReputation.getFinancialValue()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getFinancialValue()); - } - - @Test - public void testCalculateUnitRatingScore() { - spyReputation.initValues(); - assertEquals(38, spyReputation.calculateUnitRatingScore()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.calculateUnitRatingScore()); - } - - @Test - public void testGetReputationModifier() { - spyReputation.initValues(); - assertEquals(3, spyReputation.getModifier()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(0, spyReputation.getModifier()); - } - - @Test - public void testGetAverageExperience() { - spyReputation.initValues(); - assertEquals(SkillLevel.REGULAR, spyReputation.getAverageExperience()); - - // Test a brand new campaign. - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(SkillLevel.NONE, spyReputation.getAverageExperience()); - } - - @Test - public void testGetDetails() { - String expectedDetails = - "Unit Reputation: 38\n" + - " Method: Campaign Operations\n" + - "\n" + - "Experience: 10\n" + - " Average Experience: Regular\n" + - " #Regular: 16\n" + - "\n" + - "Commander: 13 (null)\n" + - " Leadership: 4\n" + - " Negotiation: 5\n" + - " Strategy: 2\n" + - " Tactics: 2\n" + - "\n" + - "Combat Record: 0\n" + - " Successful Missions: 0\n" + - " Partial Missions: 0\n" + - " Failed Missions: 0\n" + - " Contract Breaches: 0\n" + - "\n" + - "Transportation: 20\n" + - " BattleMech Bays: 4 needed / 4 available\n" + - " Fighter Bays: 2 needed / 2 available (plus 0 excess Small Craft)\n" + - " Small Craft Bays: 0 needed / 0 available\n" + - " ProtoMech Bays: 0 needed / 0 available\n" + - " Super Heavy Vehicle Bays: 0 needed / 0 available\n" + - " Heavy Vehicle Bays: 0 needed / 0 available (plus 0 excess Super Heavy)\n" + - " Light Vehicle Bays: 8 needed / 22 available (plus 0 excess Heavy and 0 excess Super Heavy)\n" + - " Battle Armor Bays: 0 needed / 0 available\n" + - " Infantry Bays: 1 needed / 4 available\n" + - " Docking Collars: 1 needed / 4 available\n" + - " Has JumpShips? Yes\n" + - " Has WarShips? No\n" + - "\n" + - "Support: -5\n" + - " Tech Support:\n" + - " Mech Techs: 4 needed / 0 available\n" + - " NOTE: ProtoMechs and BattleMechs use same techs.\n" + - " Aero Techs: 2 needed / 0 available\n" + - " Mechanics: 8 needed / 0 available\n" + - " NOTE: Vehicles and Infantry use the same mechanics.\n" + - " Battle Armor Techs: 0 needed / 0 available\n" + - " Astechs: 84 needed / 84 available\n" + - " Admin Support: 10 needed / 20 available\n" + - " Large Craft Crew:\n" + - " All fully crewed.\n" + - "\n" + - "Financial 0\n" + - " In Debt? No\n" + - "\n" + - "Criminal Activity: 0 (MHQ does not currently track criminal activity.)\n" + - "\n" + - "Inactivity Modifier: 0 (MHQ does not track end dates for missions/contracts.)"; - spyReputation.initValues(); - assertEquals(expectedDetails, spyReputation.getDetails()); - - // Test a brand new campaign. - expectedDetails = - "Unit Reputation: 0\n" + - " Method: Campaign Operations\n" + - "\n" + - "Experience: 0\n" + - " Average Experience: None\n" + - "\n" + - "\n" + - "Commander: 0 \n" + - " Leadership: 0\n" + - " Negotiation: 0\n" + - " Strategy: 0\n" + - " Tactics: 0\n" + - "\n" + - "Combat Record: 0\n" + - " Successful Missions: 0\n" + - " Partial Missions: 0\n" + - " Failed Missions: 0\n" + - " Contract Breaches: 0\n" + - "\n" + - "Transportation: 0\n" + - " BattleMech Bays: 0 needed / 0 available\n" + - " Fighter Bays: 0 needed / 0 available (plus 0 excess Small Craft)\n" + - " Small Craft Bays: 0 needed / 0 available\n" + - " ProtoMech Bays: 0 needed / 0 available\n" + - " Super Heavy Vehicle Bays: 0 needed / 0 available\n" + - " Heavy Vehicle Bays: 0 needed / 0 available (plus 0 excess Super Heavy)\n" + - " Light Vehicle Bays: 0 needed / 0 available (plus 0 excess Heavy and 0 excess Super Heavy)\n" + - " Battle Armor Bays: 0 needed / 0 available\n" + - " Infantry Bays: 0 needed / 0 available\n" + - " Docking Collars: 0 needed / 0 available\n" + - " Has JumpShips? No\n" + - " Has WarShips? No\n" + - "\n" + - "Support: 0\n" + - " Tech Support:\n" + - " Mech Techs: 0 needed / 0 available\n" + - " NOTE: ProtoMechs and BattleMechs use same techs.\n" + - " Aero Techs: 0 needed / 0 available\n" + - " Mechanics: 0 needed / 0 available\n" + - " NOTE: Vehicles and Infantry use the same mechanics.\n" + - " Battle Armor Techs: 0 needed / 0 available\n" + - " Astechs: 0 needed / 0 available\n" + - " Admin Support: 0 needed / 0 available\n" + - " Large Craft Crew:\n" + - " All fully crewed.\n" + - "\n" + - "Financial 0\n" + - " In Debt? No\n" + - "\n" + - "Criminal Activity: 0 (MHQ does not currently track criminal activity.)\n" + - "\n" + - "Inactivity Modifier: 0 (MHQ does not track end dates for missions/contracts.)"; - buildFreshCampaign(); - spyReputation.initValues(); - assertEquals(expectedDetails, spyReputation.getDetails()); - } - - @Test - public void testCalcTechSupportValue() { - assertEquals(0, spyReputation.calcTechSupportValue()); - - // Test having techs and astechs without having any combat units. - doReturn(12).when(mockCampaign).getNumberAstechs(); - doReturn(mockCampaign).when(spyReputation).getCampaign(); - List techs = new ArrayList<>(2); - techs.add(mockThunderbolt1Tech); - techs.add(mockThunderbolt2Tech); - doReturn(techs).when(mockCampaign).getTechs(); - doReturn(0).when(spyReputation).getMechTechTeamsNeeded(); - doReturn(0).when(spyReputation).getMechanicTeamsNeeded(); - doReturn(0).when(spyReputation).getAeroTechTeamsNeeded(); - doReturn(0).when(spyReputation).getBattleArmorTechTeamsNeeded(); - assertEquals(0, spyReputation.calcTechSupportValue()); - - // Test having techs without having any astechs. - doReturn(0).when(mockCampaign).getNumberAstechs(); - doReturn(mockCampaign).when(spyReputation).getCampaign(); - techs = new ArrayList<>(2); - techs.add(mockThunderbolt1Tech); - techs.add(mockThunderbolt2Tech); - doReturn(techs).when(mockCampaign).getTechs(); - doReturn(2).when(spyReputation).getMechTechTeamsNeeded(); - doReturn(0).when(spyReputation).getMechanicTeamsNeeded(); - doReturn(0).when(spyReputation).getAeroTechTeamsNeeded(); - doReturn(0).when(spyReputation).getBattleArmorTechTeamsNeeded(); - assertEquals(-5, spyReputation.calcTechSupportValue()); - - // Test having astechs without having any techs. - doReturn(12).when(mockCampaign).getNumberAstechs(); - doReturn(mockCampaign).when(spyReputation).getCampaign(); - doReturn(new ArrayList<>(0)).when(mockCampaign).getTechs(); - doReturn(2).when(spyReputation).getMechTechTeamsNeeded(); - doReturn(0).when(spyReputation).getMechanicTeamsNeeded(); - doReturn(0).when(spyReputation).getAeroTechTeamsNeeded(); - doReturn(0).when(spyReputation).getBattleArmorTechTeamsNeeded(); - assertEquals(-5, spyReputation.calcTechSupportValue()); - } - - @Test - public void testGetTransportationDetails() { - String expected = "Transportation: 20\n" + - " BattleMech Bays: 4 needed / 4 available\n" + - " Fighter Bays: 2 needed / 2 available (plus 0 excess Small Craft)\n" + - " Small Craft Bays: 0 needed / 0 available\n" + - " ProtoMech Bays: 0 needed / 0 available\n" + - " Super Heavy Vehicle Bays: 0 needed / 0 available\n" + - " Heavy Vehicle Bays: 0 needed / 0 available (plus 0 excess Super Heavy)\n" + - " Light Vehicle Bays: 8 needed / 22 available (plus 0 excess Heavy and 0 excess Super Heavy)\n" + - " Battle Armor Bays: 0 needed / 0 available\n" + - " Infantry Bays: 1 needed / 4 available\n" + - " Docking Collars: 1 needed / 4 available\n" + - " Has JumpShips? Yes\n" + - " Has WarShips? No"; - spyReputation.initValues(); - assertEquals(expected, spyReputation.getTransportationDetails()); - - // Add some heavy vehicles. - expected = "Transportation: 10\n" + - " BattleMech Bays: 4 needed / 4 available\n" + - " Fighter Bays: 2 needed / 2 available (plus 0 excess Small Craft)\n" + - " Small Craft Bays: 0 needed / 0 available\n" + - " ProtoMech Bays: 0 needed / 0 available\n" + - " Super Heavy Vehicle Bays: 0 needed / 0 available\n" + - " Heavy Vehicle Bays: 4 needed / 0 available (plus 0 excess Super Heavy)\n" + - " Light Vehicle Bays: 8 needed / 22 available (plus 0 excess Heavy and 0 excess Super Heavy)\n" + - " Battle Armor Bays: 0 needed / 0 available\n" + - " Infantry Bays: 1 needed / 4 available\n" + - " Docking Collars: 1 needed / 4 available\n" + - " Has JumpShips? Yes\n" + - " Has WarShips? No"; - doReturn(4).when(spyReputation).getHeavyVeeCount(); - assertEquals(expected, spyReputation.getTransportationDetails()); - - // Add excess heavy vehicle bays. - expected = "Transportation: 20\n" + - " BattleMech Bays: 4 needed / 4 available\n" + - " Fighter Bays: 2 needed / 2 available (plus 0 excess Small Craft)\n" + - " Small Craft Bays: 0 needed / 0 available\n" + - " ProtoMech Bays: 0 needed / 0 available\n" + - " Super Heavy Vehicle Bays: 0 needed / 0 available\n" + - " Heavy Vehicle Bays: 4 needed / 8 available (plus 0 excess Super Heavy)\n" + - " Light Vehicle Bays: 8 needed / 22 available (plus 4 excess Heavy and 0 excess Super Heavy)\n" + - " Battle Armor Bays: 0 needed / 0 available\n" + - " Infantry Bays: 1 needed / 4 available\n" + - " Docking Collars: 1 needed / 4 available\n" + - " Has JumpShips? Yes\n" + - " Has WarShips? No"; - doReturn(8).when(spyReputation).getHeavyVeeBayCount(); - assertEquals(expected, spyReputation.getTransportationDetails()); - } - - private void mockMothballed() { - mockMechMothballed = mock(Unit.class); - mockAeroMothballed = mock(Unit.class); - mockTankMothballed = mock(Unit.class); - - when(mockMechMothballed.isMothballed()).thenReturn(true); - when(mockAeroMothballed.isMothballed()).thenReturn(true); - when(mockTankMothballed.isMothballed()).thenReturn(true); - } - - private void mockSkills() { - mockMechGunnery = mock(Skill.class); - mockMechPilot = mock(Skill.class); - mockTankGunnery = mock(Skill.class); - mockTankPilot = mock(Skill.class); - mockInfantryGunnery = mock(Skill.class); - mockAeroGunnery = mock(Skill.class); - mockAeroPilot = mock(Skill.class); - mockDropGunnery = mock(Skill.class); - mockDropPilot = mock(Skill.class); - mockJumpGunnery = mock(Skill.class); - mockJumpPilot = mock(Skill.class); - mockLeader = mock(Skill.class); - mockTactics = mock(Skill.class); - mockStrategy = mock(Skill.class); - mockNegotiation = mock(Skill.class); - mockMechTechSkillRegular = mock(Skill.class); - mockMechTechSkillElite = mock(Skill.class); - mockFighterTechSkill = mock(Skill.class); - mockFighterTechSkillElite = mock(Skill.class); - mockVeeTechSkill = mock(Skill.class); - - when(mockMechGunnery.getLevel()).thenReturn(4); - when(mockMechPilot.getLevel()).thenReturn(5); - when(mockTankGunnery.getLevel()).thenReturn(4); - when(mockTankPilot.getLevel()).thenReturn(5); - when(mockInfantryGunnery.getLevel()).thenReturn(4); - when(mockAeroGunnery.getLevel()).thenReturn(4); - when(mockAeroPilot.getLevel()).thenReturn(5); - when(mockDropGunnery.getLevel()).thenReturn(4); - when(mockDropPilot.getLevel()).thenReturn(5); - when(mockJumpGunnery.getLevel()).thenReturn(4); - when(mockJumpPilot.getLevel()).thenReturn(5); - when(mockLeader.getLevel()).thenReturn(4); - when(mockTactics.getLevel()).thenReturn(2); - when(mockStrategy.getLevel()).thenReturn(2); - when(mockNegotiation.getLevel()).thenReturn(5); - when(mockMechTechSkillRegular.getLevel()).thenReturn(7); - when(mockMechTechSkillElite.getLevel()).thenReturn(5); - when(mockFighterTechSkill.getLevel()).thenReturn(7); - when(mockFighterTechSkillElite.getLevel()).thenReturn(5); - when(mockVeeTechSkill.getLevel()).thenReturn(7); - } - - private int mockThunderbolt1() { - mockThunderbolt1 = mock(BipedMech.class); - mockThunderboltUnit1 = mock(Unit.class); - mockThunderbolt1Pilot = mock(Person.class); - mockThunderbolt1Tech = mock(Person.class); - - when(mockThunderbolt1.getEntityType()).thenReturn(Entity.ETYPE_MECH); - when(mockThunderbolt1.getUnitType()).thenCallRealMethod(); - when(mockThunderboltUnit1.getEntity()).thenReturn(mockThunderbolt1); - when(mockThunderbolt1Pilot.isAdministrator()).thenReturn(false); - when(mockThunderbolt1Pilot.getPrimaryRole()).thenReturn(PersonnelRole.MECHWARRIOR); - when(mockThunderbolt1Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockThunderbolt1Pilot).getStatus(); - when(mockThunderbolt1Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockThunderbolt1Pilot.getSkill(SkillType.S_GUN_MECH)).thenReturn(mockMechGunnery); - when(mockThunderbolt1Pilot.getSkill(SkillType.S_PILOT_MECH)).thenReturn(mockMechPilot); - personnelList.add(mockThunderbolt1Pilot); - mockThunderboltUnit1.addPilotOrSoldier(mockThunderbolt1Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockThunderbolt1Pilot); - when(mockThunderboltUnit1.getCrew()).thenReturn(crew); - Crew mockThunderboltCrew = mock(Crew.class); - doReturn(mockMechPilot.getLevel()).when(mockThunderboltCrew).getPiloting(); - doReturn(mockMechGunnery.getLevel()).when(mockThunderboltCrew).getGunnery(); - when(mockThunderbolt1.getCrew()).thenReturn(mockThunderboltCrew); - when(mockThunderbolt1Tech.isAdministrator()).thenReturn(false); - when(mockThunderbolt1Tech.isTech()).thenReturn(true); - when(mockThunderbolt1Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECH_TECH); - when(mockThunderbolt1Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - when(mockThunderbolt1Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - doReturn(PersonnelStatus.ACTIVE).when(mockThunderbolt1Tech).getStatus(); - when(mockThunderbolt1Tech.getSkill(SkillType.S_TECH_MECH)).thenReturn(mockMechTechSkillRegular); - personnelList.add(mockThunderbolt1Tech); - - return 6; // astechs needed by Thunderbolt1 - } - - private int mockThunderbolt2() { - mockThunderbolt2 = mock(BipedMech.class); - mockThunderboltUnit2 = mock(Unit.class); - mockThunderbolt2Pilot = mock(Person.class); - mockThunderbolt2Tech = mock(Person.class); - - when(mockThunderbolt2.getEntityType()).thenReturn(Entity.ETYPE_MECH); - when(mockThunderbolt2.getUnitType()).thenCallRealMethod(); - when(mockThunderboltUnit2.getEntity()).thenReturn(mockThunderbolt2); - when(mockThunderbolt2Pilot.isAdministrator()).thenReturn(false); - when(mockThunderbolt2Pilot.getPrimaryRole()).thenReturn(PersonnelRole.MECHWARRIOR); - when(mockThunderbolt2Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockThunderbolt2Pilot).getStatus(); - when(mockThunderbolt2Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockThunderbolt2Pilot.getSkill(SkillType.S_GUN_MECH)).thenReturn(mockMechGunnery); - when(mockThunderbolt2Pilot.getSkill(SkillType.S_PILOT_MECH)).thenReturn(mockMechPilot); - personnelList.add(mockThunderbolt2Pilot); - mockThunderboltUnit2.addPilotOrSoldier(mockThunderbolt2Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockThunderbolt2Pilot); - when(mockThunderboltUnit2.getCrew()).thenReturn(crew); - Crew mockThunderbolt2Crew = mock(Crew.class); - doReturn(mockMechPilot.getLevel()).when(mockThunderbolt2Crew).getPiloting(); - doReturn(mockMechGunnery.getLevel()).when(mockThunderbolt2Crew).getGunnery(); - when(mockThunderbolt2.getCrew()).thenReturn(mockThunderbolt2Crew); - when(mockThunderbolt2Tech.isAdministrator()).thenReturn(false); - when(mockThunderbolt2Tech.isTech()).thenReturn(true); - when(mockThunderbolt2Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECH_TECH); - when(mockThunderbolt2Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockThunderbolt2Tech).getStatus(); - when(mockThunderbolt2Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockThunderbolt2Tech.getSkill(SkillType.S_TECH_MECH)).thenReturn(mockMechTechSkillRegular); - personnelList.add(mockThunderbolt2Tech); - return 6; // astechs needed by Thunderbolt2 - } - - private int mockGrasshopper1() { - mockGrasshopper1 = mock(BipedMech.class); - mockGrasshopperUnit1 = mock(Unit.class); - mockGrasshopper1Pilot = mock(Person.class); - mockGrasshopper1Tech = mock(Person.class); - - when(mockGrasshopper1.getEntityType()).thenReturn(Entity.ETYPE_MECH); - when(mockGrasshopper1.getUnitType()).thenCallRealMethod(); - when(mockGrasshopperUnit1.getEntity()).thenReturn(mockGrasshopper1); - when(mockGrasshopper1Pilot.isAdministrator()).thenReturn(false); - when(mockGrasshopper1Pilot.getPrimaryRole()).thenReturn(PersonnelRole.MECHWARRIOR); - when(mockGrasshopper1Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockGrasshopper1Pilot).getStatus(); - when(mockGrasshopper1Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockGrasshopper1Pilot.getSkill(SkillType.S_GUN_MECH)).thenReturn(mockMechGunnery); - when(mockGrasshopper1Pilot.getSkill(SkillType.S_PILOT_MECH)).thenReturn(mockMechPilot); - personnelList.add(mockGrasshopper1Pilot); - mockGrasshopperUnit1.addPilotOrSoldier(mockGrasshopper1Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockGrasshopper1Pilot); - when(mockGrasshopperUnit1.getCrew()).thenReturn(crew); - Crew mockGrasshopperCrew = mock(Crew.class); - doReturn(mockMechPilot.getLevel()).when(mockGrasshopperCrew).getPiloting(); - doReturn(mockMechGunnery.getLevel()).when(mockGrasshopperCrew).getGunnery(); - when(mockGrasshopper1.getCrew()).thenReturn(mockGrasshopperCrew); - when(mockGrasshopper1Tech.isAdministrator()).thenReturn(false); - when(mockGrasshopper1Tech.isTech()).thenReturn(true); - when(mockGrasshopper1Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECH_TECH); - when(mockGrasshopper1Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockGrasshopper1Tech).getStatus(); - when(mockGrasshopper1Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockGrasshopper1Tech.getSkill(SkillType.S_TECH_MECH)).thenReturn(mockMechTechSkillRegular); - personnelList.add(mockGrasshopper1Tech); - return 6; // astechs needed by Grasshopper1 - } - - private int mockGrasshopper2() { - mockGrasshopper2 = mock(BipedMech.class); - mockGrasshopperUnit2 = mock(Unit.class); - mockGrasshopper2Pilot = mock(Person.class); - mockGrasshopper2Tech = mock(Person.class); - - when(mockGrasshopper2.getEntityType()).thenReturn(Entity.ETYPE_MECH); - when(mockGrasshopper2.getUnitType()).thenCallRealMethod(); - when(mockGrasshopperUnit2.getEntity()).thenReturn(mockGrasshopper2); - when(mockGrasshopper2Pilot.isAdministrator()).thenReturn(false); - when(mockGrasshopper2Pilot.getPrimaryRole()).thenReturn(PersonnelRole.MECHWARRIOR); - when(mockGrasshopper2Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockGrasshopper2Pilot).getStatus(); - when(mockGrasshopper2Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_GUN_MECH)).thenReturn(mockMechGunnery); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_PILOT_MECH)).thenReturn(mockMechPilot); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_LEADER)).thenReturn(mockLeader); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_TACTICS)).thenReturn(mockTactics); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_STRATEGY)).thenReturn(mockStrategy); - when(mockGrasshopper2Pilot.getSkill(SkillType.S_NEG)).thenReturn(mockNegotiation); - personnelList.add(mockGrasshopper2Pilot); - mockGrasshopperUnit2.addPilotOrSoldier(mockGrasshopper2Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockGrasshopper2Pilot); - when(mockGrasshopperUnit2.getCrew()).thenReturn(crew); - Crew mockGrasshopper2Crew = mock(Crew.class); - doReturn(mockMechPilot.getLevel()).when(mockGrasshopper2Crew).getPiloting(); - doReturn(mockMechGunnery.getLevel()).when(mockGrasshopper2Crew).getGunnery(); - when(mockGrasshopper2.getCrew()).thenReturn(mockGrasshopper2Crew); - when(mockGrasshopper2Tech.isAdministrator()).thenReturn(false); - when(mockGrasshopper2Tech.isTech()).thenReturn(true); - when(mockGrasshopper2Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECH_TECH); - when(mockGrasshopper2Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockGrasshopper2Tech).getStatus(); - when(mockGrasshopper2Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockGrasshopper2Tech.getSkill(SkillType.S_TECH_MECH)).thenReturn(mockMechTechSkillElite); - personnelList.add(mockGrasshopper2Tech); - return 6; // astechs needed by Grasshopper1 - } - - private int mockBulldog1() { - mockBulldog1 = mock(Tank.class); - mockBulldogUnit1 = mock(Unit.class); - mockBulldog1Driver = mock(Person.class); - mockBulldog1Gunner1 = mock(Person.class); - mockBulldog1Gunner2 = mock(Person.class); - mockBulldog1Gunner3 = mock(Person.class); - mockBulldog1Tech = mock(Person.class); - - when(mockBulldog1.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockBulldog1.getUnitType()).thenCallRealMethod(); - when(mockBulldogUnit1.getEntity()).thenReturn(mockBulldog1); - when(mockBulldog1Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockBulldog1Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog1Gunner1.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog1Gunner2.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog1Gunner3.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog1Driver.isAdministrator()).thenReturn(false); - when(mockBulldog1Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockBulldog1Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog1Driver).getStatus(); - when(mockBulldog1Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog1Gunner1.isAdministrator()).thenReturn(false); - when(mockBulldog1Gunner1.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog1Gunner1.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog1Gunner1).getStatus(); - when(mockBulldog1Gunner1.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog1Gunner2.isAdministrator()).thenReturn(false); - when(mockBulldog1Gunner2.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog1Gunner2.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog1Gunner2).getStatus(); - when(mockBulldog1Gunner2.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog1Gunner3.isAdministrator()).thenReturn(false); - when(mockBulldog1Gunner3.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog1Gunner3.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog1Gunner3).getStatus(); - when(mockBulldog1Gunner3.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog1Tech.isAdministrator()).thenReturn(false); - when(mockBulldog1Tech.isTech()).thenReturn(true); - when(mockBulldog1Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockBulldog1Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog1Tech).getStatus(); - when(mockBulldog1Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog1Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockBulldog1Driver); - personnelList.add(mockBulldog1Gunner1); - personnelList.add(mockBulldog1Gunner2); - personnelList.add(mockBulldog1Gunner3); - personnelList.add(mockBulldog1Tech); - mockBulldogUnit1.addPilotOrSoldier(mockBulldog1Driver); - mockBulldogUnit1.addPilotOrSoldier(mockBulldog1Gunner1); - mockBulldogUnit1.addPilotOrSoldier(mockBulldog1Gunner2); - mockBulldogUnit1.addPilotOrSoldier(mockBulldog1Gunner3); - ArrayList crew = new ArrayList<>(4); - crew.add(mockBulldog1Driver); - crew.add(mockBulldog1Gunner1); - crew.add(mockBulldog1Gunner2); - crew.add(mockBulldog1Gunner3); - when(mockBulldogUnit1.getCrew()).thenReturn(crew); - Crew mockBulldog1Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockBulldog1Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockBulldog1Crew).getGunnery(); - when(mockBulldog1.getCrew()).thenReturn(mockBulldog1Crew); - return 6; // astechs needed by Bulldog1 - } - - private int mockBulldog2() { - mockBulldog2 = mock(Tank.class); - mockBulldogUnit2 = mock(Unit.class); - mockBulldog2Driver = mock(Person.class); - mockBulldog2Gunner1 = mock(Person.class); - mockBulldog2Gunner2 = mock(Person.class); - mockBulldog2Gunner3 = mock(Person.class); - mockBulldog2Tech = mock(Person.class); - - when(mockBulldog2.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockBulldog2.getUnitType()).thenCallRealMethod(); - when(mockBulldog2Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockBulldog2Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog2Gunner1.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog2Gunner2.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog2Gunner3.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldogUnit2.getEntity()).thenReturn(mockBulldog2); - when(mockBulldog2Driver.isAdministrator()).thenReturn(false); - when(mockBulldog2Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockBulldog2Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog2Driver).getStatus(); - when(mockBulldog2Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog2Driver); - when(mockBulldog2Gunner1.isAdministrator()).thenReturn(false); - when(mockBulldog2Gunner1.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog2Gunner1.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog2Gunner1).getStatus(); - when(mockBulldog2Gunner1.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog2Gunner1); - when(mockBulldog2Gunner2.isAdministrator()).thenReturn(false); - when(mockBulldog2Gunner2.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog2Gunner2.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog2Gunner2).getStatus(); - when(mockBulldog2Gunner2.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog2Gunner2); - when(mockBulldog2Gunner3.isAdministrator()).thenReturn(false); - when(mockBulldog2Gunner3.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog2Gunner3.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog2Gunner3).getStatus(); - when(mockBulldog2Gunner3.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog2Gunner3); - when(mockBulldog2Tech.isAdministrator()).thenReturn(false); - when(mockBulldog2Tech.isTech()).thenReturn(true); - when(mockBulldog2Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockBulldog2Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog2Tech).getStatus(); - when(mockBulldog2Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog2Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockBulldog2Tech); - mockBulldogUnit2.addPilotOrSoldier(mockBulldog2Driver); - mockBulldogUnit2.addPilotOrSoldier(mockBulldog2Gunner1); - mockBulldogUnit2.addPilotOrSoldier(mockBulldog2Gunner2); - mockBulldogUnit2.addPilotOrSoldier(mockBulldog2Gunner3); - ArrayList crew = new ArrayList<>(4); - crew.add(mockBulldog2Driver); - crew.add(mockBulldog2Gunner1); - crew.add(mockBulldog2Gunner2); - crew.add(mockBulldog2Gunner3); - when(mockBulldogUnit2.getCrew()).thenReturn(crew); - Crew mockBulldog2Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockBulldog2Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockBulldog2Crew).getGunnery(); - when(mockBulldog2.getCrew()).thenReturn(mockBulldog2Crew); - return 6; // astechs needed by Bulldog1 - } - - private int mockBulldog3() { - mockBulldog3 = mock(Tank.class); - mockBulldogUnit3 = mock(Unit.class); - mockBulldog3Driver = mock(Person.class); - mockBulldog3Gunner1 = mock(Person.class); - mockBulldog3Gunner2 = mock(Person.class); - mockBulldog3Gunner3 = mock(Person.class); - mockBulldog3Tech = mock(Person.class); - - when(mockBulldog3.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockBulldog3.getUnitType()).thenCallRealMethod(); - when(mockBulldog3Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockBulldog3Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog3Gunner1.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog3Gunner2.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog3Gunner3.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldogUnit3.getEntity()).thenReturn(mockBulldog3); - when(mockBulldog3Driver.isAdministrator()).thenReturn(false); - when(mockBulldog3Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockBulldog3Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog3Driver).getStatus(); - when(mockBulldog3Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog3Driver); - when(mockBulldog3Gunner1.isAdministrator()).thenReturn(false); - when(mockBulldog3Gunner1.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog3Gunner1.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog3Gunner1).getStatus(); - when(mockBulldog3Gunner1.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog3Gunner1); - when(mockBulldog3Gunner2.isAdministrator()).thenReturn(false); - when(mockBulldog3Gunner2.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog3Gunner2.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog3Gunner2).getStatus(); - when(mockBulldog3Gunner2.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog3Gunner2); - when(mockBulldog3Gunner3.isAdministrator()).thenReturn(false); - when(mockBulldog3Gunner3.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog3Gunner3.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog3Gunner3).getStatus(); - when(mockBulldog3Gunner3.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog3Gunner3); - when(mockBulldog3Tech.isAdministrator()).thenReturn(false); - when(mockBulldog3Tech.isTech()).thenReturn(true); - when(mockBulldog3Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockBulldog3Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog3Tech).getStatus(); - when(mockBulldog3Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog3Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockBulldog3Tech); - mockBulldogUnit3.addPilotOrSoldier(mockBulldog3Driver); - mockBulldogUnit3.addPilotOrSoldier(mockBulldog3Gunner1); - mockBulldogUnit3.addPilotOrSoldier(mockBulldog3Gunner2); - mockBulldogUnit3.addPilotOrSoldier(mockBulldog3Gunner3); - ArrayList crew = new ArrayList<>(4); - crew.add(mockBulldog3Driver); - crew.add(mockBulldog3Gunner1); - crew.add(mockBulldog3Gunner2); - crew.add(mockBulldog3Gunner3); - when(mockBulldogUnit3.getCrew()).thenReturn(crew); - Crew mockBulldog3Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockBulldog3Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockBulldog3Crew).getGunnery(); - when(mockBulldog3.getCrew()).thenReturn(mockBulldog3Crew); - return 6; // astechs needed by Bulldog1 - } - - private int mockBulldog4() { - mockBulldog4 = mock(Tank.class); - mockBulldogUnit4 = mock(Unit.class); - mockBulldog4Driver = mock(Person.class); - mockBulldog4Gunner1 = mock(Person.class); - mockBulldog4Gunner2 = mock(Person.class); - mockBulldog4Gunner3 = mock(Person.class); - mockBulldog4Tech = mock(Person.class); - - when(mockBulldog4.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockBulldog4.getUnitType()).thenCallRealMethod(); - when(mockBulldog4Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockBulldog4Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog4Gunner1.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog4Gunner2.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldog4Gunner3.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockBulldogUnit4.getEntity()).thenReturn(mockBulldog4); - when(mockBulldog4Driver.isAdministrator()).thenReturn(false); - when(mockBulldog4Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockBulldog4Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog4Driver).getStatus(); - when(mockBulldog4Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog4Driver); - when(mockBulldog4Gunner1.isAdministrator()).thenReturn(false); - when(mockBulldog4Gunner1.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog4Gunner1.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog4Gunner1).getStatus(); - when(mockBulldog4Gunner1.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog4Gunner1); - when(mockBulldog4Gunner2.isAdministrator()).thenReturn(false); - when(mockBulldog4Gunner2.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog4Gunner2.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog4Gunner2).getStatus(); - when(mockBulldog4Gunner2.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog4Gunner2); - when(mockBulldog4Gunner3.isAdministrator()).thenReturn(false); - when(mockBulldog4Gunner3.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockBulldog4Gunner3.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog4Gunner3).getStatus(); - when(mockBulldog4Gunner3.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockBulldog4Gunner3); - when(mockBulldog4Tech.isAdministrator()).thenReturn(false); - when(mockBulldog4Tech.isTech()).thenReturn(true); - when(mockBulldog4Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockBulldog4Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockBulldog4Tech).getStatus(); - when(mockBulldog4Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockBulldog4Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockBulldog4Tech); - mockBulldogUnit4.addPilotOrSoldier(mockBulldog4Driver); - mockBulldogUnit4.addPilotOrSoldier(mockBulldog4Gunner1); - mockBulldogUnit4.addPilotOrSoldier(mockBulldog4Gunner2); - mockBulldogUnit4.addPilotOrSoldier(mockBulldog4Gunner3); - ArrayList crew = new ArrayList<>(4); - crew.add(mockBulldog4Driver); - crew.add(mockBulldog4Gunner1); - crew.add(mockBulldog4Gunner2); - crew.add(mockBulldog4Gunner3); - when(mockBulldogUnit4.getCrew()).thenReturn(crew); - Crew mockBulldog4Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockBulldog4Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockBulldog4Crew).getGunnery(); - when(mockBulldog4.getCrew()).thenReturn(mockBulldog4Crew); - return 6; // astechs needed by Bulldog1 - } - - private int mockPackrat1() { - mockPackrat1 = mock(Tank.class); - mockPackratUnit1 = mock(Unit.class); - mockPackrat1Driver = mock(Person.class); - mockPackrat1Gunner = mock(Person.class); - mockPackrat1Tech = mock(Person.class); - - when(mockPackrat1.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockPackrat1.getUnitType()).thenCallRealMethod(); - when(mockPackrat1Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockPackrat1Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackrat1Gunner.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackratUnit1.getEntity()).thenReturn(mockPackrat1); - when(mockPackrat1Driver.isAdministrator()).thenReturn(false); - when(mockPackrat1Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockPackrat1Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat1Driver).getStatus(); - when(mockPackrat1Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat1Driver); - when(mockPackrat1Gunner.isAdministrator()).thenReturn(false); - when(mockPackrat1Gunner.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockPackrat1Gunner.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat1Gunner).getStatus(); - when(mockPackrat1Gunner.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat1Gunner); - when(mockPackrat1Tech.isAdministrator()).thenReturn(false); - when(mockPackrat1Tech.isTech()).thenReturn(true); - when(mockPackrat1Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockPackrat1Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat1Tech).getStatus(); - when(mockPackrat1Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockPackrat1Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockPackrat1Tech); - mockPackratUnit1.addPilotOrSoldier(mockPackrat1Driver); - mockPackratUnit1.addPilotOrSoldier(mockPackrat1Gunner); - ArrayList crew = new ArrayList<>(2); - crew.add(mockPackrat1Driver); - crew.add(mockPackrat1Gunner); - when(mockPackratUnit1.getCrew()).thenReturn(crew); - Crew mockPackrat1Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockPackrat1Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockPackrat1Crew).getGunnery(); - when(mockPackrat1.getCrew()).thenReturn(mockPackrat1Crew); - return 6; // astechs needed for Packrat1 - } - - private int mockPackrat2() { - mockPackrat2 = mock(Tank.class); - mockPackratUnit2 = mock(Unit.class); - mockPackrat2Driver = mock(Person.class); - mockPackrat2Gunner = mock(Person.class); - mockPackrat2Tech = mock(Person.class); - - when(mockPackrat2.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockPackrat2.getUnitType()).thenCallRealMethod(); - when(mockPackrat2Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockPackrat2Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackrat2Gunner.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackratUnit2.getEntity()).thenReturn(mockPackrat2); - when(mockPackrat2Driver.isAdministrator()).thenReturn(false); - when(mockPackrat2Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockPackrat2Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat2Driver).getStatus(); - when(mockPackrat2Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat2Driver); - when(mockPackrat2Gunner.isAdministrator()).thenReturn(false); - when(mockPackrat2Gunner.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockPackrat2Gunner.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat2Gunner).getStatus(); - when(mockPackrat2Gunner.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat2Gunner); - when(mockPackrat2Tech.isAdministrator()).thenReturn(false); - when(mockPackrat2Tech.isTech()).thenReturn(true); - when(mockPackrat2Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockPackrat2Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat2Tech).getStatus(); - when(mockPackrat2Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockPackrat2Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockPackrat2Tech); - mockPackratUnit2.addPilotOrSoldier(mockPackrat2Driver); - mockPackratUnit2.addPilotOrSoldier(mockPackrat2Gunner); - ArrayList crew = new ArrayList<>(2); - crew.add(mockPackrat2Driver); - crew.add(mockPackrat2Gunner); - when(mockPackratUnit2.getCrew()).thenReturn(crew); - Crew mockPackrat2Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockPackrat2Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockPackrat2Crew).getGunnery(); - when(mockPackrat2.getCrew()).thenReturn(mockPackrat2Crew); - return 6; // astechs needed for Packrat2 - } - - private int mockPackrat3() { - mockPackrat3 = mock(Tank.class); - mockPackratUnit3 = mock(Unit.class); - mockPackrat3Driver = mock(Person.class); - mockPackrat3Gunner = mock(Person.class); - mockPackrat3Tech = mock(Person.class); - - when(mockPackrat3.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockPackrat3.getUnitType()).thenCallRealMethod(); - when(mockPackrat3Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockPackrat3Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackrat3Gunner.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackratUnit3.getEntity()).thenReturn(mockPackrat3); - when(mockPackrat3Driver.isAdministrator()).thenReturn(false); - when(mockPackrat3Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockPackrat3Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat3Driver).getStatus(); - when(mockPackrat3Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat3Driver); - when(mockPackrat3Gunner.isAdministrator()).thenReturn(false); - when(mockPackrat3Gunner.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockPackrat3Gunner.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat3Gunner).getStatus(); - when(mockPackrat3Gunner.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat3Gunner); - when(mockPackrat3Tech.isAdministrator()).thenReturn(false); - when(mockPackrat3Tech.isTech()).thenReturn(true); - when(mockPackrat3Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockPackrat3Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat3Tech).getStatus(); - when(mockPackrat3Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockPackrat3Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockPackrat3Tech); - mockPackratUnit3.addPilotOrSoldier(mockPackrat3Driver); - mockPackratUnit3.addPilotOrSoldier(mockPackrat3Gunner); - ArrayList crew = new ArrayList<>(2); - crew.add(mockPackrat3Driver); - crew.add(mockPackrat3Gunner); - when(mockPackratUnit3.getCrew()).thenReturn(crew); - Crew mockPackrat3Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockPackrat3Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockPackrat3Crew).getGunnery(); - when(mockPackrat3.getCrew()).thenReturn(mockPackrat3Crew); - return 6; // astechs needed for Packrat3 - } - - private int mockPackrat4() { - mockPackrat4 = mock(Tank.class); - mockPackratUnit4 = mock(Unit.class); - mockPackrat4Driver = mock(Person.class); - mockPackrat4Gunner = mock(Person.class); - mockPackrat4Tech = mock(Person.class); - - when(mockPackrat4.getEntityType()).thenReturn(Entity.ETYPE_TANK); - when(mockPackrat4.getUnitType()).thenCallRealMethod(); - when(mockPackrat4Driver.getSkill(SkillType.S_PILOT_GVEE)).thenReturn(mockTankPilot); - when(mockPackrat4Driver.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackrat4Gunner.getSkill(SkillType.S_GUN_VEE)).thenReturn(mockTankGunnery); - when(mockPackratUnit4.getEntity()).thenReturn(mockPackrat4); - when(mockPackrat4Driver.isAdministrator()).thenReturn(false); - when(mockPackrat4Driver.getPrimaryRole()).thenReturn(PersonnelRole.GROUND_VEHICLE_DRIVER); - when(mockPackrat4Driver.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat4Driver).getStatus(); - when(mockPackrat4Driver.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat4Driver); - when(mockPackrat4Gunner.isAdministrator()).thenReturn(false); - when(mockPackrat4Gunner.getPrimaryRole()).thenReturn(PersonnelRole.VEHICLE_GUNNER); - when(mockPackrat4Gunner.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat4Gunner).getStatus(); - when(mockPackrat4Gunner.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockPackrat4Gunner); - when(mockPackrat4Tech.isAdministrator()).thenReturn(false); - when(mockPackrat4Tech.isTech()).thenReturn(true); - when(mockPackrat4Tech.getPrimaryRole()).thenReturn(PersonnelRole.MECHANIC); - when(mockPackrat4Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockPackrat4Tech).getStatus(); - when(mockPackrat4Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockPackrat4Tech.getSkill(SkillType.S_TECH_MECHANIC)).thenReturn(mockVeeTechSkill); - personnelList.add(mockPackrat4Tech); - mockPackratUnit4.addPilotOrSoldier(mockPackrat4Driver); - mockPackratUnit4.addPilotOrSoldier(mockPackrat4Gunner); - ArrayList crew = new ArrayList<>(2); - crew.add(mockPackrat4Driver); - crew.add(mockPackrat4Gunner); - when(mockPackratUnit4.getCrew()).thenReturn(crew); - Crew mockPackrat4Crew = mock(Crew.class); - doReturn(mockTankPilot.getLevel()).when(mockPackrat4Crew).getPiloting(); - doReturn(mockTankGunnery.getLevel()).when(mockPackrat4Crew).getGunnery(); - when(mockPackrat4.getCrew()).thenReturn(mockPackrat4Crew); - return 6; // astechs needed for Packrat4 - } - - private void mockLaserPlatoon() { - infantryPersonnel = new HashSet<>(28); - mockLaserPlatoon = mock(Infantry.class); - mockLaserPlatoonUnit = mock(Unit.class); - - when(mockLaserPlatoon.getEntityType()).thenReturn(Entity.ETYPE_INFANTRY); - when(mockLaserPlatoon.getUnitType()).thenCallRealMethod(); - when(mockLaserPlatoon.getSquadSize()).thenReturn(7); - when(mockLaserPlatoon.getSquadCount()).thenReturn(4); - when(mockLaserPlatoonUnit.getEntity()).thenReturn(mockLaserPlatoon); - ArrayList crew = new ArrayList<>(28); - for (int i = 0; i < 28; i++) { - Person mockInfantry = mock(Person.class); - when(mockInfantry.isAdministrator()).thenReturn(false); - when(mockInfantry.getPrimaryRole()).thenReturn(PersonnelRole.SOLDIER); - when(mockInfantry.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockInfantry).getStatus(); - when(mockInfantry.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockInfantry.getSkill(SkillType.S_SMALL_ARMS)).thenReturn(mockInfantryGunnery); - infantryPersonnel.add(mockInfantry); - mockLaserPlatoonUnit.addPilotOrSoldier(mockInfantry); - crew.add(mockInfantry); - } - when(mockLaserPlatoonUnit.getCrew()).thenReturn(crew); - Crew mockLaserPlatoonCrew = mock(Crew.class); - doReturn(mockInfantryGunnery.getLevel()).when(mockLaserPlatoonCrew).getGunnery(); - when(mockLaserPlatoon.getCrew()).thenReturn(mockLaserPlatoonCrew); - personnelList.addAll(infantryPersonnel); - } - - private int mockCorsair1() { - mockCorsair1 = mock(AeroSpaceFighter.class); - mockCorsairUnit1 = mock(Unit.class); - mockCorsair1Pilot = mock(Person.class); - mockCorsair1Tech = mock(Person.class); - - when(mockCorsair1.getEntityType()).thenReturn(Entity.ETYPE_AEROSPACEFIGHTER); - when(mockCorsair1.getUnitType()).thenCallRealMethod(); - when(mockCorsairUnit1.getEntity()).thenReturn(mockCorsair1); - when(mockCorsair1Pilot.isAdministrator()).thenReturn(false); - when(mockCorsair1Pilot.getSkill(SkillType.S_GUN_AERO)).thenReturn(mockAeroGunnery); - when(mockCorsair1Pilot.getSkill(SkillType.S_PILOT_AERO)).thenReturn(mockAeroPilot); - when(mockCorsair1Pilot.getPrimaryRole()).thenReturn(PersonnelRole.AEROSPACE_PILOT); - when(mockCorsair1Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCorsair1Pilot).getStatus(); - when(mockCorsair1Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockCorsair1Pilot); - mockCorsairUnit1.addPilotOrSoldier(mockCorsair1Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockCorsair1Pilot); - when(mockCorsairUnit1.getCrew()).thenReturn(crew); - when(mockCorsair1Tech.isAdministrator()).thenReturn(false); - when(mockCorsair1Tech.isTech()).thenReturn(true); - when(mockCorsair1Tech.getPrimaryRole()).thenReturn(PersonnelRole.AERO_TECH); - when(mockCorsair1Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCorsair1Tech).getStatus(); - when(mockCorsair1Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockCorsair1Tech.getSkill(SkillType.S_TECH_AERO)).thenReturn(mockFighterTechSkill); - personnelList.add(mockCorsair1Tech); - Crew mockCorsair1Crew = mock(Crew.class); - doReturn(mockAeroPilot.getLevel()).when(mockCorsair1Crew).getPiloting(); - doReturn(mockAeroGunnery.getLevel()).when(mockCorsair1Crew).getGunnery(); - when(mockCorsair1.getCrew()).thenReturn(mockCorsair1Crew); - return 6; // astechs for Corsair1 - } - - private int mockCorsair2() { - mockCorsair2 = mock(AeroSpaceFighter.class); - mockCorsairUnit2 = mock(Unit.class); - mockCorsair2Pilot = mock(Person.class); - mockCorsair2Tech = mock(Person.class); - - when(mockCorsair2.getEntityType()).thenReturn(Entity.ETYPE_AEROSPACEFIGHTER); - when(mockCorsair2.getUnitType()).thenCallRealMethod(); - when(mockCorsairUnit2.getEntity()).thenReturn(mockCorsair2); - when(mockCorsair2Pilot.isAdministrator()).thenReturn(false); - when(mockCorsair2Pilot.getSkill(SkillType.S_GUN_AERO)).thenReturn(mockAeroGunnery); - when(mockCorsair2Pilot.getSkill(SkillType.S_PILOT_AERO)).thenReturn(mockAeroPilot); - when(mockCorsair2Pilot.getPrimaryRole()).thenReturn(PersonnelRole.AEROSPACE_PILOT); - when(mockCorsair2Pilot.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCorsair2Pilot).getStatus(); - when(mockCorsair2Pilot.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - personnelList.add(mockCorsair2Pilot); - mockCorsairUnit2.addPilotOrSoldier(mockCorsair2Pilot); - ArrayList crew = new ArrayList<>(1); - crew.add(mockCorsair2Pilot); - when(mockCorsairUnit2.getCrew()).thenReturn(crew); - when(mockCorsair2Tech.isAdministrator()).thenReturn(false); - when(mockCorsair2Tech.isTech()).thenReturn(true); - when(mockCorsair2Tech.getPrimaryRole()).thenReturn(PersonnelRole.AERO_TECH); - when(mockCorsair2Tech.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCorsair2Tech).getStatus(); - when(mockCorsair2Tech.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - when(mockCorsair2Tech.getSkill(SkillType.S_TECH_AERO)).thenReturn(mockFighterTechSkillElite); - personnelList.add(mockCorsair2Tech); - Crew mockCorsair2Crew = mock(Crew.class); - doReturn(mockAeroPilot.getLevel()).when(mockCorsair2Crew).getPiloting(); - doReturn(mockAeroGunnery.getLevel()).when(mockCorsair2Crew).getGunnery(); - when(mockCorsair2.getCrew()).thenReturn(mockCorsair2Crew); - return 6; // astechs for Corsair1 - } - - private void mockSeeker() { - seekerCrew = new HashSet<>(20); - mockSeeker = mock(Dropship.class); - mockSeekerUnit = mock(Unit.class); - - when(mockSeeker.getEntityType()).thenReturn(Entity.ETYPE_DROPSHIP); - when(mockSeeker.getUnitType()).thenCallRealMethod(); - when(mockSeekerUnit.getEntity()).thenReturn(mockSeeker); - Vector bayList = new Vector<>(); - Bay transportBay = new MechBay(4, 1, 1); - bayList.add(transportBay); - transportBay = new ASFBay(2, 0, 2); - bayList.add(transportBay); - transportBay = new LightVehicleBay(22, 0, 3); - bayList.add(transportBay); - transportBay = new InfantryBay(4.0, 0, 4, PlatoonType.FOOT); - bayList.add(transportBay); - when(mockSeeker.getTransportBays()).thenReturn(bayList); - ArrayList crew = new ArrayList<>(20); - for (int i = 0; i < 20; i++) { - Person mockCrew = mock(Person.class); - when(mockCrew.isAdministrator()).thenReturn(false); - when(mockCrew.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCrew).getStatus(); - when(mockCrew.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - if (i == 0) { - when(mockCrew.getPrimaryRole()).thenReturn(PersonnelRole.VESSEL_PILOT); - when(mockCrew.getSkill(SkillType.S_PILOT_SPACE)).thenReturn(mockDropPilot); - } else { - when(mockCrew.getPrimaryRole()).thenReturn(PersonnelRole.VESSEL_GUNNER); - when(mockCrew.getSkill(SkillType.S_GUN_SPACE)).thenReturn(mockDropGunnery); - } - seekerCrew.add(mockCrew); - mockSeekerUnit.addPilotOrSoldier(mockCrew); - crew.add(mockCrew); - } - personnelList.addAll(seekerCrew); - when(mockSeekerUnit.getCrew()).thenReturn(crew); - when(mockSeekerUnit.getActiveCrew()).thenReturn(crew); - when(mockSeekerUnit.getFullCrewSize()).thenReturn(20); - Crew mockSeekerCrew = mock(Crew.class); - doReturn(mockDropPilot.getLevel()).when(mockSeekerCrew).getPiloting(); - doReturn(mockDropGunnery.getLevel()).when(mockSeekerCrew).getGunnery(); - when(mockSeeker.getCrew()).thenReturn(mockSeekerCrew); - } - - private void mockInvader() { - invaderCrew = new HashSet<>(24); - mockInvader = mock(Jumpship.class); - mockInvaderUnit = mock(Unit.class); - - when(mockInvader.getEntityType()).thenReturn(Entity.ETYPE_JUMPSHIP); - when(mockInvader.getUnitType()).thenCallRealMethod(); - when(mockInvaderUnit.getEntity()).thenReturn(mockInvader); - DockingCollar collar; - Vector collarList = new Vector<>(4); - for (int i = 0; i < 4; i++) { - collar = mock(DockingCollar.class); - collarList.add(collar); - } - when(mockInvader.getTransportBays()).thenReturn(new Vector<>(0)); - when(mockInvader.getDockingCollars()).thenReturn(collarList); - ArrayList crew = new ArrayList<>(24); - for (int i = 0; i < 24; i++) { - Person mockCrew = mock(Person.class); - when(mockCrew.isAdministrator()).thenReturn(false); - when(mockCrew.getSecondaryRole()).thenReturn(PersonnelRole.NONE); - doReturn(PersonnelStatus.ACTIVE).when(mockCrew).getStatus(); - when(mockCrew.getPrisonerStatus()).thenReturn(PrisonerStatus.FREE); - if (i == 0) { - when(mockCrew.getPrimaryRole()).thenReturn(PersonnelRole.VESSEL_PILOT); - when(mockCrew.getSkill(SkillType.S_PILOT_SPACE)).thenReturn(mockJumpPilot); - } else { - when(mockCrew.getPrimaryRole()).thenReturn(PersonnelRole.VESSEL_GUNNER); - when(mockCrew.getSkill(SkillType.S_GUN_SPACE)).thenReturn(mockJumpGunnery); - } - invaderCrew.add(mockCrew); - mockInvaderUnit.addPilotOrSoldier(mockCrew); - crew.add(mockCrew); - } - personnelList.addAll(invaderCrew); - when(mockInvaderUnit.getCrew()).thenReturn(crew); - when(mockInvaderUnit.getActiveCrew()).thenReturn(crew); - when(mockInvaderUnit.getFullCrewSize()).thenReturn(24); - Crew mockInvaderCrew = mock(Crew.class); - doReturn(mockJumpPilot.getLevel()).when(mockInvaderCrew).getPiloting(); - doReturn(mockJumpGunnery.getLevel()).when(mockInvaderCrew).getGunnery(); - when(mockInvader.getCrew()).thenReturn(mockInvaderCrew); - } -}