From 02b7023e03f921ec06430d3a3bfbf3fd4d06f12d Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 12:39:11 -0500 Subject: [PATCH 01/16] Add the ability to swap out instances of static classes --- MekHQ/src/mekhq/campaign/Campaign.java | 3 +- .../againstTheBot/AtBConfiguration.java | 3 +- .../campaign/finances/CurrencyManager.java | 5 +- .../mekhq/campaign/market/ContractMarket.java | 29 +-- .../src/mekhq/campaign/market/UnitMarket.java | 3 +- .../mekhq/campaign/mission/AtBContract.java | 19 +- .../mission/AtBDynamicScenarioFactory.java | 13 +- .../mekhq/campaign/mission/AtBScenario.java | 4 +- .../atb/AtBScenarioModifierApplicator.java | 4 +- .../src/mekhq/campaign/personnel/Person.java | 5 +- .../universe/DefaultFactionSelector.java | 2 +- .../src/mekhq/campaign/universe/Faction.java | 166 +------------ .../universe/FactionBorderTracker.java | 2 +- .../mekhq/campaign/universe/FactionHints.java | 16 +- .../src/mekhq/campaign/universe/Factions.java | 229 ++++++++++++++++++ MekHQ/src/mekhq/campaign/universe/Planet.java | 16 +- .../campaign/universe/PlanetarySystem.java | 2 +- .../universe/RATGeneratorConnector.java | 4 +- .../mekhq/campaign/universe/RATManager.java | 2 +- .../universe/RandomFactionGenerator.java | 47 ++-- .../universe/RangedFactionSelector.java | 4 +- .../src/mekhq/campaign/universe/Systems.java | 8 +- .../universe/UnitGeneratorParameters.java | 2 +- MekHQ/src/mekhq/gui/FactionComboBox.java | 4 +- MekHQ/src/mekhq/gui/InterstellarMapPanel.java | 3 +- .../gui/dialog/CampaignOptionsDialog.java | 11 +- .../gui/dialog/ChooseFactionsDialog.java | 3 +- .../gui/dialog/ContractMarketDialog.java | 6 +- .../dialog/CustomizeAtBContractDialog.java | 6 +- .../gui/dialog/CustomizePersonDialog.java | 3 +- .../mekhq/gui/dialog/DataLoadingDialog.java | 4 +- MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java | 3 +- .../gui/dialog/NewPlanetaryEventDialog.java | 3 +- .../mekhq/module/atb/AtBEventProcessor.java | 12 +- 34 files changed, 360 insertions(+), 286 deletions(-) create mode 100644 MekHQ/src/mekhq/campaign/universe/Factions.java diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index b890653431..aaa7d480df 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -138,6 +138,7 @@ import mekhq.campaign.universe.DefaultPlanetSelector; import mekhq.campaign.universe.Era; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.IUnitGenerator; import mekhq.campaign.universe.News; import mekhq.campaign.universe.NewsItem; @@ -3898,7 +3899,7 @@ public void setGMMode(boolean b) { } public Faction getFaction() { - return Faction.getFaction(factionCode); + return Factions.getInstance().getFaction(factionCode); } public String getFactionName() { diff --git a/MekHQ/src/mekhq/campaign/againstTheBot/AtBConfiguration.java b/MekHQ/src/mekhq/campaign/againstTheBot/AtBConfiguration.java index 10b6c36bcd..5a8abbe3fe 100644 --- a/MekHQ/src/mekhq/campaign/againstTheBot/AtBConfiguration.java +++ b/MekHQ/src/mekhq/campaign/againstTheBot/AtBConfiguration.java @@ -54,6 +54,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; /** * @author Neoancient @@ -291,7 +292,7 @@ public static int decodeWeightStr(String s, int i) { public static String getParentFactionType(String factionCode) { String org = AtBConfiguration.ORG_IS; - Faction faction = Faction.getFaction(factionCode); + Faction faction = Factions.getInstance().getFaction(factionCode); if (faction.isComStar()) { org = AtBConfiguration.ORG_CS; diff --git a/MekHQ/src/mekhq/campaign/finances/CurrencyManager.java b/MekHQ/src/mekhq/campaign/finances/CurrencyManager.java index 5a6c1cb7d6..659e8d850e 100644 --- a/MekHQ/src/mekhq/campaign/finances/CurrencyManager.java +++ b/MekHQ/src/mekhq/campaign/finances/CurrencyManager.java @@ -26,6 +26,7 @@ import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.Contract; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.PlanetarySystem; import org.joda.money.CurrencyUnitDataProvider; @@ -170,7 +171,7 @@ synchronized Currency getDefaultCurrency() { for (Contract contract : this.campaign.getActiveContracts()) { if (contract instanceof AtBContract) { Currency currency = possibleCurrencies.getOrDefault( - Faction.getFaction(((AtBContract)contract).getEmployerCode()).getCurrencyCode(), + Factions.getInstance().getFaction(((AtBContract)contract).getEmployerCode()).getCurrencyCode(), null); if (currency != null) { @@ -253,7 +254,7 @@ protected void registerCurrencies() { // Adjust the currency start and end dates if needed by the // start/end dates of the factions that use it - for (Faction faction : Faction.getFactions()) { + for (Faction faction : Factions.getInstance().getFactions()) { if (faction.getCurrencyCode().equals(code)) { if (faction.getStartYear() < startYear) { startYear = faction.getStartYear(); diff --git a/MekHQ/src/mekhq/campaign/market/ContractMarket.java b/MekHQ/src/mekhq/campaign/market/ContractMarket.java index c31bd8f29a..2896720293 100644 --- a/MekHQ/src/mekhq/campaign/market/ContractMarket.java +++ b/MekHQ/src/mekhq/campaign/market/ContractMarket.java @@ -47,6 +47,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.PlanetarySystem; import mekhq.campaign.universe.RandomFactionGenerator; import mekhq.campaign.universe.Systems; @@ -356,7 +357,7 @@ private void checkForSubcontracts(Campaign campaign, AtBContract contract, int u contract.setEmployerCode(employer, campaign.getGameYear()); contract.setMissionType(findAtBMissionType(unitRatingMod, RandomFactionGenerator.getInstance().getFactionHints() - .isISMajorPower(Faction.getFaction(contract.getEmployerCode())))); + .isISMajorPower(Factions.getInstance().getFaction(contract.getEmployerCode())))); if (contract.getMissionType() == AtBContract.MT_PIRATEHUNTING) { contract.setEnemyCode("PIR"); @@ -374,9 +375,9 @@ private void checkForSubcontracts(Campaign campaign, AtBContract contract, int u * (ComStar, Mercs not under contract) are more likely to have garrison-type * contracts and less likely to have battle-type contracts unless at war. */ - if (RandomFactionGenerator.getInstance().getFactionHints().isNeutral(Faction.getFaction(employer)) && - !RandomFactionGenerator.getInstance().getFactionHints().isAtWarWith(Faction.getFaction(employer), - Faction.getFaction(contract.getEnemyCode()), campaign.getLocalDate())) { + if (RandomFactionGenerator.getInstance().getFactionHints().isNeutral(Factions.getInstance().getFaction(employer)) && + !RandomFactionGenerator.getInstance().getFactionHints().isAtWarWith(Factions.getInstance().getFaction(employer), + Factions.getInstance().getFaction(contract.getEnemyCode()), campaign.getLocalDate())) { if (contract.getMissionType() == AtBContract.MT_PLANETARYASSAULT) { contract.setMissionType(AtBContract.MT_GARRISONDUTY); } else if (contract.getMissionType() == AtBContract.MT_RELIEFDUTY) { @@ -430,9 +431,9 @@ private void checkForSubcontracts(Campaign campaign, AtBContract contract, int u contract.calculateContract(campaign); //Ralgith had a version of this then the PR got added. Commenting this Out. -/* contract.setName(Faction.getFaction(employer).getShortName() + "-" + String.format("%1$tY%1$tm", contract.getStartDate()) +/* contract.setName(Factions.getInstance().getFaction(employer).getShortName() + "-" + String.format("%1$tY%1$tm", contract.getStartDate()) + "-" + AtBContract.missionTypeNames[contract.getMissionType()] - + "-" + Faction.getFaction(contract.getEnemyCode()).getShortName() + + "-" + Factions.getInstance().getFaction(contract.getEnemyCode()).getShortName() + "-" + contract.getLength());*/ return contract; @@ -444,7 +445,7 @@ protected AtBContract generateAtBSubcontract(Campaign campaign, contract.setEmployerCode(parent.getEmployerCode(), campaign.getGameYear()); contract.setMissionType(findAtBMissionType(unitRatingMod, RandomFactionGenerator.getInstance().getFactionHints() - .isISMajorPower(Faction.getFaction(contract.getEmployerCode())))); + .isISMajorPower(Factions.getInstance().getFaction(contract.getEmployerCode())))); if (contract.getMissionType() == AtBContract.MT_PIRATEHUNTING) contract.setEnemyCode("PIR"); @@ -612,13 +613,13 @@ public void setAllyRating(AtBContract contract, boolean isAttacker, int year) { if (contract.getMissionType() == AtBContract.MT_PLANETARYASSAULT) { mod += 1; } - if (Faction.getFaction(contract.getEmployerCode()).isClan() && !isAttacker) { + if (Factions.getInstance().getFaction(contract.getEmployerCode()).isClan() && !isAttacker) { //facing front-line units mod += 1; } contract.setAllySkill(getSkillRating(Compute.d6(2) + mod)); if (year > 2950 && year < 3039 && - !Faction.getFaction(contract.getEmployerCode()).isClan()) { + !Factions.getInstance().getFaction(contract.getEmployerCode()).isClan()) { mod -= 1; } contract.setAllyQuality(getQualityRating(Compute.d6(2) + mod)); @@ -639,12 +640,12 @@ public void setEnemyRating(AtBContract contract, boolean isAttacker, int year) { if (AtBContract.isMinorPower(contract.getEmployerCode())) { mod -= 1; } - if (Faction.getFaction(contract.getEmployerCode()).isClan()) { + if (Factions.getInstance().getFaction(contract.getEmployerCode()).isClan()) { mod += isAttacker?2:4; } contract.setEnemySkill(getSkillRating(Compute.d6(2) + mod)); if (year > 2950 && year < 3039 && - !Faction.getFaction(contract.getEnemyCode()).isClan()) { + !Factions.getInstance().getFaction(contract.getEnemyCode()).isClan()) { mod -= 1; } contract.setEnemyQuality(getQualityRating(Compute.d6(2) + mod)); @@ -718,8 +719,8 @@ protected void setAtBContractClauses(AtBContract contract, int unitRatingMod, Ca mods.mods[Compute.randomInt(4)] -= 1; } - if (Faction.getFaction(contract.getEnemyCode()).isClan() && - !Faction.getFaction(contract.getEmployerCode()).isClan()) { + if (Factions.getInstance().getFaction(contract.getEnemyCode()).isClan() && + !Factions.getInstance().getFaction(contract.getEmployerCode()).isClan()) { for (int i = 0; i < 4; i++) if (i == CLAUSE_SALVAGE) mods.mods[i] -= 2; else mods.mods[i] += 1; @@ -740,7 +741,7 @@ protected void setAtBContractClauses(AtBContract contract, int unitRatingMod, Ca } if (RandomFactionGenerator.getInstance().getFactionHints() - .isISMajorPower(Faction.getFaction(contract.getEmployerCode()))) { + .isISMajorPower(Factions.getInstance().getFaction(contract.getEmployerCode()))) { mods.mods[CLAUSE_SALVAGE] += -1; mods.mods[CLAUSE_TRANSPORT] += 1; } diff --git a/MekHQ/src/mekhq/campaign/market/UnitMarket.java b/MekHQ/src/mekhq/campaign/market/UnitMarket.java index 235c49dafd..6dd4627a47 100644 --- a/MekHQ/src/mekhq/campaign/market/UnitMarket.java +++ b/MekHQ/src/mekhq/campaign/market/UnitMarket.java @@ -46,6 +46,7 @@ import mekhq.campaign.mission.Mission; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.IUnitGenerator; import mekhq.campaign.universe.RandomFactionGenerator; import mekhq.campaign.universe.UnitGeneratorParameters; @@ -136,7 +137,7 @@ public void generateUnitOffers(Campaign campaign) { if (campaign.getUnitRatingMod() >= IUnitRating.DRAGOON_B) { Set factions = campaign.getCurrentSystem().getFactionSet(campaign.getLocalDate()); String faction = Utilities.getRandomItem(factions).getShortName(); - if (campaign.getFaction().isClan() || !Faction.getFaction(faction).isClan()) { + if (campaign.getFaction().isClan() || !Factions.getInstance().getFaction(faction).isClan()) { addOffers(campaign, Compute.d6() - 3, UnitMarketType.FACTORY, UnitType.MEK, faction, IUnitRating.DRAGOON_A, 6); addOffers(campaign, Compute.d6() - 2, UnitMarketType.FACTORY, UnitType.TANK, diff --git a/MekHQ/src/mekhq/campaign/mission/AtBContract.java b/MekHQ/src/mekhq/campaign/mission/AtBContract.java index cbe3391f1c..1b089df6be 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBContract.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBContract.java @@ -53,6 +53,7 @@ import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.RandomFactionGenerator; /** @@ -340,7 +341,7 @@ public static int getEffectiveNumUnits(Campaign campaign) { } public static boolean isMinorPower(String fName) { - Faction faction = Faction.getFaction(fName); + Faction faction = Factions.getInstance().getFaction(fName); if (null != faction) { return !RandomFactionGenerator.getInstance().getFactionHints().isISMajorPower(faction) && !faction.isClan(); @@ -397,7 +398,7 @@ public void calculatePaymentMultiplier(Campaign campaign) { break; } - Faction employer = Faction.getFaction(employerCode); + Faction employer = Factions.getInstance().getFaction(employerCode); if ((null != employer) && (RandomFactionGenerator.getInstance().getFactionHints().isISMajorPower(employer) || employer.isClan())) { @@ -494,7 +495,7 @@ public void checkMorale(LocalDate today, int dragoonRating) { isMinorPower(enemyCode) || enemyCode.equals("MERC")) { mod -= 1; - } else if (Faction.getFaction(enemyCode).isClan()) { + } else if (Factions.getInstance().getFaction(enemyCode).isClan()) { mod += 2; } @@ -1021,8 +1022,8 @@ public int findBigBattleType() { public boolean contractExtended (Campaign campaign) { if ((getMissionType() != MT_PIRATEHUNTING) && (getMissionType() != MT_RIOTDUTY)) { String warName = RandomFactionGenerator.getInstance() - .getFactionHints().getCurrentWar(Faction.getFaction(getEmployerCode()), - Faction.getFaction(getEnemyCode()), campaign.getLocalDate()); + .getFactionHints().getCurrentWar(Factions.getInstance().getFaction(getEmployerCode()), + Factions.getInstance().getFaction(getEnemyCode()), campaign.getLocalDate()); if (null != warName) { int extension = 0; int roll = Compute.d6(); @@ -1313,9 +1314,9 @@ public void setEmployerCode(String code, int year) { public String getEmployerName(int year) { if (mercSubcontract) { return "Mercenary (" + - Faction.getFaction(employerCode).getFullName(year) + ")"; + Factions.getInstance().getFaction(employerCode).getFullName(year) + ")"; } - return Faction.getFaction(employerCode).getFullName(year); + return Factions.getInstance().getFaction(employerCode).getFullName(year); } public String getEnemyCode() { @@ -1323,7 +1324,7 @@ public String getEnemyCode() { } public String getEnemyName(int year) { - return Faction.getFaction(enemyCode).getFullName(year); + return Factions.getInstance().getFaction(enemyCode).getFullName(year); } public void setEnemyCode(String enemyCode) { @@ -1566,7 +1567,7 @@ public AtBContract(Contract c, Campaign campaign) { missionType = MT_PLANETARYASSAULT; } } - Faction f = Faction.getFactionFromFullNameAndYear(c.getEmployer(), campaign.getGameYear()); + Faction f = Factions.getInstance().getFactionFromFullNameAndYear(c.getEmployer(), campaign.getGameYear()); if (null == f) { employerCode = "IND"; } else { diff --git a/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java index 12234c086c..a1562cd85f 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBDynamicScenarioFactory.java @@ -79,6 +79,7 @@ import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.Era; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Faction.Tag; import mekhq.campaign.universe.IUnitGenerator; import mekhq.campaign.universe.Planet; @@ -1164,7 +1165,7 @@ public static List generateBAForNova(AtBScenario scenario, List // if yes, then pick the fastest mech and load it up, adding the generated BA to the transport relationships. // non-clan forces and units that aren't stars don't become novas - if (!Faction.getFaction(factionCode).isClan() && (starUnits.size() != 5)) { + if (!Factions.getInstance().getFaction(factionCode).isClan() && (starUnits.size() != 5)) { return transportedUnits; } @@ -1290,7 +1291,7 @@ public static Entity createEntityWithCrew(String factionCode, int skill, Campaig en.setOwner(campaign.getPlayer()); en.setGame(campaign.getGame()); - Faction faction = Faction.getFaction(factionCode); + Faction faction = Factions.getInstance().getFaction(factionCode); RandomNameGenerator rng = RandomNameGenerator.getInstance(); rng.setChosenFaction(faction.getNameGenerator()); @@ -1446,7 +1447,7 @@ private static List generateUnitTypes(int unitTypeCode, int unitCount, int actualUnitType = unitTypeCode; if (unitTypeCode == ScenarioForceTemplate.SPECIAL_UNIT_TYPE_ATB_MIX) { - Faction faction = Faction.getFaction(factionCode); + Faction faction = Factions.getInstance().getFaction(factionCode); // "AtB Mix" will skip vehicles if the "use vehicles" checkbox is turned off // or if the faction is clan and "clan opfors use vehicles" is turned off @@ -1544,7 +1545,7 @@ private static List generateClanUnitTypes(int unitCount, int forceQuali * @return Unit weight string. */ private static String generateUnitWeights(List unitTypes, String faction, int weightClass, int maxWeight, int minWeight, Campaign campaign) { - Faction genFaction = Faction.getFaction(faction); + Faction genFaction = Factions.getInstance().getFaction(faction); String factionWeightString = AtBConfiguration.ORG_IS; if (genFaction.isClan() || faction.equals("MH")) { factionWeightString = AtBConfiguration.ORG_CLAN; @@ -2219,7 +2220,7 @@ private static void setScenarioRerolls(AtBDynamicScenario scenario, Campaign cam * @return "Lance" size. */ public static int getLanceSize(String factionCode) { - Faction faction = Faction.getFaction(factionCode); + Faction faction = Factions.getInstance().getFaction(factionCode); if (faction != null) { // clans and marian hegemony use a fundamental unit size of 5. if (faction.isClan() || factionCode.equals("MH")) { @@ -2344,7 +2345,7 @@ private static String getPlanetOwnerFaction(AtBContract contract, LocalDate curr List planetFactions = contract.getSystem().getFactions(currentDate); if (planetFactions != null && !planetFactions.isEmpty()) { factionCode = planetFactions.get(0); - Faction ownerFaction = Faction.getFaction(factionCode); + Faction ownerFaction = Factions.getInstance().getFaction(factionCode); if (ownerFaction.is(Tag.ABANDONED)) { factionCode = "MERC"; diff --git a/MekHQ/src/mekhq/campaign/mission/AtBScenario.java b/MekHQ/src/mekhq/campaign/mission/AtBScenario.java index 3efb209e64..fa643e9d76 100644 --- a/MekHQ/src/mekhq/campaign/mission/AtBScenario.java +++ b/MekHQ/src/mekhq/campaign/mission/AtBScenario.java @@ -59,7 +59,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.unit.Unit; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Planet; import mekhq.campaign.universe.PlanetarySystem; import mekhq.campaign.universe.Systems; @@ -1038,7 +1038,7 @@ protected void addLance(List list, String faction, */ private void addLance(List list, String faction, int skill, int quality, int weightClass, int maxWeight, Campaign campaign, int arrivalTurn) { - if (Faction.getFaction(faction).isClan()) { + if (Factions.getInstance().getFaction(faction).isClan()) { addStar(list, faction, skill, quality, weightClass, maxWeight, campaign, arrivalTurn); return; } diff --git a/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioModifierApplicator.java b/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioModifierApplicator.java index 9680dd72b5..cb53eb1084 100644 --- a/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioModifierApplicator.java +++ b/MekHQ/src/mekhq/campaign/mission/atb/AtBScenarioModifierApplicator.java @@ -42,7 +42,7 @@ import mekhq.campaign.personnel.SkillType; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.unit.Unit; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; public class AtBScenarioModifierApplicator { @@ -191,7 +191,7 @@ public static void adjustSkill(AtBDynamicScenario scenario, Campaign campaign, rsg.setMethod(RandomSkillsGenerator.M_TAHARQA); rsg.setLevel(adjustedSkill); - if (Faction.getFaction(scenario.getContract(campaign).getEnemyCode()).isClan()) { + if (Factions.getInstance().getFaction(scenario.getContract(campaign).getEnemyCode()).isClan()) { rsg.setType(RandomSkillsGenerator.T_CLAN); } diff --git a/MekHQ/src/mekhq/campaign/personnel/Person.java b/MekHQ/src/mekhq/campaign/personnel/Person.java index 51d87a238b..bdb45e0a33 100644 --- a/MekHQ/src/mekhq/campaign/personnel/Person.java +++ b/MekHQ/src/mekhq/campaign/personnel/Person.java @@ -63,6 +63,7 @@ import mekhq.campaign.unit.Unit; import mekhq.campaign.work.IPartWork; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Planet; /** @@ -343,7 +344,7 @@ public Person(String givenName, String surname, String honorific, Campaign campa secondaryDesignator = ROMDesignation.NONE; commander = false; dependent = false; - originFaction = Faction.getFaction(factionCode); + originFaction = Factions.getInstance().getFaction(factionCode); originPlanet = null; clan = originFaction.isClan(); phenotype = Phenotype.NONE; @@ -1928,7 +1929,7 @@ public static Person generateInstanceFromXML(Node wn, Campaign c, Version versio } else if (wn2.getNodeName().equalsIgnoreCase("dependent")) { retVal.dependent = Boolean.parseBoolean(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("faction")) { - retVal.originFaction = Faction.getFaction(wn2.getTextContent().trim()); + retVal.originFaction = Factions.getInstance().getFaction(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("planetId")) { String systemId = wn2.getAttributes().getNamedItem("systemId").getTextContent().trim(); String planetId = wn2.getTextContent().trim(); diff --git a/MekHQ/src/mekhq/campaign/universe/DefaultFactionSelector.java b/MekHQ/src/mekhq/campaign/universe/DefaultFactionSelector.java index 9e1ae5ad00..b2274a9c49 100644 --- a/MekHQ/src/mekhq/campaign/universe/DefaultFactionSelector.java +++ b/MekHQ/src/mekhq/campaign/universe/DefaultFactionSelector.java @@ -45,7 +45,7 @@ public DefaultFactionSelector(String factionCode) { @Override public Faction selectFaction(Campaign campaign) { if (factionCode != null) { - return Faction.getFaction(factionCode); + return Factions.getInstance().getFaction(factionCode); } else { return campaign.getFaction(); } diff --git a/MekHQ/src/mekhq/campaign/universe/Faction.java b/MekHQ/src/mekhq/campaign/universe/Faction.java index eb99b6c77c..e40d8bed50 100644 --- a/MekHQ/src/mekhq/campaign/universe/Faction.java +++ b/MekHQ/src/mekhq/campaign/universe/Faction.java @@ -22,14 +22,12 @@ package mekhq.campaign.universe; import java.awt.Color; -import java.io.FileInputStream; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -37,16 +35,10 @@ import java.util.Set; import java.util.TreeMap; -import javax.xml.parsers.DocumentBuilder; - import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import megamek.client.ratgenerator.FactionRecord; -import megamek.client.ratgenerator.RATGenerator; import megamek.common.EquipmentType; import mekhq.MekHQ; import mekhq.MekHqXmlUtil; @@ -59,10 +51,6 @@ * @author Jay Lawson */ public class Faction { - private static Map factions; - private static Map factionIdMap; - private static List choosableFactionCodes = Collections.singletonList("MERC"); - private String shortName; private String fullName; private NavigableMap nameChanges = new TreeMap<>(); @@ -95,16 +83,6 @@ public Faction(String shortName, String fullName) { end = 9999; } - public static List getChoosableFactionCodes() { - return choosableFactionCodes; - } - - public static void setChoosableFactionCodes(String... choosableFactionCodes) { - if (choosableFactionCodes.length > 0) { - Faction.choosableFactionCodes = Arrays.asList(choosableFactionCodes); - } - } - public String getShortName() { return shortName; } @@ -265,75 +243,7 @@ public boolean hasName(String name) { return false; } - public static Collection getFactions() { - return factions.values(); - } - - public static Collection getFactionList() { - return new ArrayList<>(factions.keySet()); - } - - public static Faction getFaction(String sname) { - Faction defaultFaction = new Faction(); - if (factions == null) { - return defaultFaction; - } else { - return factions.getOrDefault(sname, defaultFaction); - } - } - - public static Faction getFactionFromFullName(String fname, int year) { - return getFactionFromFullNameAndYear(fname, year); - } - - public static Faction getFactionFromFullNameAndYear(String fname, int year) { - Faction faction = null; - for (Faction f : factions.values()) { - if (f.getFullName(year).equals(fname)) { - faction = f; - break; - } - } - return faction; - } - - /** - * Helper function that gets the faction record for the specified faction, or a fallback general faction record. - * Useful for RAT generator activity. - * @param faction The faction whose MegaMek faction record to retrieve. - * @return Found faction record or null. - */ - public static FactionRecord getFactionRecordOrFallback(String faction) { - FactionRecord fRec = RATGenerator.getInstance().getFaction(faction); - if (fRec == null) { - Faction f = Faction.getFaction(faction); - if (f != null) { - if (f.isPeriphery()) { - fRec = RATGenerator.getInstance().getFaction("Periphery"); - } else if (f.isClan()) { - fRec = RATGenerator.getInstance().getFaction("CLAN"); - } else { - fRec = RATGenerator.getInstance().getFaction("IS"); - } - } - - if (fRec == null) { - MekHQ.getLogger().error(RATGenerator.class, "getFactionRecordOrFallback", - "Could not locate faction record for " + faction); - } - } - - return fRec; - } - - public static String getFactionCode(int faction) { - Faction f = factionIdMap.get(faction); - return (null != f) ? f.getShortName() : "IND"; - } - public static Faction getFactionFromXML(Node wn) throws DOMException { - final String METHOD_NAME = "getFactionFromXML(Node)"; - Faction retVal = new Faction(); NodeList nl = wn.getChildNodes(); @@ -397,86 +307,12 @@ public static Faction getFactionFromXML(Node wn) throws DOMException { } if ((retVal.eraMods != null) && (retVal.eraMods.length < 9)) { - MekHQ.getLogger().warning(Faction.class, METHOD_NAME, - retVal.fullName + " faction did not have a long enough eraMods vector"); + MekHQ.getLogger().warning(retVal.fullName + " faction did not have a long enough eraMods vector"); } return retVal; } - public static void generateFactions() throws DOMException { - final String METHOD_NAME = "generateFactions()"; - - MekHQ.getLogger().info(Faction.class, METHOD_NAME, "Starting load of faction data from XML..."); - // Initialize variables. - factions = new HashMap<>(); - factionIdMap = new HashMap<>(); - - Document xmlDoc; - - try (FileInputStream fis = new FileInputStream("data/universe/factions.xml")) { - // Using factory get an instance of document builder - DocumentBuilder db = MekHqXmlUtil.newSafeDocumentBuilder(); - - // Parse using builder to get DOM representation of the XML file - xmlDoc = db.parse(fis); - } catch (Exception ex) { - MekHQ.getLogger().error(Faction.class, METHOD_NAME, ex); - return; - } - - Element factionEle = xmlDoc.getDocumentElement(); - NodeList nl = factionEle.getChildNodes(); - - // Get rid of empty text nodes and adjacent text nodes... - // Stupid weird parsing of XML. At least this cleans it up. - factionEle.normalize(); - - // Okay, lets iterate through the children, eh? - for (int x = 0; x < nl.getLength(); x++) { - Node wn = nl.item(x); - - if (!wn.getParentNode().equals(factionEle)) { - continue; - } - - int xc = wn.getNodeType(); - - if (xc == Node.ELEMENT_NODE) { - // This is what we really care about. - // All the meat of our document is in this node type, at this - // level. - // Okay, so what element is it? - String xn = wn.getNodeName(); - - if (xn.equalsIgnoreCase("faction")) { - Faction f = getFactionFromXML(wn); - if (!factions.containsKey(f.getShortName())) { - factions.put(f.getShortName(), f); - if (null != f.getId()) { - if (!factionIdMap.containsKey(f.getId())) { - factionIdMap.put(f.getId(), f); - } else { - MekHQ.getLogger().error(Faction.class, METHOD_NAME, - String.format("Faction id \"%d\" already used for faction %s, can't re-use it for %s", - f.getId(), factionIdMap.get(f.getId()).getFullName(0), - f.getFullName(0))); - } - } - } else { - MekHQ.getLogger().error(Faction.class, METHOD_NAME, - String.format("Faction code \"%s\" already used for faction %s, can't re-use it for %s", - f.getShortName(), factions.get(f.getShortName()).getFullName(0), f.getFullName(0))); - } - } else if (xn.equalsIgnoreCase("choosableFactionCodes")) { - setChoosableFactionCodes(wn.getTextContent().split(",")); - } - } - } - MekHQ.getLogger().info(Faction.class, METHOD_NAME, - "Loaded a total of " + factions.size() + " factions"); - } - /** @return Sorted list of faction names as one string */ public static String getFactionNames(Collection factions, int year) { if (null == factions) { diff --git a/MekHQ/src/mekhq/campaign/universe/FactionBorderTracker.java b/MekHQ/src/mekhq/campaign/universe/FactionBorderTracker.java index 416661e9dc..5ae473d8bc 100644 --- a/MekHQ/src/mekhq/campaign/universe/FactionBorderTracker.java +++ b/MekHQ/src/mekhq/campaign/universe/FactionBorderTracker.java @@ -249,7 +249,7 @@ public synchronized Set getFactionsInRegion() { Thread.currentThread().interrupt(); } } - Faction f = Faction.getFaction(fKey); + Faction f = Factions.getInstance().getFaction(fKey); if (null != f) { return borders.get(f); } diff --git a/MekHQ/src/mekhq/campaign/universe/FactionHints.java b/MekHQ/src/mekhq/campaign/universe/FactionHints.java index 48009b79ab..f204017974 100644 --- a/MekHQ/src/mekhq/campaign/universe/FactionHints.java +++ b/MekHQ/src/mekhq/campaign/universe/FactionHints.java @@ -478,7 +478,7 @@ private void loadFactionHints() throws DOMException, ParseException { if (nodeName.equals("neutral")) { String fKey = wn.getAttributes().getNamedItem("faction").getTextContent().trim(); - Faction f = Faction.getFaction(fKey); + Faction f = Factions.getInstance().getFaction(fKey); if (null != f) { neutralFactions.add(f); addNeutralExceptions(f, wn); @@ -488,7 +488,7 @@ private void loadFactionHints() throws DOMException, ParseException { } } else if (nodeName.equals("deepPeriphery")) { for (String fKey : wn.getTextContent().trim().split(",")) { - Faction f = Faction.getFaction(fKey); + Faction f = Factions.getInstance().getFaction(fKey); if (null != f) { deepPeriphery.add(f); } else { @@ -498,7 +498,7 @@ private void loadFactionHints() throws DOMException, ParseException { } } else if (nodeName.equals("majorPowers")) { for (String fKey : wn.getTextContent().trim().split(",")) { - Faction f = Faction.getFaction(fKey); + Faction f = Factions.getInstance().getFaction(fKey); if (null != f) { majorPowers.add(f); } else { @@ -528,15 +528,15 @@ private void loadFactionHints() throws DOMException, ParseException { for (int j = 0; j < wn.getChildNodes().getLength(); j++) { Node wn2 = wn.getChildNodes().item(j); if (wn2.getNodeName().equals("outer")) { - outer = Faction.getFaction(wn2.getTextContent().trim()); + outer = Factions.getInstance().getFaction(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equals("inner")) { - inner = Faction.getFaction(wn2.getTextContent().trim()); + inner = Factions.getInstance().getFaction(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equals("fraction")) { fraction = Double.parseDouble(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equals("opponents")) { opponents = new ArrayList<>(); for (String fKey : wn2.getTextContent().trim().split(",")) { - Faction f = Faction.getFaction(fKey); + Faction f = Factions.getInstance().getFaction(fKey); if (null != f) { opponents.add(f); } @@ -584,7 +584,7 @@ private void setFactionHint(Map>> hint, String[] factionKeys = wn.getTextContent().trim().split(","); Faction[] parties = new Faction[factionKeys.length]; for (int i = 0; i < factionKeys.length; i++) { - parties[i] = Faction.getFaction(factionKeys[i]); + parties[i] = Factions.getInstance().getFaction(factionKeys[i]); if (null == parties[i]) { MekHQ.getLogger().error(getClass(), METHOD_NAME, "Invalid faction code in factionhints.xml: " + parties[i]); //$NON-NLS-1$ @@ -617,7 +617,7 @@ private void addNeutralExceptions(Faction faction, Node node) throws DOMExceptio String[] parties = wn.getTextContent().trim().split(","); for (String party : parties) { - final Faction f = Faction.getFaction(party); + final Faction f = Factions.getInstance().getFaction(party); if (null == f) { MekHQ.getLogger().error(getClass(), METHOD_NAME, "Invalid faction code in factionhints.xml: " + party); //$NON-NLS-1$ diff --git a/MekHQ/src/mekhq/campaign/universe/Factions.java b/MekHQ/src/mekhq/campaign/universe/Factions.java new file mode 100644 index 0000000000..0a8f056660 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/Factions.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All rights reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + +package mekhq.campaign.universe; + +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import megamek.client.ratgenerator.FactionRecord; +import megamek.client.ratgenerator.RATGenerator; +import megamek.common.annotations.Nullable; +import mekhq.MekHQ; +import mekhq.MekHqXmlUtil; + +public class Factions { + private static Factions instance; + + private Map factions = new HashMap<>(); + private Map factionIdMap = new HashMap<>(); + private List choosableFactionCodes = Collections.singletonList("MERC"); + + private RATGenerator ratGenerator; + + public Factions() { + this(RATGenerator.getInstance()); + } + + public Factions(RATGenerator ratGenerator) { + this.ratGenerator = Objects.requireNonNull(ratGenerator); + } + + public static Factions getInstance() { + if (instance == null) { + instance = new Factions(); + } + + return instance; + } + + public static void setInstance(Factions instance) { + Factions.instance = instance; + } + + public RATGenerator getRATGenerator() { + return ratGenerator; + } + + public void setRATGenerator(RATGenerator ratGenerator) { + this.ratGenerator = Objects.requireNonNull(ratGenerator); + } + + public List getChoosableFactionCodes() { + return choosableFactionCodes; + } + + public void setChoosableFactionCodes(String... choosableFactionCodes) { + if (choosableFactionCodes.length > 0) { + this.choosableFactionCodes = Arrays.asList(choosableFactionCodes); + } + } + + public Collection getFactions() { + return factions.values(); + } + + public Collection getFactionList() { + return new ArrayList<>(factions.keySet()); + } + + public Faction getFaction(String sname) { + Faction defaultFaction = new Faction(); + if (factions == null) { + return defaultFaction; + } else { + return factions.getOrDefault(sname, defaultFaction); + } + } + + public Faction getFactionFromFullName(String fname, int year) { + return getFactionFromFullNameAndYear(fname, year); + } + + public Faction getFactionFromFullNameAndYear(String fname, int year) { + Faction faction = null; + for (Faction f : factions.values()) { + if (f.getFullName(year).equals(fname)) { + faction = f; + break; + } + } + return faction; + } + + /** + * Helper function that gets the faction record for the specified faction, or a fallback general faction record. + * Useful for RAT generator activity. + * @param faction The faction whose MegaMek faction record to retrieve. + * @return Found faction record or null. + */ + public FactionRecord getFactionRecordOrFallback(String faction) { + FactionRecord fRec = ratGenerator.getFaction(faction); + if (fRec == null) { + Faction f = getFaction(faction); + if (f != null) { + if (f.isPeriphery()) { + fRec = ratGenerator.getFaction("Periphery"); + } else if (f.isClan()) { + fRec = ratGenerator.getFaction("CLAN"); + } else { + fRec = ratGenerator.getFaction("IS"); + } + } + + if (fRec == null) { + MekHQ.getLogger().error("Could not locate faction record for " + faction); + } + } + + return fRec; + } + + public String getFactionCode(int faction) { + Faction f = factionIdMap.get(faction); + return (null != f) ? f.getShortName() : "IND"; + } + + public static @Nullable Factions generateFactions() throws DOMException { + MekHQ.getLogger().info("Starting load of faction data from XML..."); + + Factions retVal = new Factions(); + + Document xmlDoc; + + try (FileInputStream fis = new FileInputStream("data/universe/factions.xml")) { + // Using factory get an instance of document builder + DocumentBuilder db = MekHqXmlUtil.newSafeDocumentBuilder(); + + // Parse using builder to get DOM representation of the XML file + xmlDoc = db.parse(fis); + } catch (Exception ex) { + MekHQ.getLogger().error(ex); + return null; + } + + Element factionEle = xmlDoc.getDocumentElement(); + NodeList nl = factionEle.getChildNodes(); + + // Get rid of empty text nodes and adjacent text nodes... + // Stupid weird parsing of XML. At least this cleans it up. + factionEle.normalize(); + + // Okay, lets iterate through the children, eh? + for (int x = 0; x < nl.getLength(); x++) { + Node wn = nl.item(x); + + if (!wn.getParentNode().equals(factionEle)) { + continue; + } + + int xc = wn.getNodeType(); + + if (xc == Node.ELEMENT_NODE) { + // This is what we really care about. + // All the meat of our document is in this node type, at this + // level. + // Okay, so what element is it? + String xn = wn.getNodeName(); + + if (xn.equalsIgnoreCase("faction")) { + Faction f = Faction.getFactionFromXML(wn); + if (!retVal.factions.containsKey(f.getShortName())) { + retVal.factions.put(f.getShortName(), f); + if (null != f.getId()) { + if (!retVal.factionIdMap.containsKey(f.getId())) { + retVal.factionIdMap.put(f.getId(), f); + } else { + MekHQ.getLogger().error( + String.format("Faction id \"%d\" already used for faction %s, can't re-use it for %s", + f.getId(), retVal.factionIdMap.get(f.getId()).getFullName(0), + f.getFullName(0))); + } + } + } else { + MekHQ.getLogger().error( + String.format("Faction code \"%s\" already used for faction %s, can't re-use it for %s", + f.getShortName(), retVal.factions.get(f.getShortName()).getFullName(0), f.getFullName(0))); + } + } else if (xn.equalsIgnoreCase("choosableFactionCodes")) { + retVal.setChoosableFactionCodes(wn.getTextContent().split(",")); + } + } + } + + MekHQ.getLogger().info("Loaded a total of " + retVal.factions.size() + " factions"); + + return retVal; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/Planet.java b/MekHQ/src/mekhq/campaign/universe/Planet.java index a1905e4061..b52e48f4c0 100644 --- a/MekHQ/src/mekhq/campaign/universe/Planet.java +++ b/MekHQ/src/mekhq/campaign/universe/Planet.java @@ -254,7 +254,7 @@ public Planet(String tsvData, List years) throws Exception { // there are a few situations where all this stuff with parens is for naught, which is // PlanetName (FactionCode) or if the PlanetName (AltName) is already in our planets "database" - if ((null == Faction.getFaction(altName)) && (null == Systems.getInstance().getSystemById(primaryName))) { + if ((null == Factions.getInstance().getFaction(altName)) && (null == Systems.getInstance().getSystemById(primaryName))) { primaryName = nameString.substring(0, parenIndex - 1); PlanetaryEvent nameChangeEvent = getOrCreateEvent(nameChangeYearDate); @@ -705,7 +705,7 @@ private static Set getFactionsFrom(Collection codes) { } Set factions = new HashSet<>(codes.size()); for (String code : codes) { - factions.add(Faction.getFaction(code)); + factions.add(Factions.getInstance().getFaction(code)); } return factions; } @@ -950,7 +950,7 @@ public String updateFromTSVPlanet(final Planet tsvPlanet, boolean dryRun) { if ((event.faction != null) && (event.faction.size() > 0)) { // the purpose of this code is to evaluate whether the current "other planet" event is // a faction change to an active, valid faction. - Faction eventFaction = Faction.getFaction(event.faction.get(0)); + Faction eventFaction = Factions.getInstance().getFaction(event.faction.get(0)); boolean eventHasActualFaction = eventFaction != null && (!eventFaction.is(Tag.INACTIVE) && !eventFaction.is(Tag.ABANDONED)); if (eventHasActualFaction) { @@ -959,8 +959,8 @@ public String updateFromTSVPlanet(final Planet tsvPlanet, boolean dryRun) { // if this planet has an "inactive and abandoned" current faction... // we also want to catch the situation where the next faction change isn't to the same exact faction if ((currentFactions.size() == 1) - && Faction.getFaction(currentFactions.get(0)).is(Tag.INACTIVE) - && Faction.getFaction(currentFactions.get(0)).is(Tag.ABANDONED)) { + && Factions.getInstance().getFaction(currentFactions.get(0)).is(Tag.INACTIVE) + && Factions.getInstance().getFaction(currentFactions.get(0)).is(Tag.ABANDONED)) { // now we travel into the future, to the next "other" event, and if this planet has acquired a faction // before the next "other" event, then we @@ -977,8 +977,8 @@ public String updateFromTSVPlanet(final Planet tsvPlanet, boolean dryRun) { List nextFactions = this.getFactions(nextEventDate); boolean factionBeforeNextEvent = !(nextFactions.size() == 1 && - Faction.getFaction(nextFactions.get(0)).is(Tag.INACTIVE) && - Faction.getFaction(nextFactions.get(0)).is(Tag.ABANDONED)); + Factions.getInstance().getFaction(nextFactions.get(0)).is(Tag.INACTIVE) && + Factions.getInstance().getFaction(nextFactions.get(0)).is(Tag.ABANDONED)); if (!factionBeforeNextEvent) { sb.append("Adding faction change in ").append(event.date.getYear()) @@ -1138,7 +1138,7 @@ private Set updateFactions(Set current, List codes, Li if (codes != otherCodes) { current = new HashSet<>(codes.size()); for (String code : codes) { - current.add(Faction.getFaction(code)); + current.add(Factions.getInstance().getFaction(code)); } } return current; diff --git a/MekHQ/src/mekhq/campaign/universe/PlanetarySystem.java b/MekHQ/src/mekhq/campaign/universe/PlanetarySystem.java index 024d296de3..d31be97148 100644 --- a/MekHQ/src/mekhq/campaign/universe/PlanetarySystem.java +++ b/MekHQ/src/mekhq/campaign/universe/PlanetarySystem.java @@ -205,7 +205,7 @@ public Set getFactionSet(LocalDate when) { //ignore cases where abandoned (ABN) is given in addition //to real factions if (factions.size() > 1) { - factions.remove(Faction.getFaction("ABN")); + factions.remove(Factions.getInstance().getFaction("ABN")); } return factions; } diff --git a/MekHQ/src/mekhq/campaign/universe/RATGeneratorConnector.java b/MekHQ/src/mekhq/campaign/universe/RATGeneratorConnector.java index 27e485b7a6..604d98fed2 100644 --- a/MekHQ/src/mekhq/campaign/universe/RATGeneratorConnector.java +++ b/MekHQ/src/mekhq/campaign/universe/RATGeneratorConnector.java @@ -47,14 +47,14 @@ public RATGeneratorConnector(int year) { try { Thread.sleep(50); } catch (InterruptedException e) { - MekHQ.getLogger().error(getClass(), "RATGeneratorConnector", e); + MekHQ.getLogger().error(e); } } RATGenerator.getInstance().loadYear(year); } private UnitTable findTable(String faction, int unitType, int weightClass, int year, int quality, Collection movementModes) { - FactionRecord fRec = Faction.getFactionRecordOrFallback(faction); + FactionRecord fRec = Factions.getInstance().getFactionRecordOrFallback(faction); if(fRec == null) { return null; } diff --git a/MekHQ/src/mekhq/campaign/universe/RATManager.java b/MekHQ/src/mekhq/campaign/universe/RATManager.java index b489f00e3d..95e365af0d 100644 --- a/MekHQ/src/mekhq/campaign/universe/RATManager.java +++ b/MekHQ/src/mekhq/campaign/universe/RATManager.java @@ -378,7 +378,7 @@ private List factionTree(String faction) { alts.remove(index); } } - Faction f = Faction.getFaction(faction); + Faction f = Factions.getInstance().getFaction(faction); if (f.isPeriphery()) { retVal.add("Periphery"); } diff --git a/MekHQ/src/mekhq/campaign/universe/RandomFactionGenerator.java b/MekHQ/src/mekhq/campaign/universe/RandomFactionGenerator.java index 5a8c4597c1..987e9adc8d 100644 --- a/MekHQ/src/mekhq/campaign/universe/RandomFactionGenerator.java +++ b/MekHQ/src/mekhq/campaign/universe/RandomFactionGenerator.java @@ -90,6 +90,10 @@ public static RandomFactionGenerator getInstance() { return rfg; } + public static void setInstance(RandomFactionGenerator instance) { + rfg = instance; + } + public void startup(Campaign c) { borderTracker.setDate(c.getLocalDate()); final PlanetarySystem location = c.getLocation().getCurrentSystem(); @@ -97,7 +101,7 @@ public void startup(Campaign c) { borderTracker.setRegionRadius(c.getCampaignOptions().getSearchRadius()); MekHQ.registerHandler(borderTracker); MekHQ.registerHandler(this); - for (Faction f : Faction.getFactions()) { + for (Faction f : Factions.getInstance().getFactions()) { if (factionHints.isDeepPeriphery(f)) { borderTracker.setBorderSize(f, BORDER_RANGE_DEEP_PERIPHERY); } @@ -223,12 +227,9 @@ public String getEmployer() { * @return The shortName of the faction to use as the opfor. */ public String getEnemy(String employer, boolean useRebels) { - final String METHOD_NAME = "getEnemy(String,boolean)"; //$NON-NLS-1$ - - Faction employerFaction = Faction.getFaction(employer); + Faction employerFaction = Factions.getInstance().getFaction(employer); if (null == employerFaction) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Could not find enemy for " + employer); //$NON-NLS-1$ + MekHQ.getLogger().error("Could not find enemy for " + employer); //$NON-NLS-1$ return "PIR"; } else { return getEnemy(employerFaction, useRebels); @@ -246,8 +247,6 @@ public String getEnemy(String employer, boolean useRebels) { * @return The faction to use as the opfor. */ public String getEnemy(Faction employer, boolean useRebels) { - final String METHOD_NAME = "getEnemy(Faction,boolean)"; //$NON-NLS-1$ - String employerName = employer != null ? employer.getShortName() : "no employer supplied or faction does not exist"; /* Rebels occur on a 1-4 (d20) on nearly every enemy chart */ @@ -268,8 +267,7 @@ public String getEnemy(Faction employer, boolean useRebels) { return enemy.getShortName(); } - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Could not find enemy for " + employerName); //$NON-NLS-1$ + MekHQ.getLogger().error("Could not find enemy for " + employerName); //$NON-NLS-1$ // Fallback; there are always pirates. return "PIR"; @@ -343,13 +341,12 @@ public Set getEmployerSet() { * @return A list of faction that share a border */ public List getEnemyList(String employerName) { - Faction employer = Faction.getFaction(employerName); + Faction employer = Factions.getInstance().getFaction(employerName); if (null == employer) { - MekHQ.getLogger().warning(getClass(), "getEnemyList(String)", //$NON-NLS-1$ - "Unknown faction key: " + employerName); //$NON-NLS-1$ + MekHQ.getLogger().warning("Unknown faction key: " + employerName); //$NON-NLS-1$ return Collections.emptyList(); } - return getEnemyList(Faction.getFaction(employerName)); + return getEnemyList(Factions.getInstance().getFaction(employerName)); } /** @@ -446,17 +443,14 @@ protected double adjustBorderWeight(double count, Faction f, Faction enemy, Loca * @return The planetId of the chosen planet, or null if there are no target candidates */ @Nullable public String getMissionTarget(String attacker, String defender) { - final String METHOD_NAME = "getMissionTarget(String, String)"; // $NON-NLS-1$ - Faction f1 = Faction.getFaction(attacker); - Faction f2 = Faction.getFaction(defender); + Faction f1 = Factions.getInstance().getFaction(attacker); + Faction f2 = Factions.getInstance().getFaction(defender); if (null == f1) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Non-existent faction key: " + attacker); // $NON-NLS-1$ + MekHQ.getLogger().error("Non-existent faction key: " + attacker); // $NON-NLS-1$ return null; } if (null == f2) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Non-existent faction key: " + attacker); // $NON-NLS-1$ + MekHQ.getLogger().error("Non-existent faction key: " + attacker); // $NON-NLS-1$ return null; } List planetList = getMissionTargetList(f1, f2); @@ -475,16 +469,13 @@ protected double adjustBorderWeight(double count, Faction f, Faction enemy, Loca * @return A list of potential mission targets */ public List getMissionTargetList(String attackerKey, String defenderKey) { - final String METHOD_NAME = "getMissionTargetList(String, String)"; //$NON-NLS-1$ - Faction attacker = Faction.getFaction(attackerKey); - Faction defender = Faction.getFaction(defenderKey); + Faction attacker = Factions.getInstance().getFaction(attackerKey); + Faction defender = Factions.getInstance().getFaction(defenderKey); if (null == attacker) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Non-existent faction key: " + attackerKey); //$NON-NLS-1$ + MekHQ.getLogger().error("Non-existent faction key: " + attackerKey); //$NON-NLS-1$ } if (null == defender) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, - "Non-existent faction key: " + defenderKey); //$NON-NLS-1$ + MekHQ.getLogger().error("Non-existent faction key: " + defenderKey); //$NON-NLS-1$ } if ((null != attacker) && (null != defender)) { return getMissionTargetList(attacker, defender); diff --git a/MekHQ/src/mekhq/campaign/universe/RangedFactionSelector.java b/MekHQ/src/mekhq/campaign/universe/RangedFactionSelector.java index c51b08f51e..3a7360ab06 100644 --- a/MekHQ/src/mekhq/campaign/universe/RangedFactionSelector.java +++ b/MekHQ/src/mekhq/campaign/universe/RangedFactionSelector.java @@ -160,7 +160,7 @@ private void createLookupMap(Campaign campaign) { } }); - Faction mercenaries = Faction.getFaction("MERC"); + Faction mercenaries = Factions.getInstance().getFaction("MERC"); TreeMap factions = new TreeMap<>(); if (weights.isEmpty()) { // If we have no valid factions, we can always @@ -218,7 +218,7 @@ private Set getEnemies(Campaign campaign) { Set enemies = new HashSet<>(); for (Contract contract : campaign.getActiveContracts()) { if (contract instanceof AtBContract) { - enemies.add(Faction.getFaction(((AtBContract)contract).getEnemyCode())); + enemies.add(Factions.getInstance().getFaction(((AtBContract)contract).getEnemyCode())); } } return enemies; diff --git a/MekHQ/src/mekhq/campaign/universe/Systems.java b/MekHQ/src/mekhq/campaign/universe/Systems.java index d6b5b3d808..5865cd28cd 100644 --- a/MekHQ/src/mekhq/campaign/universe/Systems.java +++ b/MekHQ/src/mekhq/campaign/universe/Systems.java @@ -81,7 +81,7 @@ public class Systems { // For debugging only! // unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); } catch (JAXBException e) { - MekHQ.getLogger().error(Systems.class, "", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } } @@ -96,7 +96,7 @@ public class Systems { planetMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); planetUnmarshaller = jContext.createUnmarshaller(); } catch (Exception e) { - MekHQ.getLogger().error(Systems.class, "Systems", e); + MekHQ.getLogger().error(e); } } @@ -113,6 +113,10 @@ public static Systems getInstance() { return systems; } + public static void setInstance(Systems instance) { + systems = instance; + } + private ConcurrentMap systemList = new ConcurrentHashMap<>(); /* organizes systems into a grid of 30lyx30ly squares so we can find * nearby systems without iterating through the entire planet list. */ diff --git a/MekHQ/src/mekhq/campaign/universe/UnitGeneratorParameters.java b/MekHQ/src/mekhq/campaign/universe/UnitGeneratorParameters.java index 7f1f3e2412..250e63bac5 100644 --- a/MekHQ/src/mekhq/campaign/universe/UnitGeneratorParameters.java +++ b/MekHQ/src/mekhq/campaign/universe/UnitGeneratorParameters.java @@ -67,7 +67,7 @@ public UnitGeneratorParameters clone() { * @return */ public Parameters getRATGeneratorParameters() { - FactionRecord fRec = Faction.getFactionRecordOrFallback(getFaction()); + FactionRecord fRec = Factions.getInstance().getFactionRecordOrFallback(getFaction()); String rating = RATGeneratorConnector.getFactionSpecificRating(fRec, getQuality()); List weightClasses = new ArrayList<>(); diff --git a/MekHQ/src/mekhq/gui/FactionComboBox.java b/MekHQ/src/mekhq/gui/FactionComboBox.java index 030c04429b..95f5483825 100644 --- a/MekHQ/src/mekhq/gui/FactionComboBox.java +++ b/MekHQ/src/mekhq/gui/FactionComboBox.java @@ -33,7 +33,7 @@ import javax.swing.JComboBox; import javax.swing.JList; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.gui.model.SortedComboBoxModel; /** @@ -79,7 +79,7 @@ public void addFactionEntries(Collection list, int year) { HashMap map = new HashMap(); HashSet collisions = new HashSet(); for (String key : list) { - String fullName = Faction.getFaction(key).getFullName(year); + String fullName = Factions.getInstance().getFaction(key).getFullName(year); if (map.containsValue(fullName)) { collisions.add(fullName); } diff --git a/MekHQ/src/mekhq/gui/InterstellarMapPanel.java b/MekHQ/src/mekhq/gui/InterstellarMapPanel.java index 1de87467a1..8e81e7aa14 100644 --- a/MekHQ/src/mekhq/gui/InterstellarMapPanel.java +++ b/MekHQ/src/mekhq/gui/InterstellarMapPanel.java @@ -84,6 +84,7 @@ import mekhq.campaign.Campaign; import mekhq.campaign.JumpPath; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Faction.Tag; import mekhq.campaign.universe.SocioIndustrialData; import mekhq.campaign.universe.PlanetarySystem; @@ -664,7 +665,7 @@ protected void paintComponent(Graphics g) { } Map capitals = new HashMap<>(); - for (Faction faction : Faction.getFactions()) { + for (Faction faction : Factions.getInstance().getFactions()) { capitals.put(faction, faction.getStartingPlanet(campaign.getLocalDate())); } diff --git a/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java b/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java index d462bb66ae..ccaf40f4b1 100644 --- a/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java @@ -99,6 +99,7 @@ import mekhq.campaign.personnel.enums.TimeInDisplayFormat; import mekhq.campaign.rating.UnitRatingMethod; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.RATManager; import mekhq.gui.FileDialogs; import mekhq.gui.SpecialAbilityPanel; @@ -638,8 +639,8 @@ private void initComponents() { panGeneral.add(lblFaction, gridBagConstraints); factionModel = new SortedComboBoxModel<>(); - for (String sName : Faction.getChoosableFactionCodes()) { - Faction f = Faction.getFaction(sName); + for (String sName : Factions.getInstance().getChoosableFactionCodes()) { + Faction f = Factions.getInstance().getFaction(sName); if (f.validIn(date.getYear())) { factionModel.addElement(f.getFullName(date.getYear())); } @@ -4822,7 +4823,7 @@ private void updateOptions() { GameOptions gameOpts = campaign.getGameOptions(); int campaignYear = campaign.getGameYear(); gameOpts.getOption("year").setValue(campaignYear); - campaign.setFactionCode(Faction.getFactionFromFullNameAndYear + campaign.setFactionCode(Factions.getInstance().getFactionFromFullNameAndYear (String.valueOf(comboFaction.getSelectedItem()), date.getYear()).getShortName()); if (null != comboFactionNames.getSelectedItem()) { RandomNameGenerator.getInstance().setChosenFaction((String) comboFactionNames.getSelectedItem()); @@ -5212,8 +5213,8 @@ private void btnDateActionPerformed(ActionEvent evt) { date = dc.getDate(); btnDate.setText(MekHQ.getMekHQOptions().getDisplayFormattedDate(date)); factionModel = new SortedComboBoxModel<>(); - for (String sname : Faction.getChoosableFactionCodes()) { - Faction f = Faction.getFaction(sname); + for (String sname : Factions.getInstance().getChoosableFactionCodes()) { + Faction f = Factions.getInstance().getFaction(sname); if (f.validIn(date.getYear())) { factionModel.addElement(f.getFullName(date.getYear())); } diff --git a/MekHQ/src/mekhq/gui/dialog/ChooseFactionsDialog.java b/MekHQ/src/mekhq/gui/dialog/ChooseFactionsDialog.java index 635977f06e..827872308d 100644 --- a/MekHQ/src/mekhq/gui/dialog/ChooseFactionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/ChooseFactionsDialog.java @@ -46,6 +46,7 @@ import megamek.common.util.EncodeControl; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; public class ChooseFactionsDialog extends JDialog { private static final long serialVersionUID = 805616085217507489L; @@ -160,7 +161,7 @@ private static class FactionListModel extends AbstractListModel { private List names; public FactionListModel(LocalDate date) { - for (Faction faction : Faction.getFactions()) { + for (Faction faction : Factions.getInstance().getFactions()) { factionMap.put(faction.getFullName(date.getYear()), faction); } names = new ArrayList<>(factionMap.navigableKeySet()); diff --git a/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java b/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java index 715bb34c8d..baad9869b5 100644 --- a/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/ContractMarketDialog.java @@ -46,7 +46,7 @@ import mekhq.campaign.mission.AtBContract; import mekhq.campaign.mission.Contract; import mekhq.campaign.mission.Mission; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.gui.FactionComboBox; import mekhq.gui.view.ContractSummaryPanel; @@ -304,7 +304,7 @@ public boolean isCellEditable(int row, int column) { gbc.fill = GridBagConstraints.NONE; panelRetainer.add(lblCurrentRetainer, gbc); if (null != campaign.getRetainerEmployerCode()) { - lblRetainerEmployer.setText(Faction.getFaction(campaign.getRetainerEmployerCode()).getFullName(campaign.getGameYear())); + lblRetainerEmployer.setText(Factions.getInstance().getFaction(campaign.getRetainerEmployerCode()).getFullName(campaign.getGameYear())); } gbc.gridx = 1; gbc.gridy = 0; @@ -348,7 +348,7 @@ public boolean isCellEditable(int row, int column) { lblCurrentRetainer.setVisible(true); lblRetainerEmployer.setVisible(true); btnEndRetainer.setVisible(true); - lblRetainerEmployer.setText(Faction.getFaction(campaign.getRetainerEmployerCode()).getFullName(campaign.getGameYear())); + lblRetainerEmployer.setText(Factions.getInstance().getFaction(campaign.getRetainerEmployerCode()).getFullName(campaign.getGameYear())); //Remove the selected faction and add the previous one, if any countSuccessfulContracts(); lblRetainerAvailable.setVisible(possibleRetainerContracts.size() > 0); diff --git a/MekHQ/src/mekhq/gui/dialog/CustomizeAtBContractDialog.java b/MekHQ/src/mekhq/gui/dialog/CustomizeAtBContractDialog.java index 59732067d3..bb0a8045f4 100644 --- a/MekHQ/src/mekhq/gui/dialog/CustomizeAtBContractDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CustomizeAtBContractDialog.java @@ -42,7 +42,7 @@ import mekhq.MekHQ; import mekhq.campaign.Campaign; import mekhq.campaign.mission.AtBContract; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.PlanetarySystem; import mekhq.campaign.universe.RandomFactionGenerator; import mekhq.campaign.universe.Systems; @@ -605,8 +605,8 @@ private void showAllFactions(boolean allFactions) { cbEmployer.removeAllItems(); cbEnemy.removeAllItems(); if (allFactions) { - cbEmployer.addFactionEntries(Faction.getFactionList(), campaign.getGameYear()); - cbEnemy.addFactionEntries(Faction.getFactionList(), campaign.getGameYear()); + cbEmployer.addFactionEntries(Factions.getInstance().getFactionList(), campaign.getGameYear()); + cbEnemy.addFactionEntries(Factions.getInstance().getFactionList(), campaign.getGameYear()); } else { cbEmployer.addFactionEntries(currentFactions, campaign.getGameYear()); cbEnemy.addFactionEntries(currentFactions, campaign.getGameYear()); diff --git a/MekHQ/src/mekhq/gui/dialog/CustomizePersonDialog.java b/MekHQ/src/mekhq/gui/dialog/CustomizePersonDialog.java index 641724f8ca..47dd596d1e 100644 --- a/MekHQ/src/mekhq/gui/dialog/CustomizePersonDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CustomizePersonDialog.java @@ -49,6 +49,7 @@ import mekhq.campaign.personnel.enums.Phenotype; import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Faction.Tag; import mekhq.campaign.universe.Planet; import mekhq.campaign.universe.PlanetarySystem; @@ -838,7 +839,7 @@ private void setUserPreferences() { private DefaultComboBoxModel getFactionsComboBoxModel() { int year = campaign.getGameYear(); - List orderedFactions = Faction.getFactions().stream() + List orderedFactions = Factions.getInstance().getFactions().stream() .sorted((a, b) -> a.getFullName(year).compareToIgnoreCase(b.getFullName(year))) .collect(Collectors.toList()); diff --git a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java index 71ba488cdf..f48a578290 100644 --- a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java @@ -56,7 +56,7 @@ import mekhq.campaign.mod.am.InjuryTypes; import mekhq.campaign.personnel.Bloodname; import mekhq.campaign.personnel.ranks.Ranks; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.RATManager; import mekhq.gui.preferences.JWindowPreference; import mekhq.preferences.PreferencesNode; @@ -134,7 +134,7 @@ public Campaign doInBackground() throws IOException, CampaignXmlParseException, //Initialize progress property. setProgress(0); - Faction.generateFactions(); + Factions.setInstance(Factions.generateFactions()); CurrencyManager.getInstance().loadCurrencies(); diff --git a/MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java b/MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java index d230f43976..5bc487e83a 100644 --- a/MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/GMToolsDialog.java @@ -53,6 +53,7 @@ import mekhq.campaign.personnel.enums.Phenotype; import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.IUnitGenerator; import mekhq.gui.CampaignGUI; import mekhq.gui.preferences.JComboBoxPreference; @@ -589,7 +590,7 @@ private GridBagConstraints newGridBagConstraints(int x, int y, int width, int he private List getFactionChoices(int year) { List factionChoices = new ArrayList<>(); - for (Faction faction : Faction.getFactions()) { + for (Faction faction : Factions.getInstance().getFactions()) { factionChoices.add(new FactionChoice(faction, year)); } diff --git a/MekHQ/src/mekhq/gui/dialog/NewPlanetaryEventDialog.java b/MekHQ/src/mekhq/gui/dialog/NewPlanetaryEventDialog.java index c77fe49aa6..ea90bb47db 100644 --- a/MekHQ/src/mekhq/gui/dialog/NewPlanetaryEventDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/NewPlanetaryEventDialog.java @@ -46,6 +46,7 @@ import mekhq.adapter.SocioIndustrialDataAdapter; import mekhq.campaign.Campaign; import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Planet; import mekhq.gui.preferences.JWindowPreference; import mekhq.preferences.PreferencesNode; @@ -480,7 +481,7 @@ private void updateDate() { if ((null != event) && (null != event.faction)) { factionSet = new HashSet<>(); for (String f : event.faction) { - factionSet.add(Faction.getFaction(f)); + factionSet.add(Factions.getInstance().getFaction(f)); } } factionsButton.setText(Faction.getFactionNames(factionSet, date.getYear())); diff --git a/MekHQ/src/mekhq/module/atb/AtBEventProcessor.java b/MekHQ/src/mekhq/module/atb/AtBEventProcessor.java index 87598f3d33..f02b534a38 100644 --- a/MekHQ/src/mekhq/module/atb/AtBEventProcessor.java +++ b/MekHQ/src/mekhq/module/atb/AtBEventProcessor.java @@ -42,7 +42,7 @@ import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.SkillType; import mekhq.campaign.rating.IUnitRating; -import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.IUnitGenerator; import mekhq.campaign.universe.RandomFactionGenerator; import mekhq.campaign.universe.UnitGeneratorParameters; @@ -209,20 +209,20 @@ private void addRecruitUnit(Person p) { MechSummary ms = campaign.getUnitGenerator().generate(params); if (null != ms) { - if (Faction.getFaction(faction).isClan() && ms.getName().matches(".*Platoon.*")) { + if (Factions.getInstance().getFaction(faction).isClan() && ms.getName().matches(".*Platoon.*")) { String name = "Clan " + ms.getName().replaceAll("Platoon", "Point"); ms = MechSummaryCache.getInstance().getMech(name); - MekHQ.getLogger().info(this, "looking for Clan infantry " + name); + MekHQ.getLogger().info("looking for Clan infantry " + name); } try { en = new MechFileParser(ms.getSourceFile(), ms.getEntryName()).getEntity(); } catch (EntityLoadingException ex) { en = null; - MekHQ.getLogger().error(this, "Unable to load entity: " + MekHQ.getLogger().error("Unable to load entity: " + ms.getSourceFile() + ": " + ms.getEntryName() + ": " + ex.getMessage(), ex); } } else { - MekHQ.getLogger().error(this, "Personnel market could not find " + MekHQ.getLogger().error("Personnel market could not find " + UnitType.getTypeName(unitType) + " for recruit from faction " + faction); return; } @@ -288,7 +288,7 @@ public static String getRecruitFaction(Campaign c) { if ((c.getGameYear() > 3055) && (Compute.randomInt(20) == 0)) { ArrayList clans = new ArrayList<>(); for (String f : RandomFactionGenerator.getInstance().getCurrentFactions()) { - if (Faction.getFaction(f).isClan()) { + if (Factions.getInstance().getFaction(f).isClan()) { clans.add(f); } } From 645b761176bb9f80677080c4b924ab7f2781d563 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 13:43:34 -0500 Subject: [PATCH 02/16] Add basic contract market test --- .../campaign/market/ContractMarketTest.java | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java new file mode 100644 index 0000000000..fcf7a67168 --- /dev/null +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All rights reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + +package mekhq.campaign.market; + +import mekhq.campaign.Campaign; +import mekhq.campaign.CampaignOptions; +import mekhq.campaign.CurrentLocation; +import mekhq.campaign.Hangar; +import mekhq.campaign.JumpPath; +import mekhq.campaign.finances.Accountant; +import mekhq.campaign.finances.Money; +import mekhq.campaign.force.Force; +import mekhq.campaign.mission.AtBContract; +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.rating.UnitRatingMethod; +import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.FactionHints; +import mekhq.campaign.universe.Factions; +import mekhq.campaign.universe.RandomFactionGenerator; +import mekhq.campaign.universe.PlanetarySystem; +import mekhq.campaign.universe.Systems; + +import org.junit.After; +import org.junit.Test; + +import java.time.LocalDate; +import java.util.UUID; +import java.util.Vector; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class ContractMarketTest { + @Test + public void addMercWithoutRetainerAtBContractSucceeds() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @After + public void cleanupAfterTests() { + Factions.setInstance(null); + Systems.setInstance(null); + RandomFactionGenerator.setInstance(null); + } +} From 0e226c0ff116643c4ecf008227926a65d22d60aa Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 14:49:35 -0500 Subject: [PATCH 03/16] Add additional ContractMarket tests --- .../campaign/market/ContractMarketTest.java | 407 ++++++++++++++++++ 1 file changed, 407 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java index fcf7a67168..e696f0c6fe 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -92,6 +92,12 @@ public void addMercWithoutRetainerAtBContractSucceeds() { doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + Systems systems = mock(Systems.class); Systems.setInstance(systems); @@ -136,6 +142,407 @@ public void addMercWithoutRetainerAtBContractSucceeds() { assertNotNull(contract); } + @Test + public void addMercWithoutRetainerMinorPowerAtBContractSucceeds() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(false).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void addMercWithoutRetainerEmployerNeutralAtBContractSucceeds() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void addMercWithoutRetainerEmployerNeutralAtWarAtBContractSucceeds() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + doReturn(true).when(hints).isAtWarWith(eq(employerFaction), eq(enemyFaction), any()); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void mercEmployerRetries() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + // Return "MERC" the first time to coerce a retry + when(rfg.getEmployer()).thenReturn("MERC").thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + assertTrue(contract.isMercSubcontract()); + } + + @Test + public void mercEmployerRetriesFail() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); + when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + // Return "MERC" every time + when(rfg.getEmployer()).thenReturn("MERC"); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNull(contract); + } + @After public void cleanupAfterTests() { Factions.setInstance(null); From 37c75a1c83e2665933da205d7eee102a9c8ef16c Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 15:21:04 -0500 Subject: [PATCH 04/16] Add campaign dates to tests --- .../campaign/market/ContractMarketTest.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java index e696f0c6fe..ef46c2bca1 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -54,7 +54,8 @@ public void addMercWithoutRetainerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -148,7 +149,8 @@ public void addMercWithoutRetainerMinorPowerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -242,7 +244,8 @@ public void addMercWithoutRetainerEmployerNeutralAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -336,7 +339,8 @@ public void addMercWithoutRetainerEmployerNeutralAtWarAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -431,7 +435,8 @@ public void mercEmployerRetries() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -527,7 +532,8 @@ public void mercEmployerRetriesFail() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.now()); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); + when(campaign.getGameYear()).thenReturn(3025); Factions factions = mock(Factions.class); Factions.setInstance(factions); From ada390fb046e23982ee3d4633efecf6f35da1e7b Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 15:35:08 -0500 Subject: [PATCH 05/16] Vary tests based on game year and rating --- .../campaign/market/ContractMarketTest.java | 73 ++++++++++++++----- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java index ef46c2bca1..9914ad0ea1 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -39,23 +39,55 @@ import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.UUID; import java.util.Vector; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +@RunWith(Parameterized.class) public class ContractMarketTest { + + private final int gameYear; + private final int unitRating; + private final boolean isClanEnemy; + + public ContractMarketTest(int gameYear, int unitRating, boolean isClanEnemy) { + this.gameYear = gameYear; + this.unitRating = unitRating; + this.isClanEnemy = isClanEnemy; + } + + @Parameters(name = "Run {index}: gameYear={0}, unitRating={1}, isClanEnemy={2}") + public static Iterable data() throws Throwable { + List gameYears = Arrays.asList(new Integer[] { 2750, 3025, 3055, 3067, 3120 }); + + List parameters = new ArrayList<>(); + for (int gameYear : gameYears) { + for (int rating = IUnitRating.DRAGOON_F; rating <= IUnitRating.DRAGOON_ASTAR; ++rating) { + parameters.add(new Object[] { gameYear, rating, false }); + parameters.add(new Object[] { gameYear, rating, true }); + } + } + return parameters; + } + @Test public void addMercWithoutRetainerAtBContractSucceeds() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -90,6 +122,7 @@ public void addMercWithoutRetainerAtBContractSucceeds() { String enemyFullName = "Contract Enemy"; Faction enemyFaction = mock(Faction.class); when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); @@ -148,9 +181,9 @@ public void addMercWithoutRetainerMinorPowerAtBContractSucceeds() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -185,6 +218,7 @@ public void addMercWithoutRetainerMinorPowerAtBContractSucceeds() { String enemyFullName = "Contract Enemy"; Faction enemyFaction = mock(Faction.class); when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); @@ -243,9 +277,9 @@ public void addMercWithoutRetainerEmployerNeutralAtBContractSucceeds() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -280,6 +314,7 @@ public void addMercWithoutRetainerEmployerNeutralAtBContractSucceeds() { String enemyFullName = "Contract Enemy"; Faction enemyFaction = mock(Faction.class); when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); @@ -338,9 +373,9 @@ public void addMercWithoutRetainerEmployerNeutralAtWarAtBContractSucceeds() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -375,6 +410,7 @@ public void addMercWithoutRetainerEmployerNeutralAtWarAtBContractSucceeds() { String enemyFullName = "Contract Enemy"; Faction enemyFaction = mock(Faction.class); when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); @@ -434,9 +470,9 @@ public void mercEmployerRetries() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); when(campaignOptions.getVariableContractLength()).thenReturn(false); @@ -471,6 +507,7 @@ public void mercEmployerRetries() { String enemyFullName = "Contract Enemy"; Faction enemyFaction = mock(Faction.class); when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); @@ -531,9 +568,9 @@ public void mercEmployerRetriesFail() { Campaign campaign = mock(Campaign.class); when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); - when(campaign.getUnitRatingMod()).thenReturn(IUnitRating.DRAGOON_C); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(3025, 1, 1)); - when(campaign.getGameYear()).thenReturn(3025); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); Factions factions = mock(Factions.class); Factions.setInstance(factions); From f737ffe11c3846a6821eb33372bb3d7cc91dd737 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 16:43:53 -0500 Subject: [PATCH 06/16] Add additional tests for non-merc factions --- .../campaign/market/ContractMarketTest.java | 956 ++++++++++++++++++ 1 file changed, 956 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java index 9914ad0ea1..68f85dc01f 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -586,6 +586,962 @@ public void mercEmployerRetriesFail() { assertNull(contract); } + @Test + public void mercMissiongTargetRetries() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + // Don't find the mission target and force a retry + doReturn(null).doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void mercMissionTargetRetriesFail() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + // Don't ever find the mission target and force a retry failure + doReturn(null).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNull(contract); + } + + @Test + public void addMercWithRetainerAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(employer); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void addMercWithRetainerMinorPowerAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(employer); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(false).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void addMercWithRetainerEmployerNeutralAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(employer); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void addMercWithRetainerEmployerNeutralAtWarAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(employer); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + doReturn(true).when(hints).isAtWarWith(eq(employerFaction), eq(enemyFaction), any()); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void nonMercAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn(employer); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void nonMercMinorPowerAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn(employer); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(false).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void nonMercNeutralAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn(employer); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void nonMercNeutralAtWarAtBContractSucceeds() { + String employer = "EMPLOYER"; + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn(employer); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(true).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + doReturn(true).when(hints).isAtWarWith(eq(employerFaction), eq(enemyFaction), any()); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + @After public void cleanupAfterTests() { Factions.setInstance(null); From ebd0d6faabf9138455db73ad28ee8a3eb73b9eba Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 16:44:28 -0500 Subject: [PATCH 07/16] Move Systems initialization out of getInstance --- .../src/mekhq/campaign/universe/Systems.java | 23 +++++++++++-------- .../mekhq/gui/dialog/DataLoadingDialog.java | 2 ++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/universe/Systems.java b/MekHQ/src/mekhq/campaign/universe/Systems.java index 5865cd28cd..cead13dd6f 100644 --- a/MekHQ/src/mekhq/campaign/universe/Systems.java +++ b/MekHQ/src/mekhq/campaign/universe/Systems.java @@ -104,12 +104,6 @@ public static Systems getInstance() { if (systems == null) { systems = new Systems(); } - if (!systems.initialized && !systems.initializing) { - systems.initializing = true; - systems.loader = new Thread(() -> systems.initialize(), "Planet Loader"); - systems.loader.setPriority(Thread.NORM_PRIORITY - 1); - systems.loader.start(); - } return systems; } @@ -132,6 +126,15 @@ public static void setInstance(Systems instance) { private Systems() {} + public void initialize() { + if (!initialized && !initializing) { + initializing = true; + loader = new Thread(() -> systems.initializeInternal(), "Planet Loader"); + loader.setPriority(Thread.NORM_PRIORITY - 1); + loader.start(); + } + } + private Set getSystemGrid(int x, int y) { if (!systemGrid.containsKey(x)) { return null; @@ -264,11 +267,11 @@ public Collection getHPGNetwork(LocalDate when) { // Data loading methods - private void initialize() { + private void initializeInternal() { try { generateSystems(); } catch (ParseException e) { - MekHQ.getLogger().error(getClass(), "initialize()", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } } @@ -541,14 +544,14 @@ public PlanetarySystem.PlanetarySystemEvent readPlanetarySystemEvent(Node node) public static void reload(boolean waitForFinish) { systems = null; - getInstance(); + getInstance().initialize(); if (waitForFinish) { try { while (!systems.isInitialized()) { Thread.sleep(10); } } catch (InterruptedException iex) { - MekHQ.getLogger().error(Systems.class, "reload(boolean)", iex); //$NON-NLS-1$ + MekHQ.getLogger().error(iex); //$NON-NLS-1$ } } } diff --git a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java index f48a578290..ef5ac2fca5 100644 --- a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java @@ -143,6 +143,8 @@ public Campaign doInBackground() throws IOException, CampaignXmlParseException, //Load values needed for CampaignOptionsDialog RATManager.populateCollectionNames(); + // Initialize the systems + Systems.getInstance().initialize(); while (!Systems.getInstance().isInitialized()) { try { Thread.sleep(50); From c6f4cb6bc88d29e242cc747cf8055e660cb53ea2 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 17:25:30 -0500 Subject: [PATCH 08/16] Handle retries due to jump path calc failures --- .../campaign/market/ContractMarketTest.java | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java index 68f85dc01f..d2f53c2264 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java @@ -773,6 +773,196 @@ public void mercMissionTargetRetriesFail() { AtBContract contract = market.addAtBContract(campaign); assertNull(contract); } + + @Test + public void mercJumpPathRetries() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + JumpPath jumpPath = mock(JumpPath.class); + when(jumpPath.getJumps()).thenReturn(1); + doReturn(10.0).when(jumpPath).getTotalTime(any(), anyDouble()); + // Fail to find a jump path at first, kicking off a retry + doReturn(null).doReturn(jumpPath).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + doReturn(Money.of(1)).when(campaign).calculateCostPerJump(anyBoolean(), anyBoolean()); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNotNull(contract); + } + + @Test + public void mercJumpPathFails() { + Campaign campaign = mock(Campaign.class); + when(campaign.getFactionCode()).thenReturn("MERC"); + when(campaign.getRetainerEmployerCode()).thenReturn(null); + when(campaign.getUnitRatingMod()).thenReturn(unitRating); + when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getGameYear()).thenReturn(gameYear); + + CampaignOptions campaignOptions = mock(CampaignOptions.class); + when(campaignOptions.getVariableContractLength()).thenReturn(false); + when(campaignOptions.getUnitRatingMethod()).thenReturn(UnitRatingMethod.FLD_MAN_MERCS_REV); + when(campaignOptions.usePeacetimeCost()).thenReturn(false); + when(campaign.getCampaignOptions()).thenReturn(campaignOptions); + + Accountant accountant = mock(Accountant.class); + when(accountant.getContractBase()).thenReturn(Money.of(1)); + when(accountant.getOverheadExpenses()).thenReturn(Money.of(1)); + when(campaign.getAccountant()).thenReturn(accountant); + + Hangar hangar = mock(Hangar.class); + doReturn(Money.of(1)).when(hangar).getUnitCosts(any(), any()); + when(campaign.getHangar()).thenReturn(hangar); + + Force forces = mock(Force.class); + doReturn(new Vector()).when(forces).getAllUnits(anyBoolean()); + when(campaign.getForces()).thenReturn(forces); + + Factions factions = mock(Factions.class); + Factions.setInstance(factions); + + String employer = "EMPLOYER"; + String employerFullName = "Contract Employer"; + Faction employerFaction = mock(Faction.class); + when(employerFaction.getShortName()).thenReturn(employer); + doReturn(employerFullName).when(employerFaction).getFullName(anyInt()); + doReturn(employerFaction).when(factions).getFaction(eq(employer)); + + String enemy = "ENEMY"; + String enemyFullName = "Contract Enemy"; + Faction enemyFaction = mock(Faction.class); + when(enemyFaction.getShortName()).thenReturn(enemy); + when(enemyFaction.isClan()).thenReturn(isClanEnemy); + doReturn(enemyFullName).when(employerFaction).getFullName(anyInt()); + doReturn(enemyFaction).when(factions).getFaction(eq(enemy)); + + Faction pirates = mock(Faction.class); + doReturn(pirates).when(factions).getFaction(eq("PIR")); + + Faction rebels = mock(Faction.class); + doReturn(rebels).when(factions).getFaction(eq("REB")); + + Systems systems = mock(Systems.class); + Systems.setInstance(systems); + + String current = "CURRENT"; + PlanetarySystem currentSystem = mock(PlanetarySystem.class); + when(currentSystem.getId()).thenReturn(current); + when(campaign.getCurrentSystem()).thenReturn(currentSystem); + doReturn(currentSystem).when(systems).getSystemById(eq(current)); + doReturn(currentSystem).when(campaign).getSystemByName(eq(current)); + + CurrentLocation currentLocation = mock(CurrentLocation.class); + when(campaign.getLocation()).thenReturn(currentLocation); + + String missionTarget = "TARGET"; + PlanetarySystem targetSystem = mock(PlanetarySystem.class); + when(targetSystem.getId()).thenReturn(missionTarget); + doReturn(targetSystem).when(systems).getSystemById(eq(missionTarget)); + doReturn(targetSystem).when(campaign).getSystemByName(eq(missionTarget)); + + RandomFactionGenerator rfg = mock(RandomFactionGenerator.class); + RandomFactionGenerator.setInstance(rfg); + when(rfg.getEmployer()).thenReturn(employer); + doReturn(enemy).when(rfg).getEnemy(eq(employer), anyBoolean()); + doReturn(missionTarget).when(rfg).getMissionTarget(anyString(), anyString()); + + FactionHints hints = mock(FactionHints.class); + doReturn(true).when(hints).isISMajorPower(eq(employerFaction)); + doReturn(true).when(hints).isISMajorPower(eq(enemyFaction)); + doReturn(false).when(hints).isNeutral(eq(employerFaction)); + doReturn(false).when(hints).isNeutral(eq(enemyFaction)); + when(rfg.getFactionHints()).thenReturn(hints); + + // Fail to find a jump path + doReturn(null).when(campaign).calculateJumpPath(eq(currentSystem), eq(targetSystem)); + + ContractMarket market = new ContractMarket(); + + AtBContract contract = market.addAtBContract(campaign); + assertNull(contract); + } @Test public void addMercWithRetainerAtBContractSucceeds() { From a927036eecbc6dbefdfc5ed6d753508216c093b1 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 16 Dec 2020 17:28:35 -0500 Subject: [PATCH 09/16] Rename the ContractMarket tests to better describe intent --- ...tMarketTest.java => ContractMarketAtBGenerationTests.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename MekHQ/unittests/mekhq/campaign/market/{ContractMarketTest.java => ContractMarketAtBGenerationTests.java} (99%) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java similarity index 99% rename from MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java rename to MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java index d2f53c2264..e42ce6a182 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java @@ -54,13 +54,13 @@ import static org.mockito.Mockito.*; @RunWith(Parameterized.class) -public class ContractMarketTest { +public class ContractMarketAtBGenerationTests { private final int gameYear; private final int unitRating; private final boolean isClanEnemy; - public ContractMarketTest(int gameYear, int unitRating, boolean isClanEnemy) { + public ContractMarketAtBGenerationTests(int gameYear, int unitRating, boolean isClanEnemy) { this.gameYear = gameYear; this.unitRating = unitRating; this.isClanEnemy = isClanEnemy; From 95bff6df2512948b3d08c9f29b75ca850a3a517b Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 17 Dec 2020 10:54:27 -0500 Subject: [PATCH 10/16] Move Systems creation to loadDefault and load - Likewise rename Factions::generate to loadDefault and load --- .../mekhq/campaign/io/CampaignXmlParser.java | 2 - .../src/mekhq/campaign/universe/Factions.java | 49 +++- .../src/mekhq/campaign/universe/Systems.java | 211 ++++++++---------- .../mekhq/gui/dialog/DataLoadingDialog.java | 18 +- 4 files changed, 136 insertions(+), 144 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java index 5f487e4139..2dc1fd6f66 100644 --- a/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java +++ b/MekHQ/src/mekhq/campaign/io/CampaignXmlParser.java @@ -1510,8 +1510,6 @@ private static boolean isLegacyMissingMASC(Part p) { } private static void updatePlanetaryEventsFromXML(Node wn) { - Systems.reload(true); - List events; Map> eventsMap = new HashMap<>(); diff --git a/MekHQ/src/mekhq/campaign/universe/Factions.java b/MekHQ/src/mekhq/campaign/universe/Factions.java index 0a8f056660..8ae284d5ae 100644 --- a/MekHQ/src/mekhq/campaign/universe/Factions.java +++ b/MekHQ/src/mekhq/campaign/universe/Factions.java @@ -20,6 +20,7 @@ package mekhq.campaign.universe; import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -30,12 +31,14 @@ import java.util.Objects; import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import megamek.client.ratgenerator.FactionRecord; import megamek.client.ratgenerator.RATGenerator; @@ -68,7 +71,7 @@ public static Factions getInstance() { return instance; } - public static void setInstance(Factions instance) { + public static void setInstance(@Nullable Factions instance) { Factions.instance = instance; } @@ -79,7 +82,7 @@ public RATGenerator getRATGenerator() { public void setRATGenerator(RATGenerator ratGenerator) { this.ratGenerator = Objects.requireNonNull(ratGenerator); } - + public List getChoosableFactionCodes() { return choosableFactionCodes; } @@ -123,8 +126,9 @@ public Faction getFactionFromFullNameAndYear(String fname, int year) { } /** - * Helper function that gets the faction record for the specified faction, or a fallback general faction record. - * Useful for RAT generator activity. + * Helper function that gets the faction record for the specified faction, or a + * fallback general faction record. Useful for RAT generator activity. + * * @param faction The faction whose MegaMek faction record to retrieve. * @return Found faction record or null. */ @@ -155,22 +159,47 @@ public String getFactionCode(int faction) { return (null != f) ? f.getShortName() : "IND"; } - public static @Nullable Factions generateFactions() throws DOMException { + /** + * Loads the default Factions data. + * + * @throws DOMException + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public static Factions loadDefault() + throws DOMException, SAXException, IOException, ParserConfigurationException { MekHQ.getLogger().info("Starting load of faction data from XML..."); + Factions factions = load("data/universe/factions.xml"); + + MekHQ.getLogger().info("Loaded a total of " + factions.factions.size() + " factions"); + + return factions; + } + + /** + * Loads Factions data from a file. + * + * @param factionsPath The path to the XML file containing Factions data. + * + * @throws DOMException + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public static Factions load(String factionsPath) + throws DOMException, SAXException, IOException, ParserConfigurationException { Factions retVal = new Factions(); Document xmlDoc; - try (FileInputStream fis = new FileInputStream("data/universe/factions.xml")) { + try (FileInputStream fis = new FileInputStream(factionsPath)) { // Using factory get an instance of document builder DocumentBuilder db = MekHqXmlUtil.newSafeDocumentBuilder(); // Parse using builder to get DOM representation of the XML file xmlDoc = db.parse(fis); - } catch (Exception ex) { - MekHQ.getLogger().error(ex); - return null; } Element factionEle = xmlDoc.getDocumentElement(); @@ -222,8 +251,6 @@ public String getFactionCode(int faction) { } } - MekHQ.getLogger().info("Loaded a total of " + retVal.factions.size() + " factions"); - return retVal; } } diff --git a/MekHQ/src/mekhq/campaign/universe/Systems.java b/MekHQ/src/mekhq/campaign/universe/Systems.java index cead13dd6f..8b54b25162 100644 --- a/MekHQ/src/mekhq/campaign/universe/Systems.java +++ b/MekHQ/src/mekhq/campaign/universe/Systems.java @@ -19,6 +19,7 @@ package mekhq.campaign.universe; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; @@ -63,12 +64,9 @@ */ public class Systems { - private final static Object LOADING_LOCK = new Object[0]; private static Systems systems; - //private static ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.Planets", new EncodeControl()); //$NON-NLS-1$ - - // Marshaller / unmarshaller instances + // Marshaller / unmarshaller instances private static Marshaller marshaller; private static Unmarshaller unmarshaller; static { @@ -112,27 +110,17 @@ public static void setInstance(Systems instance) { } private ConcurrentMap systemList = new ConcurrentHashMap<>(); - /* organizes systems into a grid of 30lyx30ly squares so we can find - * nearby systems without iterating through the entire planet list. */ + /** + * Organizes systems into a grid of 30lyx30ly squares so we can find nearby + * systems without iterating through the entire planet list. + */ private HashMap>> systemGrid = new HashMap<>(); // HPG Network cache (to not recalculate all the damn time) private Collection hpgNetworkCache = null; private LocalDate hpgNetworkCacheDate = null; - private Thread loader; - private boolean initialized = false; - private boolean initializing = false; - - private Systems() {} - - public void initialize() { - if (!initialized && !initializing) { - initializing = true; - loader = new Thread(() -> systems.initializeInternal(), "Planet Loader"); - loader.setPriority(Thread.NORM_PRIORITY - 1); - loader.start(); - } + private Systems() { } private Set getSystemGrid(int x, int y) { @@ -160,12 +148,12 @@ public PlanetarySystem getSystemByName(String name, LocalDate when) { } public List getNearbySystems(final double centerX, final double centerY, int distance) { - List neighbors = new ArrayList<>(); + List neighbors = new ArrayList<>(); - visitNearbySystems(centerX, centerY, distance, neighbors::add); + visitNearbySystems(centerX, centerY, distance, neighbors::add); - neighbors.sort(Comparator.comparingDouble(o -> o.getDistanceTo(centerX, centerY))); - return neighbors; + neighbors.sort(Comparator.comparingDouble(o -> o.getDistanceTo(centerX, centerY))); + return neighbors; } public List getNearbySystems(final PlanetarySystem system, int distance) { @@ -265,27 +253,61 @@ public Collection getHPGNetwork(LocalDate when) { return result; } -// Data loading methods + // Data loading methods - private void initializeInternal() { - try { - generateSystems(); - } catch (ParseException e) { - MekHQ.getLogger().error(e); - } - } + /** + * Loads the default Systems data. + * + * @throws DOMException + * @throws IOException + * @throws FileNotFoundException + * @throws ParseException + */ + public static Systems loadDefault() + throws DOMException, FileNotFoundException, IOException, ParseException { + MekHQ.getLogger().info("Starting load of system data from XML..."); + long currentTime = System.currentTimeMillis(); + + Systems systems = load("data/universe/planetary_systems", "data/universe/systems.xml"); - private void done() { - initialized = true; - initializing = false; + MekHQ.getLogger().info(String.format(Locale.ROOT, "Loaded a total of %d systems in %.3fs.", + systems.systemList.size(), (System.currentTimeMillis() - currentTime) / 1000.0)); + + systems.logVeryCloseSystems(); + + return systems; } - public boolean isInitialized() { - return initialized; + /** + * Loads Systems data from files. + * + * @param planetsPath The path to the folder containing planetary XML files. + * @param defaultFilePath The path to the file with default systems data. + * + * @throws DOMException + * @throws IOException + * @throws FileNotFoundException + * @throws ParseException + */ + public static Systems load(String planetsPath, String defaultFilePath) + throws DOMException, IOException, ParseException, FileNotFoundException { + Systems systems = new Systems(); + + // Step 1: Read the default file + try (FileInputStream fis = new FileInputStream(defaultFilePath)) { + systems.updateSystems(fis); + } + + // Step 2: Load all the xml files within the planets subdirectory, if it exists + Utilities.parseXMLFiles(planetsPath, systems::updateSystems); + + // Step 3: Cleanup any systems that have issues + systems.cleanupSystems(); + + return systems; } private void updateSystems(FileInputStream source) { - final String METHOD_NAME = "updateSystems(FileInputStream)"; //$NON-NLS-1$ // JAXB unmarshaller closes the stream it doesn't own. Bad JAXB. BAD. try (InputStream is = new FilterInputStream(source) { @Override @@ -316,86 +338,45 @@ public void close() { } } } } catch (JAXBException e) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, e); + MekHQ.getLogger().error(e); } catch (IOException e) { - MekHQ.getLogger().error(getClass(), METHOD_NAME, e); + MekHQ.getLogger().error(e); } } - private void generateSystems() throws DOMException, ParseException { - generateSystems("data/universe/planetary_systems", "data/universe/systems.xml"); - } - - private void generateSystems(String planetsPath, String defaultFilePath) throws DOMException, ParseException { - - MekHQ.getLogger().info(this, "Starting load of system data from XML..."); - long currentTime = System.currentTimeMillis(); - synchronized (LOADING_LOCK) { - // Step 1: Initialize variables. - if (null == systemList) { - systemList = new ConcurrentHashMap<>(); - } - systemList.clear(); - if (null == systemGrid) { - systemGrid = new HashMap<>(); - } - // Be nice to the garbage collector - for (Map.Entry>> systemGridColumn : systemGrid.entrySet()) { - for (Map.Entry> systemGridElement : systemGridColumn.getValue().entrySet()) { - if (null != systemGridElement.getValue()) { - systemGridElement.getValue().clear(); - } - } - if (null != systemGridColumn.getValue()) { - systemGridColumn.getValue().clear(); - } - } - systemGrid.clear(); - - // Step 2: Read the default file - try (FileInputStream fis = new FileInputStream(defaultFilePath)) { - updateSystems(fis); - } catch (Exception ex) { - MekHQ.getLogger().error(this, ex); - } - - // Step 3: Load all the xml files within the planets subdirectory, if it exists - Utilities.parseXMLFiles(planetsPath, this::updateSystems); - - List toRemove = new ArrayList<>(); - for (PlanetarySystem system : systemList.values()) { - if ((null == system.getX()) || (null == system.getY())) { - MekHQ.getLogger().error(this, String.format("System \"%s\" is missing coordinates", system.getId())); - toRemove.add(system); - continue; - } - //make sure the primary slot is not larger than the number of planets - if (system.getPrimaryPlanetPosition() > system.getPlanets().size()) { - MekHQ.getLogger().error(this, String.format("System \"%s\" has a primary slot greater than the number of planets", system.getId())); - toRemove.add(system); - continue; - } - int x = (int) (system.getX() / 30.0); - int y = (int) (system.getY() / 30.0); - systemGrid.computeIfAbsent(x, k -> new HashMap<>()); - systemGrid.get(x).computeIfAbsent(y, k -> new HashSet<>()); - systemGrid.get(x).get(y).add(system); + private void cleanupSystems() { + List toRemove = new ArrayList<>(); + for (PlanetarySystem system : systemList.values()) { + if ((null == system.getX()) || (null == system.getY())) { + MekHQ.getLogger().error(String.format("System \"%s\" is missing coordinates", system.getId())); + toRemove.add(system); + continue; } - for (PlanetarySystem system : toRemove) { - systemList.remove(system.getId()); + //make sure the primary slot is not larger than the number of planets + if (system.getPrimaryPlanetPosition() > system.getPlanets().size()) { + MekHQ.getLogger().error(String.format("System \"%s\" has a primary slot greater than the number of planets", system.getId())); + toRemove.add(system); + continue; } - done(); + int x = (int) (system.getX() / 30.0); + int y = (int) (system.getY() / 30.0); + systemGrid.computeIfAbsent(x, k -> new HashMap<>()); + systemGrid.get(x).computeIfAbsent(y, k -> new HashSet<>()); + systemGrid.get(x).get(y).add(system); } - MekHQ.getLogger().info(this, String.format(Locale.ROOT, - "Loaded a total of %d systems in %.3fs.", - systemList.size(), (System.currentTimeMillis() - currentTime) / 1000.0)); + for (PlanetarySystem system : toRemove) { + systemList.remove(system.getId()); + } + } + + private void logVeryCloseSystems() { // Planetary sanity check time! for (PlanetarySystem system : systemList.values()) { List veryCloseSystems = getNearbySystems(system, 1); if (veryCloseSystems.size() > 1) { for (PlanetarySystem closeSystem : veryCloseSystems) { if (!system.getId().equals(closeSystem.getId())) { - MekHQ.getLogger().warning(this, String.format(Locale.ROOT, + MekHQ.getLogger().warning(String.format(Locale.ROOT, "Extremely close systems detected. Data error? %s <-> %s: %.3f ly", //$NON-NLS-1$ system.getId(), closeSystem.getId(), system.getDistanceTo(closeSystem))); } @@ -495,7 +476,7 @@ public void writePlanetaryEvent(Writer out, Planet.PlanetaryEvent event) { try { planetMarshaller.marshal(event, out); } catch (Exception e) { - MekHQ.getLogger().error(getClass(), "writePlanet(Writer,Planet.PlanetaryEvent)", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } } @@ -508,7 +489,7 @@ public void writePlanetarySystemEvent(Writer out, PlanetarySystem.PlanetarySyste try { marshaller.marshal(event, out); } catch (Exception e) { - MekHQ.getLogger().error(getClass(), "writePlanet(Writer,Planet.PlanetaryEvent)", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } } @@ -522,7 +503,7 @@ public Planet.PlanetaryEvent readPlanetaryEvent(Node node) { try { return (Planet.PlanetaryEvent) planetUnmarshaller.unmarshal(node); } catch (JAXBException e) { - MekHQ.getLogger().error(getClass(), "readPlanetaryEvent(Node)", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } return null; } @@ -537,25 +518,11 @@ public PlanetarySystem.PlanetarySystemEvent readPlanetarySystemEvent(Node node) try { return (PlanetarySystem.PlanetarySystemEvent) unmarshaller.unmarshal(node); } catch (JAXBException e) { - MekHQ.getLogger().error(getClass(), "readPlanetarySystemEvent(Node)", e); //$NON-NLS-1$ + MekHQ.getLogger().error(e); } return null; } - public static void reload(boolean waitForFinish) { - systems = null; - getInstance().initialize(); - if (waitForFinish) { - try { - while (!systems.isInitialized()) { - Thread.sleep(10); - } - } catch (InterruptedException iex) { - MekHQ.getLogger().error(iex); //$NON-NLS-1$ - } - } - } - /** @return true if the planet was known and got updated, false otherwise */ /*public boolean updatePlanetaryEvents(String id, Collection events) { return updatePlanetaryEvents(id, events, false); diff --git a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java index ef5ac2fca5..94a6c56fdf 100644 --- a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java @@ -27,6 +27,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.text.ParseException; import java.util.List; import java.util.ResourceBundle; import java.util.concurrent.ExecutionException; @@ -38,6 +39,10 @@ import javax.swing.JOptionPane; import javax.swing.JProgressBar; import javax.swing.SwingWorker; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.DOMException; +import org.xml.sax.SAXException; import megamek.client.generator.RandomNameGenerator; import megamek.client.generator.RandomCallsignGenerator; @@ -129,12 +134,13 @@ class Task extends SwingWorker { private boolean cancelled = false; @Override - public Campaign doInBackground() throws IOException, CampaignXmlParseException, NullEntityException { + public Campaign doInBackground() throws IOException, CampaignXmlParseException, NullEntityException, + DOMException, ParseException, SAXException, ParserConfigurationException { //region Progress 0 //Initialize progress property. setProgress(0); - Factions.setInstance(Factions.generateFactions()); + Factions.setInstance(Factions.loadDefault()); CurrencyManager.getInstance().loadCurrencies(); @@ -144,13 +150,7 @@ public Campaign doInBackground() throws IOException, CampaignXmlParseException, RATManager.populateCollectionNames(); // Initialize the systems - Systems.getInstance().initialize(); - while (!Systems.getInstance().isInitialized()) { - try { - Thread.sleep(50); - } catch (InterruptedException ignored) { - } - } + Systems.setInstance(Systems.loadDefault()); RandomNameGenerator.getInstance(); RandomCallsignGenerator.getInstance(); From a092a32bffe549524e953a9a1610194512eb870c Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 17 Dec 2020 11:00:00 -0500 Subject: [PATCH 11/16] Add integration test for Systems::loadDefault --- .../universe/SystemsIntegrationTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java diff --git a/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java b/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java new file mode 100644 index 0000000000..0f3956a4c9 --- /dev/null +++ b/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java @@ -0,0 +1,29 @@ +package mekhq.campaign.universe; + +import static org.junit.Assert.*; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.ParseException; + +import org.junit.Test; +import org.w3c.dom.DOMException; + +public class SystemsIntegrationTest { + @Test + public void loadDefaultTest() + throws DOMException, FileNotFoundException, IOException, ParseException { + Systems systems = Systems.loadDefault(); + + assertNotNull(systems); + + PlanetarySystem terra = systems.getSystemById("Terra"); + assertNotNull(terra); + assertEquals(0.0, terra.getX(), 0.001); + assertEquals(0.0, terra.getY(), 0.001); + + Planet thirdRock = terra.getPlanetById("Terra"); + assertNotNull(thirdRock); + assertEquals(thirdRock, terra.getPlanet(3)); + } +} From bfc9c3642648f6c9bfcc8ec5b992e48753f7d52e Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 17 Dec 2020 11:01:59 -0500 Subject: [PATCH 12/16] Add missing copyright header --- .../universe/SystemsIntegrationTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java b/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java index 0f3956a4c9..4f00d729dd 100644 --- a/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java +++ b/MekHQ/unittests/mekhq/campaign/universe/SystemsIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All rights reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + package mekhq.campaign.universe; import static org.junit.Assert.*; From 4847898b2ad850d2a0d15b57c0bb30640a97f5ed Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 17 Dec 2020 11:09:39 -0500 Subject: [PATCH 13/16] Add integration test for Factions --- .../universe/FactionsIntegrationTest.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 MekHQ/unittests/mekhq/campaign/universe/FactionsIntegrationTest.java diff --git a/MekHQ/unittests/mekhq/campaign/universe/FactionsIntegrationTest.java b/MekHQ/unittests/mekhq/campaign/universe/FactionsIntegrationTest.java new file mode 100644 index 0000000000..0f59d301a2 --- /dev/null +++ b/MekHQ/unittests/mekhq/campaign/universe/FactionsIntegrationTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All rights reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + +package mekhq.campaign.universe; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; + +import org.junit.Test; +import org.w3c.dom.DOMException; +import org.xml.sax.SAXException; + +public class FactionsIntegrationTest { + @Test + public void loadDefaultTest() + throws DOMException, SAXException, IOException, ParserConfigurationException { + Factions factions = Factions.loadDefault(); + + assertNotNull(factions); + + List choosableFactionCodes = factions.getChoosableFactionCodes(); + assertNotNull(choosableFactionCodes); + assertTrue(choosableFactionCodes.contains("MERC")); + assertTrue(choosableFactionCodes.contains("FS")); + + for (String factionCode : choosableFactionCodes) { + assertNotNull(String.format("Missing faction %s in choosable faction list", factionCode), + factions.getFaction(factionCode)); + } + + Faction capellans = factions.getFaction("CC"); + assertNotNull(capellans); + assertFalse(capellans.isClan()); + assertEquals("Sian", capellans.getStartingPlanet(LocalDate.of(3025, 1, 1))); + assertTrue(capellans.is(Faction.Tag.IS)); + assertTrue(capellans.is(Faction.Tag.MAJOR)); + + Faction comStar = factions.getFaction("CS"); + assertNotNull(comStar); + assertTrue(comStar.isComStar()); + assertEquals("Terra", comStar.getStartingPlanet(LocalDate.of(3025, 1, 1))); + assertEquals("Tukayyid", comStar.getStartingPlanet(LocalDate.of(3067, 1, 1))); + assertTrue(comStar.is(Faction.Tag.IS)); + assertTrue(comStar.is(Faction.Tag.INACTIVE)); + assertTrue(comStar.is(Faction.Tag.MAJOR)); + + Faction ghostBear = factions.getFaction("CGB"); + assertNotNull(ghostBear); + assertTrue(ghostBear.isClan()); + assertEquals("Arcadia (Clan)", ghostBear.getStartingPlanet(LocalDate.of(3025, 1, 1))); + assertEquals("Alshain", ghostBear.getStartingPlanet(LocalDate.of(3067, 1, 1))); + assertTrue(ghostBear.is(Faction.Tag.CLAN)); + assertTrue(ghostBear.is(Faction.Tag.MAJOR)); + } +} From 9f0648f385d46b0f84785665c45257809dc82ee0 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Thu, 17 Dec 2020 17:02:17 -0500 Subject: [PATCH 14/16] Add integration tests for the ContractMarket itself --- .../market/ContractMarketIntegrationTest.java | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java new file mode 100644 index 0000000000..65f36bf933 --- /dev/null +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2020 - The MegaMek Team. All rights reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ + +package mekhq.campaign.market; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.UUID; + +import javax.xml.parsers.ParserConfigurationException; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.w3c.dom.DOMException; +import org.xml.sax.SAXException; + +import megamek.common.Bay; +import megamek.common.Crew; +import megamek.common.CrewType; +import megamek.common.EquipmentType; +import megamek.common.Mech; +import mekhq.campaign.Campaign; +import mekhq.campaign.CampaignOptions; +import mekhq.campaign.force.Force; +import mekhq.campaign.mission.AtBContract; +import mekhq.campaign.mission.Contract; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.personnel.enums.PersonnelStatus; +import mekhq.campaign.personnel.ranks.Ranks; +import mekhq.campaign.rating.UnitRatingMethod; +import mekhq.campaign.unit.Unit; +import mekhq.campaign.universe.Factions; +import mekhq.campaign.universe.RandomFactionGenerator; +import mekhq.campaign.universe.Systems; + +public class ContractMarketIntegrationTest { + private static final int REASONABLE_GENERATION_ATTEMPTS = 3; + + private Campaign campaign; + + @BeforeClass + public static void setupStatics() + throws DOMException, SAXException, IOException, ParserConfigurationException, ParseException { + EquipmentType.initializeTypes(); + Factions.setInstance(Factions.loadDefault()); + Systems.setInstance(Systems.loadDefault()); + Ranks.initializeRankSystems(); + } + + @AfterClass + public static void cleanupStatics() { + Systems.setInstance(null); + RandomFactionGenerator.setInstance(null); + Factions.setInstance(null); + } + + @Before + public void setupCampaign() { + CampaignOptions options = new CampaignOptions(); + options.setUnitRatingMethod(UnitRatingMethod.NONE); + + campaign = new Campaign(); + campaign.setCampaignOptions(options); + + RandomFactionGenerator.getInstance().startup(campaign); + + fillHangar(campaign); + } + + @Test + public void addAtBContractMercsTest() { + ContractMarket market = new ContractMarket(); + + // Simulate clicking GM Add on the contract market three times + for (int ii = 0; ii < REASONABLE_GENERATION_ATTEMPTS; ++ii) { + market.addAtBContract(campaign); + } + + assertFalse(market.getContracts().isEmpty()); + } + + @Test + public void generateContractOffersMercsTest() { + ContractMarket market = new ContractMarket(); + + // Simulate three months of contract generation ... + boolean foundContract = false; + for (int ii = 0; ii < REASONABLE_GENERATION_ATTEMPTS; ++ii) { + market.generateContractOffers(campaign, true); + + // ... and one of these three should get us a contract! + foundContract |= market.getContracts().size() > 0; + } + + assertTrue(foundContract); + } + + @Test + public void addAtBContractMercRetainerTest() { + campaign.setRetainerEmployerCode("LA"); + + ContractMarket market = new ContractMarket(); + + // Simulate clicking GM Add on the contract market three times + for (int ii = 0; ii < 3; ++ii) { + market.addAtBContract(campaign); + } + + assertFalse(market.getContracts().isEmpty()); + } + + @Test + public void generateContractOffersMercRetainerTest() { + campaign.setRetainerEmployerCode("CS"); + + ContractMarket market = new ContractMarket(); + + // Simulate three months of contract generation ... + boolean foundContract = false; + for (int ii = 0; ii < REASONABLE_GENERATION_ATTEMPTS; ++ii) { + market.generateContractOffers(campaign, true); + + // ... and one of these three should get us a contract! + foundContract |= market.getContracts().size() > 0; + } + + assertTrue(foundContract); + } + + @Test + public void generateContractOffersMercSubcontractTest() { + AtBContract existing = mock(AtBContract.class); + when(existing.getId()).thenReturn(1); + when(existing.getScenarios()).thenReturn(new ArrayList<>()); + when(existing.isActive()).thenReturn(true); + when(existing.getEmployerCode()).thenReturn("FWL"); + when(existing.getEnemyCode()).thenReturn("CC"); + when(existing.getSystemId()).thenReturn("Sian"); + when(existing.getEndingDate()).thenReturn(campaign.getLocalDate().plusDays(3000)); + campaign.importMission(existing); + + ContractMarket market = new ContractMarket(); + + // TODO: find a way to mock MMRandom + + // Simulate two years of contract generation to get a sub contract ... + boolean foundContract = false; + for (int ii = 0; ii < 24; ++ii) { + market.generateContractOffers(campaign, true); + + // ... and hopefully, one of these should get us a sub-contract! 3 of 12 chance. + for (Contract c : market.getContracts()) { + foundContract |= (c instanceof AtBContract) + && (((AtBContract) c).getParentContract() == existing); + } + + if (foundContract) { + break; + } + } + + assertTrue(foundContract); + } + + @Test + public void addAtBContractHouseTest() { + campaign.setFactionCode("DC"); + + ContractMarket market = new ContractMarket(); + + // Simulate clicking GM Add on the contract market three times + for (int ii = 0; ii < 3; ++ii) { + market.addAtBContract(campaign); + } + + assertFalse(market.getContracts().isEmpty()); + } + + @Test + public void generateContractOffersHouseTest() { + campaign.setFactionCode("FS"); + + ContractMarket market = new ContractMarket(); + + // Simulate three months of contract generation ... + boolean foundContract = false; + for (int ii = 0; ii < REASONABLE_GENERATION_ATTEMPTS; ++ii) { + market.generateContractOffers(campaign, true); + + // ... and one of these three should get us a contract! + foundContract |= market.getContracts().size() > 0; + } + + assertTrue(foundContract); + } + + private void fillHangar(Campaign campaign) { + // Add 12 mechs in 3 forces + for (int jj = 0; jj < 3; ++jj) { + Force force = new Force("Force " + String.valueOf(jj)); + for (int ii = 0; ii < 4; ++ii) { + Unit unit = createMech(campaign); + force.addUnit(unit.getId()); + + campaign.getHangar().addUnit(unit); + } + + campaign.addForce(force, campaign.getForces()); + } + } + + private Unit createMech(Campaign campaign) { + Mech entity = mock(Mech.class); + when(entity.getCrew()).thenReturn(new Crew(CrewType.SINGLE)); + when(entity.getTransportBays()).thenReturn(new java.util.Vector()); + Unit unit = new Unit(entity, campaign); + unit.setId(UUID.randomUUID()); + unit.addPilotOrSoldier(createPilot()); + return unit; + } + + private Person createPilot() { + Person person = mock(Person.class); + when(person.getId()).thenReturn(UUID.randomUUID()); + when(person.getStatus()).thenReturn(PersonnelStatus.ACTIVE); + return person; + } +} From af7948905571ace67d29c20549c505f0db25914a Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 18 Dec 2020 16:00:23 -0500 Subject: [PATCH 15/16] Use new MMRandom mocking ability to make subcontracts deterministic --- .../market/ContractMarketIntegrationTest.java | 55 +++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java index 65f36bf933..3fc1dbfce4 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketIntegrationTest.java @@ -37,9 +37,12 @@ import org.xml.sax.SAXException; import megamek.common.Bay; +import megamek.common.Compute; import megamek.common.Crew; import megamek.common.CrewType; import megamek.common.EquipmentType; +import megamek.common.MMRandom; +import megamek.common.MMRoll; import megamek.common.Mech; import mekhq.campaign.Campaign; import mekhq.campaign.CampaignOptions; @@ -163,25 +166,45 @@ public void generateContractOffersMercSubcontractTest() { ContractMarket market = new ContractMarket(); - // TODO: find a way to mock MMRandom - - // Simulate two years of contract generation to get a sub contract ... - boolean foundContract = false; - for (int ii = 0; ii < 24; ++ii) { - market.generateContractOffers(campaign, true); - - // ... and hopefully, one of these should get us a sub-contract! 3 of 12 chance. - for (Contract c : market.getContracts()) { - foundContract |= (c instanceof AtBContract) - && (((AtBContract) c).getParentContract() == existing); + java.security.SecureRandom realRng = new java.security.SecureRandom(); + MMRandom rng = mock(MMRandom.class); + // Override and ensure we are guaranteed a sub-contract + MMRoll roll1d6 = mock(MMRoll.class); + when(roll1d6.getIntValue()).thenReturn(6); + doReturn(roll1d6).when(rng).d6(); + doReturn(roll1d6).when(rng).d6(eq(1)); + MMRoll roll2d6 = mock(MMRoll.class); + when(roll2d6.getIntValue()).thenReturn(12); + doReturn(roll2d6).when(rng).d6(eq(2)); + // Keep the rest random + doAnswer(inv -> { + int max = inv.getArgument(0); + return realRng.nextInt(max); + }).when(rng).randomInt(anyInt()); + + try { + Compute.setRNG(rng); + + // Simulate three months of contract generation to get a sub contract ... + boolean foundContract = false; + for (int ii = 0; ii < REASONABLE_GENERATION_ATTEMPTS; ++ii) { + market.generateContractOffers(campaign, true); + + // ... and hopefully, one of these should get us a sub-contract! 3 of 12 chance. + for (Contract c : market.getContracts()) { + foundContract |= (c instanceof AtBContract) + && (((AtBContract) c).getParentContract() == existing); + } + + if (foundContract) { + break; + } } - if (foundContract) { - break; - } + assertTrue(foundContract); + } finally { + Compute.setRNG(MMRandom.R_DEFAULT); } - - assertTrue(foundContract); } @Test From 30aeaf1616d95fb1de04cbe918be9adc07369d15 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 30 Dec 2020 10:00:10 -0500 Subject: [PATCH 16/16] Resolve PR comments --- .../ContractMarketAtBGenerationTests.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java b/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java index e42ce6a182..96b8868aac 100644 --- a/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java +++ b/MekHQ/unittests/mekhq/campaign/market/ContractMarketAtBGenerationTests.java @@ -86,7 +86,7 @@ public void addMercWithoutRetainerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -182,7 +182,7 @@ public void addMercWithoutRetainerMinorPowerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -278,7 +278,7 @@ public void addMercWithoutRetainerEmployerNeutralAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -374,7 +374,7 @@ public void addMercWithoutRetainerEmployerNeutralAtWarAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -471,7 +471,7 @@ public void mercEmployerRetries() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -569,7 +569,7 @@ public void mercEmployerRetriesFail() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); Factions factions = mock(Factions.class); @@ -592,7 +592,7 @@ public void mercMissiongTargetRetries() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -689,7 +689,7 @@ public void mercMissionTargetRetriesFail() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -780,7 +780,7 @@ public void mercJumpPathRetries() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -877,7 +877,7 @@ public void mercJumpPathFails() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -971,7 +971,7 @@ public void addMercWithRetainerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(employer); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1067,7 +1067,7 @@ public void addMercWithRetainerMinorPowerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(employer); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1163,7 +1163,7 @@ public void addMercWithRetainerEmployerNeutralAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(employer); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1259,7 +1259,7 @@ public void addMercWithRetainerEmployerNeutralAtWarAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn("MERC"); when(campaign.getRetainerEmployerCode()).thenReturn(employer); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1355,7 +1355,7 @@ public void nonMercAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn(employer); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1451,7 +1451,7 @@ public void nonMercMinorPowerAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn(employer); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1547,7 +1547,7 @@ public void nonMercNeutralAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn(employer); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class); @@ -1643,7 +1643,7 @@ public void nonMercNeutralAtWarAtBContractSucceeds() { when(campaign.getFactionCode()).thenReturn(employer); when(campaign.getRetainerEmployerCode()).thenReturn(null); when(campaign.getUnitRatingMod()).thenReturn(unitRating); - when(campaign.getLocalDate()).thenReturn(LocalDate.of(gameYear, 1, 1)); + when(campaign.getLocalDate()).thenReturn(LocalDate.ofYearDay(gameYear, 1)); when(campaign.getGameYear()).thenReturn(gameYear); CampaignOptions campaignOptions = mock(CampaignOptions.class);