diff --git a/MekHQ/resources/mekhq/resources/CampaignGUI.properties b/MekHQ/resources/mekhq/resources/CampaignGUI.properties index 9231516110..ae6b13b8ca 100644 --- a/MekHQ/resources/mekhq/resources/CampaignGUI.properties +++ b/MekHQ/resources/mekhq/resources/CampaignGUI.properties @@ -90,6 +90,7 @@ miAdvanceMultipleDays.text=Advance Multiple Days... miRandomBloodnames.text=Bloodname Randomization for All Personnel miBatchXP.text=Mass Personnel Training... miScenarioEditor.text=Scenario Template Editor... +miCompanyGenerator.text=Company Generator... # Help Menu menuHelp.text=Help diff --git a/MekHQ/resources/mekhq/resources/CompleteMissionDialog.properties b/MekHQ/resources/mekhq/resources/CompleteMissionDialog.properties deleted file mode 100644 index c13560a25c..0000000000 --- a/MekHQ/resources/mekhq/resources/CompleteMissionDialog.properties +++ /dev/null @@ -1,4 +0,0 @@ -lblOutcome.text=Outcome: -btnDone.text=OK -btnCancel.text=Cancel -title.text=Complete Mission \ No newline at end of file diff --git a/MekHQ/resources/mekhq/resources/GUI.properties b/MekHQ/resources/mekhq/resources/GUI.properties index b71078966b..47b1c7c6e4 100644 --- a/MekHQ/resources/mekhq/resources/GUI.properties +++ b/MekHQ/resources/mekhq/resources/GUI.properties @@ -24,6 +24,7 @@ Generate.text=Generate GMMode.text=GM Mode GMMode.toolTipText=The contents of this menu are intended solely for GM use. Import.text=Import +InvalidOptions.title=Error: Invalid Option Selection None.text=None Ok.text=Ok Ok.toolTipText=Confirm the changes and close the dialog. @@ -156,7 +157,7 @@ editKillLog.text=Edit Kill Log... assignKill.text=Assign Kill... exportPersonnel.text=Export Personnel sack.text=Sack... -## Randomization Menu +### Randomization Menu randomizationMenu.text=Randomization Menu miRandomName.single.text=Randomize Name miRandomName.bulk.text=Randomize Names @@ -174,7 +175,7 @@ miRandomOriginFaction.single.text=Randomize Origin Faction miRandomOriginFaction.bulk.text=Randomize Origin Factions miRandomOriginPlanet.single.text=Randomize Origin Planet miRandomOriginPlanet.bulk.text=Randomize Origin Planets -## GM Menu +### GM Menu gmMode.text=GM Mode changePrisonerStatus.text=Change Prisoner Status removePerson.text=Remove Person @@ -208,7 +209,7 @@ ProcurementTableMouseAdapter.ProcuredItem.report=Procured ProcurementTableMouseAdapter.CannotAffordToPurchaseItem.report=You cannot afford to purchase %s ProcurementTableMouseAdapter.GMAdded.report=GM Added %s -### UnitTableMouseAdapter Class - TODO : unfinished, with cleanup required +#### UnitTableMouseAdapter Class - TODO : unfinished, with cleanup required deleteUnitsCount.text=%d units removeQ.title=Remove? confirmRemove.text=Do you really want to remove %s? @@ -322,6 +323,22 @@ btnNewDecade.toolTipText=Advance to the first day of the next decade (e.g. 01-JA ### CampaignPresetSelectionDialog Class CampaignPresetSelectionDialog.title=Select Campaign Preset +### CompleteMissionDialog Class +CompleteMissionDialog.title=Complete Mission +lblOutcomeStatus.text=Outcome +lblOutcomeStatus.toolTipText=This is the mission's outcome, with Active meaning the mission has not been completed. + +### CompanyGenerationDialog Class +CompanyGenerationDialog.title=Company Generator +CompanyGenerationDialog.btnGenerate.toolTipText=Generates a company based on the provided options. Currently, this immediately applies it to the campaign, making this functionally identical to Apply in the current implementation. +CompanyGenerationDialog.btnApply.toolTipText=Immediately complete all remaining generation and apply the changes to the campaign. +CompanyGenerationDialog.btnRestore.toolTipText=Restores the options on the current dialog to the default options for the currently selected company generation method. +CompanyGenerationDialog.btnImport.toolTipText=Import the current options from an XML file. +CompanyGenerationDialog.btnExport.toolTipText=Export the current options to an XML file. + +### CompanyGenerationOptionsDialog Class +CompanyGenerationOptionsDialog.title=Company Generation Options + ### ContractMarketDialog Class ContractMarketDialog.title=Contract Market @@ -331,7 +348,7 @@ txtPresetName.text=Enter Preset Name txtPresetName.toolTipText=This is the name of the preset, which we recommend ensuring is unique. txtPresetDescription.text=Enter Preset Description txtPresetDescription.toolTipText=This is used to describe the preset in the selection screen. -## Continuous Panel +## Startup Panel startupCampaignPresetPanel.title=Startup Options startupCampaignPresetPanel.toolTipText=These are options that are only applied when starting a new campaign. chkSpecifyDate.text=Specify Starting Date @@ -348,7 +365,11 @@ chkSpecifyRankSystem.text=Specify Rank System chkSpecifyRankSystem.toolTipText=This allows you to specify the starting rank system for a campaign. The default starting rank system is the Second Star League Defense Force. comboRankSystem.toolTipText=This is the rank system the campaign will start with. lblContractCount.text=Starting Contract Count (Unimplemented) -lblContractCount.toolTipText=Specify the number of contracts generated by the contract market at the start of a campaign. The default starting contract count is 2 (AtB Contract Market). +lblContractCount.toolTipText=Specify the number of contracts generated by the contract market at the start of a campaign. The default starting contract count is 2 (Against the Bot Contract Market). +chkSpecifyCompanyGenerationOptions.text=Specify Company Generation Options (Unimplemented) +chkSpecifyCompanyGenerationOptions.toolTipText=This allows you to specify the default company generation options to use when starting a new campaign. +btnCompanyGenerationOptions.text=View Company Generation Options +btnCompanyGenerationOptions.toolTipText=This lets you view and edit the current company generation options. ## Continuous Panel continuousCampaignPresetPanel.title=Continuous Options continuousCampaignPresetPanel.toolTipText=These are options that are applied when starting a new campaign and can be applied to a pre-existing campaign. @@ -570,7 +591,7 @@ PersonnelFilterStyle.STANDARD.toolTipText=This is the standard filter style for PersonnelFilterStyle.INDIVIDUAL_ROLE.text=Individual Role PersonnelFilterStyle.INDIVIDUAL_ROLE.toolTipText=This filter style provides filters that allow one to filter personnel by each individual role, without the filter groupings as seen previously. PersonnelFilterStyle.ALL.text=All -PersonnelFilterStyle.ALL.toolTipText=This filter style provides all of the standard AND individual role filters. +PersonnelFilterStyle.ALL.toolTipText=This filter style provides all the standard AND individual role filters. #### PersonnelTableModelColumn Enum PersonnelTableModelColumn.RANK.text=Rank @@ -658,8 +679,8 @@ PersonnelTabView.OTHER.toolTipText=View various values for a person that are oth -#### Menus -### AssignPersonToUnitMenu Class +##### Menus +#### AssignPersonToUnitMenu Class AssignPersonToUnitMenu.title=Assign to Unit asPilotMenu.text=As Pilot asDriverMenu.text=As Driver @@ -670,10 +691,10 @@ asConsoleCommanderMenu.text=As Command Commander asSoldierMenu.text=As Soldier asNavigatorMenu.text=As Navigator -### AssignTechToUnitMenu Class +#### AssignTechToUnitMenu Class AssignTechToUnitMenu.title=As Tech -### AssignUnitToPersonMenu Class +#### AssignUnitToPersonMenu Class AssignUnitToPersonMenu.title=Assign Person pilotMenu.text=Pilot driverMenu.text=Driver @@ -685,7 +706,7 @@ soldierMenu.text=Soldier navigatorMenu.text=Navigator miUnassignCrew.text=Unassign Crew -### AssignUnitToTechMenu Class +#### AssignUnitToTechMenu Class AssignUnitToTechMenu.title=Tech miAssignTech.text=%s (%sm) miUnassignTech.text=Unassign Tech @@ -713,6 +734,167 @@ UnitMarketTableModel.columnNames=Market,Type,Weight Class,Unit,Price,Percent,Del #### CampaignPresetPanel Class btnEditPreset.toolTipText=Edit the selected preset, which allows you to make changes to it and overwrite the current saved preset. +#### CompanyGenerationOptionsPanel Class +### Base Information Panel +baseInformationPanel.title=Base Information +lblCompanyGenerationMethod.text=Company Generation Method +lblCompanyGenerationMethod.toolTipText=This is the method of company generator to use. These have hardcoded differences described in their tooltips. +chkGenerateMercenaryCompanyCommandLance.text=Generate Company Command Lance +chkGenerateMercenaryCompanyCommandLance.toolTipText=This generates a lance containing the company commander to lead the mercenary company.
Otherwise, the company commander leads the first lance generate, either first company or the first independent lance. +lblCompanyCount.text=Company Count +lblCompanyCount.toolTipText=The number of companies to generate, from 0 to 5. +lblIndividualLanceCount.text=Individual Lance Count +lblIndividualLanceCount.toolTipText=The number of individual lances to generate, from 0 to 2. +lblLancesPerCompany.text=Lances per Company +lblLancesPerCompany.toolTipText=The number of lances generated per company, from 2 to 6. +lblLanceSize.text=BattleMechs per Lance +lblLanceSize.toolTipText=The number of BattleMechs to generate per lance, from 3 to 6. +### Personnel Panel +personnelPanel.title=Personnel +lblTotalSupportPersonnel.text=Number of Support Personnel: %d +lblTotalSupportPersonnel.toolTipText=This is the maximum number of starting support personnel for the force. This does not include assistants. +supportPersonnelNumbersPanel.title=Support Personnel Assignment +supportPersonnelNumber.toolTipText=The number of %s(s) to hire. +chkPoolAssistants.text=Pool Assistants +chkPoolAssistants.toolTipText=Automatically fills the unit's astech and medic pools, otherwise they are hired as permanent members of the unit. +chkGenerateCaptains.text=Generate Captains +chkGenerateCaptains.toolTipText=This creates Captains for every company after the first, or for every company when using a mercenary company command lance.
They have two officer skill increases, and are assigned the rank of Captain. +chkAssignCompanyCommanderFlag.text=Assign Commander Flag +chkAssignCompanyCommanderFlag.toolTipText=This assigns the Commander flag to the generated Company Commander, designating them as the overall commander for the mercenary company. +chkApplyOfficerStatBonusToWorstSkill.text=Apply Officer Stat Bonus to Weaker Skill +chkApplyOfficerStatBonusToWorstSkill.toolTipText=This applies the single officer stat bonus to the weaker of their primary skills, normally piloting. +chkAssignBestCompanyCommander.text=Assign Best Company Commander +chkAssignBestCompanyCommander.toolTipText=This assigns the best person as the Company Commander. This is determined based on Tactical Genius, their combined command skill levels, and then their combat skill level. +chkPrioritizeCompanyCommanderCombatSkills.text=Prioritize Company Commander Combat Skills Over Command Skills +chkPrioritizeCompanyCommanderCombatSkills.toolTipText=Prioritize Company Commander sorting based on their combat skill experience level over their combined command skill levels. +chkAssignBestOfficers.text=Assign Best Officers +chkAssignBestOfficers.toolTipText=This assigns the best people as officers. This is determined based on Tactical Genius, their combined command skill levels, and then their combat skill level.
If Assign Best Company Commander is disabled this sort will also be used to select the Company Commander. +chkPrioritizeOfficerCombatSkills.text=Prioritize Officer Combat Skills Over Command Skills +chkPrioritizeOfficerCombatSkills.toolTipText=Prioritize officer sorting based on their combat skill experience level over their combined command skill levels. +chkAssignMostSkilledToPrimaryLances.text=Assign Most Skilled to Primary Lances +chkAssignMostSkilledToPrimaryLances.toolTipText=This assigns the most skilled personnel to the highest lances in the TO&E, determined based on Tactical Genius and then by their combat skill level.
If Assign Best Company Commander and Assign Best Officers are both disabled then this sort will apply to all generated personnel, with the person sorted first as the Company Commander,
followed by one person per lance as an officer, and finally the normal personnel. +chkAutomaticallyAssignRanks.text=Automatically Assign Ranks +chkAutomaticallyAssignRanks.toolTipText=This automatically assigns ranks to all hired personnel, with officers getting officer ranks dependent on the size force they command
while MechWarriors are assigned Sergeant ranks and support personnel are assigned Corporal ranks. +chkAssignFounderFlag.text=Assign Founder Flag +chkAssignFounderFlag.toolTipText=This automatically applies the founder flag to all generated personnel. +### Starting Simulation Panel +startingSimulationPanel.title=Starting Simulation +chkRunStartingSimulation.text=Run Starting Simulation +chkRunStartingSimulation.toolTipText=This will simulate any enabled simulations for duration years, starting that length before the current day. +lblSimulationDuration.text=Starting Simulation Duration +lblSimulationDuration.toolTipText=This is the duration, in years, of the starting simulation +chkSimulateRandomMarriages.text=Simulate Random Marriages +chkSimulateRandomMarriages.toolTipText=This runs random marriages for the duration of the simulation. +chkSimulateRandomProcreation.text=Simulate Random Procreation +chkSimulateRandomProcreation.toolTipText=This runs random procreation for the duration of the simulation. +### Units Panel +unitsPanel.title=Units +lblBattleMechWeightClassGenerationMethod.text=BattleMech Weight Class Generation Method +lblBattleMechWeightClassGenerationMethod.toolTipText=This is the method to use in generating the weight classes used to generate BattleMechs for the force. +lblBattleMechQualityGenerationMethod.text=BattleMech Quality Generation Method +lblBattleMechQualityGenerationMethod.toolTipText=This is the method to use in generating the quality levels used to generate BattleMechs for the force. +chkNeverGenerateStarLeagueMechs.text=Never Generate Star League 'Mechs +chkNeverGenerateStarLeagueMechs.toolTipText=Never generate from the Star League BattleMech Tables. Clan factions will instead generate solely from Secondline and lower Clan tables. +chkOnlyGenerateStarLeagueMechs.text=Only Generate Star League 'Mechs +chkOnlyGenerateStarLeagueMechs.toolTipText=Only generate from the Star League BattleMech Tables. Clan factions will instead generate from Frontline and higher Clan tables. +chkOnlyGenerateOmniMechs.text=Only Generate OmniMechs +chkOnlyGenerateOmniMechs.toolTipText=Only allow OmniMechs to be generated.
General / Inner Sphere Faction: This option may lead to gaps in the force, as the Star League didn't have OmniMechs and OmniMech availability varies heavily even after their Inner Sphere introduction.
Clan Faction: This option may lead to gaps in the force unless the following steps are taken. First, ensure that year is 2876 or later. Second, enable the Only Generate Star League 'Mechs option as that will force generation to a minimum of Clan Frontline BattleMechs. +chkGenerateUnitsAsAttached.text=Generate Units as Attached +chkGenerateUnitsAsAttached.toolTipText=All units rolled during company creation are attached units as per the Against the Bot rules.
These cost half as much when paying for units at startup, but are either converted into shares or are taken by the MechWarrior when they retire
(provided the campaign options are enabled). +chkAssignBestRollToCompanyCommander.text=Assign Best Roll to Unit Commander +chkAssignBestRollToCompanyCommander.toolTipText=This assigns the best rolled unit to the unit commander.
The heaviest Star League weight class will be assigned to them if a Star League 'Mech is rolled, or otherwise they will be assigned the heaviest 'Mech. +chkSortStarLeagueUnitsFirst.text=Sort Star League Units First +chkSortStarLeagueUnitsFirst.toolTipText=This sorts any Star League rolls, so they will be assigned to either the highest rank officers (with Keep Officer Rolls Separate) or to lances in order of the roll. +chkGroupByWeight.text=Group Units by Weight +chkGroupByWeight.toolTipText=This groups the rolls so that the 'Mechs are sorted into lances (largely) by weight class.
Otherwise, you can expect lances to have highly varied weight classes between the 'Mechs. +chkGroupByQuality.text=Group Units by Quality +chkGroupByQuality.toolTipText=This groups the rolls so that the highest quality will go to lances higher in the order of assignment. +chkKeepOfficerRollsSeparate.text=Keep Officer Rolls Separate +chkKeepOfficerRollsSeparate.toolTipText=This separates out the officer rolls from combat personnel rolls when using any of the above sorts.
This follows the spirit of the Against the Bot rules, but means that officers will in general have heavier 'Mechs than their lance. +lblStarLeagueYear.text=Star League Year +lblStarLeagueYear.toolTipText=This is the year to use when rolling for Star League 'Mechs. Valid years are 2571 to 2780, with 2765 being the default. +chkAssignTechsToUnits.text=Assign Techs to Units +chkAssignTechsToUnits.toolTipText=This automatically assigns techs to units during company generation. +### Unit Panel +unitPanel.title=Unit +lblForceNamingMethod.text=Force Naming Method +lblForceNamingMethod.toolTipText=This is the method used for generating lance and company names, producing names like "Baker Company", "Bravo Company", and "Beta Company". +chkGenerateForceIcons.text=Generate Force Icons +chkGenerateForceIcons.toolTipText=This will automatically create force icons for generated lances and companies, displaying the weight class, type, formation, and faction background (if possible, otherwise using Mercenary). +chkGenerateOriginNodeForceIcon.text=Generate Origin Node Force Icon +chkGenerateOriginNodeForceIcon.toolTipText=This will automatically generate a force icon for the origin force node. +chkUseOriginNodeForceIconLogo.text=Use Faction Logo for Origin Node Force Icon +chkUseOriginNodeForceIconLogo.toolTipText=This generates an origin node force icon containing the faction's logo. If there isn't one specified in Factions.xml, it will use the normal central BattleMech instead. +forceWeightLimitsPanel.title=Force Weight Limits +forceWeightLimitsPanel.toolTipText=These are the weight levels used for determining the force icon weight level. All limits are the maximum tonnage for their weight class, with anything above the value for Assault being considered as Super Heavy. +### Spares Panel +sparesPanel.title=Spares +chkGenerateMothballedSpareUnits.text=Generate Mothballed Spare Units +chkGenerateMothballedSpareUnits.toolTipText=This generates the specified percentage of active units as mothballed spares kept by the company to replace destroyed 'Mechs. +lblSparesPercentOfActiveUnits.text=Generated Percentage of Active Units +lblSparesPercentOfActiveUnits.toolTipText=This is the percentage of active units for which a mothballed unit will be generated. +lblPartGenerationMethod.text=Spare Part Generation Method +lblPartGenerationMethod.toolTipText=This generates spare parts for the unit based on the specified generation method, normally using the units generated include any generated as mothballed spares. +lblStartingArmourWeight.text=Starting Armour Weight +lblStartingArmourWeight.toolTipText=This is the weight of spare armour to generate at the start of the campaign. Each type of armour is generated based on the percentage weight it is of the total armour, rounded to the nearest point.
The recommended value to use is 20 tons per lance. +chkGenerateSpareAmmunition.text=Generate Spare Ammunition +chkGenerateSpareAmmunition.toolTipText=This generates spare standard ammunition for any weapons in the force. +lblNumberReloadsPerWeapon.text=Reloads per Weapon +lblNumberReloadsPerWeapon.toolTipText=This is the number of reloads to generate per weapon requiring the specified ammunition type. +chkGenerateFractionalMachineGunAmmunition.text=Generate Fractional Machine Gun Ammunition +chkGenerateFractionalMachineGunAmmunition.toolTipText=Generate 50 rounds of machine gun ammunition per machine gun instead of the full ammunition bin, which has a default count of 100 (half ton) or 200 (full ton) rounds. +### Contracts Panel +contractsPanel.title=Contracts (Unimplemented) +chkSelectStartingContract.text=Select Starting Contract +chkSelectStartingContract.toolTipText=This enables a panel where the company's starting contract can be selected.
(This panel will only show when there is not an active contract and a contract market is enabled) +chkStartCourseToContractPlanet.text=Start Course to Contract Planet +chkStartCourseToContractPlanet.toolTipText=This automatically charts and starts the company's travel towards the planet of the selected contract. +### Finances Panel +financesPanel.title=Finances +chkProcessFinances.text=Process Finances +chkProcessFinances.toolTipText=Process finances during startup.
The company will always be left with a minimum of the starting float, although they may have to take out a significant loan if that option is enabled.
If disabled, the initial contract payment will be paid out normally. +financialCreditsPanel.title=Credits +lblStartingCash.text=Starting C-Bills +lblStartingCash.toolTipText=The number of C-Bills to start with, minus expenses, if not randomizing the starting cash. +chkRandomizeStartingCash.text=Randomize Starting C-Bills +chkRandomizeStartingCash.toolTipText=This overrides the starting C-Bills with a random roll of nd6 million C-Bills, with the n specified below. +lblRandomStartingCashDiceCount.text=Random Starting C-Bills d6 Count +lblRandomStartingCashDiceCount.toolTipText=This is the number of d6s rolled to generate the random starting C-Bills when randomizing starting funds.
The base value of 18 will generate approximately 63m C-Bills, which is enough for a company in 3025 with a small float.
For later eras 22 to 30 per company is recommended. +lblMinimumStartingFloat.text=Minimum Starting Float +lblMinimumStartingFloat.toolTipText=This is the minimum number of available C-Bills the company will start with following generation. The minimum value to start with is 0 C-Bills. +chkIncludeInitialContractPayment.text=Include Initial Contract Selection Payment In Calculations +chkIncludeInitialContractPayment.toolTipText=Include the payment from the selected contract as part of the starting funds. This will mean the force may spend this cash during force creation, up to the limit of the minimum starting float.

If disabled, the initial contract payment will be paid out normally. +chkStartingLoan.text=Starting Loan +chkStartingLoan.toolTipText=Take a loan containing the remaining cost of the unit after the starting cash has been expended, leaving the starting float as available C-Bills.
The loan will be 2 years long, monthly payments, 100% collateral, and at 15% interest. +financialDebitsPanel.title=Debits +chkPayForSetup.text=Pay for Setup +chkPayForSetup.toolTipText=Pay for the generated unit from the starting cash, to a minimum of the starting float. +chkPayForPersonnel.text=Pay for Personnel +chkPayForPersonnel.toolTipText=Pay to hire personnel, at the standard hiring rate of two months salary. +chkPayForUnits.text=Pay for Units +chkPayForUnits.toolTipText=Pay for units, at either their full purchase cost or half of it if they are a person's attached unit. +chkPayForParts.text=Pay for Parts +chkPayForParts.toolTipText=Pay for the spare parts generated, if any are generated. +chkPayForArmour.text=Pay for Armour +chkPayForArmour.toolTipText=Pay for the spare armour generated, if any is generated. +chkPayForAmmunition.text=Pay for Ammunition +chkPayForAmmunition.toolTipText=Pay for the spare ammunition generated, if any is generated. +### Surprises Panel +surprisesPanel.title=Surprises (Unimplemented) +surprisesPanel.toolTipText=Surprises are applied to the campaign immediately, with no user input, at the end of company generation. +chkGenerateSurprises.text=Generate Surprises +chkGenerateSurprises.toolTipText=Allow the generation of surprises. These are immediately applied to the campaign at the end of company generation. +mysteryBoxPanel.title=Mystery Boxes +mysteryBoxPanel.toolTipText=Mystery Boxes each contain a 'Mech and between two and four parts randomly determined based on the individual type. +chkGenerateMysteryBoxes.text=Generate Mystery Boxes +chkGenerateMysteryBoxes.toolTipText=Allow the generation of enabled mystery box types, if any are enabled. +### Option Validation Warnings +CompanyGenerationOptionsPanel.InvalidGenerationSize.text=You must select at least one company or independent lance to generate +CompanyGenerationOptionsPanel.OverMaximumSupportPersonnel.title=Over Maximum Support Personnel +CompanyGenerationOptionsPanel.OverMaximumSupportPersonnel.text=The specified number of support personnel to generate is over the recommended maximum number of support personnel. Select "Ok" to continue, or "Cancel" to make changes to these Company Generation Options. +CompanyGenerationOptionsPanel.UnderHalfMaximumSupportPersonnel.title=Under Half Maximum Support Personnel +CompanyGenerationOptionsPanel.UnderHalfMaximumSupportPersonnel.text=The specified number of support personnel to generate is under half the recommended maximum number of support personnel. Select "Ok" to continue, or "Cancel" to make changes to these Company Generation Options. + #### LayeredForceIconCreationPanel Class lblIcon.accessibleName=The current layered force icon btnNewIcon.text=New Icon @@ -741,7 +923,8 @@ chkAllowClanOrigins.text=Clan Origin Faction Generated for Non-Clan Factions chkAllowClanOrigins.toolTipText=Generate Clan origin factions for factions that are not tagged as Clan. chkExtraRandomOrigin.text=Extra Random Planetary Origin chkExtraRandomOrigin.toolTipText=Random origin is randomized to the planetary level when selected, rather than just randomizing to the system level
(with the planet being the primary planet). - +### Option Validation Warnings +RandomOriginOptionsPanel.InvalidSpecifiedPlanet.text=You must select a valid specified planet. ##### Panes diff --git a/MekHQ/resources/mekhq/resources/MekHqOptionsDialog.properties b/MekHQ/resources/mekhq/resources/MekHqOptionsDialog.properties index ea2f17b47c..ff0997cd29 100644 --- a/MekHQ/resources/mekhq/resources/MekHqOptionsDialog.properties +++ b/MekHQ/resources/mekhq/resources/MekHqOptionsDialog.properties @@ -9,8 +9,12 @@ displayTab.title=Display Options labelDisplayDateFormat.text=Display Date Format labelLongDisplayDateFormat.text=Long Display Date Format invalidDateFormat.error=Invalid Date Format -optionHistoricalDailyLog.text=Temporarily retain daily log history +optionHistoricalDailyLog.text=Temporarily Retain Daily Log History optionHistoricalDailyLog.toolTipText=Keeps a limited historical daily report in-memory during the gaming session. May result in increased memory usage. +chkCompanyGeneratorStartup.text=Company Generator Startup outside of AtB (Unimplemented) +chkCompanyGeneratorStartup.toolTipText=Adds the ability to use the company generator on startup outside of AtB campaigns. +chkShowCompanyGenerator.text=Show Company Generator +chkShowCompanyGenerator.toolTipText=Add a company generator menu item under the Manage Campaign header on the menu bar to allow one to generate a company after startup. labelCommandCenterDisplay.text=Command Center Display Options optionCommandCenterUseUnitMarket.text=Find Units Links to Unit Market (if enabled) @@ -108,5 +112,7 @@ optionOutstandingScenariosNag.toolTipText=This allows you to ignore the daily wa #Miscellaneous Tab miscellaneousTab.title=Miscellaneous Options -labelStartGameDelay.text=Delay Timer -optionStartGameDelay.toolTipText=Number of milliseconds to wait before sending another unit. If the application tends to hang when starting a game in MegaMek or does not transfer all units or settings, try increasing this value. +lblStartGameDelay.text=Delay Timer +lblStartGameDelay.toolTipText=Number of milliseconds to wait before sending another unit.
If the application tends to hang when starting a game in MegaMek or does not transfer all units or settings, try increasing this value. +lblDefaultCompanyGenerationMethod.text=Default Company Generation Method +lblDefaultCompanyGenerationMethod.toolTipText=This is the default company generation method to be used on load. diff --git a/MekHQ/resources/mekhq/resources/Universe.properties b/MekHQ/resources/mekhq/resources/Universe.properties new file mode 100644 index 0000000000..59f73ce49c --- /dev/null +++ b/MekHQ/resources/mekhq/resources/Universe.properties @@ -0,0 +1,221 @@ +# This is used to store any mekhq/campaign/universe Resources + +## General Universe Resources + +## Enums +# Alphabet Enum - This is sorted by the grouping then letter, not in the same order as they are listed in the enum, because it is more readable this way. +Alphabets.A.ccb1943.text=Able +Alphabets.B.ccb1943.text=Baker +Alphabets.C.ccb1943.text=Charlie +Alphabets.D.ccb1943.text=Dog +Alphabets.E.ccb1943.text=Easy +Alphabets.F.ccb1943.text=Fox +Alphabets.G.ccb1943.text=George +Alphabets.H.ccb1943.text=How +Alphabets.I.ccb1943.text=Item +Alphabets.J.ccb1943.text=Jig +Alphabets.K.ccb1943.text=King +Alphabets.L.ccb1943.text=Love +Alphabets.M.ccb1943.text=Mike +Alphabets.N.ccb1943.text=Nan +Alphabets.O.ccb1943.text=Oboe +Alphabets.P.ccb1943.text=Peter +Alphabets.Q.ccb1943.text=Queen +Alphabets.R.ccb1943.text=Roger +Alphabets.S.ccb1943.text=Sugar +Alphabets.T.ccb1943.text=Tare +Alphabets.U.ccb1943.text=Uncle +Alphabets.V.ccb1943.text=Victor +Alphabets.W.ccb1943.text=William +Alphabets.X.ccb1943.text=Xray +Alphabets.Y.ccb1943.text=Yoke +Alphabets.Z.ccb1943.text=Zebra +Alphabets.A.icao1956.text=Alfa +Alphabets.B.icao1956.text=Bravo +Alphabets.C.icao1956.text=Charlie +Alphabets.D.icao1956.text=Delta +Alphabets.E.icao1956.text=Echo +Alphabets.F.icao1956.text=Foxtrot +Alphabets.G.icao1956.text=Golf +Alphabets.H.icao1956.text=Hotel +Alphabets.I.icao1956.text=India +Alphabets.J.icao1956.text=Juliett +Alphabets.K.icao1956.text=Kilo +Alphabets.L.icao1956.text=Lima +Alphabets.M.icao1956.text=Mike +Alphabets.N.icao1956.text=November +Alphabets.O.icao1956.text=Oscar +Alphabets.P.icao1956.text=Papa +Alphabets.Q.icao1956.text=Quebec +Alphabets.R.icao1956.text=Romeo +Alphabets.S.icao1956.text=Sierra +Alphabets.T.icao1956.text=Tango +Alphabets.U.icao1956.text=Uniform +Alphabets.V.icao1956.text=Victor +Alphabets.W.icao1956.text=Whiskey +Alphabets.X.icao1956.text=Xray +Alphabets.Y.icao1956.text=Yankee +Alphabets.Z.icao1956.text=Zulu +Alphabets.A.english.text=A +Alphabets.B.english.text=B +Alphabets.C.english.text=C +Alphabets.D.english.text=D +Alphabets.E.english.text=E +Alphabets.F.english.text=F +Alphabets.G.english.text=G +Alphabets.H.english.text=H +Alphabets.I.english.text=I +Alphabets.J.english.text=J +Alphabets.K.english.text=K +Alphabets.L.english.text=L +Alphabets.M.english.text=M +Alphabets.N.english.text=N +Alphabets.O.english.text=O +Alphabets.P.english.text=P +Alphabets.Q.english.text=Q +Alphabets.R.english.text=R +Alphabets.S.english.text=S +Alphabets.T.english.text=T +Alphabets.U.english.text=U +Alphabets.V.english.text=V +Alphabets.W.english.text=W +Alphabets.X.english.text=X +Alphabets.Y.english.text=Y +Alphabets.Z.english.text=Z +Alphabets.A.greek.text=Alpha +Alphabets.B.greek.text=Beta +Alphabets.C.greek.text=Gamma +Alphabets.D.greek.text=Delta +Alphabets.E.greek.text=Epsilon +Alphabets.F.greek.text=Zeta +Alphabets.G.greek.text=Eta +Alphabets.H.greek.text=Theta +Alphabets.I.greek.text=Iota +Alphabets.J.greek.text=Kappa +Alphabets.K.greek.text=Lambda +Alphabets.L.greek.text=Mu +Alphabets.M.greek.text=Nu +Alphabets.N.greek.text=Xi +Alphabets.O.greek.text=Omicron +Alphabets.P.greek.text=Pi +Alphabets.Q.greek.text=Rho +Alphabets.R.greek.text=Sigma +Alphabets.S.greek.text=Tau +Alphabets.T.greek.text=Upsilon +Alphabets.U.greek.text=Phi +Alphabets.V.greek.text=Chi +Alphabets.W.greek.text=Psi +Alphabets.X.greek.text=Omega +Alphabets.Y.greek.text=Ena +Alphabets.Z.greek.text=Dio + +# BattleMechQualityGenerationMethod Enum +BattleMechQualityGenerationMethod.AGAINST_THE_BOT.text=AtB +BattleMechQualityGenerationMethod.AGAINST_THE_BOT.toolTipText=This follows the AtB rules for base quality generation.
Generates (before modifiers): 28% F, 44% D, 19% C, 6% B, 3% A. +BattleMechQualityGenerationMethod.WINDCHILD.text=Windchild +BattleMechQualityGenerationMethod.WINDCHILD.toolTipText=This is a variant of the AtB method that generates a higher base quality.
Generates (before modifiers): 17% F, 25% D, 31% C, 19% B, 8% A. +BattleMechQualityGenerationMethod.F.text=F +BattleMechQualityGenerationMethod.F.toolTipText=This generates a force solely containing units of F quality. +BattleMechQualityGenerationMethod.D.text=D +BattleMechQualityGenerationMethod.D.toolTipText=This generates a force solely containing units of D quality. +BattleMechQualityGenerationMethod.C.text=C +BattleMechQualityGenerationMethod.C.toolTipText=This generates a force solely containing units of C quality. +BattleMechQualityGenerationMethod.B.text=B +BattleMechQualityGenerationMethod.B.toolTipText=This generates a force solely containing units of B quality. +BattleMechQualityGenerationMethod.A.text=A +BattleMechQualityGenerationMethod.A.toolTipText=This generates a force solely containing units of A quality. +BattleMechQualityGenerationMethod.A_STAR.text=A* +BattleMechQualityGenerationMethod.A_STAR.toolTipText=This generates a force solely containing units of A* quality. + +# BattleMechWeightClassGenerationMethod Enum +BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT.text=AtB +BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT.toolTipText=This follows the core AtB rules to generate a mercenary company.
Generates (before modifiers): 8% Nothing, 33% Light, 42% Medium, 14% Heavy, 3% Assault. +BattleMechWeightClassGenerationMethod.WINDCHILD.text=Windchild +BattleMechWeightClassGenerationMethod.WINDCHILD.toolTipText=This is a variant of the AtB Method that guarantees generating a valid BattleMech. As part of doing so, it creates a force weighted closer to the average Inner Sphere 'Mech weights in 3039.
Generates (before modifiers): 28% Light, 44% Medium, 19% Heavy, 8% Assault (rounded properly). +BattleMechWeightClassGenerationMethod.WINDCHILD_LIGHT.text=Windchild (Light Force) +BattleMechWeightClassGenerationMethod.WINDCHILD_LIGHT.toolTipText=This is a variant of the Windchild Method that creates a light force, weighted around light and medium 'Mechs.
Generates (before modifiers): 50% Light, 31% Medium, 14% Heavy, 6% Assault (rounded normally). +BattleMechWeightClassGenerationMethod.WINDCHILD_MEDIUM.text=Windchild (Medium Force) +BattleMechWeightClassGenerationMethod.WINDCHILD_MEDIUM.toolTipText=This is a variant of the Windchild Method that creates a medium force, weighted around medium 'Mechs.
Generates (before modifiers): 25% Light, 50% Medium, 19% Heavy, 6% Assault. +BattleMechWeightClassGenerationMethod.WINDCHILD_HEAVY.text=Windchild (Heavy Force) +BattleMechWeightClassGenerationMethod.WINDCHILD_HEAVY.toolTipText=This is a variant of the Windchild Method that creates a heavy force, weighted around medium and heavy 'Mechs.
Generates (before modifiers): 17% Light, 31% Medium, 33% Heavy, 19% Assault. +BattleMechWeightClassGenerationMethod.WINDCHILD_ASSAULT.text=Windchild (Assault Force) +BattleMechWeightClassGenerationMethod.WINDCHILD_ASSAULT.toolTipText=This is a variant of the Windchild Method that creates an assault force, weighted around heavy and assault 'Mechs.
Generates (before modifiers): 8% Light, 19% Medium, 33% Heavy, 39% Assault (rounded normally). +BattleMechWeightClassGenerationMethod.LIGHT.text=Light +BattleMechWeightClassGenerationMethod.LIGHT.toolTipText=This generates a force containing just light 'Mechs. +BattleMechWeightClassGenerationMethod.MEDIUM.text=Medium +BattleMechWeightClassGenerationMethod.MEDIUM.toolTipText=This generates a force containing just medium 'Mechs. +BattleMechWeightClassGenerationMethod.HEAVY.text=Heavy +BattleMechWeightClassGenerationMethod.HEAVY.toolTipText=This generates a force containing just heavy 'Mechs. +BattleMechWeightClassGenerationMethod.ASSAULT.text=Assault +BattleMechWeightClassGenerationMethod.ASSAULT.toolTipText=This generates a force containing just assault 'Mechs. + +# CompanyGenerationMethod Enum +CompanyGenerationMethod.AGAINST_THE_BOT.text=AtB +CompanyGenerationMethod.AGAINST_THE_BOT.toolTipText=This follows the core AtB rules to generate a mercenary company. +CompanyGenerationMethod.WINDCHILD.text=Windchild +CompanyGenerationMethod.WINDCHILD.toolTipText=This is a variant of the AtB Method that assigns the commanding officer a rank better fitting the force size, and handles BattleMech quality differently so that Clan 'Mechs can generate from any quality. + +# CompanyGenerationPersonType Enum +CompanyGenerationPersonType.MECHWARRIOR_COMPANY_COMMANDER.text=MechWarrior Company Commander +CompanyGenerationPersonType.MECHWARRIOR_COMPANY_COMMANDER.toolTipText=They are the MechWarrior who leads the entire Mercenary company. +CompanyGenerationPersonType.MECHWARRIOR_CAPTAIN.text=MechWarrior Captain +CompanyGenerationPersonType.MECHWARRIOR_CAPTAIN.toolTipText=They lead a BattleMech company from their BattleMech. +CompanyGenerationPersonType.MECHWARRIOR_LIEUTENANT.text=MechWarrior Lieutenant +CompanyGenerationPersonType.MECHWARRIOR_LIEUTENANT.toolTipText=They lead a BattleMech lance from their BattleMech. +CompanyGenerationPersonType.MECHWARRIOR.text=MechWarrior +CompanyGenerationPersonType.MECHWARRIOR.toolTipText=They pilot a BattleMech. +CompanyGenerationPersonType.SUPPORT.text=Support +CompanyGenerationPersonType.SUPPORT.toolTipText=They are one of the primary support personnel (techs, doctors, or administrators) for the Mercenary company. +CompanyGenerationPersonType.ASSISTANT.text=Assistant +CompanyGenerationPersonType.ASSISTANT.toolTipText=They assist one of the primary support personnel as a Medic or Astech. + +# ForceNamingMethod Enum +ForceNamingMethod.CCB_1943.text=CCB (1943) +ForceNamingMethod.CCB_1943.toolTipText=This generates names using the Combined Communications Board's WW2 calling alphabet as settled upon in 1943.
Produces names like "Able Lance", "Charlie Company", and "Easy Company". +ForceNamingMethod.ICAO_1956.text=ICAO (1956) +ForceNamingMethod.ICAO_1956.toolTipText=This generates names using the International Radiotelephony Spelling Alphabet, also known as the NATO phonetic alphabet.
Produces names like "Bravo Lance", "Charlie Company", and "Hotel Lance" +ForceNamingMethod.ENGLISH_ALPHABET.text=English Alphabet +ForceNamingMethod.ENGLISH_ALPHABET.toolTipText=This generates names using the English Alphabet.
Produces names like "A Lance", "V Company", and "X Lance". +ForceNamingMethod.GREEK_ALPHABET.text=Greek Alphabet +ForceNamingMethod.GREEK_ALPHABET.toolTipText=This generates names using the Greek Alphabet, with one and two taking the place of the final two characters as Greek only has 24 characters.
Produces names like "Alpha Lance", "Beta Company", and "Omega Lance". + +# MysteryBoxType Enum +MysteryBoxType.THIRD_SUCCESSION_WAR.text=Third Succession War Mystery Box +MysteryBoxType.THIRD_SUCCESSION_WAR.toolTipText=This generates a random BattleMech and two to four parts based on the year 3000.
Expect a light to medium IntroTech BattleMech and some common equipment, but you can never tell what one might find salvageable on the battleground. +MysteryBoxType.STAR_LEAGUE_ROYAL.text=Star League Royal Division Mystery Box +MysteryBoxType.STAR_LEAGUE_ROYAL.toolTipText=This generates a random BattleMech and two to four parts based on the units of the Star League Royal Division.
Expect the best technology of the Star League and their preferred 'Mechs. +MysteryBoxType.STAR_LEAGUE_REGULAR.text=Star League Defence Force Mystery Box +MysteryBoxType.STAR_LEAGUE_REGULAR.toolTipText=This generates a random BattleMech and two to four parts based on the units of the Star League Regular Army. +MysteryBoxType.INNER_SPHERE_EXPERIMENTAL.text=Inner Sphere Experimental Tech Mystery Box +MysteryBoxType.INNER_SPHERE_EXPERIMENTAL.toolTipText=This generates a random experimental Inner Sphere BattleMech and two to four experimental parts based on the current campaign date.
Expect weird and wacky technology and new, rare, and/or unusual Inner Sphere 'Mechs and parts from this mystery box. +MysteryBoxType.CLAN_KESHIK.text=Clan Keshik Mystery Box +MysteryBoxType.CLAN_KESHIK.toolTipText=This generates a random Clan 'Mech used by their Keshik forces and two to four parts based on the current year.
Expect the best technology of the Clans, as used by their elite.
This returns a Star League Royal Mystery Box if the current year predates the Clans. +MysteryBoxType.CLAN_FRONT_LINE.text=Clan Front Line Mystery Box +MysteryBoxType.CLAN_FRONT_LINE.toolTipText=This generates a Clan front line 'Mech and two to four parts based on the current year.
This returns a Star League Royal Mystery Box if the current year predates the Clans. +MysteryBoxType.CLAN_SECOND_LINE.text=Clan Second Line Mystery Box +MysteryBoxType.CLAN_SECOND_LINE.toolTipText=This generates a Clan second line 'Mech and two to four parts based on the current year.
This returns a Star League Defence Force Mystery Box if the current year predates the Clans. +MysteryBoxType.CLAN_EXPERIMENTAL.text=Clan Experimental Tech Mystery Box +MysteryBoxType.CLAN_EXPERIMENTAL.toolTipText=This generates a random experimental Clan BattleMech and two to four experimental Clan parts based on the current campaign date.
Expect weird and wacky Clan technology, unusual 'Mechs... or maybe just getting them early!
This returns an Inner Sphere Experimental Mystery Box if the current year predates the Clans. + +# PartGenerationMethod Enum +PartGenerationMethod.DISABLED.text=Disabled +PartGenerationMethod.DISABLED.toolTipText=Part Generation is disabled. +PartGenerationMethod.WINDCHILD.text=Windchild +PartGenerationMethod.WINDCHILD.toolTipText=Windchild's method generates one part for every three in the input, rounded normally.
This means you get a single part if you have two to four parts, and another part for each interval above that. +PartGenerationMethod.MISHRA.text=Mishra +PartGenerationMethod.MISHRA.toolTipText=Mishra's method only applies to 'Mech units and isolates based on 'Mech parts. It starts with three parts for every one in the input, then removes all engines before capping the remaining parts based on the following rules.
1) All Heat Sinks are capped at 30 per type.
2) All 'Mech Heads [Sensors, Life Support] are capped at 2 per weight/type.
3) All Gyros are capped at 1 per weight/type.
4) MASC is capped at 1 per type.
5) Any other parts are capped at 6. +PartGenerationMethod.SINGLE.text=Single Copy +PartGenerationMethod.SINGLE.toolTipText=This returns a part for every part in the input. +PartGenerationMethod.DOUBLE.text=Double Copy +PartGenerationMethod.DOUBLE.toolTipText=This returns two parts for every one in the input. +PartGenerationMethod.TRIPLE.text=Triple Copy +PartGenerationMethod.TRIPLE.toolTipText=This returns three parts for every one in the input. + +## Generators +# AbstractCompanyGenerator +AbstractCompanyGenerator.CommandLance.text=\u0020Command Lance +AbstractCompanyGenerator.Company.text=\u0020Company +AbstractCompanyGenerator.Lance.text=\u0020Lance +AbstractCompanyGenerator.CompanyStartupFunding.text=Remaining Company Startup Funding +AbstractCompanyGenerator.CompanyStartupFundedWithoutLoan.report=The company has been founded with an initial float of %s. +AbstractCompanyGenerator.CompanyStartupFundedWithLoan.report=The company has been founded with an initial float of %s and a loan totalling %s. diff --git a/MekHQ/src/mekhq/MHQConstants.java b/MekHQ/src/mekhq/MHQConstants.java index 97ccc31bd1..5272e4a6ba 100644 --- a/MekHQ/src/mekhq/MHQConstants.java +++ b/MekHQ/src/mekhq/MHQConstants.java @@ -43,16 +43,19 @@ public final class MHQConstants extends SuiteConstants { public static final String LONG_DISPLAY_DATE_FORMAT = "longDisplayDateFormat"; public static final String HISTORICAL_DAILY_LOG = "historicalDailyLog"; public static final int MAX_HISTORICAL_LOG_DAYS = 120; // max number of days that will be stored in the history, also used as a limit in the UI + public static final String COMPANY_GENERATOR_STARTUP = "companyGeneratorStartup"; + public static final String SHOW_COMPANY_GENERATOR = "showCompanyGenerator"; //region Command Center public static final String COMMAND_CENTER_USE_UNIT_MARKET = "commandCenterUseUnitMarket"; public static final String COMMAND_CENTER_MRMS = "commandCenterMRMS"; //endregion Command Center - //region Personnel Tab Display Options + //region Personnel Tab public static final String PERSONNEL_FILTER_STYLE = "personnelFilterStyle"; public static final String PERSONNEL_FILTER_ON_PRIMARY_ROLE = "personnelFilterOnPrimaryRole"; - //endregion Personnel Tab Display Options + //endregion Personnel Tab + //endregion Display //region Colours public static final String DEPLOYED_FOREGROUND = "deployedForeground"; @@ -88,7 +91,6 @@ public final class MHQConstants extends SuiteConstants { public static final String PAID_RETIREMENT_FOREGROUND = "paidRetirementForeground"; public static final String PAID_RETIREMENT_BACKGROUND = "paidRetirementBackground"; //endregion Colours - //endregion Display //region Autosave public static final String AUTOSAVE_NODE = "mekhq/prefs/autosave"; @@ -120,6 +122,7 @@ public final class MHQConstants extends SuiteConstants { //region File Paths public static final String FILE_PATH_NODE = "mekhq/prefs/filepaths"; + public static final String COMPANY_GENERATION_DIRECTORY_PATH = "companyGenerationDirectoryPath"; public static final String RANK_SYSTEMS_DIRECTORY_PATH = "rankSystemsDirectoryPath"; public static final String INDIVIDUAL_RANK_SYSTEM_DIRECTORY_PATH = "individualRankSystemDirectoryPath"; public static final String LAYERED_FORCE_ICON_DIRECTORY_PATH = "layeredForceIconDirectoryPath"; @@ -139,27 +142,42 @@ public final class MHQConstants extends SuiteConstants { //region Miscellaneous Options public static final String MISCELLANEOUS_NODE = "mekhq/prefs/miscellaneous"; public static final String START_GAME_DELAY = "startGameDelay"; + public static final String DEFAULT_COMPANY_GENERATION_METHOD = "defaultCompanyGenerationMethod"; //endregion Miscellaneous Options //endregion MHQOptions //region File Paths // This holds all required file paths not saved as part of MekHQ Options - public static final String LAYERED_FORCE_ICON_TYPE_PATH = "Pieces/Types/"; - public static final String LAYERED_FORCE_ICON_FORMATION_PATH = "Pieces/Formations/"; public static final String LAYERED_FORCE_ICON_ADJUSTMENT_PATH = "Pieces/Adjustments/"; public static final String LAYERED_FORCE_ICON_ALPHANUMERIC_PATH = "Pieces/Alphanumerics/"; - public static final String LAYERED_FORCE_ICON_SPECIAL_MODIFIER_PATH = "Pieces/Special Modifiers/"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_BORDER_PATH = "Operational Indicators (Border)/"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_TAB_PATH = "Operational Indicators (Tab)/"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FULLY_OPERATIONAL_FILE_PATH = "(01) Green - Fully Operational.png"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_SUBSTANTIALLY_OPERATIONAL_FILE_PATH = "(02) Yellow - Substantially Operational.png"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_MARGINALLY_OPERATIONAL_FILE_PATH = "(03) Red - Marginally Operational.png"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_NOT_OPERATIONAL_FILE_PATH = "(04) Gray - Not Operational.png"; - public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FACTORY_FRESH_FILE_PATH = "(05) Blue - Factory Fresh.png"; + public static final String LAYERED_FORCE_ICON_ALPHANUMERIC_BOTTOM_RIGHT_PATH = "Bottom Right/"; + public static final String LAYERED_FORCE_ICON_ALPHANUMERIC_HQ_FILENAME = "HQ.png"; public static final String LAYERED_FORCE_ICON_BACKGROUND_PATH = "Pieces/Backgrounds/"; + public static final String LAYERED_FORCE_ICON_FORMATION_PATH = "Pieces/Formations/"; + public static final String LAYERED_FORCE_ICON_FORMATION_CLAN_PATH = "Clan/"; + public static final String LAYERED_FORCE_ICON_FORMATION_STAR_FILENAME = "(02) Star.png"; + public static final String LAYERED_FORCE_ICON_FORMATION_TRINARY_FILENAME = "(06) Trinary.png"; + public static final String LAYERED_FORCE_ICON_FORMATION_COMSTAR_PATH = "ComStar/"; + public static final String LAYERED_FORCE_ICON_FORMATION_LEVEL_II_FILENAME = "(02) Level II.png"; + public static final String LAYERED_FORCE_ICON_FORMATION_LEVEL_III_FILENAME = "(04) Level III.png"; + public static final String LAYERED_FORCE_ICON_FORMATION_INNER_SPHERE_PATH = "Inner Sphere/"; + public static final String LAYERED_FORCE_ICON_FORMATION_LANCE_FILENAME = "(04) Lance.png"; + public static final String LAYERED_FORCE_ICON_FORMATION_COMPANY_FILENAME = "(05) Company.png"; public static final String LAYERED_FORCE_ICON_FRAME_PATH = "Pieces/Frames/"; public static final String LAYERED_FORCE_ICON_DEFAULT_FRAME_FILENAME = "Frame.png"; public static final String LAYERED_FORCE_ICON_LOGO_PATH = "Pieces/Logos/"; + public static final String LAYERED_FORCE_ICON_SPECIAL_MODIFIER_PATH = "Pieces/Special Modifiers/"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_BORDER_PATH = "Operational Indicators (Border)/"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_TAB_PATH = "Operational Indicators (Tab)/"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FULLY_OPERATIONAL_FILENAME = "(01) Green - Fully Operational.png"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_SUBSTANTIALLY_OPERATIONAL_FILENAME = "(02) Yellow - Substantially Operational.png"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_MARGINALLY_OPERATIONAL_FILENAME = "(03) Red - Marginally Operational.png"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_NOT_OPERATIONAL_FILENAME = "(04) Gray - Not Operational.png"; + public static final String LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FACTORY_FRESH_FILENAME = "(05) Blue - Factory Fresh.png"; + public static final String LAYERED_FORCE_ICON_TYPE_PATH = "Pieces/Types/"; + public static final String LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH = "StratOps/"; + public static final String LAYERED_FORCE_ICON_BATTLEMECH_LEFT_FILENAME = "BattleMech (Left).png"; + public static final String LAYERED_FORCE_ICON_BATTLEMECH_CENTER_FILENAME = "BattleMech (Center).png"; public static final String CUSTOM_MECHFILES_DIRECTORY_PATH = "data/mechfiles/customs/"; public static final String AWARDS_DIRECTORY_PATH = "data/universe/awards/"; public static final String RATINFO_DIR = "data/universe/ratdata/"; diff --git a/MekHQ/src/mekhq/MHQOptions.java b/MekHQ/src/mekhq/MHQOptions.java index 9db30df56d..81e59540fb 100644 --- a/MekHQ/src/mekhq/MHQOptions.java +++ b/MekHQ/src/mekhq/MHQOptions.java @@ -19,6 +19,7 @@ package mekhq; import megamek.SuiteOptions; +import mekhq.campaign.universe.enums.CompanyGenerationMethod; import mekhq.gui.enums.ForceIconOperationalStatusStyle; import mekhq.gui.enums.PersonnelFilterStyle; @@ -28,7 +29,7 @@ import java.time.format.DateTimeFormatter; public final class MHQOptions extends SuiteOptions { - //region Display + //region Display Tab public String getDisplayDateFormat() { return userPreferences.node(MHQConstants.DISPLAY_NODE).get(MHQConstants.DISPLAY_DATE_FORMAT, "yyyy-MM-dd"); } @@ -65,7 +66,22 @@ public void setHistoricalDailyLog(boolean value) { userPreferences.node(MHQConstants.DISPLAY_NODE).putBoolean(MHQConstants.HISTORICAL_DAILY_LOG, value); } - //region Expanded MekHQ Display Options + public boolean getCompanyGeneratorStartup() { + return userPreferences.node(MHQConstants.DISPLAY_NODE).getBoolean(MHQConstants.COMPANY_GENERATOR_STARTUP, false); + } + + public void setCompanyGeneratorStartup(final boolean value) { + userPreferences.node(MHQConstants.DISPLAY_NODE).putBoolean(MHQConstants.COMPANY_GENERATOR_STARTUP, value); + } + + public boolean getShowCompanyGenerator() { + return userPreferences.node(MHQConstants.DISPLAY_NODE).getBoolean(MHQConstants.SHOW_COMPANY_GENERATOR, true); + } + + public void setShowCompanyGenerator(final boolean value) { + userPreferences.node(MHQConstants.DISPLAY_NODE).putBoolean(MHQConstants.SHOW_COMPANY_GENERATOR, value); + } + //region Command Center Display public boolean getCommandCenterUseUnitMarket() { return userPreferences.node(MHQConstants.DISPLAY_NODE).getBoolean(MHQConstants.COMMAND_CENTER_USE_UNIT_MARKET, true); @@ -102,7 +118,7 @@ public void setPersonnelFilterOnPrimaryRole(boolean value) { userPreferences.node(MHQConstants.DISPLAY_NODE).putBoolean(MHQConstants.PERSONNEL_FILTER_ON_PRIMARY_ROLE, value); } //endregion Personnel Tab Display Options - //endregion Expanded MekHQ Display Options + //endregion Display Tab //region Colours public Color getDeployedForeground() { @@ -367,7 +383,6 @@ public void setPaidRetirementBackground(Color value) { userPreferences.node(MHQConstants.DISPLAY_NODE).putInt(MHQConstants.PAID_RETIREMENT_BACKGROUND, value.getRGB()); } //endregion Colours - //endregion Display //region Autosave public boolean getNoAutosaveValue() { @@ -557,6 +572,14 @@ public String getLayeredForceIconPath() { public void setLayeredForceIconPath(final String value) { userPreferences.node(MHQConstants.FILE_PATH_NODE).put(MHQConstants.LAYERED_FORCE_ICON_DIRECTORY_PATH, value); } + + public String getCompanyGenerationDirectoryPath() { + return userPreferences.node(MHQConstants.FILE_PATH_NODE).get(MHQConstants.COMPANY_GENERATION_DIRECTORY_PATH, "mmconf/mhqCompanyGenerationPresets/"); + } + + public void setCompanyGenerationDirectoryPath(final String value) { + userPreferences.node(MHQConstants.FILE_PATH_NODE).put(MHQConstants.COMPANY_GENERATION_DIRECTORY_PATH, value); + } //endregion File Paths //region Nag Tab @@ -574,8 +597,17 @@ public int getStartGameDelay() { return userPreferences.node(MHQConstants.MISCELLANEOUS_NODE).getInt(MHQConstants.START_GAME_DELAY, 1000); } - public void setStartGameDelay(int startGameDelay) { + public void setStartGameDelay(final int startGameDelay) { userPreferences.node(MHQConstants.MISCELLANEOUS_NODE).putInt(MHQConstants.START_GAME_DELAY, startGameDelay); } + + public CompanyGenerationMethod getDefaultCompanyGenerationMethod() { + return CompanyGenerationMethod.valueOf(userPreferences.node(MHQConstants.MISCELLANEOUS_NODE) + .get(MHQConstants.DEFAULT_COMPANY_GENERATION_METHOD, CompanyGenerationMethod.WINDCHILD.name())); + } + + public void setDefaultCompanyGenerationMethod(final CompanyGenerationMethod value) { + userPreferences.node(MHQConstants.MISCELLANEOUS_NODE).put(MHQConstants.DEFAULT_COMPANY_GENERATION_METHOD, value.name()); + } //endregion Miscellaneous Options } diff --git a/MekHQ/src/mekhq/Utilities.java b/MekHQ/src/mekhq/Utilities.java index 585efa0f19..051aa2b56d 100644 --- a/MekHQ/src/mekhq/Utilities.java +++ b/MekHQ/src/mekhq/Utilities.java @@ -438,7 +438,7 @@ public static boolean isOmniVariant(Entity entity1, Entity entity2) { public static int generateExpLevel(int bonus) { int roll = Compute.d6(2) + bonus; - if (roll < 2) { + if (roll <= 2) { return SkillType.EXP_ULTRA_GREEN; } else if (roll < 6) { return SkillType.EXP_GREEN; diff --git a/MekHQ/src/mekhq/campaign/Campaign.java b/MekHQ/src/mekhq/campaign/Campaign.java index f5b2184515..18ed52a56e 100644 --- a/MekHQ/src/mekhq/campaign/Campaign.java +++ b/MekHQ/src/mekhq/campaign/Campaign.java @@ -782,13 +782,21 @@ public void importScenario(Scenario scenario) { scenarios.put(scenario.getId(), scenario); } + public void addUnitToForce(final @Nullable Unit unit, final Force force) { + addUnitToForce(unit, force.getId()); + } + /** * Add unit to an existing force. This method will also assign that force's id to the unit. * * @param u * @param id */ - public void addUnitToForce(Unit u, int id) { + public void addUnitToForce(@Nullable Unit u, int id) { + if (u == null) { + return; + } + Force force = forceIds.get(id); Force prevForce = forceIds.get(u.getForceId()); boolean useTransfers = false; @@ -1236,7 +1244,7 @@ public Person newDependent(boolean baby) { * @param role The primary role * @return A new {@link Person}. */ - public Person newPerson(PersonnelRole role) { + public Person newPerson(final PersonnelRole role) { return newPerson(role, PersonnelRole.NONE); } @@ -1262,9 +1270,11 @@ public Person newPerson(final PersonnelRole primaryRole, final PersonnelRole sec * @param gender The gender of the person to be generated, or a randomize it value * @return A new {@link Person}. */ - public Person newPerson(final PersonnelRole primaryRole, final String factionCode, final Gender gender) { + public Person newPerson(final PersonnelRole primaryRole, final String factionCode, + final Gender gender) { return newPerson(primaryRole, PersonnelRole.NONE, - new DefaultFactionSelector(getCampaignOptions().getRandomOriginOptions(), factionCode), + new DefaultFactionSelector(getCampaignOptions().getRandomOriginOptions(), + (factionCode == null) ? null : Factions.getInstance().getFaction(factionCode)), getPlanetSelector(), gender); } @@ -1281,9 +1291,20 @@ public Person newPerson(final PersonnelRole primaryRole, final String factionCod */ public Person newPerson(final PersonnelRole primaryRole, final PersonnelRole secondaryRole, final AbstractFactionSelector factionSelector, - final AbstractPlanetSelector planetSelector, Gender gender) { - AbstractPersonnelGenerator personnelGenerator = getPersonnelGenerator(factionSelector, planetSelector); - return newPerson(primaryRole, secondaryRole, personnelGenerator, gender); + final AbstractPlanetSelector planetSelector, final Gender gender) { + return newPerson(primaryRole, secondaryRole, + getPersonnelGenerator(factionSelector, planetSelector), gender); + } + + /** + * Generate a new {@link Person} of the given role, using the supplied {@link AbstractPersonnelGenerator} + * @param primaryRole The primary role of the {@link Person}. + * @param personnelGenerator The {@link AbstractPersonnelGenerator} to use when creating the {@link Person}. + * @return A new {@link Person} configured using {@code personnelGenerator}. + */ + public Person newPerson(final PersonnelRole primaryRole, + final AbstractPersonnelGenerator personnelGenerator) { + return newPerson(primaryRole, PersonnelRole.NONE, personnelGenerator, Gender.RANDOMIZE); } /** @@ -1295,8 +1316,9 @@ public Person newPerson(final PersonnelRole primaryRole, final PersonnelRole sec * @return A new {@link Person} configured using {@code personnelGenerator}. */ public Person newPerson(final PersonnelRole primaryRole, final PersonnelRole secondaryRole, - final AbstractPersonnelGenerator personnelGenerator, final Gender gender) { - Person person = personnelGenerator.generate(this, primaryRole, secondaryRole, gender); + final AbstractPersonnelGenerator personnelGenerator, + final Gender gender) { + final Person person = personnelGenerator.generate(this, primaryRole, secondaryRole, gender); // Assign a random portrait after we generate a new person if (getCampaignOptions().usePortraitForRole(primaryRole)) { @@ -5155,10 +5177,10 @@ public int findAtBPartsAvailabilityLevel(IAcquisitionWork acquisition, StringBui } public void resetAstechMinutes() { - astechPoolMinutes = 480 * getNumberPrimaryAstechs() + 240 - * getNumberSecondaryAstechs(); - astechPoolOvertime = 240 * getNumberPrimaryAstechs() + 120 - * getNumberSecondaryAstechs(); + astechPoolMinutes = Person.PRIMARY_ROLE_SUPPORT_TIME * getNumberPrimaryAstechs() + + Person.PRIMARY_ROLE_OVERTIME_SUPPORT_TIME * getNumberSecondaryAstechs(); + astechPoolOvertime = Person.SECONDARY_ROLE_SUPPORT_TIME * getNumberPrimaryAstechs() + + Person.SECONDARY_ROLE_OVERTIME_SUPPORT_TIME * getNumberSecondaryAstechs(); } public void setAstechPoolMinutes(int minutes) { @@ -5560,12 +5582,15 @@ public void assignRandomPortraitFor(final Person person) { * @param person The {@link Person} who should receive a randomized origin. */ public void assignRandomOriginFor(final Person person) { - final AbstractFactionSelector factionSelector = getFactionSelector(); - final AbstractPlanetSelector planetSelector = getPlanetSelector(); + final Faction faction = getFactionSelector().selectFaction(this); + if (faction != null) { + person.setOriginFaction(faction); + } - final Faction faction = factionSelector.selectFaction(this); - person.setOriginFaction(faction); - person.setOriginPlanet(planetSelector.selectPlanet(this, faction)); + final Planet planet = getPlanetSelector().selectPlanet(this, faction); + if (planet != null) { + person.setOriginPlanet(planet); + } } /** diff --git a/MekHQ/src/mekhq/campaign/CampaignPreset.java b/MekHQ/src/mekhq/campaign/CampaignPreset.java index 18d7365097..5f18a02e4d 100644 --- a/MekHQ/src/mekhq/campaign/CampaignPreset.java +++ b/MekHQ/src/mekhq/campaign/CampaignPreset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -24,8 +24,8 @@ import megamek.common.util.EncodeControl; import megamek.common.util.sorter.NaturalOrderComparator; import megamek.utils.MegaMekXmlUtil; -import mekhq.MekHQ; import mekhq.MHQConstants; +import mekhq.MekHQ; import mekhq.MekHqXmlUtil; import mekhq.campaign.event.OptionsChangedEvent; import mekhq.campaign.personnel.PersonnelOptions; @@ -36,6 +36,7 @@ import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Planet; import mekhq.campaign.universe.Systems; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; import mekhq.io.migration.FactionMigrator; import org.apache.logging.log4j.LogManager; import org.w3c.dom.Document; @@ -75,6 +76,7 @@ public class CampaignPreset { private Planet planet; private RankSystem rankSystem; private int contractCount; + private CompanyGenerationOptions companyGenerationOptions; // Continuous private GameOptions gameOptions; @@ -91,14 +93,14 @@ public CampaignPreset() { public CampaignPreset(final boolean userData) { this("Title", "", userData, null, null, null, null, - 2, null, null, null, + 2, null, null, null, null, new Hashtable<>(), new Hashtable<>()); } public CampaignPreset(final Campaign campaign) { this(campaign.getName(), "", true, campaign.getLocalDate(), campaign.getFaction(), campaign.getCurrentSystem().getPrimaryPlanet(), campaign.getRankSystem(), 2, - campaign.getGameOptions(), campaign.getCampaignOptions(), + null, campaign.getGameOptions(), campaign.getCampaignOptions(), campaign.getRandomSkillPreferences(), SkillType.getSkillHash(), SpecialAbility.getAllSpecialAbilities()); } @@ -106,7 +108,9 @@ public CampaignPreset(final Campaign campaign) { public CampaignPreset(final String title, final String description, final boolean userData, final @Nullable LocalDate date, final @Nullable Faction faction, final @Nullable Planet planet, final @Nullable RankSystem rankSystem, - final int contractCount, final @Nullable GameOptions gameOptions, + final int contractCount, + final @Nullable CompanyGenerationOptions companyGenerationOptions, + final @Nullable GameOptions gameOptions, final @Nullable CampaignOptions campaignOptions, final @Nullable RandomSkillPreferences randomSkillPreferences, final Hashtable skills, @@ -122,6 +126,7 @@ public CampaignPreset(final String title, final String description, final boolea setPlanet(planet); setRankSystem(rankSystem); setContractCount(contractCount); + setCompanyGenerationOptions(companyGenerationOptions); // Continuous setGameOptions(gameOptions); @@ -189,6 +194,14 @@ public int getContractCount() { public void setContractCount(final int contractCount) { this.contractCount = contractCount; } + + public CompanyGenerationOptions getCompanyGenerationOptions() { + return companyGenerationOptions; + } + + public void setCompanyGenerationOptions(final @Nullable CompanyGenerationOptions companyGenerationOptions) { + this.companyGenerationOptions = companyGenerationOptions; + } //endregion Startup //region Continuous @@ -283,6 +296,7 @@ public void writeToFile(final JFrame frame, @Nullable File file) { path += ".xml"; file = new File(path); } + try (OutputStream fos = new FileOutputStream(file); OutputStream bos = new BufferedOutputStream(fos); OutputStreamWriter osw = new OutputStreamWriter(bos, StandardCharsets.UTF_8); @@ -323,6 +337,9 @@ public void writeToXML(final PrintWriter pw, int indent) { getRankSystem().writeToXML(pw, indent, false); } MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "contractCount", getContractCount()); + if (getCompanyGenerationOptions() != null) { + getCompanyGenerationOptions().writeToXML(pw, indent, null); + } //endregion Startup //region Continuous @@ -434,6 +451,9 @@ public static List loadCampaignPresetsFromDirectory(final @Nulla case "contractCount": preset.setContractCount(Integer.parseInt(wn.getTextContent().trim())); break; + case "companyGenerationOptions": + preset.setCompanyGenerationOptions(CompanyGenerationOptions.parseFromXML(wn.getChildNodes(), version)); + break; //endregion Startup //region Continuous @@ -482,8 +502,8 @@ public static List loadCampaignPresetsFromDirectory(final @Nulla break; } } - } catch (Exception e) { - LogManager.getLogger().error("", e); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); return null; } return preset; diff --git a/MekHQ/src/mekhq/campaign/RandomOriginOptions.java b/MekHQ/src/mekhq/campaign/RandomOriginOptions.java index af150fc800..a46c58782e 100644 --- a/MekHQ/src/mekhq/campaign/RandomOriginOptions.java +++ b/MekHQ/src/mekhq/campaign/RandomOriginOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -28,6 +28,9 @@ import java.io.PrintWriter; +/** + * @author Justin "Windchild" Bowen + */ public class RandomOriginOptions { //region Variable Declarations private boolean randomizeOrigin; @@ -229,6 +232,8 @@ public void writeToXML(final PrintWriter pw, int indent) { case "extraRandomOrigin": options.setExtraRandomOrigin(Boolean.parseBoolean(wn.getTextContent().trim())); break; + default: + break; } } } catch (Exception ex) { diff --git a/MekHQ/src/mekhq/campaign/finances/Money.java b/MekHQ/src/mekhq/campaign/finances/Money.java index 3df360e2a8..2a432bdd10 100644 --- a/MekHQ/src/mekhq/campaign/finances/Money.java +++ b/MekHQ/src/mekhq/campaign/finances/Money.java @@ -158,6 +158,13 @@ public String toAmountAndNameString() { return CurrencyManager.getInstance().getUiAmountAndNamePrinter().print(getWrapped().toMoney(RoundingMode.HALF_EVEN)); } + /** + * @return a new money object, rounded to use a scale of 0 with no trailing 0's + */ + public Money round() { + return new Money(getWrapped().withScale(0, RoundingMode.HALF_UP)); + } + //region File I/O public String toXmlString() { return CurrencyManager.getInstance().getXmlMoneyFormatter().print(getWrapped().toMoney(RoundingMode.HALF_EVEN)); diff --git a/MekHQ/src/mekhq/campaign/icons/enums/LayeredForceIconOperationalStatus.java b/MekHQ/src/mekhq/campaign/icons/enums/LayeredForceIconOperationalStatus.java index 0818278cbc..cfe1732c3d 100644 --- a/MekHQ/src/mekhq/campaign/icons/enums/LayeredForceIconOperationalStatus.java +++ b/MekHQ/src/mekhq/campaign/icons/enums/LayeredForceIconOperationalStatus.java @@ -26,14 +26,16 @@ * This is the Operational Status of a force or unit, as part of automatically assigning and * updating the force's LayeredForceIcon on a new day. It is also used to determine the Operation * Status for a unit. + * + * @author Justin "Windchild" Bowen */ public enum LayeredForceIconOperationalStatus { //region Enum Declarations - FULLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FULLY_OPERATIONAL_FILE_PATH), - SUBSTANTIALLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_SUBSTANTIALLY_OPERATIONAL_FILE_PATH), - MARGINALLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_MARGINALLY_OPERATIONAL_FILE_PATH), - NOT_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_NOT_OPERATIONAL_FILE_PATH), - FACTORY_FRESH(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FACTORY_FRESH_FILE_PATH); + FULLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FULLY_OPERATIONAL_FILENAME), + SUBSTANTIALLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_SUBSTANTIALLY_OPERATIONAL_FILENAME), + MARGINALLY_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_MARGINALLY_OPERATIONAL_FILENAME), + NOT_OPERATIONAL(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_NOT_OPERATIONAL_FILENAME), + FACTORY_FRESH(MHQConstants.LAYERED_FORCE_ICON_OPERATIONAL_STATUS_FACTORY_FRESH_FILENAME); //endregion Enum Declarations //region Variable Declarations diff --git a/MekHQ/src/mekhq/campaign/parts/Armor.java b/MekHQ/src/mekhq/campaign/parts/Armor.java index ff38503a83..b58051279c 100644 --- a/MekHQ/src/mekhq/campaign/parts/Armor.java +++ b/MekHQ/src/mekhq/campaign/parts/Armor.java @@ -181,6 +181,10 @@ public int getAmount() { return amount; } + public void addAmount(final int amount) { + this.amount += amount; + } + public int getAmountNeeded() { return amountNeeded; } diff --git a/MekHQ/src/mekhq/campaign/personnel/Person.java b/MekHQ/src/mekhq/campaign/personnel/Person.java index f4ed024207..c3be473f59 100644 --- a/MekHQ/src/mekhq/campaign/personnel/Person.java +++ b/MekHQ/src/mekhq/campaign/personnel/Person.java @@ -2406,11 +2406,15 @@ public Skills getSkills() { return skills; } - @Nullable - public Skill getSkill(String skillName) { + public @Nullable Skill getSkill(String skillName) { return skills.getSkill(skillName); } + public int getSkillLevel(final String skillName) { + final Skill skill = getSkill(skillName); + return (skill == null) ? 0 : skill.getExperienceLevel(); + } + public void addSkill(String skillName, Skill skill) { skills.addSkill(skillName, skill); } diff --git a/MekHQ/src/mekhq/campaign/unit/Unit.java b/MekHQ/src/mekhq/campaign/unit/Unit.java index 801f87c083..9c41fcb220 100644 --- a/MekHQ/src/mekhq/campaign/unit/Unit.java +++ b/MekHQ/src/mekhq/campaign/unit/Unit.java @@ -3406,6 +3406,10 @@ public Image getImage(Component component) { return commander; } + public boolean hasCommander() { + return getCommander() != null; + } + public void resetPilotAndEntity() { entity.getCrew().resetGameState(); if (entity.getCrew().getSlotCount() > 1) { diff --git a/MekHQ/src/mekhq/campaign/universe/Faction.java b/MekHQ/src/mekhq/campaign/universe/Faction.java index 388a70b138..16734b0b89 100644 --- a/MekHQ/src/mekhq/campaign/universe/Faction.java +++ b/MekHQ/src/mekhq/campaign/universe/Faction.java @@ -24,6 +24,7 @@ import megamek.common.annotations.Nullable; import mekhq.MekHqXmlUtil; import mekhq.Utilities; +import mekhq.campaign.Campaign; import org.apache.logging.log4j.LogManager; import org.w3c.dom.DOMException; import org.w3c.dom.Node; @@ -52,6 +53,10 @@ public class Faction { private int[] eraMods; private Color color; private String currencyCode = ""; // Currency of the faction, if any + private String layeredForceIconBackgroundCategory; + private String layeredForceIconBackgroundFilename; + private String layeredForceIconLogoCategory; + private String layeredForceIconLogoFilename; private Set tags; private int start; // Start year (inclusive) private int end; // End year (inclusive) @@ -69,7 +74,11 @@ public Faction(final String shortName, final String fullName) { color = Color.LIGHT_GRAY; startingPlanet = "Terra"; eraMods = null; - tags = EnumSet.noneOf(Faction.Tag.class); + setLayeredForceIconBackgroundCategory(""); + setLayeredForceIconBackgroundFilename(null); + setLayeredForceIconLogoCategory(""); + setLayeredForceIconLogoFilename(null); + tags = EnumSet.noneOf(Tag.class); start = 0; end = 9999; } @@ -104,8 +113,12 @@ public String getNameGenerator() { return nameGenerator; } - public String getStartingPlanet(final LocalDate year) { - final Map.Entry change = planetChanges.floorEntry(year); + public @Nullable PlanetarySystem getStartingPlanet(final Campaign campaign, final LocalDate date) { + return campaign.getSystemById(getStartingPlanet(date)); + } + + public String getStartingPlanet(final LocalDate date) { + final Map.Entry change = planetChanges.floorEntry(date); return (change == null) ? startingPlanet : change.getValue(); } @@ -172,6 +185,38 @@ public String getCurrencyCode() { return currencyCode; } + public String getLayeredForceIconBackgroundCategory() { + return layeredForceIconBackgroundCategory; + } + + public void setLayeredForceIconBackgroundCategory(final String layeredForceIconBackgroundCategory) { + this.layeredForceIconBackgroundCategory = layeredForceIconBackgroundCategory; + } + + public @Nullable String getLayeredForceIconBackgroundFilename() { + return layeredForceIconBackgroundFilename; + } + + public void setLayeredForceIconBackgroundFilename(final @Nullable String layeredForceIconBackgroundFilename) { + this.layeredForceIconBackgroundFilename = layeredForceIconBackgroundFilename; + } + + public String getLayeredForceIconLogoCategory() { + return layeredForceIconLogoCategory; + } + + public void setLayeredForceIconLogoCategory(final String layeredForceIconLogoCategory) { + this.layeredForceIconLogoCategory = layeredForceIconLogoCategory; + } + + public @Nullable String getLayeredForceIconLogoFilename() { + return layeredForceIconLogoFilename; + } + + public void setLayeredForceIconLogoFilename(final @Nullable String layeredForceIconLogoFilename) { + this.layeredForceIconLogoFilename = layeredForceIconLogoFilename; + } + //region Checks public boolean isPlayable() { return is(Tag.PLAYABLE); @@ -294,6 +339,14 @@ public static Faction getFactionFromXML(Node wn) throws DOMException { } } else if (wn2.getNodeName().equalsIgnoreCase("currencyCode")) { retVal.currencyCode = wn2.getTextContent(); + } else if (wn2.getNodeName().equalsIgnoreCase("layeredForceIconBackgroundCategory")) { + retVal.setLayeredForceIconBackgroundCategory(wn2.getTextContent().trim()); + } else if (wn2.getNodeName().equalsIgnoreCase("layeredForceIconBackgroundFilename")) { + retVal.setLayeredForceIconBackgroundFilename(wn2.getTextContent().trim()); + } else if (wn2.getNodeName().equalsIgnoreCase("layeredForceIconLogoCategory")) { + retVal.setLayeredForceIconLogoCategory(wn2.getTextContent().trim()); + } else if (wn2.getNodeName().equalsIgnoreCase("layeredForceIconLogoFilename")) { + retVal.setLayeredForceIconLogoFilename(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("tags")) { Arrays.stream(wn2.getTextContent().split(",")).map(tag -> tag.toUpperCase(Locale.ROOT)) .map(Tag::valueOf).forEach(tag -> retVal.tags.add(tag)); diff --git a/MekHQ/src/mekhq/campaign/universe/companyGeneration/AtBRandomMechParameters.java b/MekHQ/src/mekhq/campaign/universe/companyGeneration/AtBRandomMechParameters.java new file mode 100644 index 0000000000..bbcd6cd43b --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/companyGeneration/AtBRandomMechParameters.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021-2022 - 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.companyGeneration; + +import megamek.common.EntityWeightClass; + +/** + * This class contains the parameters used to generate a random mech, and allows sorting and + * swapping the order of rolled parameters while keeping them connected. + * + * @author Justin "Windchild" Bowen + */ +public class AtBRandomMechParameters { + //region Variable Declarations + private int weight; + private int quality; + private boolean starLeague; + //endregion Variable Declarations + + //region Constructors + public AtBRandomMechParameters(final int weight, final int quality) { + setWeight(weight); + setQuality(quality); + setStarLeague(weight == EntityWeightClass.WEIGHT_SUPER_HEAVY); + } + //endregion Constructors + + //region Getters/Setters + public int getWeight() { + return weight; + } + + public void setWeight(final int weight) { + this.weight = weight; + } + + public int getQuality() { + return quality; + } + + public void setQuality(final int quality) { + this.quality = quality; + } + + public boolean isStarLeague() { + return starLeague; + } + + public void setStarLeague(final boolean starLeague) { + this.starLeague = starLeague; + } + //endregion Getters/Setters +} diff --git a/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationOptions.java b/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationOptions.java new file mode 100644 index 0000000000..d5480dce54 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationOptions.java @@ -0,0 +1,1274 @@ +/* + * Copyright (c) 2021-2022 - 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.companyGeneration; + +import megamek.Version; +import megamek.common.EntityWeightClass; +import megamek.common.annotations.Nullable; +import mekhq.MHQConstants; +import mekhq.MekHqXmlUtil; +import mekhq.campaign.RandomOriginOptions; +import mekhq.campaign.personnel.enums.PersonnelRole; +import mekhq.campaign.universe.enums.*; +import org.apache.logging.log4j.LogManager; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +/** + * @author Justin "Windchild" Bowen + */ +public class CompanyGenerationOptions implements Serializable { + //region Variable Declarations + private static final long serialVersionUID = 3034123423672457769L; + + // Base Information + private CompanyGenerationMethod method; + private boolean generateMercenaryCompanyCommandLance; + private int companyCount; + private int individualLanceCount; + private int lancesPerCompany; + private int lanceSize; + private int starLeagueYear; + + // Personnel + private Map supportPersonnel; + private boolean poolAssistants; + private boolean generateCaptains; + private boolean assignCompanyCommanderFlag; + private boolean applyOfficerStatBonusToWorstSkill; + private boolean assignBestCompanyCommander; + private boolean prioritizeCompanyCommanderCombatSkills; + private boolean assignBestOfficers; + private boolean prioritizeOfficerCombatSkills; + private boolean assignMostSkilledToPrimaryLances; + private boolean automaticallyAssignRanks; + private boolean assignFounderFlag; + + // Personnel Randomization + private RandomOriginOptions randomOriginOptions; + + // Starting Simulation + private boolean runStartingSimulation; + private int simulationDuration; + private boolean simulateRandomMarriages; + private boolean simulateRandomProcreation; + + // Units + private BattleMechWeightClassGenerationMethod battleMechWeightClassGenerationMethod; + private BattleMechQualityGenerationMethod battleMechQualityGenerationMethod; + private boolean neverGenerateStarLeagueMechs; + private boolean onlyGenerateStarLeagueMechs; + private boolean onlyGenerateOmniMechs; + private boolean generateUnitsAsAttached; + private boolean assignBestRollToCompanyCommander; + private boolean sortStarLeagueUnitsFirst; + private boolean groupByWeight; + private boolean groupByQuality; + private boolean keepOfficerRollsSeparate; + private boolean assignTechsToUnits; + + // Unit + private ForceNamingMethod forceNamingMethod; + private boolean generateForceIcons; + private boolean generateOriginNodeForceIcon; + private boolean useOriginNodeForceIconLogo; + private TreeMap forceWeightLimits; + + // Spares + private boolean generateMothballedSpareUnits; + private int sparesPercentOfActiveUnits; + private PartGenerationMethod partGenerationMethod; + private int startingArmourWeight; + private boolean generateSpareAmmunition; + private int numberReloadsPerWeapon; + private boolean generateFractionalMachineGunAmmunition; + + // Contracts + private boolean selectStartingContract; + private boolean startCourseToContractPlanet; + + // Finances + private boolean processFinances; + private int startingCash; + private boolean randomizeStartingCash; + private int randomStartingCashDiceCount; + private int minimumStartingFloat; + private boolean includeInitialContractPayment; + private boolean startingLoan; + private boolean payForSetup; + private boolean payForPersonnel; + private boolean payForUnits; + private boolean payForParts; + private boolean payForArmour; + private boolean payForAmmunition; + + // Surprises + private boolean generateSurprises; + private boolean generateMysteryBoxes; + private Map generateMysteryBoxTypes; + //endregion Variable Declarations + + //region Constructors + public CompanyGenerationOptions(final CompanyGenerationMethod method) { + // Base Information + setMethod(method); + setGenerateMercenaryCompanyCommandLance(false); + setCompanyCount(1); + setIndividualLanceCount(0); + setLancesPerCompany(3); + setLanceSize(4); + setStarLeagueYear(2765); + + // Personnel + final Map supportPersonnel = new HashMap<>(); + if (method.isWindchild()) { + supportPersonnel.put(PersonnelRole.MECH_TECH, 5); + supportPersonnel.put(PersonnelRole.MECHANIC, 1); + supportPersonnel.put(PersonnelRole.AERO_TECH, 1); + supportPersonnel.put(PersonnelRole.DOCTOR, 1); + supportPersonnel.put(PersonnelRole.ADMINISTRATOR_COMMAND, 1); + supportPersonnel.put(PersonnelRole.ADMINISTRATOR_LOGISTICS, 1); + supportPersonnel.put(PersonnelRole.ADMINISTRATOR_TRANSPORT, 1); + supportPersonnel.put(PersonnelRole.ADMINISTRATOR_HR, 1); + } else { // Defaults to AtB + supportPersonnel.put(PersonnelRole.MECH_TECH, 10); + supportPersonnel.put(PersonnelRole.DOCTOR, 1); + supportPersonnel.put(PersonnelRole.ADMINISTRATOR_LOGISTICS, 1); + } + setSupportPersonnel(supportPersonnel); + setPoolAssistants(true); + setGenerateCaptains(method.isWindchild()); + setAssignCompanyCommanderFlag(true); + setApplyOfficerStatBonusToWorstSkill(method.isWindchild()); + setAssignBestCompanyCommander(method.isWindchild()); + setPrioritizeCompanyCommanderCombatSkills(false); + setAssignBestOfficers(method.isWindchild()); + setPrioritizeOfficerCombatSkills(false); + setAssignMostSkilledToPrimaryLances(method.isWindchild()); + setAutomaticallyAssignRanks(true); + setAssignFounderFlag(true); + + // Personnel Randomization + setRandomOriginOptions(new RandomOriginOptions(false)); + + // Starting Simulation + setRunStartingSimulation(method.isWindchild()); + setSimulationDuration(5); + setSimulateRandomMarriages(method.isWindchild()); + setSimulateRandomProcreation(method.isWindchild()); + + // Units + setBattleMechWeightClassGenerationMethod(method.isAtB() + ? BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT + : BattleMechWeightClassGenerationMethod.WINDCHILD); + setBattleMechQualityGenerationMethod(method.isAtB() + ? BattleMechQualityGenerationMethod.AGAINST_THE_BOT + : BattleMechQualityGenerationMethod.WINDCHILD); + setNeverGenerateStarLeagueMechs(false); + setOnlyGenerateStarLeagueMechs(false); + setOnlyGenerateOmniMechs(false); + setGenerateUnitsAsAttached(method.isAtB()); + setAssignBestRollToCompanyCommander(method.isWindchild()); + setSortStarLeagueUnitsFirst(true); + setGroupByWeight(true); + setGroupByQuality(method.isWindchild()); + setKeepOfficerRollsSeparate(method.isAtB()); + setAssignTechsToUnits(true); + + // Unit + setForceNamingMethod(ForceNamingMethod.CCB_1943); + setGenerateForceIcons(true); + setGenerateOriginNodeForceIcon(true); + setUseOriginNodeForceIconLogo(false); + setForceWeightLimits(new TreeMap<>()); + getForceWeightLimits().put(390, EntityWeightClass.WEIGHT_ASSAULT); + getForceWeightLimits().put(280, EntityWeightClass.WEIGHT_HEAVY); + getForceWeightLimits().put(200, EntityWeightClass.WEIGHT_MEDIUM); + getForceWeightLimits().put(130, EntityWeightClass.WEIGHT_LIGHT); + getForceWeightLimits().put(60, EntityWeightClass.WEIGHT_ULTRA_LIGHT); + + // Spares + setGenerateMothballedSpareUnits(false); + setSparesPercentOfActiveUnits(10); + setPartGenerationMethod(PartGenerationMethod.WINDCHILD); + setStartingArmourWeight(60); + setGenerateSpareAmmunition(method.isWindchild()); + setNumberReloadsPerWeapon(4); + setGenerateFractionalMachineGunAmmunition(true); + + // Contracts + setSelectStartingContract(true); + setStartCourseToContractPlanet(true); + + // Finances + setProcessFinances(true); + setStartingCash(60000000); + setRandomizeStartingCash(method.isWindchild()); + setRandomStartingCashDiceCount(17); + setMinimumStartingFloat(method.isWindchild() ? 3500000 : 0); + setIncludeInitialContractPayment(method.isWindchild()); + setStartingLoan(!method.isWindchild()); + setPayForSetup(true); + setPayForPersonnel(true); + setPayForUnits(true); + setPayForParts(true); + setPayForArmour(true); + setPayForAmmunition(true); + + // Surprises + setGenerateSurprises(true); + setGenerateMysteryBoxes(true); + setGenerateMysteryBoxTypes(new HashMap<>()); + getGenerateMysteryBoxTypes().put(MysteryBoxType.STAR_LEAGUE_REGULAR, true); + } + //endregion Constructors + + //region Getters/Setters + //region Base Information + public CompanyGenerationMethod getMethod() { + return method; + } + + public void setMethod(final CompanyGenerationMethod method) { + this.method = method; + } + + public boolean isGenerateMercenaryCompanyCommandLance() { + return generateMercenaryCompanyCommandLance; + } + + public void setGenerateMercenaryCompanyCommandLance(final boolean generateMercenaryCompanyCommandLance) { + this.generateMercenaryCompanyCommandLance = generateMercenaryCompanyCommandLance; + } + + public int getCompanyCount() { + return companyCount; + } + + public void setCompanyCount(final int companyCount) { + this.companyCount = companyCount; + } + + public int getIndividualLanceCount() { + return individualLanceCount; + } + + public void setIndividualLanceCount(final int individualLanceCount) { + this.individualLanceCount = individualLanceCount; + } + + public int getLancesPerCompany() { + return lancesPerCompany; + } + + public void setLancesPerCompany(final int lancesPerCompany) { + this.lancesPerCompany = lancesPerCompany; + } + + public int getLanceSize() { + return lanceSize; + } + + public void setLanceSize(final int lanceSize) { + this.lanceSize = lanceSize; + } + + public int getStarLeagueYear() { + return starLeagueYear; + } + + public void setStarLeagueYear(final int starLeagueYear) { + this.starLeagueYear = starLeagueYear; + } + //endregion Base Information + + //region Personnel + public Map getSupportPersonnel() { + return supportPersonnel; + } + + public void setSupportPersonnel(final Map supportPersonnel) { + this.supportPersonnel = supportPersonnel; + } + + public boolean isPoolAssistants() { + return poolAssistants; + } + + public void setPoolAssistants(final boolean poolAssistants) { + this.poolAssistants = poolAssistants; + } + + public boolean isGenerateCaptains() { + return generateCaptains; + } + + public void setGenerateCaptains(final boolean generateCaptains) { + this.generateCaptains = generateCaptains; + } + + public boolean isAssignCompanyCommanderFlag() { + return assignCompanyCommanderFlag; + } + + public void setAssignCompanyCommanderFlag(final boolean assignCompanyCommanderFlag) { + this.assignCompanyCommanderFlag = assignCompanyCommanderFlag; + } + + public boolean isApplyOfficerStatBonusToWorstSkill() { + return applyOfficerStatBonusToWorstSkill; + } + + public void setApplyOfficerStatBonusToWorstSkill(final boolean applyOfficerStatBonusToWorstSkill) { + this.applyOfficerStatBonusToWorstSkill = applyOfficerStatBonusToWorstSkill; + } + + public boolean isAssignBestCompanyCommander() { + return assignBestCompanyCommander; + } + + public void setAssignBestCompanyCommander(final boolean assignBestCompanyCommander) { + this.assignBestCompanyCommander = assignBestCompanyCommander; + } + + public boolean isPrioritizeCompanyCommanderCombatSkills() { + return prioritizeCompanyCommanderCombatSkills; + } + + public void setPrioritizeCompanyCommanderCombatSkills(final boolean prioritizeCompanyCommanderCombatSkills) { + this.prioritizeCompanyCommanderCombatSkills = prioritizeCompanyCommanderCombatSkills; + } + + public boolean isAssignBestOfficers() { + return assignBestOfficers; + } + + public void setAssignBestOfficers(final boolean assignBestOfficers) { + this.assignBestOfficers = assignBestOfficers; + } + + public boolean isPrioritizeOfficerCombatSkills() { + return prioritizeOfficerCombatSkills; + } + + public void setPrioritizeOfficerCombatSkills(final boolean prioritizeOfficerCombatSkills) { + this.prioritizeOfficerCombatSkills = prioritizeOfficerCombatSkills; + } + + public boolean isAssignMostSkilledToPrimaryLances() { + return assignMostSkilledToPrimaryLances; + } + + public void setAssignMostSkilledToPrimaryLances(final boolean assignMostSkilledToPrimaryLances) { + this.assignMostSkilledToPrimaryLances = assignMostSkilledToPrimaryLances; + } + + public boolean isAutomaticallyAssignRanks() { + return automaticallyAssignRanks; + } + + public void setAutomaticallyAssignRanks(final boolean automaticallyAssignRanks) { + this.automaticallyAssignRanks = automaticallyAssignRanks; + } + + public boolean isAssignFounderFlag() { + return assignFounderFlag; + } + + public void setAssignFounderFlag(final boolean assignFounderFlag) { + this.assignFounderFlag = assignFounderFlag; + } + //endregion Personnel + + //region Personnel Randomization + public RandomOriginOptions getRandomOriginOptions() { + return randomOriginOptions; + } + + public void setRandomOriginOptions(final RandomOriginOptions randomOriginOptions) { + this.randomOriginOptions = randomOriginOptions; + } + //endregion Personnel Randomization + + //region Starting Simulation + public boolean isRunStartingSimulation() { + return runStartingSimulation; + } + + public void setRunStartingSimulation(final boolean runStartingSimulation) { + this.runStartingSimulation = runStartingSimulation; + } + + public int getSimulationDuration() { + return simulationDuration; + } + + public void setSimulationDuration(final int simulationDuration) { + this.simulationDuration = simulationDuration; + } + + public boolean isSimulateRandomMarriages() { + return simulateRandomMarriages; + } + + public void setSimulateRandomMarriages(final boolean simulateRandomMarriages) { + this.simulateRandomMarriages = simulateRandomMarriages; + } + + public boolean isSimulateRandomProcreation() { + return simulateRandomProcreation; + } + + public void setSimulateRandomProcreation(final boolean simulateRandomProcreation) { + this.simulateRandomProcreation = simulateRandomProcreation; + } + //endregion Starting Simulation + + //region Units + public BattleMechWeightClassGenerationMethod getBattleMechWeightClassGenerationMethod() { + return battleMechWeightClassGenerationMethod; + } + + public void setBattleMechWeightClassGenerationMethod( + final BattleMechWeightClassGenerationMethod battleMechWeightClassGenerationMethod) { + this.battleMechWeightClassGenerationMethod = battleMechWeightClassGenerationMethod; + } + + public BattleMechQualityGenerationMethod getBattleMechQualityGenerationMethod() { + return battleMechQualityGenerationMethod; + } + + public void setBattleMechQualityGenerationMethod( + final BattleMechQualityGenerationMethod battleMechQualityGenerationMethod) { + this.battleMechQualityGenerationMethod = battleMechQualityGenerationMethod; + } + + public boolean isNeverGenerateStarLeagueMechs() { + return neverGenerateStarLeagueMechs; + } + + public void setNeverGenerateStarLeagueMechs(final boolean neverGenerateStarLeagueMechs) { + this.neverGenerateStarLeagueMechs = neverGenerateStarLeagueMechs; + } + + public boolean isOnlyGenerateStarLeagueMechs() { + return onlyGenerateStarLeagueMechs; + } + + public void setOnlyGenerateStarLeagueMechs(final boolean onlyGenerateStarLeagueMechs) { + this.onlyGenerateStarLeagueMechs = onlyGenerateStarLeagueMechs; + } + + public boolean isOnlyGenerateOmniMechs() { + return onlyGenerateOmniMechs; + } + + public void setOnlyGenerateOmniMechs(final boolean onlyGenerateOmniMechs) { + this.onlyGenerateOmniMechs = onlyGenerateOmniMechs; + } + + public boolean isGenerateUnitsAsAttached() { + return generateUnitsAsAttached; + } + + public void setGenerateUnitsAsAttached(final boolean generateUnitsAsAttached) { + this.generateUnitsAsAttached = generateUnitsAsAttached; + } + + public boolean isAssignBestRollToCompanyCommander() { + return assignBestRollToCompanyCommander; + } + + public void setAssignBestRollToCompanyCommander(final boolean assignBestRollToCompanyCommander) { + this.assignBestRollToCompanyCommander = assignBestRollToCompanyCommander; + } + + public boolean isSortStarLeagueUnitsFirst() { + return sortStarLeagueUnitsFirst; + } + + public void setSortStarLeagueUnitsFirst(final boolean sortStarLeagueUnitsFirst) { + this.sortStarLeagueUnitsFirst = sortStarLeagueUnitsFirst; + } + + public boolean isGroupByWeight() { + return groupByWeight; + } + + public void setGroupByWeight(final boolean groupByWeight) { + this.groupByWeight = groupByWeight; + } + + public boolean isGroupByQuality() { + return groupByQuality; + } + + public void setGroupByQuality(final boolean groupByQuality) { + this.groupByQuality = groupByQuality; + } + + public boolean isKeepOfficerRollsSeparate() { + return keepOfficerRollsSeparate; + } + + public void setKeepOfficerRollsSeparate(final boolean keepOfficerRollsSeparate) { + this.keepOfficerRollsSeparate = keepOfficerRollsSeparate; + } + + public boolean isAssignTechsToUnits() { + return assignTechsToUnits; + } + + public void setAssignTechsToUnits(final boolean assignTechsToUnits) { + this.assignTechsToUnits = assignTechsToUnits; + } + //endregion Units + + //region Unit + public ForceNamingMethod getForceNamingMethod() { + return forceNamingMethod; + } + + public void setForceNamingMethod(final ForceNamingMethod forceNamingMethod) { + this.forceNamingMethod = forceNamingMethod; + } + + public boolean isGenerateForceIcons() { + return generateForceIcons; + } + + public void setGenerateForceIcons(final boolean generateForceIcons) { + this.generateForceIcons = generateForceIcons; + } + + public boolean isGenerateOriginNodeForceIcon() { + return generateOriginNodeForceIcon; + } + + public void setGenerateOriginNodeForceIcon(final boolean generateOriginNodeForceIcon) { + this.generateOriginNodeForceIcon = generateOriginNodeForceIcon; + } + + public boolean isUseOriginNodeForceIconLogo() { + return useOriginNodeForceIconLogo; + } + + public void setUseOriginNodeForceIconLogo(final boolean useOriginNodeForceIconLogo) { + this.useOriginNodeForceIconLogo = useOriginNodeForceIconLogo; + } + + public TreeMap getForceWeightLimits() { + return forceWeightLimits; + } + + public void setForceWeightLimits(final TreeMap forceWeightLimits) { + this.forceWeightLimits = forceWeightLimits; + } + //endregion Unit + + //region Spares + public boolean isGenerateMothballedSpareUnits() { + return generateMothballedSpareUnits; + } + + public void setGenerateMothballedSpareUnits(final boolean generateMothballedSpareUnits) { + this.generateMothballedSpareUnits = generateMothballedSpareUnits; + } + + public int getSparesPercentOfActiveUnits() { + return sparesPercentOfActiveUnits; + } + + public void setSparesPercentOfActiveUnits(final int sparesPercentOfActiveUnits) { + this.sparesPercentOfActiveUnits = sparesPercentOfActiveUnits; + } + + public PartGenerationMethod getPartGenerationMethod() { + return partGenerationMethod; + } + + public void setPartGenerationMethod(final PartGenerationMethod partGenerationMethod) { + this.partGenerationMethod = partGenerationMethod; + } + + public int getStartingArmourWeight() { + return startingArmourWeight; + } + + public void setStartingArmourWeight(final int startingArmourWeight) { + this.startingArmourWeight = startingArmourWeight; + } + + public boolean isGenerateSpareAmmunition() { + return generateSpareAmmunition; + } + + public void setGenerateSpareAmmunition(final boolean generateSpareAmmunition) { + this.generateSpareAmmunition = generateSpareAmmunition; + } + + public int getNumberReloadsPerWeapon() { + return numberReloadsPerWeapon; + } + + public void setNumberReloadsPerWeapon(final int numberReloadsPerWeapon) { + this.numberReloadsPerWeapon = numberReloadsPerWeapon; + } + + public boolean isGenerateFractionalMachineGunAmmunition() { + return generateFractionalMachineGunAmmunition; + } + + public void setGenerateFractionalMachineGunAmmunition(final boolean generateFractionalMachineGunAmmunition) { + this.generateFractionalMachineGunAmmunition = generateFractionalMachineGunAmmunition; + } + //endregion Spares + + //region Contracts + public boolean isSelectStartingContract() { + return selectStartingContract; + } + + public void setSelectStartingContract(final boolean selectStartingContract) { + this.selectStartingContract = selectStartingContract; + } + + public boolean isStartCourseToContractPlanet() { + return startCourseToContractPlanet; + } + + public void setStartCourseToContractPlanet(final boolean startCourseToContractPlanet) { + this.startCourseToContractPlanet = startCourseToContractPlanet; + } + //endregion Contracts + + //region Finances + public boolean isProcessFinances() { + return processFinances; + } + + public void setProcessFinances(final boolean processFinances) { + this.processFinances = processFinances; + } + + public int getStartingCash() { + return startingCash; + } + + public void setStartingCash(final int startingCash) { + this.startingCash = startingCash; + } + + public boolean isRandomizeStartingCash() { + return randomizeStartingCash; + } + + public void setRandomizeStartingCash(final boolean randomizeStartingCash) { + this.randomizeStartingCash = randomizeStartingCash; + } + + public int getRandomStartingCashDiceCount() { + return randomStartingCashDiceCount; + } + + public void setRandomStartingCashDiceCount(final int randomStartingCashDiceCount) { + this.randomStartingCashDiceCount = randomStartingCashDiceCount; + } + + public int getMinimumStartingFloat() { + return minimumStartingFloat; + } + + public void setMinimumStartingFloat(final int minimumStartingFloat) { + this.minimumStartingFloat = minimumStartingFloat; + } + + public boolean isIncludeInitialContractPayment() { + return includeInitialContractPayment; + } + + public void setIncludeInitialContractPayment(final boolean includeInitialContractPayment) { + this.includeInitialContractPayment = includeInitialContractPayment; + } + + public boolean isStartingLoan() { + return startingLoan; + } + + public void setStartingLoan(final boolean startingLoan) { + this.startingLoan = startingLoan; + } + + public boolean isPayForSetup() { + return payForSetup; + } + + public void setPayForSetup(final boolean payForSetup) { + this.payForSetup = payForSetup; + } + + public boolean isPayForPersonnel() { + return payForPersonnel; + } + + public void setPayForPersonnel(final boolean payForPersonnel) { + this.payForPersonnel = payForPersonnel; + } + + public boolean isPayForUnits() { + return payForUnits; + } + + public void setPayForUnits(final boolean payForUnits) { + this.payForUnits = payForUnits; + } + + public boolean isPayForParts() { + return payForParts; + } + + public void setPayForParts(final boolean payForParts) { + this.payForParts = payForParts; + } + + public boolean isPayForArmour() { + return payForArmour; + } + + public void setPayForArmour(final boolean payForArmour) { + this.payForArmour = payForArmour; + } + + public boolean isPayForAmmunition() { + return payForAmmunition; + } + + public void setPayForAmmunition(final boolean payForAmmunition) { + this.payForAmmunition = payForAmmunition; + } + //endregion Finances + + //region Surprises + public boolean isGenerateSurprises() { + return generateSurprises; + } + + public void setGenerateSurprises(final boolean generateSurprises) { + this.generateSurprises = generateSurprises; + } + + public boolean isGenerateMysteryBoxes() { + return generateMysteryBoxes; + } + + public void setGenerateMysteryBoxes(final boolean generateMysteryBoxes) { + this.generateMysteryBoxes = generateMysteryBoxes; + } + + public Map getGenerateMysteryBoxTypes() { + return generateMysteryBoxTypes; + } + + public void setGenerateMysteryBoxTypes(final Map generateMysteryBoxTypes) { + this.generateMysteryBoxTypes = generateMysteryBoxTypes; + } + //endregion Surprises + //endregion Getters/Setters + + //region File IO + /** + * Writes these options to an XML file + * @param file the file to write to, or null to not write to a file + */ + public void writeToFile(@Nullable File file) { + if (file == null) { + return; + } + String path = file.getPath(); + if (!path.endsWith(".xml")) { + path += ".xml"; + file = new File(path); + } + + try (OutputStream fos = new FileOutputStream(file); + OutputStream bos = new BufferedOutputStream(fos); + OutputStreamWriter osw = new OutputStreamWriter(bos, StandardCharsets.UTF_8); + PrintWriter pw = new PrintWriter(osw)) { + // Then save it out to that file. + pw.println(""); + writeToXML(pw, 0, MHQConstants.VERSION); + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + } + } + + /** + * @param pw the print writer to write to + * @param indent the indent level to write at + * @param version the version these options were written to file in. This may be null, in which + * case they are being written to file as a part of a larger save than just these + * options (e.g. saved as part of Campaign or CampaignOptions) + */ + public void writeToXML(final PrintWriter pw, int indent, final @Nullable Version version) { + if (version == null) { + MekHqXmlUtil.writeSimpleXMLOpenTag(pw, indent++, "companyGenerationOptions"); + } else { + MekHqXmlUtil.writeSimpleXMLOpenTag(pw, indent++, "companyGenerationOptions", "version", version); + } + + // Base Information + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "method", getMethod().name()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateMercenaryCompanyCommandLance", isGenerateMercenaryCompanyCommandLance()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "companyCount", getCompanyCount()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "individualLanceCount", getIndividualLanceCount()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "lancesPerCompany", getLancesPerCompany()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "lanceSize", getLanceSize()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "starLeagueYear", getStarLeagueYear()); + + // Personnel + MekHqXmlUtil.writeSimpleXMLOpenTag(pw, indent++, "supportPersonnel"); + for (final Entry entry : getSupportPersonnel().entrySet()) { + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, entry.getKey().name(), entry.getValue()); + } + MekHqXmlUtil.writeSimpleXMLCloseTag(pw, --indent, "supportPersonnel"); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "poolAssistants", isPoolAssistants()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateCaptains", isGenerateCaptains()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignCompanyCommanderFlag", isAssignCompanyCommanderFlag()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "applyOfficerStatBonusToWorstSkill", isApplyOfficerStatBonusToWorstSkill()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignBestCompanyCommander", isAssignBestCompanyCommander()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "prioritizeCompanyCommanderCombatSkills", isPrioritizeCompanyCommanderCombatSkills()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignBestOfficers", isAssignBestOfficers()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "prioritizeOfficerCombatSkills", isPrioritizeOfficerCombatSkills()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignMostSkilledToPrimaryLances", isAssignMostSkilledToPrimaryLances()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "automaticallyAssignRanks", isAutomaticallyAssignRanks()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignFounderFlag", isAssignFounderFlag()); + + // Personnel Randomization + getRandomOriginOptions().writeToXML(pw, indent); + + // Starting Simulation + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "runStartingSimulation", isRunStartingSimulation()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "simulationDuration", getSimulationDuration()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "simulateRandomMarriages", isSimulateRandomMarriages()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "simulateRandomProcreation", isSimulateRandomProcreation()); + + // Units + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "battleMechWeightClassGenerationMethod", getBattleMechWeightClassGenerationMethod().name()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "battleMechQualityGenerationMethod", getBattleMechQualityGenerationMethod().name()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "neverGenerateStarLeagueMechs", isNeverGenerateStarLeagueMechs()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "onlyGenerateStarLeagueMechs", isOnlyGenerateStarLeagueMechs()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "onlyGenerateOmniMechs", isOnlyGenerateOmniMechs()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateUnitsAsAttached", isGenerateUnitsAsAttached()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignBestRollToCompanyCommander", isAssignBestRollToCompanyCommander()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "sortStarLeagueUnitsFirst", isSortStarLeagueUnitsFirst()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "groupByWeight", isGroupByWeight()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "groupByQuality", isGroupByQuality()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "keepOfficerRollsSeparate", isKeepOfficerRollsSeparate()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "assignTechsToUnits", isAssignTechsToUnits()); + + // Unit + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "forceNamingMethod", getForceNamingMethod().name()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateForceIcons", isGenerateForceIcons()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateOriginNodeForceIcon", isGenerateOriginNodeForceIcon()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "useOriginNodeForceIconLogo", isUseOriginNodeForceIconLogo()); + MekHqXmlUtil.writeSimpleXMLOpenTag(pw, indent++, "forceWeightLimits"); + for (final Entry entry : getForceWeightLimits().entrySet()) { + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, entry.getKey().toString(), entry.getValue()); + } + MekHqXmlUtil.writeSimpleXMLCloseTag(pw, --indent, "forceWeightLimits"); + + // Spares + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateMothballedSpareUnits", isGenerateMothballedSpareUnits()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "sparesPercentOfActiveUnits", getSparesPercentOfActiveUnits()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "partGenerationMethod", getPartGenerationMethod().name()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "startingArmourWeight", getStartingArmourWeight()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateSpareAmmunition", isGenerateSpareAmmunition()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "numberReloadsPerWeapon", getNumberReloadsPerWeapon()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateFractionalMachineGunAmmunition", isGenerateFractionalMachineGunAmmunition()); + + // Contracts + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "selectStartingContract", isSelectStartingContract()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "startCourseToContractPlanet", isStartCourseToContractPlanet()); + + // Finances + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "processFinances", isProcessFinances()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "startingCash", getStartingCash()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "randomizeStartingCash", isRandomizeStartingCash()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "randomStartingCashDiceCount", getRandomStartingCashDiceCount()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "minimumStartingFloat", getMinimumStartingFloat()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "includeInitialContractPayment", isIncludeInitialContractPayment()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "startingLoan", isStartingLoan()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForSetup", isPayForSetup()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForPersonnel", isPayForPersonnel()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForUnits", isPayForUnits()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForParts", isPayForParts()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForArmour", isPayForArmour()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "payForAmmunition", isPayForAmmunition()); + + // Surprises + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateSurprises", isGenerateSurprises()); + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, "generateMysteryBoxes", isGenerateMysteryBoxes()); + MekHqXmlUtil.writeSimpleXMLOpenTag(pw, indent++, "generateMysteryBoxTypes"); + for (final Entry entry : getGenerateMysteryBoxTypes().entrySet()) { + MekHqXmlUtil.writeSimpleXMLTag(pw, indent, entry.getKey().name(), entry.getValue()); + } + MekHqXmlUtil.writeSimpleXMLCloseTag(pw, --indent, "generateMysteryBoxTypes"); + MekHqXmlUtil.writeSimpleXMLCloseTag(pw, --indent, "companyGenerationOptions"); + } + + /** + * @param file the XML file to parse the company generation options from. This should not be null, + * but null values are handled nicely. + * @return the parsed CompanyGenerationOptions, or the default Windchild options if there is an + * issue parsing the file. + */ + public static CompanyGenerationOptions parseFromXML(final @Nullable File file) { + if (file == null) { + LogManager.getLogger().error("Received a null file, returning the default Windchild options"); + return new CompanyGenerationOptions(CompanyGenerationMethod.WINDCHILD); + } + final Element element; + + // Open up the file. + try (InputStream is = new FileInputStream(file)) { + element = MekHqXmlUtil.newSafeDocumentBuilder().parse(is).getDocumentElement(); + } catch (Exception e) { + LogManager.getLogger().error("Failed to open file, returning the default Windchild options", e); + return new CompanyGenerationOptions(CompanyGenerationMethod.WINDCHILD); + } + element.normalize(); + + final Version version = new Version(element.getAttribute("version")); + final NodeList nl = element.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + final Node wn = nl.item(i); + if ("companyGenerationOptions".equals(wn.getNodeName()) && wn.hasChildNodes()) { + final CompanyGenerationOptions options = parseFromXML(wn.getChildNodes(), version); + if (options != null) { + return options; + } + } + } + LogManager.getLogger().error("Failed to parse file, returning the default Windchild options"); + return new CompanyGenerationOptions(CompanyGenerationMethod.WINDCHILD); + } + + /** + * @param nl the node list to parse the options from + * @param ignoredVersion the Version of the XML to parse from. This is included for future-proofing + * @return the parsed company generation options, or null if the parsing fails + */ + public static @Nullable CompanyGenerationOptions parseFromXML(final NodeList nl, + final Version ignoredVersion) { + final CompanyGenerationOptions options = new CompanyGenerationOptions(CompanyGenerationMethod.WINDCHILD); + try { + for (int x = 0; x < nl.getLength(); x++) { + final Node wn = nl.item(x); + switch (wn.getNodeName()) { + //region Base Information + case "method": + options.setMethod(CompanyGenerationMethod.valueOf(wn.getTextContent().trim())); + break; + case "generateMercenaryCompanyCommandLance": + options.setGenerateMercenaryCompanyCommandLance(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "companyCount": + options.setCompanyCount(Integer.parseInt(wn.getTextContent().trim())); + break; + case "individualLanceCount": + options.setIndividualLanceCount(Integer.parseInt(wn.getTextContent().trim())); + break; + case "lancesPerCompany": + options.setLancesPerCompany(Integer.parseInt(wn.getTextContent().trim())); + break; + case "lanceSize": + options.setLanceSize(Integer.parseInt(wn.getTextContent().trim())); + break; + case "starLeagueYear": + options.setStarLeagueYear(Integer.parseInt(wn.getTextContent().trim())); + break; + //endregion Base Information + + //region Personnel + case "supportPersonnel": { + options.setSupportPersonnel(new HashMap<>()); + final NodeList nl2 = wn.getChildNodes(); + for (int y = 0; y < nl2.getLength(); y++) { + final Node wn2 = nl2.item(y); + try { + options.getSupportPersonnel().put( + PersonnelRole.valueOf(wn2.getNodeName().trim()), + Integer.parseInt(wn2.getTextContent().trim())); + } catch (Exception ignored) { + + } + } + break; + } + case "poolAssistants": + options.setPoolAssistants(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "generateCaptains": + options.setGenerateCaptains(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignCompanyCommanderFlag": + options.setAssignCompanyCommanderFlag(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "applyOfficerStatBonusToWorstSkill": + options.setApplyOfficerStatBonusToWorstSkill(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignBestCompanyCommander": + options.setAssignBestCompanyCommander(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "prioritizeCompanyCommanderCombatSkills": + options.setPrioritizeCompanyCommanderCombatSkills(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignBestOfficers": + options.setAssignBestOfficers(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "prioritizeOfficerCombatSkills": + options.setPrioritizeOfficerCombatSkills(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignMostSkilledToPrimaryLances": + options.setAssignMostSkilledToPrimaryLances(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "automaticallyAssignRanks": + options.setAutomaticallyAssignRanks(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignFounderFlag": + options.setAssignFounderFlag(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Personnel + + //region Personnel Randomization + case "randomOriginOptions": + if (!wn.hasChildNodes()) { + continue; + } + final RandomOriginOptions randomOriginOptions = RandomOriginOptions.parseFromXML(wn.getChildNodes(), false); + if (randomOriginOptions != null) { + options.setRandomOriginOptions(randomOriginOptions); + } + break; + //endregion Personnel Randomization + + //region Starting Simulation + case "runStartingSimulation": + options.setRunStartingSimulation(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "simulationDuration": + options.setSimulationDuration(Integer.parseInt(wn.getTextContent().trim())); + break; + case "simulateRandomMarriages": + options.setSimulateRandomMarriages(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "simulateRandomProcreation": + options.setSimulateRandomProcreation(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Starting Simulation + + //region Units + case "battleMechWeightClassGenerationMethod": + options.setBattleMechWeightClassGenerationMethod(BattleMechWeightClassGenerationMethod.valueOf(wn.getTextContent().trim())); + break; + case "battleMechQualityGenerationMethod": + options.setBattleMechQualityGenerationMethod(BattleMechQualityGenerationMethod.valueOf(wn.getTextContent().trim())); + break; + case "neverGenerateStarLeagueMechs": + options.setNeverGenerateStarLeagueMechs(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "onlyGenerateStarLeagueMechs": + options.setOnlyGenerateStarLeagueMechs(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "onlyGenerateOmniMechs": + options.setOnlyGenerateOmniMechs(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "generateUnitsAsAttached": + options.setGenerateUnitsAsAttached(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignBestRollToCompanyCommander": + options.setAssignBestRollToCompanyCommander(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "sortStarLeagueUnitsFirst": + options.setSortStarLeagueUnitsFirst(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "groupByWeight": + options.setGroupByWeight(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "groupByQuality": + options.setGroupByQuality(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "keepOfficerRollsSeparate": + options.setKeepOfficerRollsSeparate(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "assignTechsToUnits": + options.setAssignTechsToUnits(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Units + + //region Unit + case "forceNamingMethod": + options.setForceNamingMethod(ForceNamingMethod.valueOf(wn.getTextContent().trim())); + break; + case "generateForceIcons": + options.setGenerateForceIcons(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "generateOriginNodeForceIcon": + options.setGenerateOriginNodeForceIcon(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "useOriginNodeForceIconLogo": + options.setUseOriginNodeForceIconLogo(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "forceWeightLimits": { + options.setForceWeightLimits(new TreeMap<>()); + final NodeList nl2 = wn.getChildNodes(); + for (int y = 0; y < nl2.getLength(); y++) { + final Node wn2 = nl2.item(y); + try { + options.getForceWeightLimits().put( + Integer.parseInt(wn2.getNodeName().trim()), + Integer.parseInt(wn2.getTextContent().trim())); + } catch (Exception ignored) { + + } + } + break; + } + //endregion Units + + //region Spares + case "generateMothballedSpareUnits": + options.setGenerateMothballedSpareUnits(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "sparesPercentOfActiveUnits": + options.setSparesPercentOfActiveUnits(Integer.parseInt(wn.getTextContent().trim())); + break; + case "partGenerationMethod": + options.setPartGenerationMethod(PartGenerationMethod.valueOf(wn.getTextContent().trim())); + break; + case "startingArmourWeight": + options.setStartingArmourWeight(Integer.parseInt(wn.getTextContent().trim())); + break; + case "generateSpareAmmunition": + options.setGenerateSpareAmmunition(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "numberReloadsPerWeapon": + options.setNumberReloadsPerWeapon(Integer.parseInt(wn.getTextContent().trim())); + break; + case "generateFractionalMachineGunAmmunition": + options.setGenerateFractionalMachineGunAmmunition(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Spares + + //region Contracts + case "selectStartingContract": + options.setSelectStartingContract(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "startCourseToContractPlanet": + options.setStartCourseToContractPlanet(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Contracts + + //region Finances + case "processFinances": + options.setProcessFinances(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "startingCash": + options.setStartingCash(Integer.parseInt(wn.getTextContent().trim())); + break; + case "randomizeStartingCash": + options.setRandomizeStartingCash(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "randomStartingCashDiceCount": + options.setRandomStartingCashDiceCount(Integer.parseInt(wn.getTextContent().trim())); + break; + case "minimumStartingFloat": + options.setMinimumStartingFloat(Integer.parseInt(wn.getTextContent().trim())); + break; + case "includeInitialContractPayment": + options.setIncludeInitialContractPayment(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "startingLoan": + options.setStartingLoan(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForSetup": + options.setPayForSetup(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForPersonnel": + options.setPayForPersonnel(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForUnits": + options.setPayForUnits(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForParts": + options.setPayForParts(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForArmour": + options.setPayForArmour(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "payForAmmunition": + options.setPayForAmmunition(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + //endregion Finances + + //region Surprises + case "generateSurprises": + options.setGenerateSurprises(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "generateMysteryBoxes": + options.setGenerateMysteryBoxes(Boolean.parseBoolean(wn.getTextContent().trim())); + break; + case "generateMysteryBoxTypes": { + options.setGenerateMysteryBoxTypes(new HashMap<>()); + final NodeList nl2 = wn.getChildNodes(); + for (int y = 0; y < nl2.getLength(); y++) { + final Node wn2 = nl2.item(y); + try { + options.getGenerateMysteryBoxTypes().put( + MysteryBoxType.valueOf(wn2.getNodeName().trim()), + Boolean.parseBoolean(wn2.getTextContent().trim())); + } catch (Exception ignored) { + + } + } + break; + } + //endregion Surprises + + default: + break; + } + } + } catch (Exception ex) { + LogManager.getLogger().error("", ex); + return null; + } + + return options; + } + //endregion File IO +} diff --git a/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationPersonTracker.java b/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationPersonTracker.java new file mode 100644 index 0000000000..db8e7e56e5 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/companyGeneration/CompanyGenerationPersonTracker.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021-2022 - 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.companyGeneration; + +import megamek.common.Entity; +import megamek.common.annotations.Nullable; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.universe.enums.CompanyGenerationPersonType; + +/** + * @author Justin "Windchild" Bowen + */ +public class CompanyGenerationPersonTracker { + //region Variable Declarations + private CompanyGenerationPersonType personType; + private Person person; + private AtBRandomMechParameters parameters; + private Entity entity; + //endregion Variable Declarations + + //region Constructors + public CompanyGenerationPersonTracker(final Person person) { + this(CompanyGenerationPersonType.MECHWARRIOR, person); + } + + public CompanyGenerationPersonTracker(final CompanyGenerationPersonType personType, + final Person person) { + setPersonType(personType); + setPerson(person); + setParameters(null); + setEntity(null); + } + //endregion Constructors + + //region Getters/Setters + public CompanyGenerationPersonType getPersonType() { + return personType; + } + + public void setPersonType(final CompanyGenerationPersonType personType) { + this.personType = personType; + } + + public Person getPerson() { + return person; + } + + public void setPerson(final Person person) { + this.person = person; + } + + public @Nullable AtBRandomMechParameters getParameters() { + return parameters; + } + + public void setParameters(final @Nullable AtBRandomMechParameters parameters) { + this.parameters = parameters; + } + + public @Nullable Entity getEntity() { + return entity; + } + + public void setEntity(final @Nullable Entity entity) { + this.entity = entity; + } + //endregion Getters/Setters +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/Alphabet.java b/MekHQ/src/mekhq/campaign/universe/enums/Alphabet.java new file mode 100644 index 0000000000..90433ef965 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/Alphabet.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum Alphabet { + //region Enum Declarations + A("Alphabets.A.ccb1943.text", "Alphabets.A.icao1956.text", "Alphabets.A.english.text", "Alphabets.A.greek.text"), + B("Alphabets.B.ccb1943.text", "Alphabets.B.icao1956.text", "Alphabets.B.english.text", "Alphabets.B.greek.text"), + C("Alphabets.C.ccb1943.text", "Alphabets.C.icao1956.text", "Alphabets.C.english.text", "Alphabets.C.greek.text"), + D("Alphabets.D.ccb1943.text", "Alphabets.D.icao1956.text", "Alphabets.D.english.text", "Alphabets.D.greek.text"), + E("Alphabets.E.ccb1943.text", "Alphabets.E.icao1956.text", "Alphabets.E.english.text", "Alphabets.E.greek.text"), + F("Alphabets.F.ccb1943.text", "Alphabets.F.icao1956.text", "Alphabets.F.english.text", "Alphabets.F.greek.text"), + G("Alphabets.G.ccb1943.text", "Alphabets.G.icao1956.text", "Alphabets.G.english.text", "Alphabets.G.greek.text"), + H("Alphabets.H.ccb1943.text", "Alphabets.H.icao1956.text", "Alphabets.H.english.text", "Alphabets.H.greek.text"), + I("Alphabets.I.ccb1943.text", "Alphabets.I.icao1956.text", "Alphabets.I.english.text", "Alphabets.I.greek.text"), + J("Alphabets.J.ccb1943.text", "Alphabets.J.icao1956.text", "Alphabets.J.english.text", "Alphabets.J.greek.text"), + K("Alphabets.K.ccb1943.text", "Alphabets.K.icao1956.text", "Alphabets.K.english.text", "Alphabets.K.greek.text"), + L("Alphabets.L.ccb1943.text", "Alphabets.L.icao1956.text", "Alphabets.L.english.text", "Alphabets.L.greek.text"), + M("Alphabets.M.ccb1943.text", "Alphabets.M.icao1956.text", "Alphabets.M.english.text", "Alphabets.M.greek.text"), + N("Alphabets.N.ccb1943.text", "Alphabets.N.icao1956.text", "Alphabets.N.english.text", "Alphabets.N.greek.text"), + O("Alphabets.O.ccb1943.text", "Alphabets.O.icao1956.text", "Alphabets.O.english.text", "Alphabets.O.greek.text"), + P("Alphabets.P.ccb1943.text", "Alphabets.P.icao1956.text", "Alphabets.P.english.text", "Alphabets.P.greek.text"), + Q("Alphabets.Q.ccb1943.text", "Alphabets.Q.icao1956.text", "Alphabets.Q.english.text", "Alphabets.Q.greek.text"), + R("Alphabets.R.ccb1943.text", "Alphabets.R.icao1956.text", "Alphabets.R.english.text", "Alphabets.R.greek.text"), + S("Alphabets.S.ccb1943.text", "Alphabets.S.icao1956.text", "Alphabets.S.english.text", "Alphabets.S.greek.text"), + T("Alphabets.T.ccb1943.text", "Alphabets.T.icao1956.text", "Alphabets.T.english.text", "Alphabets.T.greek.text"), + U("Alphabets.U.ccb1943.text", "Alphabets.U.icao1956.text", "Alphabets.U.english.text", "Alphabets.U.greek.text"), + V("Alphabets.V.ccb1943.text", "Alphabets.V.icao1956.text", "Alphabets.V.english.text", "Alphabets.V.greek.text"), + W("Alphabets.W.ccb1943.text", "Alphabets.W.icao1956.text", "Alphabets.W.english.text", "Alphabets.W.greek.text"), + X("Alphabets.X.ccb1943.text", "Alphabets.X.icao1956.text", "Alphabets.X.english.text", "Alphabets.X.greek.text"), + Y("Alphabets.Y.ccb1943.text", "Alphabets.Y.icao1956.text", "Alphabets.Y.english.text", "Alphabets.Y.greek.text"), + Z("Alphabets.Z.ccb1943.text", "Alphabets.Z.icao1956.text", "Alphabets.Z.english.text", "Alphabets.Z.greek.text"); + //endregion Enum Declarations + + //region Variable Declarations + private final String ccb1943; // CCB 1943 Military Phonetic Alphabet + private final String icao1956; // ICAO 1956 Military Phonetic Alphabet + private final String english; // English Alphabet + private final String greek; // Greek Alphabet + //endregion Variable Declarations + + //region Constructors + Alphabet(final String ccb1943, final String icao1956, final String english, final String greek) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.ccb1943 = resources.getString(ccb1943); + this.icao1956 = resources.getString(icao1956); + this.english = resources.getString(english); + this.greek = resources.getString(greek); + } + //endregion Constructors + + //region Getters + public String getCCB1943() { + return ccb1943; + } + + public String getICAO1956() { + return icao1956; + } + + public String getEnglish() { + return english; + } + + public String getGreek() { + return greek; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isA() { + return this == A; + } + + public boolean isB() { + return this == B; + } + + public boolean isC() { + return this == C; + } + + public boolean isD() { + return this == D; + } + + public boolean isE() { + return this == E; + } + + public boolean isF() { + return this == F; + } + + public boolean isG() { + return this == G; + } + + public boolean isH() { + return this == H; + } + + public boolean isI() { + return this == I; + } + + public boolean isJ() { + return this == J; + } + + public boolean isK() { + return this == K; + } + + public boolean isL() { + return this == L; + } + + public boolean isM() { + return this == M; + } + + public boolean isN() { + return this == N; + } + + public boolean isO() { + return this == O; + } + + public boolean isP() { + return this == P; + } + + public boolean isQ() { + return this == Q; + } + + public boolean isR() { + return this == R; + } + + public boolean isS() { + return this == S; + } + + public boolean isT() { + return this == T; + } + + public boolean isU() { + return this == U; + } + + public boolean isV() { + return this == V; + } + + public boolean isW() { + return this == W; + } + + public boolean isX() { + return this == X; + } + + public boolean isY() { + return this == Y; + } + + public boolean isZ() { + return this == Z; + } + //endregion Boolean Comparison Methods +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/BattleMechQualityGenerationMethod.java b/MekHQ/src/mekhq/campaign/universe/enums/BattleMechQualityGenerationMethod.java new file mode 100644 index 0000000000..b34ac8ee4d --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/BattleMechQualityGenerationMethod.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; +import mekhq.campaign.universe.generators.battleMechQualityGenerators.*; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum BattleMechQualityGenerationMethod { + //region Enum Declarations + AGAINST_THE_BOT("BattleMechQualityGenerationMethod.AGAINST_THE_BOT.text", "BattleMechQualityGenerationMethod.AGAINST_THE_BOT.toolTipText"), + WINDCHILD("BattleMechQualityGenerationMethod.WINDCHILD.text", "BattleMechQualityGenerationMethod.WINDCHILD.toolTipText"), + F("BattleMechQualityGenerationMethod.F.text", "BattleMechQualityGenerationMethod.F.toolTipText"), + D("BattleMechQualityGenerationMethod.D.text", "BattleMechQualityGenerationMethod.D.toolTipText"), + C("BattleMechQualityGenerationMethod.C.text", "BattleMechQualityGenerationMethod.C.toolTipText"), + B("BattleMechQualityGenerationMethod.B.text", "BattleMechQualityGenerationMethod.B.toolTipText"), + A("BattleMechQualityGenerationMethod.A.text", "BattleMechQualityGenerationMethod.A.toolTipText"), + A_STAR("BattleMechQualityGenerationMethod.A_STAR.text", "BattleMechQualityGenerationMethod.A_STAR.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + BattleMechQualityGenerationMethod(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isAgainstTheBot() { + return this == AGAINST_THE_BOT; + } + + public boolean isWindchild() { + return this == WINDCHILD; + } + + public boolean isF() { + return this == F; + } + + public boolean isD() { + return this == D; + } + + public boolean isC() { + return this == C; + } + + public boolean isB() { + return this == B; + } + + public boolean isA() { + return this == A; + } + + public boolean isAStar() { + return this == A_STAR; + } + //endregion Boolean Comparison Methods + + public AbstractBattleMechQualityGenerator getGenerator() { + switch (this) { + case AGAINST_THE_BOT: + return new AtBBattleMechQualityGenerator(); + case F: + return new FBattleMechQualityGenerator(); + case D: + return new DBattleMechQualityGenerator(); + case C: + return new CBattleMechQualityGenerator(); + case B: + return new BBattleMechQualityGenerator(); + case A: + return new ABattleMechQualityGenerator(); + case A_STAR: + return new AStarBattleMechQualityGenerator(); + case WINDCHILD: + default: + return new WindchildBattleMechQualityGenerator(); + } + } + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/BattleMechWeightClassGenerationMethod.java b/MekHQ/src/mekhq/campaign/universe/enums/BattleMechWeightClassGenerationMethod.java new file mode 100644 index 0000000000..bd693c6085 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/BattleMechWeightClassGenerationMethod.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; +import mekhq.campaign.universe.generators.battleMechWeightClassGenerators.*; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum BattleMechWeightClassGenerationMethod { + //region Enum Declarations + AGAINST_THE_BOT("BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT.text", "BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT.toolTipText"), + WINDCHILD("BattleMechWeightClassGenerationMethod.WINDCHILD.text", "BattleMechWeightClassGenerationMethod.WINDCHILD.toolTipText"), + WINDCHILD_LIGHT("BattleMechWeightClassGenerationMethod.WINDCHILD_LIGHT.text", "BattleMechWeightClassGenerationMethod.WINDCHILD_LIGHT.toolTipText"), + WINDCHILD_MEDIUM("BattleMechWeightClassGenerationMethod.WINDCHILD_MEDIUM.text", "BattleMechWeightClassGenerationMethod.WINDCHILD_MEDIUM.toolTipText"), + WINDCHILD_HEAVY("BattleMechWeightClassGenerationMethod.WINDCHILD_HEAVY.text", "BattleMechWeightClassGenerationMethod.WINDCHILD_HEAVY.toolTipText"), + WINDCHILD_ASSAULT("BattleMechWeightClassGenerationMethod.WINDCHILD_ASSAULT.text", "BattleMechWeightClassGenerationMethod.WINDCHILD_ASSAULT.toolTipText"), + LIGHT("BattleMechWeightClassGenerationMethod.LIGHT.text", "BattleMechWeightClassGenerationMethod.LIGHT.toolTipText"), + MEDIUM("BattleMechWeightClassGenerationMethod.MEDIUM.text", "BattleMechWeightClassGenerationMethod.MEDIUM.toolTipText"), + HEAVY("BattleMechWeightClassGenerationMethod.HEAVY.text", "BattleMechWeightClassGenerationMethod.HEAVY.toolTipText"), + ASSAULT("BattleMechWeightClassGenerationMethod.ASSAULT.text", "BattleMechWeightClassGenerationMethod.ASSAULT.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + BattleMechWeightClassGenerationMethod(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isAgainstTheBot() { + return this == AGAINST_THE_BOT; + } + + public boolean isWindchild() { + return this == WINDCHILD; + } + + public boolean isWindchildLight() { + return this == WINDCHILD_LIGHT; + } + + public boolean isWindchildMedium() { + return this == WINDCHILD_MEDIUM; + } + + public boolean isWindchildHeavy() { + return this == WINDCHILD_HEAVY; + } + + public boolean isWindchildAssault() { + return this == WINDCHILD_ASSAULT; + } + + public boolean isLight() { + return this == LIGHT; + } + + public boolean isMedium() { + return this == MEDIUM; + } + + public boolean isHeavy() { + return this == HEAVY; + } + + public boolean isAssault() { + return this == ASSAULT; + } + //endregion Boolean Comparison Methods + + public AbstractBattleMechWeightClassGenerator getGenerator() { + switch (this) { + case AGAINST_THE_BOT: + return new AtBBattleMechWeightClassGenerator(); + case WINDCHILD_LIGHT: + return new WindchildLightBattleMechWeightClassGenerator(); + case WINDCHILD_MEDIUM: + return new WindchildMediumBattleMechWeightClassGenerator(); + case WINDCHILD_HEAVY: + return new WindchildHeavyBattleMechWeightClassGenerator(); + case WINDCHILD_ASSAULT: + return new WindchildAssaultBattleMechWeightClassGenerator(); + case LIGHT: + return new LightBattleMechWeightClassGenerator(); + case MEDIUM: + return new MediumBattleMechWeightClassGenerator(); + case HEAVY: + return new HeavyBattleMechWeightClassGenerator(); + case ASSAULT: + return new AssaultBattleMechWeightClassGenerator(); + case WINDCHILD: + default: + return new WindchildBattleMechWeightClassGenerator(); + } + } + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationMethod.java b/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationMethod.java new file mode 100644 index 0000000000..627034e2dc --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationMethod.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; +import mekhq.campaign.Campaign; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.generators.companyGenerators.*; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum CompanyGenerationMethod { + //region Enum Declarations + AGAINST_THE_BOT("CompanyGenerationMethod.AGAINST_THE_BOT.text", "CompanyGenerationMethod.AGAINST_THE_BOT.toolTipText"), + WINDCHILD("CompanyGenerationMethod.WINDCHILD.text", "CompanyGenerationMethod.WINDCHILD.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + CompanyGenerationMethod(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isAtB() { + return this == AGAINST_THE_BOT; + } + + public boolean isWindchild() { + return this == WINDCHILD; + } + //endregion Boolean Comparison Methods + + public AbstractCompanyGenerator getGenerator(final Campaign campaign, + final CompanyGenerationOptions options) { + switch (this) { + case AGAINST_THE_BOT: + return new AtBCompanyGenerator(campaign, options); + case WINDCHILD: + default: + return new WindchildCompanyGenerator(campaign, options); + } + } + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationPersonType.java b/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationPersonType.java new file mode 100644 index 0000000000..14b8fef9f6 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/CompanyGenerationPersonType.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum CompanyGenerationPersonType { + //region Enum Declarations + MECHWARRIOR_COMPANY_COMMANDER("CompanyGenerationPersonType.MECHWARRIOR_COMPANY_COMMANDER.text", "CompanyGenerationPersonType.MECHWARRIOR_COMPANY_COMMANDER.toolTipText"), + MECHWARRIOR_CAPTAIN("CompanyGenerationPersonType.MECHWARRIOR_CAPTAIN.text", "CompanyGenerationPersonType.MECHWARRIOR_CAPTAIN.toolTipText"), + MECHWARRIOR_LIEUTENANT("CompanyGenerationPersonType.MECHWARRIOR_LIEUTENANT.text", "CompanyGenerationPersonType.MECHWARRIOR_LIEUTENANT.toolTipText"), + MECHWARRIOR("CompanyGenerationPersonType.MECHWARRIOR.text", "CompanyGenerationPersonType.MECHWARRIOR.toolTipText"), + SUPPORT("CompanyGenerationPersonType.SUPPORT.text", "CompanyGenerationPersonType.SUPPORT.toolTipText"), + ASSISTANT("CompanyGenerationPersonType.ASSISTANT.text", "CompanyGenerationPersonType.ASSISTANT.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + CompanyGenerationPersonType(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isMechWarriorCompanyCommander() { + return this == MECHWARRIOR_COMPANY_COMMANDER; + } + + public boolean isMechWarriorCaptain() { + return this == MECHWARRIOR_CAPTAIN; + } + + public boolean isMechWarriorLieutenant() { + return this == MECHWARRIOR_LIEUTENANT; + } + + public boolean isMechWarrior() { + return this == MECHWARRIOR; + } + + public boolean isSupport() { + return this == SUPPORT; + } + + public boolean isAssistant() { + return this == ASSISTANT; + } + + public boolean isOfficer() { + return isMechWarriorCaptain() || isMechWarriorLieutenant(); + } + + public boolean isCombat() { + return isMechWarriorCompanyCommander() || isMechWarriorCaptain() + || isMechWarriorLieutenant() || isMechWarrior(); + } + //endregion Boolean Comparison Methods + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/EraFlag.java b/MekHQ/src/mekhq/campaign/universe/enums/EraFlag.java index 1e78d49cf2..9cd4bed44c 100644 --- a/MekHQ/src/mekhq/campaign/universe/enums/EraFlag.java +++ b/MekHQ/src/mekhq/campaign/universe/enums/EraFlag.java @@ -18,6 +18,9 @@ */ package mekhq.campaign.universe.enums; +/** + * @author Justin "Windchild" Bowen + */ public enum EraFlag { //region Enum Declarations PRE_SPACEFLIGHT, diff --git a/MekHQ/src/mekhq/campaign/universe/enums/ForceNamingMethod.java b/MekHQ/src/mekhq/campaign/universe/enums/ForceNamingMethod.java new file mode 100644 index 0000000000..9f43794583 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/ForceNamingMethod.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum ForceNamingMethod { + //region Enum Declarations + CCB_1943("ForceNamingMethod.CCB_1943.text", "ForceNamingMethod.CCB_1943.toolTipText"), + ICAO_1956("ForceNamingMethod.ICAO_1956.text", "ForceNamingMethod.ICAO_1956.toolTipText"), + ENGLISH_ALPHABET("ForceNamingMethod.ENGLISH_ALPHABET.text", "ForceNamingMethod.ENGLISH_ALPHABET.toolTipText"), + GREEK_ALPHABET("ForceNamingMethod.GREEK_ALPHABET.text", "ForceNamingMethod.GREEK_ALPHABET.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + ForceNamingMethod(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isCCB1943() { + return this == CCB_1943; + } + + public boolean isICAO1956() { + return this == ICAO_1956; + } + + public boolean isEnglishAlphabet() { + return this == ENGLISH_ALPHABET; + } + + public boolean isGreekAlphabet() { + return this == GREEK_ALPHABET; + } + //endregion Boolean Comparison Methods + + public String getValue(final Alphabet alphabet) { + switch (this) { + case ICAO_1956: + return alphabet.getICAO1956(); + case ENGLISH_ALPHABET: + return alphabet.getEnglish(); + case GREEK_ALPHABET: + return alphabet.getGreek(); + case CCB_1943: + default: + return alphabet.getCCB1943(); + } + } + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/MysteryBoxType.java b/MekHQ/src/mekhq/campaign/universe/enums/MysteryBoxType.java new file mode 100644 index 0000000000..96f62f4f05 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/MysteryBoxType.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum MysteryBoxType { + //region Enum Declarations + THIRD_SUCCESSION_WAR("MysteryBoxType.THIRD_SUCCESSION_WAR.text", "MysteryBoxType.THIRD_SUCCESSION_WAR.toolTipText"), + STAR_LEAGUE_ROYAL("MysteryBoxType.STAR_LEAGUE_ROYAL.text", "MysteryBoxType.STAR_LEAGUE_ROYAL.toolTipText"), + STAR_LEAGUE_REGULAR("MysteryBoxType.STAR_LEAGUE_REGULAR.text", "MysteryBoxType.STAR_LEAGUE_REGULAR.toolTipText"), + INNER_SPHERE_EXPERIMENTAL("MysteryBoxType.INNER_SPHERE_EXPERIMENTAL.text", "MysteryBoxType.INNER_SPHERE_EXPERIMENTAL.toolTipText"), + CLAN_KESHIK("MysteryBoxType.CLAN_KESHIK.text", "MysteryBoxType.CLAN_KESHIK.toolTipText"), + CLAN_FRONT_LINE("MysteryBoxType.CLAN_FRONT_LINE.text", "MysteryBoxType.CLAN_FRONT_LINE.toolTipText"), + CLAN_SECOND_LINE("MysteryBoxType.CLAN_SECOND_LINE.text", "MysteryBoxType.CLAN_SECOND_LINE.toolTipText"), + CLAN_EXPERIMENTAL("MysteryBoxType.CLAN_EXPERIMENTAL.text", "MysteryBoxType.CLAN_EXPERIMENTAL.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + MysteryBoxType(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isThirdSuccessionWar() { + return this == THIRD_SUCCESSION_WAR; + } + + public boolean isStarLeagueRoyal() { + return this == STAR_LEAGUE_ROYAL; + } + + public boolean isStarLeagueRegular() { + return this == STAR_LEAGUE_REGULAR; + } + + public boolean isInnerSphereExperimental() { + return this == INNER_SPHERE_EXPERIMENTAL; + } + + public boolean isClanKeshik() { + return this == CLAN_KESHIK; + } + + public boolean isClanFrontLine() { + return this == CLAN_FRONT_LINE; + } + + public boolean isClanSecondLine() { + return this == CLAN_SECOND_LINE; + } + + public boolean isClanExperimental() { + return this == CLAN_EXPERIMENTAL; + } + //endregion Boolean Comparison Methods + +/* + public AbstractMysteryBox getMysteryBox() { + switch (this) { + case STAR_LEAGUE_ROYAL: + return new StarLeagueRoyalMysteryBox(); + case STAR_LEAGUE_REGULAR: + return new StarLeagueRegularMysteryBox(); + case INNER_SPHERE_EXPERIMENTAL: + return new InnerSphereExperimentalMysteryBox(); + case CLAN_KESHIK: + return new ClanKeshikMysteryBox(); + case CLAN_FRONT_LINE: + return new ClanFrontLineMysteryBox(); + case CLAN_SECOND_LINE: + return new ClanSecondLineMysteryBox(); + case CLAN_EXPERIMENTAL: + return new ClanExperimentalMysteryBox(); + case THIRD_SUCCESSION_WAR: + default: + return new ThirdSuccessionWarMysteryBox(); + } + } +*/ + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/enums/PartGenerationMethod.java b/MekHQ/src/mekhq/campaign/universe/enums/PartGenerationMethod.java new file mode 100644 index 0000000000..c610f6b249 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/enums/PartGenerationMethod.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.enums; + +import megamek.common.util.EncodeControl; +import mekhq.MekHQ; +import mekhq.campaign.universe.generators.partGenerators.AbstractPartGenerator; +import mekhq.campaign.universe.generators.partGenerators.MishraPartGenerator; +import mekhq.campaign.universe.generators.partGenerators.MultiplePartGenerator; +import mekhq.campaign.universe.generators.partGenerators.WindchildPartGenerator; +import org.apache.logging.log4j.LogManager; + +import java.util.ResourceBundle; + +/** + * @author Justin "Windchild" Bowen + */ +public enum PartGenerationMethod { + //region Enum Declarations + DISABLED("PartGenerationMethod.DISABLED.text", "PartGenerationMethod.DISABLED.toolTipText"), + WINDCHILD("PartGenerationMethod.WINDCHILD.text", "PartGenerationMethod.WINDCHILD.toolTipText"), + MISHRA("PartGenerationMethod.MISHRA.text", "PartGenerationMethod.MISHRA.toolTipText"), + SINGLE("PartGenerationMethod.SINGLE.text", "PartGenerationMethod.SINGLE.toolTipText"), + DOUBLE("PartGenerationMethod.DOUBLE.text", "PartGenerationMethod.DOUBLE.toolTipText"), + TRIPLE("PartGenerationMethod.TRIPLE.text", "PartGenerationMethod.TRIPLE.toolTipText"); + //endregion Enum Declarations + + //region Variable Declarations + private final String name; + private final String toolTipText; + //endregion Variable Declarations + + //region Constructors + PartGenerationMethod(final String name, final String toolTipText) { + final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + this.name = resources.getString(name); + this.toolTipText = resources.getString(toolTipText); + } + //endregion Constructors + + //region Getters + public String getToolTipText() { + return toolTipText; + } + //endregion Getters + + //region Boolean Comparison Methods + public boolean isDisabled() { + return this == DISABLED; + } + + public boolean isWindchild() { + return this == WINDCHILD; + } + + public boolean isMishra() { + return this == MISHRA; + } + + public boolean isSingle() { + return this == SINGLE; + } + + public boolean isDouble() { + return this == DOUBLE; + } + + public boolean isTriple() { + return this == TRIPLE; + } + //endregion Boolean Comparison Methods + + public AbstractPartGenerator getGenerator() { + switch (this) { + case MISHRA: + return new MishraPartGenerator(); + case SINGLE: + return new MultiplePartGenerator(this, 1); + case DOUBLE: + return new MultiplePartGenerator(this, 2); + case TRIPLE: + return new MultiplePartGenerator(this, 3); + case DISABLED: + LogManager.getLogger().error("Attempted to get a generator when the part generator is Disabled. Returning Windchild"); + case WINDCHILD: + default: + return new WindchildPartGenerator(); + } + } + + @Override + public String toString() { + return name; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/ABattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/ABattleMechQualityGenerator.java new file mode 100644 index 0000000000..d44dd320a5 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/ABattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class ABattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public ABattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.A); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_A; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AStarBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AStarBattleMechQualityGenerator.java new file mode 100644 index 0000000000..b1fb23fc40 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AStarBattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class AStarBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public AStarBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.A_STAR); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_ASTAR; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AbstractBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AbstractBattleMechQualityGenerator.java new file mode 100644 index 0000000000..b421901a07 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AbstractBattleMechQualityGenerator.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * This was designed to provide options for the method of quality generation for Company Generators, + * and any use outside of them should take this specific design into consideration. + * @author Justin "Windchild" Bowen + */ +public abstract class AbstractBattleMechQualityGenerator { + //region Variable Declarations + private final BattleMechQualityGenerationMethod method; + //endregion Variable Declarations + + //region Constructors + protected AbstractBattleMechQualityGenerator(final BattleMechQualityGenerationMethod method) { + this.method = method; + } + //endregion Constructors + + //region Getters + public BattleMechQualityGenerationMethod getMethod() { + return method; + } + //endregion Getters + + /** + * @param roll the modified roll to use + * @return the generated IUnitRating magic int for Dragoon Quality + */ + public abstract int generate(final int roll); +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AtBBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AtBBattleMechQualityGenerator.java new file mode 100644 index 0000000000..06e4a340e5 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/AtBBattleMechQualityGenerator.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class AtBBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public AtBBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.AGAINST_THE_BOT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 2: + case 3: + case 4: + case 5: + return IUnitRating.DRAGOON_F; + case 6: + case 7: + case 8: + return IUnitRating.DRAGOON_D; + case 9: + case 10: + return IUnitRating.DRAGOON_C; + case 11: + return IUnitRating.DRAGOON_B; + case 12: + return IUnitRating.DRAGOON_A; + default: + return IUnitRating.DRAGOON_ASTAR; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/BBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/BBattleMechQualityGenerator.java new file mode 100644 index 0000000000..5c7f44bcac --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/BBattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class BBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public BBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.B); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_B; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/CBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/CBattleMechQualityGenerator.java new file mode 100644 index 0000000000..f325f33a56 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/CBattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class CBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public CBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.C); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_C; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/DBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/DBattleMechQualityGenerator.java new file mode 100644 index 0000000000..146301c2ad --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/DBattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class DBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public DBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.D); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_D; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/FBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/FBattleMechQualityGenerator.java new file mode 100644 index 0000000000..7dfac52ce7 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/FBattleMechQualityGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class FBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public FBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.F); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return IUnitRating.DRAGOON_F; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/WindchildBattleMechQualityGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/WindchildBattleMechQualityGenerator.java new file mode 100644 index 0000000000..5d4f3bd4c3 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechQualityGenerators/WindchildBattleMechQualityGenerator.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechQualityGenerators; + +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.enums.BattleMechQualityGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildBattleMechQualityGenerator extends AbstractBattleMechQualityGenerator { + //region Constructors + public WindchildBattleMechQualityGenerator() { + super(BattleMechQualityGenerationMethod.WINDCHILD); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 2: + case 3: + case 4: + return IUnitRating.DRAGOON_F; + case 5: + case 6: + return IUnitRating.DRAGOON_D; + case 7: + case 8: + return IUnitRating.DRAGOON_C; + case 9: + case 10: + return IUnitRating.DRAGOON_B; + case 11: + case 12: + return IUnitRating.DRAGOON_A; + default: + return IUnitRating.DRAGOON_ASTAR; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AbstractBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AbstractBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..313a064c57 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AbstractBattleMechWeightClassGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * This was designed to provide options for the method of weight generation for Company Generators, + * and any use outside of them should take this specific design into consideration. + * @author Justin "Windchild" Bowen + */ +public abstract class AbstractBattleMechWeightClassGenerator { + //region Variable Declarations + private final BattleMechWeightClassGenerationMethod method; + //endregion Variable Declarations + + //region Constructors + protected AbstractBattleMechWeightClassGenerator(final BattleMechWeightClassGenerationMethod method) { + this.method = method; + } + //endregion Constructors + + //region Getters + public BattleMechWeightClassGenerationMethod getMethod() { + return method; + } + //endregion Getters + + /** + * @param roll the modified roll to use + * @return the generated EntityWeightClass, returning EntityWeightClass.WEIGHT_ULTRA_LIGHT to + * signify no generation and EntityWeightClass.WEIGHT_SUPER_HEAVY to signify Star League-era + * generation. + */ + public abstract int generate(final int roll); +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AssaultBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AssaultBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..c6d4f1dd75 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AssaultBattleMechWeightClassGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class AssaultBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public AssaultBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.ASSAULT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return EntityWeightClass.WEIGHT_ASSAULT; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AtBBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AtBBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..a975932223 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/AtBBattleMechWeightClassGenerator.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class AtBBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public AtBBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.AGAINST_THE_BOT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 2: + case 3: + return EntityWeightClass.WEIGHT_ULTRA_LIGHT; + case 4: + case 5: + case 6: + return EntityWeightClass.WEIGHT_LIGHT; + case 7: + case 8: + case 9: + return EntityWeightClass.WEIGHT_MEDIUM; + case 10: + case 11: + return EntityWeightClass.WEIGHT_HEAVY; + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/HeavyBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/HeavyBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..51d5587582 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/HeavyBattleMechWeightClassGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class HeavyBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public HeavyBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.HEAVY); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return EntityWeightClass.WEIGHT_HEAVY; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/LightBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/LightBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..55cd020669 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/LightBattleMechWeightClassGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class LightBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public LightBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.LIGHT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return EntityWeightClass.WEIGHT_LIGHT; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/MediumBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/MediumBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..6800cfd68c --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/MediumBattleMechWeightClassGenerator.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class MediumBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public MediumBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.MEDIUM); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + return EntityWeightClass.WEIGHT_MEDIUM; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildAssaultBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildAssaultBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..406ae66a42 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildAssaultBattleMechWeightClassGenerator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildAssaultBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public WindchildAssaultBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.WINDCHILD_ASSAULT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 3: + return EntityWeightClass.WEIGHT_LIGHT; + case 4: + case 5: + return EntityWeightClass.WEIGHT_MEDIUM; + case 2: + case 6: + case 7: + return EntityWeightClass.WEIGHT_HEAVY; + case 8: + case 9: + case 10: + case 11: + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..d39ac3ae6a --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildBattleMechWeightClassGenerator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public WindchildBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.WINDCHILD); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 2: + case 3: + case 4: + case 5: + return EntityWeightClass.WEIGHT_LIGHT; + case 6: + case 7: + case 8: + return EntityWeightClass.WEIGHT_MEDIUM; + case 9: + case 10: + return EntityWeightClass.WEIGHT_HEAVY; + case 11: + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildHeavyBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildHeavyBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..7c7d45278f --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildHeavyBattleMechWeightClassGenerator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildHeavyBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public WindchildHeavyBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.WINDCHILD_HEAVY); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 2: + case 3: + case 4: + return EntityWeightClass.WEIGHT_LIGHT; + case 6: + case 7: + return EntityWeightClass.WEIGHT_MEDIUM; + case 8: + case 9: + case 10: + return EntityWeightClass.WEIGHT_HEAVY; + case 5: + case 11: + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildLightBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildLightBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..0b5e34b712 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildLightBattleMechWeightClassGenerator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildLightBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public WindchildLightBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.WINDCHILD_LIGHT); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 4: + case 5: + case 6: + case 7: + return EntityWeightClass.WEIGHT_LIGHT; + case 3: + case 8: + case 9: + return EntityWeightClass.WEIGHT_MEDIUM; + case 10: + case 11: + return EntityWeightClass.WEIGHT_HEAVY; + case 2: + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildMediumBattleMechWeightClassGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildMediumBattleMechWeightClassGenerator.java new file mode 100644 index 0000000000..ff819ef963 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/battleMechWeightClassGenerators/WindchildMediumBattleMechWeightClassGenerator.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.battleMechWeightClassGenerators; + +import megamek.common.EntityWeightClass; +import mekhq.campaign.universe.enums.BattleMechWeightClassGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildMediumBattleMechWeightClassGenerator extends AbstractBattleMechWeightClassGenerator { + //region Constructors + public WindchildMediumBattleMechWeightClassGenerator() { + super(BattleMechWeightClassGenerationMethod.WINDCHILD_MEDIUM); + } + //endregion Constructors + + @Override + public int generate(final int roll) { + switch (roll) { + case 8: + case 9: + return EntityWeightClass.WEIGHT_LIGHT; + case 4: + case 5: + case 6: + case 7: + return EntityWeightClass.WEIGHT_MEDIUM; + case 3: + case 10: + case 11: + return EntityWeightClass.WEIGHT_HEAVY; + case 2: + case 12: + return EntityWeightClass.WEIGHT_ASSAULT; + default: + return EntityWeightClass.WEIGHT_SUPER_HEAVY; + } + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AbstractCompanyGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AbstractCompanyGenerator.java new file mode 100644 index 0000000000..ddd665d51f --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AbstractCompanyGenerator.java @@ -0,0 +1,1719 @@ +/* + * Copyright (c) 2021-2022 - 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.generators.companyGenerators; + +import megamek.common.*; +import megamek.common.annotations.Nullable; +import megamek.common.options.OptionsConstants; +import megamek.common.util.EncodeControl; +import mekhq.MHQConstants; +import mekhq.MHQStaticDirectoryManager; +import mekhq.MekHQ; +import mekhq.Utilities; +import mekhq.campaign.Campaign; +import mekhq.campaign.finances.Loan; +import mekhq.campaign.finances.Money; +import mekhq.campaign.finances.enums.FinancialTerm; +import mekhq.campaign.finances.enums.TransactionType; +import mekhq.campaign.force.Force; +import mekhq.campaign.icons.ForcePieceIcon; +import mekhq.campaign.icons.LayeredForceIcon; +import mekhq.campaign.icons.enums.LayeredForceIconLayer; +import mekhq.campaign.mission.Contract; +import mekhq.campaign.parts.AmmoStorage; +import mekhq.campaign.parts.Armor; +import mekhq.campaign.parts.Part; +import mekhq.campaign.parts.equipment.AmmoBin; +import mekhq.campaign.personnel.Person; +import mekhq.campaign.personnel.Skill; +import mekhq.campaign.personnel.SkillType; +import mekhq.campaign.personnel.enums.PersonnelRole; +import mekhq.campaign.personnel.generator.AbstractPersonnelGenerator; +import mekhq.campaign.personnel.ranks.Rank; +import mekhq.campaign.unit.Unit; +import mekhq.campaign.universe.*; +import mekhq.campaign.universe.companyGeneration.AtBRandomMechParameters; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationPersonTracker; +import mekhq.campaign.universe.enums.Alphabet; +import mekhq.campaign.universe.enums.CompanyGenerationMethod; +import mekhq.campaign.universe.enums.CompanyGenerationPersonType; +import mekhq.campaign.universe.generators.battleMechQualityGenerators.AbstractBattleMechQualityGenerator; +import mekhq.campaign.universe.generators.battleMechWeightClassGenerators.AbstractBattleMechWeightClassGenerator; +import mekhq.campaign.universe.selectors.factionSelectors.AbstractFactionSelector; +import mekhq.campaign.universe.selectors.factionSelectors.DefaultFactionSelector; +import mekhq.campaign.universe.selectors.factionSelectors.RangedFactionSelector; +import mekhq.campaign.universe.selectors.planetSelectors.AbstractPlanetSelector; +import mekhq.campaign.universe.selectors.planetSelectors.DefaultPlanetSelector; +import mekhq.campaign.universe.selectors.planetSelectors.RangedPlanetSelector; +import mekhq.campaign.work.WorkTime; +import org.apache.logging.log4j.LogManager; + +import java.time.LocalDate; +import java.util.*; +import java.util.Map.Entry; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +/** + * Startup: + * Second Panel: Presets, Date, Starting Faction, Starting Planet, AtB + * Third Panel: Campaign Options + * Fifth Panel: Start of the Company Generator + * + * Ideas: + * First panel is the options panel + * Second panel is the generated personnel panel, where you can customize and reroll personnel + * Third panel is the generated units panel, where you can customize applicable units + * Fourth panel is the parts list, which is customizable + * Fifth panel is a view generated pairings, and allows the reorder of the preset lances + * + * Second to Last panel of the dialog should be the contract market when coming from quickstart, to select starting contract + * Final panel is the starting finances overview + * + * Button that lets you pop out the options panel with everything disabled + * + * TODO - Wave 3: + * Contract Market Pane + * Campaign Options Pane, Campaign Options Dialog Base Validation + * Date Pane + * Loan Selection Pane + * Implement Loan Options + * Probably some stuff from public requests + * TODO - Wave 4: + * Startup GUI Rework + * TODO - Wave 5: + * Company Generator GUI + * Implement Contracts + * Add dependent generation options, that apply pre-module simulation + * TODO - Wave 6: + * Suite Options loading during startup, during the first load of a newer version (use a SuiteOption to track) + * Add MegaMek Options as a panel during the startup + * TODO - Wave 7: + * Implement Era-based Part Generators + * Implement Surprises + * Implement Mystery Boxes + * Generate spare personnel (?) + * Optional: Mercenaries may customize their 'Mechs, with clantech if enabled only post-3055 + * Think about generating custom setups for specific canon mercenary groups or factions + * - these would be surprise based, probably using a data file + * - special weapons, special units, and similar + * + * @author Justin "Windchild" Bowen + */ +public abstract class AbstractCompanyGenerator { + //region Variable Declarations + private final CompanyGenerationMethod method; + private final CompanyGenerationOptions options; + private final AbstractPersonnelGenerator personnelGenerator; + private final AbstractBattleMechWeightClassGenerator battleMechWeightClassGenerator; + private final AbstractBattleMechQualityGenerator battleMechQualityGenerator; + + private final ResourceBundle resources = ResourceBundle.getBundle("mekhq.resources.Universe", + MekHQ.getMHQOptions().getLocale(), new EncodeControl()); + //endregion Variable Declarations + + //region Constructors + protected AbstractCompanyGenerator(final CompanyGenerationMethod method, final Campaign campaign, + final CompanyGenerationOptions options) { + this.method = method; + this.options = options; + this.personnelGenerator = campaign.getPersonnelGenerator(createFactionSelector(), createPlanetSelector()); + this.battleMechWeightClassGenerator = getOptions().getBattleMechWeightClassGenerationMethod().getGenerator(); + this.battleMechQualityGenerator = getOptions().getBattleMechQualityGenerationMethod().getGenerator(); + } + //endregion Constructors + + //region Getters/Setters + public CompanyGenerationMethod getMethod() { + return method; + } + + public CompanyGenerationOptions getOptions() { + return options; + } + + public AbstractPersonnelGenerator getPersonnelGenerator() { + return personnelGenerator; + } + + /** + * @return a newly created Faction Selector + */ + private AbstractFactionSelector createFactionSelector() { + return getOptions().getRandomOriginOptions().isRandomizeOrigin() + ? new RangedFactionSelector(getOptions().getRandomOriginOptions()) + : new DefaultFactionSelector(getOptions().getRandomOriginOptions()); + } + + /** + * @return a newly created Planet Selector based on the provided options + */ + private AbstractPlanetSelector createPlanetSelector() { + return getOptions().getRandomOriginOptions().isRandomizeOrigin() + ? new RangedPlanetSelector(getOptions().getRandomOriginOptions()) + : new DefaultPlanetSelector(getOptions().getRandomOriginOptions()); + } + + public AbstractBattleMechWeightClassGenerator getBattleMechWeightClassGenerator() { + return battleMechWeightClassGenerator; + } + + public AbstractBattleMechQualityGenerator getBattleMechQualityGenerator() { + return battleMechQualityGenerator; + } + //endregion Getters/Setters + + //region Determination Methods + /** + * @return the number of lances to generate + */ + private int determineNumberOfLances() { + return (getOptions().getCompanyCount() * getOptions().getLancesPerCompany()) + + getOptions().getIndividualLanceCount() + + (getOptions().isGenerateMercenaryCompanyCommandLance() ? 1 : 0); + } + + /** + * @return the number of Captains + */ + private int determineNumberOfCaptains() { + return getOptions().isGenerateCaptains() + ? Math.max((getOptions().getCompanyCount() + - (getOptions().isGenerateMercenaryCompanyCommandLance() ? 0 : 1)), 0) + : 0; + } + //endregion Determination Methods + + //region Personnel + /** + * @param campaign the campaign to use to generate the personnel + * @return the list of generated personnel within their individual trackers + */ + public List generatePersonnel(final Campaign campaign) { + final List trackers = generateCombatPersonnel(campaign); + trackers.addAll(generateSupportPersonnel(campaign)); + return trackers; + } + + //region Combat Personnel + /** + * @param campaign the campaign to use to generate the combat personnel + * @return the list of generated combat personnel within their individual trackers + */ + private List generateCombatPersonnel(final Campaign campaign) { + final int numMechWarriors = determineNumberOfLances() * getOptions().getLanceSize(); + + final List initialTrackers = IntStream.range(0, numMechWarriors) + .mapToObj(i -> new CompanyGenerationPersonTracker( + campaign.newPerson(PersonnelRole.MECHWARRIOR, getPersonnelGenerator()))) + .collect(Collectors.toList()); + + final List sortedTrackers = new ArrayList<>(); + + Comparator personnelSorter; + + // First, Assign the Company Commander + if (getOptions().isAssignBestCompanyCommander()) { + // Tactical Genius makes for the best commanders + personnelSorter = Comparator.comparing(t -> t.getPerson().getOptions().booleanOption(OptionsConstants.MISC_TACTICAL_GENIUS)); + + // Then prioritize either combat or command skills based on the selected option + if (getOptions().isPrioritizeCompanyCommanderCombatSkills()) { + personnelSorter = personnelSorter + .thenComparingInt(t -> t.getPerson().getExperienceLevel(campaign, false)) + .thenComparingInt(t -> Stream.of(SkillType.S_LEADER, SkillType.S_STRATEGY, SkillType.S_TACTICS) + .mapToInt(s -> t.getPerson().getSkillLevel(s)).sum()); + } else { + personnelSorter = personnelSorter + .thenComparingInt(t -> Stream.of(SkillType.S_LEADER, SkillType.S_STRATEGY, SkillType.S_TACTICS) + .mapToInt(s -> t.getPerson().getSkillLevel(s)).sum()) + .thenComparingInt(t -> t.getPerson().getExperienceLevel(campaign, false)); + } + // Always need to reverse it at the end + personnelSorter = personnelSorter.reversed(); + + // Find the best commander using the minimum value from the comparator, use a fallback + // that can never occur. Then remove the commander from the initial trackers + sortedTrackers.add(initialTrackers.stream() + .min(personnelSorter) + .orElse(new CompanyGenerationPersonTracker( + campaign.newPerson(PersonnelRole.MECHWARRIOR, getPersonnelGenerator())))); + initialTrackers.remove(sortedTrackers.get(0)); + } + + // Second, Assign the Officers + if (getOptions().isAssignBestOfficers()) { + // Tactical Genius makes for the best officers + personnelSorter = Comparator.comparing(t -> + t.getPerson().getOptions().booleanOption(OptionsConstants.MISC_TACTICAL_GENIUS)); + // Then prioritize either combat or command skills based on the selected option + if (getOptions().isPrioritizeOfficerCombatSkills()) { + personnelSorter = personnelSorter + .thenComparingInt(t -> t.getPerson().getExperienceLevel(campaign, false)) + .thenComparingInt(t -> Stream.of(SkillType.S_LEADER, SkillType.S_STRATEGY, SkillType.S_TACTICS) + .mapToInt(s -> t.getPerson().getSkillLevel(s)).sum()); + } else { + personnelSorter = personnelSorter + .thenComparingInt(t -> Stream.of(SkillType.S_LEADER, SkillType.S_STRATEGY, SkillType.S_TACTICS) + .mapToInt(s -> t.getPerson().getSkillLevel(s)).sum()) + .thenComparingInt(t -> t.getPerson().getExperienceLevel(campaign, false)); + } + // Always need to reverse it at the end + personnelSorter = personnelSorter.reversed(); + + // Sort the current trackers based on the provided sorter, then select one per lance + // minus the one for taken by the company commander if they're already assigned + sortedTrackers.addAll(initialTrackers.stream() + .sorted(personnelSorter) + .collect(Collectors.toList()) + .subList(0, determineNumberOfLances() - (getOptions().isAssignBestCompanyCommander() ? 1 : 0))); + + // Finally, remove the officers from the initial trackers + initialTrackers.removeAll(sortedTrackers); + } + + // Default Sort is Tactical Genius First + personnelSorter = Comparator.comparing(t -> + t.getPerson().getOptions().booleanOption(OptionsConstants.MISC_TACTICAL_GENIUS)); + if (getOptions().isAssignMostSkilledToPrimaryLances()) { + // Unless we are prioritizing the most skilled, then we also care about experience level + personnelSorter = personnelSorter + .thenComparingInt(t -> t.getPerson().getExperienceLevel(campaign, false)); + } + + // Sort whatever is left of the initial trackers before adding them to the initial trackers + initialTrackers.sort(personnelSorter.reversed()); + sortedTrackers.addAll(initialTrackers); + + // Then generate the individuals based on their sorted trackers + generateCommandingOfficer(campaign, sortedTrackers.get(0), numMechWarriors); + generateOfficers(sortedTrackers); + generateStandardMechWarriors(campaign, sortedTrackers); + + return sortedTrackers; + } + + /** + * Turns a person into the commanding officer of the force being generated + * 1) Assigns the Commander flag (if that option is true) + * 2) Improves Gunnery and Piloting by one level + * 3) Gets two random officer skill increases + * 4) Gets the highest rank possible assigned to them + * + * @param campaign the campaign to use in generating the commanding officer + * @param tracker the commanding officer's tracker + * @param numMechWarriors the number of MechWarriors in their force, used to determine their rank + */ + private void generateCommandingOfficer(final Campaign campaign, + final CompanyGenerationPersonTracker tracker, + final int numMechWarriors) { + tracker.setPersonType(CompanyGenerationPersonType.MECHWARRIOR_COMPANY_COMMANDER); + tracker.getPerson().setCommander(getOptions().isAssignCompanyCommanderFlag()); + tracker.getPerson().improveSkill(SkillType.S_GUN_MECH); + tracker.getPerson().improveSkill(SkillType.S_PILOT_MECH); + assignRandomOfficerSkillIncrease(tracker, 2); + + if (getOptions().isAutomaticallyAssignRanks()) { + generateCommandingOfficerRank(campaign, tracker, numMechWarriors); + } + } + + /** + * @param campaign the campaign to use in generating the commanding officer's rank + * @param tracker the commanding officer's tracker + * @param numMechWarriors the number of MechWarriors in their force, used to determine their rank + */ + protected abstract void generateCommandingOfficerRank(final Campaign campaign, + final CompanyGenerationPersonTracker tracker, + final int numMechWarriors); + + /** + * This generates the initial officer list and assigns the type + * + * @param trackers the list of all generated personnel in their trackers + */ + private void generateOfficers(final List trackers) { + // First, we need to determine the captain threshold + final int captainThreshold = determineNumberOfCaptains() + 1; + // Starting at 1, as 0 is the mercenary company commander + for (int i = 1; i < determineNumberOfLances(); i++) { + // Set the Person Type on the tracker, so we can properly reroll later + trackers.get(i).setPersonType((i < captainThreshold) + ? CompanyGenerationPersonType.MECHWARRIOR_CAPTAIN + : CompanyGenerationPersonType.MECHWARRIOR_LIEUTENANT); + // Generate the individual officer + generateOfficer(trackers.get(i)); + } + } + + /** + * This generates an officer based on the provided options. + * + * Custom addition for larger generation: + * For every company (with a mercenary company command lance) or for every company + * after the first (as the mercenary company commander is the leader of that company) you + * generate a O4 - Captain, provided that captain generation is enabled. These get + * two officer skill boosts instead of 1, and the rank of O4 - Captain instead of O3 - Lieutenant. + * + * An Officer gets: + * 1) An increase of one to either the highest or lowest skill of gunnery or piloting, depending + * on the set options + * 2) Two random officer skill increases if they are a Captain, otherwise they get one + * 3) A rank of O4 - Captain for Captains, otherwise O3 - Lieutenant + * + * @param tracker the officer's tracker + */ + private void generateOfficer(final CompanyGenerationPersonTracker tracker) { + if (!tracker.getPersonType().isOfficer()) { + LogManager.getLogger().error(tracker.getPerson().getFullTitle() + + " is not a valid officer for the officer generation, cannot generate them as an officer."); + return; + } + + // Improve Skills + final Skill gunnery = tracker.getPerson().getSkill(SkillType.S_GUN_MECH); + final Skill piloting = tracker.getPerson().getSkill(SkillType.S_PILOT_MECH); + if ((gunnery == null) && (piloting != null)) { + tracker.getPerson().improveSkill(SkillType.S_GUN_MECH); + } else if ((gunnery != null) && (piloting == null)) { + tracker.getPerson().improveSkill(SkillType.S_PILOT_MECH); + } else if (gunnery == null) { + // Both are null... this shouldn't occur. In this case, boost both + tracker.getPerson().improveSkill(SkillType.S_GUN_MECH); + tracker.getPerson().improveSkill(SkillType.S_PILOT_MECH); + } else { + tracker.getPerson().improveSkill((((gunnery.getLevel() > piloting.getLevel()) + && getOptions().isApplyOfficerStatBonusToWorstSkill()) ? piloting : gunnery) + .getType().getName()); + } + + if (tracker.getPersonType().isMechWarriorCaptain()) { + // Assign Random Officer Skill Increase + assignRandomOfficerSkillIncrease(tracker, 2); + + if (getOptions().isAutomaticallyAssignRanks()) { + // Assign Rank of O4 - Captain + tracker.getPerson().setRank(Rank.RWO_MAX + 4); + } + } else { + // Assign Random Officer Skill Increase + assignRandomOfficerSkillIncrease(tracker, 1); + + if (getOptions().isAutomaticallyAssignRanks()) { + // Assign Rank of O3 - Lieutenant + tracker.getPerson().setRank(Rank.RWO_MAX + 3); + } + } + } + + /** + * This randomly assigns officer skill increases during officer creation. + * The skill level is improved by one level per roll, but if the skill is newly acquired + * it applies a second boost so that the value is set to 1. + * + * @param tracker the tracker to assign the skill increases to + * @param boosts the number of boosts to apply + */ + private void assignRandomOfficerSkillIncrease(final CompanyGenerationPersonTracker tracker, + final int boosts) { + for (int i = 0; i < boosts; i++) { + switch (Utilities.dice(1, 3)) { + case 0: + tracker.getPerson().improveSkill(SkillType.S_LEADER); + if (tracker.getPerson().getSkillLevel(SkillType.S_LEADER) == 0) { + tracker.getPerson().improveSkill(SkillType.S_LEADER); + } + break; + case 1: + tracker.getPerson().improveSkill(SkillType.S_STRATEGY); + if (tracker.getPerson().getSkillLevel(SkillType.S_STRATEGY) == 0) { + tracker.getPerson().improveSkill(SkillType.S_STRATEGY); + } + break; + case 2: + tracker.getPerson().improveSkill(SkillType.S_TACTICS); + if (tracker.getPerson().getSkillLevel(SkillType.S_TACTICS) == 0) { + tracker.getPerson().improveSkill(SkillType.S_TACTICS); + } + break; + default: + break; + } + } + } + + /** + * Sets up standard MechWarriors from the provided trackers + * + * @param campaign the campaign to generate the MechWarriors based on + * @param trackers the list of all generated trackers + */ + private void generateStandardMechWarriors(final Campaign campaign, + final List trackers) { + for (final CompanyGenerationPersonTracker tracker : trackers) { + if (!tracker.getPersonType().isMechWarrior()) { + continue; + } + + generateStandardMechWarrior(campaign, tracker); + } + } + + /** + * This sets up a standard MechWarrior + * 1) Assigns rank of E12 - Sergeant, or E4 for Clan, WoB, and ComStar + * + * @param campaign the campaign to generate the MechWarrior based on + * @param tracker the MechWarrior tracker to set up + */ + private void generateStandardMechWarrior(final Campaign campaign, + final CompanyGenerationPersonTracker tracker) { + if (getOptions().isAutomaticallyAssignRanks()) { + tracker.getPerson().setRank((campaign.getFaction().isComStarOrWoB() || campaign.getFaction().isClan()) + ? 4 : 12); + } + } + //endregion Combat Personnel + + //region Support Personnel + /** + * @param campaign the campaign to generate from + * @return a list of all support personnel + */ + private List generateSupportPersonnel(final Campaign campaign) { + final List trackers = new ArrayList<>(); + + for (final Entry entry : getOptions().getSupportPersonnel().entrySet()) { + for (int i = 0; i < entry.getValue(); i++) { + trackers.add(new CompanyGenerationPersonTracker(CompanyGenerationPersonType.SUPPORT, + generateSupportPerson(campaign, entry.getKey()))); + } + } + return trackers; + } + + /** + * @param campaign the campaign to generate from + * @param role the created person's primary role + * @return the newly created support person with the provided role + */ + private Person generateSupportPerson(final Campaign campaign, final PersonnelRole role) { + final Person person = campaign.newPerson(role, getPersonnelGenerator()); + // All support personnel get assigned Corporal or equivalent as their rank + if (getOptions().isAutomaticallyAssignRanks()) { + switch (campaign.getRankSystem().getCode()) { + case "CCWH": + case "CLAN": + break; + case "CG": + case "WOBM": + case "MAF": + person.setRank(4); + break; + default: + person.setRank(8); + break; + } + } + return person; + } + + /** + * @param campaign the campaign to use in creating the assistants + * @param trackers the trackers to add the newly created assistants to + */ + private void generateAssistants(final Campaign campaign, + final List trackers) { + // If you don't want to use pooled assistants, then this generates them as personnel instead + if (getOptions().isPoolAssistants()) { + return; + } + + final int assistantRank; + switch (campaign.getRankSystem().getCode()) { + case "CCWH": + case "CLAN": + assistantRank = 0; + break; + case "CG": + case "WOBM": + case "MAF": + assistantRank = 4; + break; + default: + assistantRank = 2; + break; + } + + for (int i = 0; i < campaign.getAstechNeed(); i++) { + final Person astech = campaign.newPerson(PersonnelRole.ASTECH, getPersonnelGenerator()); + if (getOptions().isAutomaticallyAssignRanks()) { + astech.setRank(assistantRank); + } + trackers.add(new CompanyGenerationPersonTracker(CompanyGenerationPersonType.ASSISTANT, astech)); + } + + for (int i = 0; i < campaign.getMedicsNeed(); i++) { + final Person medic = campaign.newPerson(PersonnelRole.MEDIC, getPersonnelGenerator()); + if (getOptions().isAutomaticallyAssignRanks()) { + medic.setRank(assistantRank); + } + trackers.add(new CompanyGenerationPersonTracker(CompanyGenerationPersonType.ASSISTANT, medic)); + } + } + //endregion Support Personnel + + /** + * This does the final personnel processing + * @param campaign the campaign to use in processing and to add the personnel to + * @param trackers ALL trackers for the campaign + */ + private void finalizePersonnel(final Campaign campaign, + final List trackers) { + // Assign the founder flag if we need to + if (getOptions().isAssignFounderFlag()) { + trackers.forEach(tracker -> tracker.getPerson().setFounder(true)); + } + + // Recruit all the personnel, GM-style so that the initial hiring cost is calculated as part + // of the financial model + trackers.forEach(t -> campaign.recruitPerson(t.getPerson(), true)); + + // Now that they are recruited, we can simulate backwards a few years and generate marriages + // and children + if (getOptions().isRunStartingSimulation()) { + LocalDate date = campaign.getLocalDate().minusYears(getOptions().getSimulationDuration()).minusDays(1); + while (date.isBefore(campaign.getLocalDate())) { + date = date.plusDays(1); + + for (final CompanyGenerationPersonTracker tracker : trackers) { + if (getOptions().isSimulateRandomMarriages()) { + campaign.getMarriage().processNewDay(campaign, date, tracker.getPerson()); + } + + if (getOptions().isSimulateRandomProcreation()) { + campaign.getProcreation().processNewDay(campaign, date, tracker.getPerson()); + } + } + } + } + } + //endregion Personnel + + //region Units + //region Unit Generation Parameters + /** + * This generates the unit generation parameters and assigns them to their trackers + * @param trackers the list of all personnel trackers + */ + public void generateUnitGenerationParameters(List trackers) { + // First, we need to create the unit generation parameters + final List parameters = createUnitGenerationParameters(trackers); + + // Then, we need to separate out the best roll for the unit commander if that option is enabled + if (getOptions().isAssignBestRollToCompanyCommander()) { + int bestIndex = 0; + AtBRandomMechParameters bestParameters = parameters.get(bestIndex); + for (int i = 1; i < parameters.size(); i++) { + final AtBRandomMechParameters checkParameters = parameters.get(i); + if (bestParameters.isStarLeague() == checkParameters.isStarLeague()) { + if (bestParameters.getWeight() == checkParameters.getWeight()) { + if (bestParameters.getQuality() < checkParameters.getQuality()) { + bestParameters = checkParameters; + bestIndex = i; + } + } else if (bestParameters.getWeight() < checkParameters.getWeight()) { + bestParameters = checkParameters; + bestIndex = i; + } + } else if (!bestParameters.isStarLeague() && checkParameters.isStarLeague()) { + bestParameters = checkParameters; + bestIndex = i; + } + } + + if (bestIndex != 0) { + Collections.swap(parameters, 0, bestIndex); + } + } + + // Now, we need to apply the various sorts based on the provided options + Comparator parametersComparator = (p1, p2) -> 0; + + if (getOptions().isSortStarLeagueUnitsFirst()) { + parametersComparator = parametersComparator.thenComparing(AtBRandomMechParameters::isStarLeague); + } + + if (getOptions().isGroupByWeight()) { + parametersComparator = parametersComparator.thenComparingInt(AtBRandomMechParameters::getWeight); + } + + if (getOptions().isGroupByQuality()) { + parametersComparator = parametersComparator.thenComparingInt(AtBRandomMechParameters::getQuality); + } + + parametersComparator = parametersComparator.reversed(); + + if (getOptions().isKeepOfficerRollsSeparate()) { + final int firstNonOfficer = determineNumberOfLances(); + parameters.subList(getOptions().isAssignBestRollToCompanyCommander() ? 1 : 0, firstNonOfficer) + .sort(parametersComparator); + parameters.subList(firstNonOfficer, parameters.size()).sort(parametersComparator); + } else { + // Officer Rolls are not separated. However, if the unit commander is assigned the best + // roll we don't sort the unit commander, just the rest of the rolls + if (getOptions().isAssignBestRollToCompanyCommander()) { + parameters.subList(1, parameters.size()).sort(parametersComparator); + } else { + parameters.sort(parametersComparator); + } + + trackers = sortPersonnelIntoLances(trackers); + } + + // Now that everything is nicely sorted, we can set the parameters. Parameters will ALWAYS + // be of a length equal to or less than that of trackers, as we don't generate parameters + // for support personnel. + for (int i = 0; i < parameters.size(); i++) { + trackers.get(i).setParameters(parameters.get(i)); + } + } + + /** + * @param trackers the list of all personnel trackers + * @return a list of the generated RandomMechParameters. These have NOT been assigned to the + * individual trackers + */ + private List createUnitGenerationParameters( + final List trackers) { + return trackers.stream().filter(tracker -> tracker.getPersonType().isCombat()) + .map(this::createUnitGenerationParameter).collect(Collectors.toList()); + } + + /** + * Creates an individual set of parameters, rerolling the weight if Star League + * (EntityWeightClass.WEIGHT_SUPER_HEAVY) is rolled originally. + * + * @param tracker the tracker to generate the parameters based on + * @return the created parameters + */ + private AtBRandomMechParameters createUnitGenerationParameter( + final CompanyGenerationPersonTracker tracker) { + final AtBRandomMechParameters parameters = new AtBRandomMechParameters( + getOptions().isOnlyGenerateStarLeagueMechs() ? EntityWeightClass.WEIGHT_SUPER_HEAVY + : rollBattleMechWeight(tracker, !getOptions().isNeverGenerateStarLeagueMechs()), + rollBattleMechQuality(tracker)); + if (parameters.isStarLeague()) { + parameters.setWeight(rollBattleMechWeight(tracker, false)); + } + return parameters; + } + + /** + * @param tracker the tracker to roll based on + * @param initialRoll if this isn't the initial roll, then we need to cap the Entity Weight + * Class at EntityWeightClass.WEIGHT_ASSAULT + * @return the weight to use in generating the BattleMech, which may be + * EntityWeightClass.WEIGHT_NONE to not generate a BattleMech or + * EntityWeightClass.WEIGHT_SUPER_HEAVY to generate a Star League BattleMech + */ + private int rollBattleMechWeight(final CompanyGenerationPersonTracker tracker, + final boolean initialRoll) { + final int roll = Utilities.dice(2, 6) + getUnitGenerationParameterModifier(tracker); + final int entityWeightClass = getBattleMechWeightClassGenerator().generate(roll); + return initialRoll ? entityWeightClass : Math.min(entityWeightClass, EntityWeightClass.WEIGHT_ASSAULT); + } + + /** + * @param tracker the tracker to roll based on + * @return the quality to use in generating the BattleMech + */ + private int rollBattleMechQuality(final CompanyGenerationPersonTracker tracker) { + return getBattleMechQualityGenerator().generate( + Utilities.dice(2, 6) + getUnitGenerationParameterModifier(tracker)); + } + + /** + * @param tracker the tracker to get the unit generation parameter modifier for + * @return the modifier value + */ + private int getUnitGenerationParameterModifier(final CompanyGenerationPersonTracker tracker) { + switch (tracker.getPersonType()) { + case MECHWARRIOR_COMPANY_COMMANDER: + return 2; + case MECHWARRIOR_CAPTAIN: + case MECHWARRIOR_LIEUTENANT: + return 1; + case MECHWARRIOR: + return 0; + default: + // Shouldn't be hit, but a safety for attempting non-combat generation + LogManager.getLogger().error("Attempting to generate a unit for a " + tracker.getPersonType() + ", returning a -20 modifier"); + return -20; + } + } + + /** + * @param trackers the trackers to sort into their lances + * @return a new List containing the sorted personnel + */ + private List sortPersonnelIntoLances( + final List trackers) { + // We start by creating the return list, the Captains list, the Lieutenants list + // and the MechWarriors list + final List sortedTrackers = new ArrayList<>(); + final List captains = trackers.stream().filter(tracker -> + tracker.getPersonType().isMechWarriorCaptain()).collect(Collectors.toList()); + final List lieutenants = trackers.stream().filter(tracker -> + tracker.getPersonType().isMechWarriorLieutenant()).collect(Collectors.toList()); + final List standardMechWarriors = trackers.stream().filter(tracker -> + tracker.getPersonType().isMechWarrior()).collect(Collectors.toList()); + + // Sort Command Lance + organizeTrackersIntoLance(sortedTrackers, trackers.get(0), standardMechWarriors); + + // If the command lance is part of a company, we sort the rest of that company immediately + if (!getOptions().isGenerateMercenaryCompanyCommandLance() && (getOptions().getCompanyCount() > 0)) { + for (int i = 1; i < getOptions().getLancesPerCompany(); i++) { + organizeTrackersIntoLance(sortedTrackers, lieutenants.remove(0), standardMechWarriors); + } + } + + // Sort into Companies + while (!captains.isEmpty()) { + // Assign the Captain's Lance + organizeTrackersIntoLance(sortedTrackers, captains.remove(0), standardMechWarriors); + // Then assign the other lances + for (int y = 1; y < getOptions().getLancesPerCompany(); y++) { + organizeTrackersIntoLance(sortedTrackers, lieutenants.remove(0), standardMechWarriors); + } + } + + // Sort any individual lances + while (!lieutenants.isEmpty()) { + organizeTrackersIntoLance(sortedTrackers, lieutenants.remove(0), standardMechWarriors); + } + + return sortedTrackers; + } + + /** + * @param sortedTrackers the list to add the now sorted lance to + * @param officer the officer to lead the lance + * @param standardMechWarriors the list of normal MechWarriors who can be assigned to this lance. + */ + private void organizeTrackersIntoLance(final List sortedTrackers, + final CompanyGenerationPersonTracker officer, + final List standardMechWarriors) { + sortedTrackers.add(officer); + if (standardMechWarriors.size() <= getOptions().getLanceSize() - 1) { + sortedTrackers.addAll(standardMechWarriors); + standardMechWarriors.clear(); + } else { + for (int i = 1; (i < getOptions().getLanceSize()) && !standardMechWarriors.isEmpty(); i++) { + sortedTrackers.add(standardMechWarriors.remove(0)); + } + } + } + //endregion Unit Generation Parameters + + //region Entities + /** + * @param campaign the campaign to generate for + * @param trackers the list of all personnel trackers + */ + public void generateEntities(final Campaign campaign, + final List trackers) { + trackers.stream().filter(tracker -> tracker.getPersonType().isCombat()) + .forEach(tracker -> generateEntity(campaign, tracker)); + } + + /** + * This generates a single entity and assigns it to the specified tracker. + * @param campaign the campaign to generate for + * @param tracker the tracker to generate based on the parameters and to assign the result to + */ + private void generateEntity(final Campaign campaign, + final CompanyGenerationPersonTracker tracker) { + tracker.setEntity((tracker.getParameters() == null) ? null + : generateEntity(campaign, tracker.getParameters(), tracker.getPerson().getOriginFaction())); + } + + /** + * This generates a single entity, thus allowing for individual rerolls + * @param campaign the campaign to generate for + * @param parameters the parameters to use in generation + * @param faction the faction to generate the Entity from + * @return the entity generated, or null otherwise + */ + private @Nullable Entity generateEntity(final Campaign campaign, + final AtBRandomMechParameters parameters, + final Faction faction) { + // Ultra-Light means no mech generated + if (parameters.getWeight() == EntityWeightClass.WEIGHT_ULTRA_LIGHT) { + return null; + } + + final MechSummary mechSummary = generateMechSummary(campaign, parameters, faction); + + if (mechSummary == null) { + LogManager.getLogger().error("Failed to generate an entity due to a null mech summary for faction " + faction.getShortName()); + return null; + } + + try { + return new MechFileParser(mechSummary.getSourceFile(), mechSummary.getEntryName()).getEntity(); + } catch (Exception ex) { + LogManager.getLogger().error("Failed to generate entity", ex); + return null; + } + } + + /** + * @param campaign the campaign to generate for + * @param parameters the parameters to use in generation + * @param faction the faction to generate the mech from + * @return the MechSummary generated from the provided parameters, or null if generation fails + */ + protected abstract @Nullable MechSummary generateMechSummary(final Campaign campaign, + final AtBRandomMechParameters parameters, + final Faction faction); + + /** + * @param campaign the campaign to generate for + * @param parameters the parameters to use in generation + * @param faction the faction code to use in generation + * @param year the year to use in generation + * @return the MechSummary generated from the provided parameters, or null if generation fails + */ + protected @Nullable MechSummary generateMechSummary(final Campaign campaign, + final AtBRandomMechParameters parameters, + final String faction, int year) { + Predicate filter = ms -> + (!campaign.getCampaignOptions().limitByYear() || (year > ms.getYear())); + if (getOptions().isOnlyGenerateOmniMechs()) { + filter = filter.and(ms -> "Omni".equalsIgnoreCase(ms.getUnitSubType())); + } + + return campaign.getUnitGenerator().generate(faction, UnitType.MEK, + parameters.getWeight(), year, parameters.getQuality(), filter); + } + //endregion Entities + + /** + * @param campaign the campaign to add the units to + * @param trackers the list of trackers to assign to their units + * @return the list of created units + */ + private List createUnits(final Campaign campaign, + final List trackers) { + final List units = new ArrayList<>(); + for (final CompanyGenerationPersonTracker tracker : trackers) { + if (tracker.getEntity() == null) { + continue; + } + + final Unit unit = campaign.addNewUnit(tracker.getEntity(), false, 0); + unit.addPilotOrSoldier(tracker.getPerson()); + if (getOptions().isGenerateUnitsAsAttached()) { + tracker.getPerson().setOriginalUnit(unit); + } + units.add(unit); + } + return units; + } + + /** + * @param trackers the list of trackers including the support 'Mech techs + * @param units the list of units to have techs assigned to (order does not matter) + */ + private void assignTechsToUnits(final List trackers, + final List units) { + if (!getOptions().isAssignTechsToUnits()) { + return; + } + + final List mechTechs = trackers.parallelStream() + .filter(tracker -> tracker.getPersonType().isSupport()) + .filter(tracker -> tracker.getPerson().getPrimaryRole().isMechTech()) + .collect(Collectors.toList()); + if (mechTechs.isEmpty()) { + return; + } + + units.sort(Comparator.comparingDouble(Unit::getMaintenanceTime)); + int numberMechTechs = mechTechs.size(); + for (int i = 0; (i < units.size()) && !mechTechs.isEmpty(); i++) { + final Person mechTech = mechTechs.get(i % numberMechTechs).getPerson(); + if (mechTech.getMaintenanceTimeUsing() + units.get(i).getMaintenanceTime() <= Person.PRIMARY_ROLE_SUPPORT_TIME) { + units.get(i).setTech(mechTech); + } else { + mechTechs.remove(i % numberMechTechs--); + } + } + } + //endregion Units + + //region Unit + /** + * This generates the TO&E structure, and assigns personnel to their individual lances. + * @param campaign the campaign to generate the unit within + * @param trackers a CLONED list of trackers properly organized into lances + */ + private void generateUnit(final Campaign campaign, + final List trackers) { + final Force originForce = campaign.getForce(0); + final Alphabet[] alphabet = Alphabet.values(); + ForcePieceIcon background = null; + + if (getOptions().isGenerateForceIcons()) { + if (campaign.getFaction().getLayeredForceIconBackgroundFilename() != null) { + background = new ForcePieceIcon(LayeredForceIconLayer.BACKGROUND, + campaign.getFaction().getLayeredForceIconBackgroundCategory(), + campaign.getFaction().getLayeredForceIconBackgroundFilename()); + } + + // Create the Origin Force Icon + if (getOptions().isGenerateOriginNodeForceIcon()) { + final LayeredForceIcon layeredForceIcon = new LayeredForceIcon(); + + // Logo / Type + if (getOptions().isUseOriginNodeForceIconLogo() + && (campaign.getFaction().getLayeredForceIconLogoFilename() != null)) { + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.LOGO, new ArrayList<>()); + layeredForceIcon.getPieces().get(LayeredForceIconLayer.LOGO) + .add(new ForcePieceIcon(LayeredForceIconLayer.LOGO, + campaign.getFaction().getLayeredForceIconLogoCategory(), + campaign.getFaction().getLayeredForceIconLogoFilename())); + } else { + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.TYPE, new ArrayList<>()); + layeredForceIcon.getPieces().get(LayeredForceIconLayer.TYPE) + .add(new ForcePieceIcon(LayeredForceIconLayer.TYPE, + MHQConstants.LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH, + MHQConstants.LAYERED_FORCE_ICON_BATTLEMECH_CENTER_FILENAME)); + } + + // Background + if (background != null) { + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.BACKGROUND, new ArrayList<>()); + layeredForceIcon.getPieces().get(LayeredForceIconLayer.BACKGROUND).add(background.clone()); + } + + originForce.setForceIcon(layeredForceIcon); + } + } + + // Generate the Mercenary Company Command Lance + if (getOptions().isGenerateMercenaryCompanyCommandLance()) { + final Force commandLance = createLance(campaign, originForce, trackers, campaign.getName() + + resources.getString("AbstractCompanyGenerator.CommandLance.text"), background); + if (getOptions().isGenerateForceIcons() + && (commandLance.getForceIcon() instanceof LayeredForceIcon)) { + final LayeredForceIcon icon = (LayeredForceIcon) commandLance.getForceIcon(); + icon.getPieces().putIfAbsent(LayeredForceIconLayer.ALPHANUMERIC, new ArrayList<>()); + icon.getPieces().get(LayeredForceIconLayer.ALPHANUMERIC) + .add(new ForcePieceIcon(LayeredForceIconLayer.ALPHANUMERIC, + MHQConstants.LAYERED_FORCE_ICON_ALPHANUMERIC_BOTTOM_RIGHT_PATH, + MHQConstants.LAYERED_FORCE_ICON_ALPHANUMERIC_HQ_FILENAME)); + } + } + + // Create Companies + for (int i = 0; i < getOptions().getCompanyCount(); i++) { + final Force company = new Force(getOptions().getForceNamingMethod().getValue(alphabet[i]) + + resources.getString("AbstractCompanyGenerator.Company.text")); + campaign.addForce(company, originForce); + for (int y = 0; y < getOptions().getLancesPerCompany(); y++) { + createLance(campaign, company, trackers, alphabet[y], background); + } + + if (getOptions().isGenerateForceIcons()) { + createLayeredForceIcon(campaign, company, false, background); + } + } + + // Create Individual Lances + for (int i = 0 ; i < getOptions().getIndividualLanceCount(); i++) { + createLance(campaign, originForce, trackers, alphabet[i + getOptions().getCompanyCount()], background); + } + } + + /** + * This creates a lance with a standard name + * @param campaign the campaign to generate the unit within + * @param head the force to append the new lance to + * @param trackers the list of trackers, properly ordered to be assigned to the lance + * @param alphabet the alphabet value to determine the lance name from + * @param background the background force piece icon, which is null when there's no valid background + */ + private void createLance(final Campaign campaign, final Force head, + final List trackers, + final Alphabet alphabet, final @Nullable ForcePieceIcon background) { + createLance(campaign, head, trackers, + getOptions().getForceNamingMethod().getValue(alphabet) + + resources.getString("AbstractCompanyGenerator.Lance.text"), + background); + } + + /** + * @param campaign the campaign to generate the unit within + * @param head the force to append the new lance to + * @param trackers the list of trackers, properly ordered to be assigned to the lance + * @param name the lance's name + * @param background the background force piece icon, which is null when there's no valid background + * @return the newly created lance + */ + private Force createLance(final Campaign campaign, final Force head, + final List trackers, + final String name, final @Nullable ForcePieceIcon background) { + final Force lance = new Force(name); + campaign.addForce(lance, head); + for (int i = 0; (i < getOptions().getLanceSize()) && !trackers.isEmpty(); i++) { + campaign.addUnitToForce(trackers.remove(0).getPerson().getUnit(), lance); + } + + if (getOptions().isGenerateForceIcons()) { + createLayeredForceIcon(campaign, lance, true, background); + } + + return lance; + } + + /** + * This creates a layered force icon for a force + * @param campaign the campaign the force is a part of + * @param force the force to create a layered force icon for + * @param isLance whether the force is a lance or a company + * @param background the background force piece icon, which is null when there's no valid background + */ + private void createLayeredForceIcon(final Campaign campaign, final Force force, + final boolean isLance, + final @Nullable ForcePieceIcon background) { + if (MHQStaticDirectoryManager.getForceIcons() == null) { + return; + } + + final LayeredForceIcon layeredForceIcon = new LayeredForceIcon(); + + // Type + final String filename = String.format("%s.png", + EntityWeightClass.getClassName(determineForceWeightClass(campaign, force, isLance))); + try { + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.TYPE, new ArrayList<>()); + if (MHQStaticDirectoryManager.getForceIcons().getItem( + LayeredForceIconLayer.TYPE.getLayerPath() + MHQConstants.LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH, + filename) == null) { + layeredForceIcon.getPieces().get(LayeredForceIconLayer.TYPE).add( + new ForcePieceIcon(LayeredForceIconLayer.TYPE, + MHQConstants.LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH, + MHQConstants.LAYERED_FORCE_ICON_BATTLEMECH_CENTER_FILENAME)); + } else { + layeredForceIcon.getPieces().get(LayeredForceIconLayer.TYPE).add( + new ForcePieceIcon(LayeredForceIconLayer.TYPE, + MHQConstants.LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH, + MHQConstants.LAYERED_FORCE_ICON_BATTLEMECH_LEFT_FILENAME)); + layeredForceIcon.getPieces().get(LayeredForceIconLayer.TYPE).add( + new ForcePieceIcon(LayeredForceIconLayer.TYPE, + MHQConstants.LAYERED_FORCE_ICON_TYPE_STRAT_OPS_PATH, filename)); + } + } catch (Exception ex) { + LogManager.getLogger().error("Cannot create a layered force icon, setting " + force + " to the default", ex); + force.setForceIcon(new LayeredForceIcon()); + return; + } + + // Formation + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.FORMATION, new ArrayList<>()); + if (campaign.getFaction().isClan()) { + layeredForceIcon.getPieces().get(LayeredForceIconLayer.FORMATION) + .add(new ForcePieceIcon(LayeredForceIconLayer.FORMATION, + MHQConstants.LAYERED_FORCE_ICON_FORMATION_CLAN_PATH, + isLance ? MHQConstants.LAYERED_FORCE_ICON_FORMATION_STAR_FILENAME + : MHQConstants.LAYERED_FORCE_ICON_FORMATION_TRINARY_FILENAME)); + } else if (campaign.getFaction().isComStarOrWoB()) { + layeredForceIcon.getPieces().get(LayeredForceIconLayer.FORMATION) + .add(new ForcePieceIcon(LayeredForceIconLayer.FORMATION, + MHQConstants.LAYERED_FORCE_ICON_FORMATION_COMSTAR_PATH, + isLance ? MHQConstants.LAYERED_FORCE_ICON_FORMATION_LEVEL_II_FILENAME + : MHQConstants.LAYERED_FORCE_ICON_FORMATION_LEVEL_III_FILENAME)); + } else { + layeredForceIcon.getPieces().get(LayeredForceIconLayer.FORMATION) + .add(new ForcePieceIcon(LayeredForceIconLayer.FORMATION, + MHQConstants.LAYERED_FORCE_ICON_FORMATION_INNER_SPHERE_PATH, + isLance ? MHQConstants.LAYERED_FORCE_ICON_FORMATION_LANCE_FILENAME + : MHQConstants.LAYERED_FORCE_ICON_FORMATION_COMPANY_FILENAME)); + } + + // Background + if (background != null) { + layeredForceIcon.getPieces().putIfAbsent(LayeredForceIconLayer.BACKGROUND, new ArrayList<>()); + layeredForceIcon.getPieces().get(LayeredForceIconLayer.BACKGROUND).add(background.clone()); + } + + force.setForceIcon(layeredForceIcon); + } + + /** + * This determines the weight class of a force (lance or company) based on the units within + * @param campaign the campaign to determine based on + * @param force the force to determine the weight class for + * @param isLance whether the force is a lance or a company + * @return the weight class of the force + */ + private int determineForceWeightClass(final Campaign campaign, final Force force, + final boolean isLance) { + double weight = force.getAllUnits(true).stream().map(campaign::getUnit) + .filter(unit -> (unit != null) && (unit.getEntity() != null)) + .mapToDouble(unit -> unit.getEntity().getWeight()).sum(); + weight = weight * 4.0 / (getOptions().getLanceSize() * (isLance ? 1 : getOptions().getLancesPerCompany())); + final Entry entry = getOptions().getForceWeightLimits().ceilingEntry((int) Math.round(weight)); + return (entry == null) ? EntityWeightClass.WEIGHT_SUPER_HEAVY : entry.getValue(); + } + //endregion Unit + + //region Spares + /** + * This generates any mothballed spare entities for the force + * @param campaign the campaign to generate for + * @param trackers the trackers containing the generated combat entities + * @return the list of all generated entities to mothball as spares + */ + public List generateMothballedEntities(final Campaign campaign, + final List trackers) { + // Determine how many entities to generate + final int numberMothballedEntities; + if (getOptions().isGenerateMothballedSpareUnits() + && (getOptions().getSparesPercentOfActiveUnits() > 0)) { + // No free units for null rolls! + numberMothballedEntities = Math.toIntExact(Math.round( + trackers.stream().map(CompanyGenerationPersonTracker::getEntity) + .filter(Objects::nonNull).count() + * (getOptions().getSparesPercentOfActiveUnits() / 100.0))); + } else { + numberMothballedEntities = 0; + } + + // Return if we aren't generating any mothballed entities + if (numberMothballedEntities <= 0) { + return new ArrayList<>(); + } + + // Create the return list + final List mothballedEntities = new ArrayList<>(); + + // Create the Faction Selector + final AbstractFactionSelector factionSelector = createFactionSelector(); + + // Create the Mothballed Entities + for (int i = 0; i < numberMothballedEntities; i++) { + final Faction faction = factionSelector.selectFaction(campaign); + if (faction == null) { + LogManager.getLogger().error("Failed to generate a valid faction, and thus cannot generate a mothballed 'Mech"); + continue; + } + + // Create the parameters to generate the 'Mech from + final AtBRandomMechParameters parameters = new AtBRandomMechParameters( + getBattleMechWeightClassGenerator().generate(Utilities.dice(2, 6)), + getBattleMechQualityGenerator().generate(Utilities.dice(2, 6)) + ); + + // We want to ensure we get a 'Mech generated + while (parameters.getWeight() == EntityWeightClass.WEIGHT_ULTRA_LIGHT) { + parameters.setWeight(getBattleMechWeightClassGenerator().generate(Utilities.dice(2, 6))); + } + + // Generate the 'Mech, and add it to the mothballed entities list + final Entity entity = generateEntity(campaign, parameters, faction); + if (entity != null) { + mothballedEntities.add(entity); + } + } + return mothballedEntities; + } + + /** + * @param campaign the campaign to add the units to + * @param mothballedEntities the list of generated spare 'Mech entities to add and mothball + * @return the list of created units + */ + private List createMothballedSpareUnits(final Campaign campaign, + final List mothballedEntities) { + final List mothballedUnits = mothballedEntities.stream() + .map(entity -> campaign.addNewUnit(entity, false, 0)) + .collect(Collectors.toList()); + mothballedUnits.forEach(Unit::completeMothball); + return mothballedUnits; + } + + /** + * @param units the list of units to generate spare parts based on + * @return the list of randomly generated parts + */ + public List generateSpareParts(final List units) { + return getOptions().getPartGenerationMethod().isDisabled() ? new ArrayList<>() + : getOptions().getPartGenerationMethod().getGenerator().generate(units, false, false); + } + + /** + * @param units the list of units to generate spare armour based on + * @return the generated armour + */ + public List generateArmour(final List units) { + if (getOptions().getStartingArmourWeight() <= 0) { + return new ArrayList<>(); + } + + final List unitAssignedArmour = units.stream() + .flatMap(unit -> unit.getParts().stream()) + .filter(part -> part instanceof Armor) + .map(part -> (Armor) part) + .collect(Collectors.toList()); + final List armour = mergeIdenticalArmour(unitAssignedArmour); + final double armourTonnageMultiplier = getOptions().getStartingArmourWeight() + / armour.stream().mapToDouble(Armor::getTonnage).sum(); + armour.forEach(a -> a.setAmount(Math.toIntExact(Math.round(a.getAmount() * armourTonnageMultiplier)))); + return armour; + } + + /** + * This clones and merges armour determined by the custom check below together + * @param unmergedArmour the unmerged list of armour, which may be assigned to a unit + * @return the merged list of armour + */ + private List mergeIdenticalArmour(final List unmergedArmour) { + final List mergedArmour = new ArrayList<>(); + unmergedArmour.forEach(armour -> { + boolean unmerged = true; + for (final Armor a : mergedArmour) { + if (areSameArmour(a, armour)) { + a.addAmount(armour.getAmount()); + unmerged = false; + break; + } + } + + if (unmerged) { + final Armor a = armour.clone(); + a.setMode(WorkTime.NORMAL); + a.setOmniPodded(false); + mergedArmour.add(a); + } + }); + return mergedArmour; + } + + /** + * This is a custom equals comparison utilized by this class to determine if two Armour Parts + * are the same + * @param a1 the first Armour part + * @param a2 the second Armour part + * @return whether this class considers both types of Armour to be the same. This DIFFERS + * from Armor::equals + */ + private boolean areSameArmour(final Armor a1, final Armor a2) { + return (a1.getClass() == a2.getClass()) + && a1.isSameType(a2) + && (a1.isClan() == a2.isClan()) + && (a1.getQuality() == a2.getQuality()) + && (a1.getHits() == a2.getHits()) + && (a1.getSkillMin() == a2.getSkillMin()); + } + + /** + * @param campaign the campaign to generate ammunition for + * @param units the list of units to generate ammunition for + * @return the generated ammunition + */ + public List generateAmmunition(final Campaign campaign, final List units) { + if (!getOptions().isGenerateSpareAmmunition() || ((getOptions().getNumberReloadsPerWeapon() <= 0) + && !getOptions().isGenerateFractionalMachineGunAmmunition())) { + return new ArrayList<>(); + } + + final List ammoBins = units.stream() + .flatMap(unit -> unit.getParts().stream()) + .filter(part -> part instanceof AmmoBin) + .map(part -> (AmmoBin) part) + .collect(Collectors.toList()); + + final List ammunition = new ArrayList<>(); + final boolean generateReloads = getOptions().getNumberReloadsPerWeapon() > 0; + ammoBins.forEach(ammoBin -> { + if (getOptions().isGenerateFractionalMachineGunAmmunition() && ammoBinIsMachineGun(ammoBin)) { + ammunition.add(new AmmoStorage(0, ammoBin.getType(), 50, campaign)); + } else if (generateReloads) { + ammunition.add(new AmmoStorage(0, ammoBin.getType(), + ammoBin.getFullShots() * getOptions().getNumberReloadsPerWeapon(), campaign)); + } + }); + + return ammunition; + } + + /** + * @param ammoBin the ammo bin to check + * @return whether the ammo bin's ammo type is a machine gun type + */ + private boolean ammoBinIsMachineGun(final AmmoBin ammoBin) { + switch (ammoBin.getType().getAmmoType()) { + case AmmoType.T_MG: + case AmmoType.T_MG_HEAVY: + case AmmoType.T_MG_LIGHT: + return true; + default: + return false; + } + } + //endregion Spares + + //region Contract + /** + * This processes the selected contract + * @param campaign the campaign to apply changes to + * @param contract the selected contract, if any + */ + private void processContract(final Campaign campaign, final @Nullable Contract contract) { + if (contract == null) { + return; + } + + if (getOptions().isStartCourseToContractPlanet()) { + campaign.getLocation().setJumpPath(contract.getJumpPath(campaign)); + } + } + //endregion Contract + + //region Finances + /** + * This processes the full financial setup for a campaign based on the one's options + * + * @param campaign the campaign to process finances for + * @param trackers the trackers containing the personnel to get the hiring cost for + * @param units the list of units to get the cost for + * @param parts the list of parts to get the cost for + * @param armour the list of different armours to get the cost for + * @param ammunition the list of ammunition to get the cost for + * @param contract the contract to potentially process the initial contract payment, which may + * be null. + */ + private void processFinances(final Campaign campaign, + final List trackers, + final List units, final List parts, + final List armour, final List ammunition, + final @Nullable Contract contract) { + // Don't bother processing if it's disabled + if (!getOptions().isProcessFinances()) { + return; + } + + // Create Base Parsing Variables + Money startingCash = generateStartingCash(); + Money minimumStartingFloat = Money.of(getOptions().getMinimumStartingFloat()); + Money loan = Money.zero(); + + // Process Initial Contract Payment + if (getOptions().isIncludeInitialContractPayment() && (contract != null)) { + startingCash = startingCash.plus(contract.getTotalAdvanceAmount()); + } + + if (getOptions().isPayForSetup()) { + // Calculate the total costs of setup + final Money costs = calculateHiringCosts(campaign, trackers) + .plus(calculateUnitCosts(units)) + .plus(calculatePartCosts(parts)) + .plus(calculateArmourCosts(armour)) + .plus(calculateAmmunitionCosts(ammunition)); + + // Determine the maximum costs before a loan needs to be taken, and determine the + // starting cash based on it. + final Money maximumPreLoanCosts = startingCash.minus(minimumStartingFloat); + if (maximumPreLoanCosts.isGreaterOrEqualThan(costs)) { + startingCash = startingCash.minus(costs); + } else { + // Otherwise, the starting cash is the minimum float, with a loan created with the + // remaining costs if that option is selected + startingCash = minimumStartingFloat; + if (getOptions().isStartingLoan()) { + loan = costs.minus(maximumPreLoanCosts).round(); + } + } + + // Round the starting cash so we don't have any weird trailing numbers + startingCash = startingCash.round(); + + // Credit the campaign with the starting cash if it is positive + if (startingCash.isPositive()) { + campaign.getFinances().credit(TransactionType.STARTING_CAPITAL, + campaign.getLocalDate(), startingCash, + resources.getString("AbstractCompanyGenerator.CompanyStartupFunding.text")); + } + + // Add the loan if there's one to add + if (!loan.isZero()) { + campaign.getFinances().addLoan(new Loan(loan, 15, 2, FinancialTerm.MONTHLY, + 100, campaign.getLocalDate())); + } + } else { + // Credit the campaign with the starting cash if it is positive + startingCash = startingCash.isGreaterOrEqualThan(minimumStartingFloat) ? startingCash + : minimumStartingFloat; + + // Credit the campaign with the starting cash if it is positive + if (startingCash.isPositive()) { + campaign.getFinances().credit(TransactionType.STARTING_CAPITAL, + campaign.getLocalDate(), startingCash, + resources.getString("AbstractCompanyGenerator.CompanyStartupFunding.text")); + } + } + + // Report the financial state in the daily report + if (loan.isZero()) { + campaign.addReport(String.format( + resources.getString("AbstractCompanyGenerator.CompanyStartupFundedWithoutLoan.report"), + startingCash)); + } else { + campaign.addReport(String.format( + resources.getString("AbstractCompanyGenerator.CompanyStartupFundedWithLoan.report"), + startingCash, loan)); + } + } + + /** + * @return the amount of starting cash generated for the Mercenary Company + */ + private Money generateStartingCash() { + return getOptions().isRandomizeStartingCash() ? rollRandomStartingCash() + : Money.of(getOptions().getStartingCash()); + } + + /** + * @return the option dice count d6 million c-bills, or zero if randomize starting cash is disabled + */ + private Money rollRandomStartingCash() { + return getOptions().isRandomizeStartingCash() + ? Money.of(Math.pow(10, 6)).multipliedBy(Utilities.dice(getOptions().getRandomStartingCashDiceCount(), 6)) + : Money.zero(); + } + + /** + * @param campaign the campaign to use in determining the hiring costs + * @param trackers the trackers containing the personnel to get the hiring cost for + * @return the cost of hiring the personnel, or zero if you aren't paying for hiring costs + */ + private Money calculateHiringCosts(final Campaign campaign, + final List trackers) { + if (!getOptions().isPayForPersonnel()) { + return Money.zero(); + } + + Money hiringCosts = Money.zero(); + for (final CompanyGenerationPersonTracker tracker : trackers) { + hiringCosts = hiringCosts.plus(tracker.getPerson().getSalary(campaign).multipliedBy(2)); + } + return hiringCosts; + } + + /** + * @param units the list of units to get the cost for + * @return the cost of the units, or zero if you aren't paying for units + */ + private Money calculateUnitCosts(final List units) { + if (!getOptions().isPayForUnits()) { + return Money.zero(); + } + + Money unitCosts = Money.zero(); + + for (final Unit unit : units) { + if (unit.hasCommander() && getOptions().isGenerateUnitsAsAttached()) { + unitCosts = unitCosts.plus(unit.getBuyCost().dividedBy(2)); + } else { + unitCosts = unitCosts.plus(unit.getBuyCost()); + } + } + + return unitCosts; + } + + /** + * @param parts the list of parts to get the cost for + * @return the cost of the parts, or zero if you aren't paying for parts + */ + private Money calculatePartCosts(final List parts) { + if (!getOptions().isPayForParts()) { + return Money.zero(); + } + + Money partCosts = Money.zero(); + for (final Part part : parts) { + partCosts = partCosts.plus(part.getStickerPrice()); + } + return partCosts; + } + + /** + * @param armours the list of different armours to get the cost for + * @return the cost of the armour, or zero if you aren't paying for armour + */ + private Money calculateArmourCosts(final List armours) { + if (!getOptions().isPayForArmour()) { + return Money.zero(); + } + + Money armourCosts = Money.zero(); + for (final Armor armour : armours) { + armourCosts = armourCosts.plus(armour.getStickerPrice()); + } + return armourCosts; + } + + /** + * @param ammunition the list of ammunition to get the cost for + * @return the cost of the ammunition, or zero if you aren't paying for ammunition + */ + private Money calculateAmmunitionCosts(final List ammunition) { + if (!getOptions().isPayForAmmunition()) { + return Money.zero(); + } + + Money ammunitionCosts = Money.zero(); + for (final AmmoStorage ammoStorage : ammunition) { + ammunitionCosts = ammunitionCosts.plus(ammoStorage.getStickerPrice()); + } + + return ammunitionCosts; + } + //endregion Finances + + //region Surprises +/* + private void generateSurprises(final Campaign campaign) { + if (!getOptions().isGenerateSurprises()) { + return; + } + + generateMysteryBoxes(campaign); + } + + private void generateMysteryBoxes(final Campaign campaign) { + if (!getOptions().isGenerateMysteryBoxes()) { + return; + } + + final MysteryBoxType[] mysteryBoxTypes = MysteryBoxType.values(); + final List mysteryBoxes = new ArrayList<>(); + for (int i = 0; i < getOptions().getGenerateMysteryBoxTypes().length; i++) { + if (getOptions().getGenerateMysteryBoxTypes()[i]) { + mysteryBoxes.add(mysteryBoxTypes[i].getMysteryBox()); + } + } + + // TODO : Processing of mystery boxes + } + */ + //endregion Surprises + + //region Apply to Campaign + /** + * Phase One: Starting Planet and Finalizing Personnel, Unit, and Units + * + * @param campaign the campaign to apply the generation to + * @param trackers the trackers containing all the data required for Phase One + * @return a list of the newly created units to add to the campaign + */ + public List applyPhaseOneToCampaign(final Campaign campaign, + final List trackers) { + // Process Personnel + // If we aren't using the pool, generate all the Astechs and Medics required + generateAssistants(campaign, trackers); + + // This does all the final personnel processing, including recruitment and running random + // marriages + finalizePersonnel(campaign, trackers); + + // We can only fill the pool after finalizing and recruiting our support personnel + if (getOptions().isPoolAssistants()) { + campaign.fillAstechPool(); + campaign.fillMedicPool(); + } + + // Process Units + final List units = createUnits(campaign, trackers); + + // Assign Techs to Units + assignTechsToUnits(trackers, units); + + // Generate the Forces and Assign Units to them + generateUnit(campaign, sortPersonnelIntoLances(trackers)); + + return units; + } + + /** + * Phase Two: Finalizing Spares + * + * @param campaign the campaign to apply the generation to + * @param mothballedEntities the generated mothballed spare entities + * @param parts the generated spare parts + * @param armour the generated spare armour + * @param ammunition the generated spare armour + * @return a list of the generated mothballed spare units + */ + public List applyPhaseTwoToCampaign(final Campaign campaign, + final List mothballedEntities, + final List parts, final List armour, + final List ammunition) { + final List mothballedUnits = createMothballedSpareUnits(campaign, mothballedEntities); + parts.forEach(p -> campaign.getWarehouse().addPart(p, true)); + armour.forEach(a -> campaign.getWarehouse().addPart(a, true)); + ammunition.forEach(a -> campaign.getWarehouse().addPart(a, true)); + return mothballedUnits; + } + + + /** + * Phase Three: Finalizing Contract and Finances + * + * @param campaign the campaign to apply the generation to + * @param trackers the trackers containing all the data required for Phase One, which + * includes all Personnel + * @param units the units added to the campaign, including any mothballed units + * @param parts the spare parts generated + * @param armour the spare armour generated + * @param ammunition the spare ammunition generated + * @param contract the contract selected, if any + */ + public void applyPhaseThreeToCampaign(final Campaign campaign, + final List trackers, + final List units, final List parts, + final List armour, + final List ammunition, + final @Nullable Contract contract) { + // Process Contract + processContract(campaign, contract); + + // Process Finances + processFinances(campaign, trackers, units, parts, armour, ammunition, contract); + } + //endregion Apply to Campaign +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AtBCompanyGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AtBCompanyGenerator.java new file mode 100644 index 0000000000..5bfcb4b288 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/AtBCompanyGenerator.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2021-2022 - 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.generators.companyGenerators; + +import megamek.common.MechSummary; +import megamek.common.annotations.Nullable; +import mekhq.campaign.Campaign; +import mekhq.campaign.personnel.ranks.Rank; +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.companyGeneration.AtBRandomMechParameters; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationPersonTracker; +import mekhq.campaign.universe.enums.CompanyGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class AtBCompanyGenerator extends AbstractCompanyGenerator { + //region Constructors + public AtBCompanyGenerator(final Campaign campaign, final CompanyGenerationOptions options) { + super(CompanyGenerationMethod.AGAINST_THE_BOT, campaign, options); + } + //endregion Constructors + + //region Personnel + /** + * @param campaign the campaign to use in generating the commanding officer's rank + * @param tracker the commanding officer's tracker + * @param numMechWarriors the number of MechWarriors in their force, used to determine their rank + */ + @Override + protected void generateCommandingOfficerRank(final Campaign campaign, + final CompanyGenerationPersonTracker tracker, + final int numMechWarriors) { + if (numMechWarriors >= 36) { + tracker.getPerson().setRank(Rank.RWO_MAX + (campaign.getFaction().isComStarOrWoB() ? 7 : 8)); + } else if (numMechWarriors >= 12) { + tracker.getPerson().setRank(Rank.RWO_MAX + (campaign.getFaction().isComStarOrWoB() ? 7 : 5)); + } else if (numMechWarriors >= 4) { + tracker.getPerson().setRank(Rank.RWO_MAX + 4); + } else { + tracker.getPerson().setRank(Rank.RWO_MAX + 3); + } + } + //endregion Personnel + + //region Units + /** + * @param campaign the campaign to generate for + * @param parameters the parameters to use in generation + * @param faction the faction to generate the mech from + * @return the MechSummary generated from the provided parameters, or null if generation fails + */ + @Override + protected @Nullable MechSummary generateMechSummary(final Campaign campaign, + final AtBRandomMechParameters parameters, + final Faction faction) { + if (parameters.isStarLeague() && !faction.isComStarOrWoB()) { + if (faction.isClan()) { + // Clanners generate from Front Line tables instead of Star League + parameters.setQuality(IUnitRating.DRAGOON_B); + return generateMechSummary(campaign, parameters, faction.getShortName(), campaign.getGameYear()); + } else { + // Roll on the Star League Royal table if you get a SL mech with A* Rating + final String factionCode = (parameters.getQuality() == IUnitRating.DRAGOON_ASTAR) ? "SL.R" : "SL"; + return generateMechSummary(campaign, parameters, factionCode, getOptions().getStarLeagueYear()); + } + } else { + // Clanners Generate from 2nd Line Tables + if (faction.isClan()) { + parameters.setQuality(IUnitRating.DRAGOON_C); + } + return generateMechSummary(campaign, parameters, faction.getShortName(), campaign.getGameYear()); + } + } + //endregion Units +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/WindchildCompanyGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/WindchildCompanyGenerator.java new file mode 100644 index 0000000000..2aaf2e9c08 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/companyGenerators/WindchildCompanyGenerator.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021-2022 - 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.generators.companyGenerators; + +import megamek.common.MechSummary; +import megamek.common.annotations.Nullable; +import mekhq.campaign.Campaign; +import mekhq.campaign.personnel.ranks.Rank; +import mekhq.campaign.rating.IUnitRating; +import mekhq.campaign.universe.Faction; +import mekhq.campaign.universe.companyGeneration.AtBRandomMechParameters; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationPersonTracker; +import mekhq.campaign.universe.enums.CompanyGenerationMethod; + +/** + * @author Justin "Windchild" Bowen + */ +public class WindchildCompanyGenerator extends AbstractCompanyGenerator { + //region Constructors + public WindchildCompanyGenerator(final Campaign campaign, final CompanyGenerationOptions options) { + super(CompanyGenerationMethod.WINDCHILD, campaign, options); + } + //endregion Constructors + + //region Personnel + /** + * Set based on greater than instead of the greater than or equal to of AtB + * @param campaign the campaign to use in generating the commanding officer's rank + * @param tracker the commanding officer's tracker + * @param numMechWarriors the number of MechWarriors in their force, used to determine their rank + */ + @Override + protected void generateCommandingOfficerRank(final Campaign campaign, + final CompanyGenerationPersonTracker tracker, + final int numMechWarriors) { + if (numMechWarriors > 36) { + tracker.getPerson().setRank(Rank.RWO_MAX + (campaign.getFaction().isComStarOrWoB() ? 7 : 8)); + } else if (numMechWarriors > 12) { + tracker.getPerson().setRank(Rank.RWO_MAX + (campaign.getFaction().isComStarOrWoB() ? 7 : 5)); + } else if (numMechWarriors > 4) { + tracker.getPerson().setRank(Rank.RWO_MAX + 4); + } else { + tracker.getPerson().setRank(Rank.RWO_MAX + 3); + } + } + //endregion Personnel + + //region Units + /** + * This generates Clan 'Mechs differently, so you can get any of the quality ratings for clanners. + * + * @param campaign the campaign to generate for + * @param parameters the parameters to use in generation + * @param faction the faction to generate the mech from + * @return the MechSummary generated from the provided parameters, or null if generation fails + */ + @Override + protected @Nullable MechSummary generateMechSummary(final Campaign campaign, + final AtBRandomMechParameters parameters, + final Faction faction) { + if (parameters.isStarLeague()) { + if (faction.isClan()) { + // Clanners generate using the Keshik Table if they roll A*, otherwise they roll on + // the Front Line tables + parameters.setQuality((parameters.getQuality() == IUnitRating.DRAGOON_ASTAR) + ? IUnitRating.DRAGOON_ASTAR : IUnitRating.DRAGOON_B); + return generateMechSummary(campaign, parameters, faction.getShortName(), campaign.getGameYear()); + } else { + // Roll on the Star League Royal table if you get a SL mech with A* Rating + final String factionCode = (parameters.getQuality() == IUnitRating.DRAGOON_ASTAR) ? "SL.R" : "SL"; + return generateMechSummary(campaign, parameters, factionCode, getOptions().getStarLeagueYear()); + } + } else { + // Clanners Generate from 2nd Line (or lesser) Tables (core AtB is just 2nd Line, + // but this is more interesting) + if (faction.isClan() && (parameters.getQuality() > IUnitRating.DRAGOON_C)) { + parameters.setQuality(IUnitRating.DRAGOON_C); + } + return generateMechSummary(campaign, parameters, faction.getShortName(), campaign.getGameYear()); + } + } + //endregion Units +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/AbstractPartGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/AbstractPartGenerator.java new file mode 100644 index 0000000000..b90d451a3f --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/AbstractPartGenerator.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.partGenerators; + +import mekhq.campaign.Warehouse; +import mekhq.campaign.parts.Armor; +import mekhq.campaign.parts.Part; +import mekhq.campaign.parts.equipment.AmmoBin; +import mekhq.campaign.unit.Unit; +import mekhq.campaign.universe.enums.PartGenerationMethod; +import mekhq.campaign.work.WorkTime; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Justin "Windchild" Bowen + */ +public abstract class AbstractPartGenerator { + //region Variable Declarations + private final PartGenerationMethod method; + //endregion Variable Declarations + + //region Constructors + protected AbstractPartGenerator(final PartGenerationMethod method) { + this.method = method; + } + //endregion Constructors + + //region Getters + public PartGenerationMethod getMethod() { + return method; + } + //endregion Getters + + /** + * This generates based on the parts from a list of units, optionally excluding armour and + * ammunition. + * + * @param units the list of units to generate parts based off of + * @param includeArmour whether to include armour in the parts generated + * @param includeAmmunition whether to include ammunition in the parts generated + * @return the generated list of parts + */ + public List generate(final List units, final boolean includeArmour, + final boolean includeAmmunition) { + final List parts = new ArrayList<>(); + units.forEach(unit -> unit.getParts().stream() + .filter(part -> (includeArmour || !(part instanceof Armor)) + && (includeAmmunition || !(part instanceof AmmoBin))) + .forEach(parts::add)); + return generate(parts); + } + + /** + * @param inputParts a list of parts, which are not guaranteed to be unique, sorted, nor + * unassigned. Implementors are required to clone the parts as required. + * @return the list of generated parts + */ + public List generate(final List inputParts) { + return generateWarehouse(inputParts).getParts().stream() + .filter(part -> part.getQuantity() > 0).collect(Collectors.toList()); + } + + /** + * @param inputParts a list of parts, which are not guaranteed to be unique, sorted, nor + * unassigned. Implementors are required to clone the parts as required. + * @return a warehouse containing the generated parts + */ + public abstract Warehouse generateWarehouse(final List inputParts); + + /** + * This creates a clone of the input part, with it not being omni-podded if it was originally. + * @param inputPart the input part to clone + * @return the cloned part + */ + protected Part clonePart(final Part inputPart) { + final Part part = inputPart.clone(); + part.setMode(WorkTime.NORMAL); + part.setOmniPodded(false); + return part; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MishraPartGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MishraPartGenerator.java new file mode 100644 index 0000000000..729f5599bd --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MishraPartGenerator.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.partGenerators; + +import megamek.common.Mech; +import mekhq.campaign.Warehouse; +import mekhq.campaign.parts.*; +import mekhq.campaign.parts.equipment.HeatSink; +import mekhq.campaign.parts.equipment.MASC; +import mekhq.campaign.unit.Unit; +import mekhq.campaign.universe.enums.PartGenerationMethod; + +import java.util.List; + +/** + * The Rules for this Generator: + * 1) Remove all non-'Mech Units + * 2) Start with Triple Parts + * 3) Remove all Engines + * 3) All Heat Sinks are capped at 30 per type + * 4) All 'Mech Heads [Sensors, Life Support] are capped at 2 per weight/type + * 5) All Gyros are capped at 1 per weight/type + * 6) MASC is capped at 1 per type + * 7) Any other parts are capped at 6. + * + * @author Justin "Windchild" Bowen + */ +public class MishraPartGenerator extends MultiplePartGenerator { + //region Constructors + public MishraPartGenerator() { + super(PartGenerationMethod.MISHRA, 3); + } + //endregion Constructors + + @Override + public List generate(final List units, final boolean includeArmour, + final boolean includeAmmunition) { + units.removeIf(unit -> !(unit.getEntity() instanceof Mech)); + return super.generate(units, includeArmour, includeAmmunition); + } + + @Override + public Warehouse generateWarehouse(final List inputParts) { + final Warehouse warehouse = super.generateWarehouse(inputParts); + warehouse.getParts().removeIf(part -> part instanceof EnginePart); + warehouse.forEachPart(part -> { + if (part instanceof HeatSink) { + part.setQuantity(Math.min(part.getQuantity(), 30)); + } else if ((part instanceof MekCockpit) || (part instanceof MekLifeSupport) + || (part instanceof MekSensor) + || ((part instanceof MekLocation) && ((MekLocation) part).getLoc() == Mech.LOC_HEAD)) { + part.setQuantity(Math.min(part.getQuantity(), 2)); + } else if ((part instanceof MekGyro) || (part instanceof MASC)) { + part.setQuantity(Math.min(part.getQuantity(), 1)); + } else { + part.setQuantity(Math.min(part.getQuantity(), 6)); + } + }); + return warehouse; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MultiplePartGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MultiplePartGenerator.java new file mode 100644 index 0000000000..8e49cd1333 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/MultiplePartGenerator.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.partGenerators; + +import mekhq.campaign.Warehouse; +import mekhq.campaign.parts.Part; +import mekhq.campaign.universe.enums.PartGenerationMethod; + +import java.util.List; + +/** + * @author Justin "Windchild" Bowen + */ +public class MultiplePartGenerator extends AbstractPartGenerator { + //region Variable Declarations + private final int multiple; + //endregion Variable Declarations + + //region Constructors + public MultiplePartGenerator(final PartGenerationMethod method, final int multiple) { + super(method); + this.multiple = multiple; + } + //endregion Constructors + + //region Getters + public int getMultiple() { + return multiple; + } + //endregion Getters + + @Override + public Warehouse generateWarehouse(final List inputParts) { + final Warehouse warehouse = new Warehouse(); + inputParts.forEach(part -> warehouse.addPart(clonePart(part), true)); + warehouse.forEachPart(part -> part.setQuantity(part.getQuantity() * getMultiple())); + return warehouse; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/WindchildPartGenerator.java b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/WindchildPartGenerator.java new file mode 100644 index 0000000000..f17d74d3b0 --- /dev/null +++ b/MekHQ/src/mekhq/campaign/universe/generators/partGenerators/WindchildPartGenerator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.campaign.universe.generators.partGenerators; + +import mekhq.campaign.Warehouse; +import mekhq.campaign.parts.Part; +import mekhq.campaign.universe.enums.PartGenerationMethod; + +import java.util.List; + +/** + * 1 Part for every 3, rounded normally. + * This means you get 1 part for 2-4 in the input array, plus another for every interval above that. + * + * @author Justin "Windchild" Bowen + */ +public class WindchildPartGenerator extends AbstractPartGenerator { + //region Constructors + public WindchildPartGenerator() { + super(PartGenerationMethod.WINDCHILD); + } + //endregion Constructors + + @Override + public Warehouse generateWarehouse(final List inputParts) { + final Warehouse warehouse = new Warehouse(); + inputParts.forEach(part -> warehouse.addPart(clonePart(part), true)); + warehouse.forEachPart(part -> part.setQuantity((int) Math.round(part.getQuantity() / 3.0))); + return warehouse; + } +} diff --git a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/AbstractFactionSelector.java b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/AbstractFactionSelector.java index 1ae37b7cf0..6281d16392 100644 --- a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/AbstractFactionSelector.java +++ b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/AbstractFactionSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2019-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -18,6 +18,7 @@ */ package mekhq.campaign.universe.selectors.factionSelectors; +import megamek.common.annotations.Nullable; import mekhq.campaign.Campaign; import mekhq.campaign.RandomOriginOptions; import mekhq.campaign.universe.Faction; @@ -56,7 +57,7 @@ public void setOptionsDirect(final RandomOriginOptions options) { * @param campaign The {@link Campaign} within which this {@link Faction} exists. * @return A {@link Faction} selected for {@code campaign}. */ - public abstract Faction selectFaction(final Campaign campaign); + public abstract @Nullable Faction selectFaction(final Campaign campaign); /** * Clears any cache associated with faction selection. diff --git a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/DefaultFactionSelector.java b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/DefaultFactionSelector.java index a112ee86f1..e76bbdbffe 100644 --- a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/DefaultFactionSelector.java +++ b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/DefaultFactionSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2019-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -22,7 +22,6 @@ import mekhq.campaign.Campaign; import mekhq.campaign.RandomOriginOptions; import mekhq.campaign.universe.Faction; -import mekhq.campaign.universe.Factions; /** * Selects a {@link Faction} object. @@ -42,17 +41,6 @@ public DefaultFactionSelector(final RandomOriginOptions options) { super(options); } - /** - * Creates a new DefaultFactionSelector using the specified faction. - * @param options the {@link RandomOriginOptions} to use in faction selection - * @param factionCode The short name of the {@link Faction}. - */ - @Deprecated // Replaced with it being based on Faction - public DefaultFactionSelector(final RandomOriginOptions options, - final @Nullable String factionCode) { - this(options, (factionCode == null) ? null : Factions.getInstance().getFaction(factionCode)); - } - /** * Creates a new DefaultFactionSelector using the specified faction * @param options the {@link RandomOriginOptions} to use in faction selection @@ -75,7 +63,7 @@ public void setFaction(final @Nullable Faction faction) { //endregion Getters/Setters @Override - public Faction selectFaction(final Campaign campaign) { + public @Nullable Faction selectFaction(final Campaign campaign) { return (getFaction() == null) ? campaign.getFaction() : getFaction(); } } diff --git a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/RangedFactionSelector.java b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/RangedFactionSelector.java index e4b7c580de..883e9b721d 100644 --- a/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/RangedFactionSelector.java +++ b/MekHQ/src/mekhq/campaign/universe/selectors/factionSelectors/RangedFactionSelector.java @@ -90,7 +90,7 @@ public void setCachedFactions(final @Nullable WeightedDoubleMap cachedF //endregion Getters/Setters @Override - public Faction selectFaction(final Campaign campaign) { + public @Nullable Faction selectFaction(final Campaign campaign) { final Planet planet = getOptions().determinePlanet(campaign.getCurrentSystem().getPrimaryPlanet()); if ((getCachedFactions() == null) || !planet.equals(getCachedPlanet()) diff --git a/MekHQ/src/mekhq/gui/BriefingTab.java b/MekHQ/src/mekhq/gui/BriefingTab.java index 5714cb86fa..99afe2032c 100644 --- a/MekHQ/src/mekhq/gui/BriefingTab.java +++ b/MekHQ/src/mekhq/gui/BriefingTab.java @@ -32,6 +32,7 @@ import mekhq.campaign.force.Lance; import mekhq.campaign.mission.*; import mekhq.campaign.mission.atb.AtBScenarioFactory; +import mekhq.campaign.mission.enums.MissionStatus; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.SkillType; import mekhq.campaign.personnel.enums.PersonnelRole; @@ -339,9 +340,13 @@ private void completeMission() { return; } - CompleteMissionDialog cmd = new CompleteMissionDialog(getFrame(), true, mission); - cmd.setVisible(true); - if (cmd.getStatus().isActive()) { + final CompleteMissionDialog cmd = new CompleteMissionDialog(getFrame()); + if (!cmd.showDialog().isConfirmed()) { + return; + } + + final MissionStatus status = cmd.getStatus(); + if (status.isActive()) { return; } @@ -383,7 +388,7 @@ && getCampaign().getFinances().getBalance().isGreaterOrEqualThan(rdd.totalPayout } } - getCampaign().completeMission(mission, cmd.getStatus()); + getCampaign().completeMission(mission, status); MekHQ.triggerEvent(new MissionCompletedEvent(mission)); if (getCampaign().getCampaignOptions().getUseAtB() && (mission instanceof AtBContract)) { diff --git a/MekHQ/src/mekhq/gui/CampaignGUI.java b/MekHQ/src/mekhq/gui/CampaignGUI.java index 60f0999317..4e348a998f 100644 --- a/MekHQ/src/mekhq/gui/CampaignGUI.java +++ b/MekHQ/src/mekhq/gui/CampaignGUI.java @@ -120,6 +120,7 @@ public class CampaignGUI extends JPanel { private JMenuItem miShipSearch; private JMenuItem miRetirementDefectionDialog; private JMenuItem miAdvanceMultipleDays; + private JMenuItem miCompanyGenerator; private EnumMap standardTabs; @@ -1020,7 +1021,7 @@ private void initMenu() { //region Manage Campaign Menu // The Manage Campaign menu uses the following Mnemonic keys as of 19-March-2020: - // A, B, G, M, S + // A, B, C, G, M, S JMenu menuManage = new JMenu(resourceMap.getString("menuManageCampaign.text")); menuManage.setMnemonic(KeyEvent.VK_C); menuManage.setName("manageMenu"); @@ -1054,15 +1055,22 @@ private void initMenu() { }); menuManage.add(miScenarioEditor); + miCompanyGenerator = new JMenuItem(resourceMap.getString("miCompanyGenerator.text")); + miCompanyGenerator.setMnemonic(KeyEvent.VK_C); + miCompanyGenerator.setVisible(MekHQ.getMHQOptions().getShowCompanyGenerator()); + miCompanyGenerator.addActionListener(evt -> + new CompanyGenerationDialog(getFrame(), getCampaign()).setVisible(true)); + menuManage.add(miCompanyGenerator); + menuBar.add(menuManage); //endregion Manage Campaign Menu //region Help Menu // The Help menu uses the following Mnemonic keys as of 19-March-2020: // A - JMenu menuHelp = new JMenu(resourceMap.getString("menuHelp.text")); // NOI18N + JMenu menuHelp = new JMenu(resourceMap.getString("menuHelp.text")); menuHelp.setMnemonic(KeyEvent.VK_SLASH); - menuHelp.setName("helpMenu"); // NOI18N + menuHelp.setName("helpMenu"); JMenuItem menuAboutItem = new JMenuItem(resourceMap.getString("menuAbout.text")); menuAboutItem.setMnemonic(KeyEvent.VK_A); @@ -2487,6 +2495,11 @@ public void handlePersonUpdate(PersonEvent ev) { } } + @Subscribe + public void handle(final MekHQOptionsChangedEvent evt) { + miCompanyGenerator.setVisible(MekHQ.getMHQOptions().getShowCompanyGenerator()); + } + public void refreshLocation() { lblLocation.setText(getCampaign().getLocation().getReport(getCampaign().getLocalDate())); } diff --git a/MekHQ/src/mekhq/gui/FileDialogs.java b/MekHQ/src/mekhq/gui/FileDialogs.java index 6291c811e2..eacbb3304a 100644 --- a/MekHQ/src/mekhq/gui/FileDialogs.java +++ b/MekHQ/src/mekhq/gui/FileDialogs.java @@ -281,7 +281,6 @@ public static Optional openScenarioTemplate(JFrame frame) { * @return the file selected, if any */ public static Optional saveScenarioTemplate(JFrame frame, ScenarioTemplate template) { - String fileName = String.format( "%s.xml", //$NON-NLS-1$ template.name); @@ -329,4 +328,31 @@ public static Optional saveStarMap(JFrame frame) { value.ifPresent(x -> MekHQ.getStarMapsDirectory().setValue(x.getParent())); return value; } + + /** + * Displays a dialog window from which the user can select an .xml file to open. + * + * @return the file selected, if any + */ + public static Optional openCompanyGenerationOptions(final JFrame frame) { + Optional value = GUI.fileDialogOpen(frame, "Load Company Generation Options", + FileType.XML, MekHQ.getMHQOptions().getCompanyGenerationDirectoryPath()); + + value.ifPresent(x -> MekHQ.getMHQOptions().setCompanyGenerationDirectoryPath(x.getParent())); + return value; + } + + /** + * Displays a dialog window from which the user can select a .xml file to save to. + * + * @return the file selected, if any + */ + public static Optional saveCompanyGenerationOptions(final JFrame frame) { + Optional value = GUI.fileDialogSave(frame, "Save Company Generation Options", + FileType.XML, MekHQ.getMHQOptions().getCompanyGenerationDirectoryPath(), + "myoptions.xml"); + + value.ifPresent(x -> MekHQ.getMHQOptions().setCompanyGenerationDirectoryPath(x.getParent())); + return value; + } } diff --git a/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java new file mode 100644 index 0000000000..5e327f1e2a --- /dev/null +++ b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationDialog.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.gui.dialog; + +import megamek.client.ui.baseComponents.MMButton; +import megamek.client.ui.enums.ValidationState; +import megamek.common.Entity; +import megamek.common.annotations.Nullable; +import mekhq.MekHQ; +import mekhq.campaign.Campaign; +import mekhq.campaign.event.OrganizationChangedEvent; +import mekhq.campaign.mission.Contract; +import mekhq.campaign.parts.AmmoStorage; +import mekhq.campaign.parts.Armor; +import mekhq.campaign.parts.Part; +import mekhq.campaign.unit.Unit; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationPersonTracker; +import mekhq.campaign.universe.generators.companyGenerators.AbstractCompanyGenerator; +import mekhq.gui.baseComponents.AbstractMHQValidationButtonDialog; +import mekhq.gui.panels.CompanyGenerationOptionsPanel; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * This is currently just a temporary dialog over the CompanyGenerationOptionsPanel. + * Wave 5 will be when this gets redone to be far nicer and more customizable. + * @author Justin "Windchild" Bowen + */ +public class CompanyGenerationDialog extends AbstractMHQValidationButtonDialog { + //region Variable Declarations + private Campaign campaign; + private CompanyGenerationOptions companyGenerationOptions; + private CompanyGenerationOptionsPanel companyGenerationOptionsPanel; + //endregion Variable Declarations + + //region Constructors + public CompanyGenerationDialog(final JFrame frame, final Campaign campaign) { + super(frame, "CompanyGenerationDialog", "CompanyGenerationDialog.title"); + setCampaign(campaign); + setCompanyGenerationOptions(null); + initialize(); + } + //endregion Constructors + + //region Getters/Setters + public Campaign getCampaign() { + return campaign; + } + + public void setCampaign(final Campaign campaign) { + this.campaign = campaign; + } + + public @Nullable CompanyGenerationOptions getCompanyGenerationOptions() { + return companyGenerationOptions; + } + + public void setCompanyGenerationOptions(final @Nullable CompanyGenerationOptions companyGenerationOptions) { + this.companyGenerationOptions = companyGenerationOptions; + } + + public CompanyGenerationOptionsPanel getCompanyGenerationOptionsPanel() { + return companyGenerationOptionsPanel; + } + + public void setCompanyGenerationOptionsPanel(final CompanyGenerationOptionsPanel companyGenerationOptionsPanel) { + this.companyGenerationOptionsPanel = companyGenerationOptionsPanel; + } + //endregion Getters/Setters + + //region Initialization + @Override + protected Container createCenterPane() { + setCompanyGenerationOptionsPanel(new CompanyGenerationOptionsPanel(getFrame(), getCampaign(), + getCompanyGenerationOptions())); + return new JScrollPane(getCompanyGenerationOptionsPanel()); + } + + @Override + protected JPanel createButtonPanel() { + final JPanel panel = new JPanel(new GridLayout(2, 3)); + + setOkButton(new MMButton("btnGenerate", resources, "Generate.text", + "CompanyGenerationDialog.btnGenerate.toolTipText", this::okButtonActionPerformed)); + panel.add(getOkButton()); + + panel.add(new MMButton("btnApply", resources, "Apply.text", + "CompanyGenerationDialog.btnApply.toolTipText", this::okButtonActionPerformed)); + + panel.add(new MMButton("btnCancel", resources, "Cancel.text", + "Cancel.toolTipText", this::cancelActionPerformed)); + + panel.add(new MMButton("btnRestore", resources, "RestoreDefaults.text", + "CompanyGenerationDialog.btnRestore.toolTipText", + evt -> getCompanyGenerationOptionsPanel().setOptions())); + + panel.add(new MMButton("btnImport", resources, "Import.text", + "CompanyGenerationDialog.btnImport.toolTipText", + evt -> getCompanyGenerationOptionsPanel().importOptionsFromXML())); + + panel.add(new MMButton("btnExport", resources, "Export.text", + "CompanyGenerationDialog.btnExport.toolTipText", + evt -> getCompanyGenerationOptionsPanel().exportOptionsToXML())); + + return panel; + } + //endregion Initialization + + @Override + protected void okAction() { + final CompanyGenerationOptions options = getCompanyGenerationOptionsPanel().createOptionsFromPanel(); + final AbstractCompanyGenerator generator = options.getMethod().getGenerator(getCampaign(), options); + + final List trackers = generator.generatePersonnel(getCampaign()); + generator.generateUnitGenerationParameters(trackers); + generator.generateEntities(getCampaign(), trackers); + final List units = generator.applyPhaseOneToCampaign(getCampaign(), trackers); + + final List mothballedEntities = generator.generateMothballedEntities(getCampaign(), trackers); + final List parts = generator.generateSpareParts(units); + final List armour = generator.generateArmour(units); + final List ammunition = generator.generateAmmunition(getCampaign(), units); + units.addAll(generator.applyPhaseTwoToCampaign(getCampaign(), mothballedEntities, parts, armour, ammunition)); + + final Contract contract = null; + generator.applyPhaseThreeToCampaign(getCampaign(), trackers, units, parts, armour, ammunition, contract); + + MekHQ.triggerEvent(new OrganizationChangedEvent(getCompanyGenerationOptionsPanel().getCampaign().getForces())); + } + + @Override + protected ValidationState validateAction(final boolean display) { + return getCompanyGenerationOptionsPanel().validateOptions(display); + } +} diff --git a/MekHQ/src/mekhq/gui/dialog/CompanyGenerationOptionsDialog.java b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationOptionsDialog.java new file mode 100644 index 0000000000..a5602717ea --- /dev/null +++ b/MekHQ/src/mekhq/gui/dialog/CompanyGenerationOptionsDialog.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.gui.dialog; + +import megamek.client.ui.enums.ValidationState; +import megamek.common.annotations.Nullable; +import mekhq.campaign.Campaign; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.gui.baseComponents.AbstractMHQValidationButtonDialog; +import mekhq.gui.panels.CompanyGenerationOptionsPanel; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Justin "Windchild" Bowen + */ +public class CompanyGenerationOptionsDialog extends AbstractMHQValidationButtonDialog { + //region Variable Declarations + private final Campaign campaign; + private final CompanyGenerationOptions companyGenerationOptions; + private CompanyGenerationOptionsPanel companyGenerationOptionsPanel; + //endregion Variable Declarations + + //region Constructors + public CompanyGenerationOptionsDialog(final JFrame frame, final Campaign campaign, + final @Nullable CompanyGenerationOptions companyGenerationOptions) { + super(frame, "CompanyGenerationOptionsDialog", "CompanyGenerationOptionsDialog.title"); + this.campaign = campaign; + this.companyGenerationOptions = companyGenerationOptions; + initialize(); + } + //endregion Constructors + + //region Getters/Setters + public Campaign getCampaign() { + return campaign; + } + + public @Nullable CompanyGenerationOptions getCompanyGenerationOptions() { + return companyGenerationOptions; + } + + public CompanyGenerationOptionsPanel getCompanyGenerationOptionsPanel() { + return companyGenerationOptionsPanel; + } + + public void setCompanyGenerationOptionsPanel(final CompanyGenerationOptionsPanel companyGenerationOptionsPanel) { + this.companyGenerationOptionsPanel = companyGenerationOptionsPanel; + } + //endregion Getters/Setters + + //region Initialization + @Override + protected Container createCenterPane() { + setCompanyGenerationOptionsPanel(new CompanyGenerationOptionsPanel(getFrame(), getCampaign(), + getCompanyGenerationOptions())); + return getCompanyGenerationOptionsPanel(); + } + //endregion Initialization + + //region Button Actions + @Override + protected ValidationState validateAction(final boolean display) { + return getCompanyGenerationOptionsPanel().validateOptions(display); + } + //endregion Button Actions + + public @Nullable CompanyGenerationOptions getSelectedItem() { + return getResult().isConfirmed() ? getCompanyGenerationOptionsPanel().createOptionsFromPanel() + : getCompanyGenerationOptions(); + } +} diff --git a/MekHQ/src/mekhq/gui/dialog/CompleteMissionDialog.java b/MekHQ/src/mekhq/gui/dialog/CompleteMissionDialog.java index fcabf2bcfc..46600dd43c 100644 --- a/MekHQ/src/mekhq/gui/dialog/CompleteMissionDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CompleteMissionDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2020 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2010-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -18,61 +18,53 @@ */ package mekhq.gui.dialog; -import java.awt.*; -import java.util.ResourceBundle; +import megamek.client.ui.baseComponents.MMComboBox; +import mekhq.campaign.mission.enums.MissionStatus; +import mekhq.gui.baseComponents.AbstractMHQButtonDialog; import javax.swing.*; +import javax.swing.GroupLayout.Alignment; +import java.awt.*; -import megamek.common.util.EncodeControl; -import mekhq.MekHQ; -import mekhq.campaign.mission.Mission; -import mekhq.campaign.mission.enums.MissionStatus; -import megamek.client.ui.preferences.JWindowPreference; -import megamek.client.ui.preferences.PreferencesNode; - -public class CompleteMissionDialog extends JDialog { +public class CompleteMissionDialog extends AbstractMHQButtonDialog { //region Variable Declarations - private MissionStatus status; + private MMComboBox comboOutcomeStatus; //endregion Variable Declarations //region Constructors - public CompleteMissionDialog(JFrame parent, boolean modal, Mission mission) { - super(parent, modal); - this.status = mission.getStatus(); - initComponents(); - setLocationRelativeTo(parent); - setUserPreferences(); + public CompleteMissionDialog(final JFrame frame) { + super(frame, "CompleteMissionDialog", "CompleteMissionDialog.title"); + initialize(); } //endregion Constructors - //region Initialization - private void initComponents() { - final ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.CompleteMissionDialog", - MekHQ.getMHQOptions().getLocale(), new EncodeControl()); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setName("Form"); - setTitle(resourceMap.getString("title.text")); - - getContentPane().setLayout(new GridBagLayout()); + //region Getters/Setters + public MMComboBox getComboOutcomeStatus() { + return comboOutcomeStatus; + } - int gridx = 0; - int gridy = 0; + public MissionStatus getStatus() { + final MissionStatus status = getComboOutcomeStatus().getSelectedItem(); + return (status == null) ? MissionStatus.ACTIVE : status; + } - JLabel lblOutcome = new JLabel(resourceMap.getString("lblOutcome.text")); - lblOutcome.setName("lblOutcome"); - GridBagConstraints gridBagConstraints = new GridBagConstraints(); - gridBagConstraints.gridx = gridx++; - gridBagConstraints.gridy = gridy++; - gridBagConstraints.gridwidth = 1; - gridBagConstraints.anchor = GridBagConstraints.WEST; - gridBagConstraints.insets = new Insets(5, 5, 5, 5); - getContentPane().add(lblOutcome, gridBagConstraints); + public void setComboOutcomeStatus(final MMComboBox comboOutcomeStatus) { + this.comboOutcomeStatus = comboOutcomeStatus; + } + //endregion Getters/Setters - DefaultComboBoxModel outcomeModel = new DefaultComboBoxModel<>(MissionStatus.values()); - JComboBox choiceOutcome = new JComboBox<>(outcomeModel); - choiceOutcome.setName("choiceOutcome"); - choiceOutcome.setSelectedItem(getStatus()); - choiceOutcome.setRenderer(new DefaultListCellRenderer() { + //region Initialization + @Override + protected Container createCenterPane() { + // Create Panel Components + final JLabel lblOutcomeStatus = new JLabel(resources.getString("lblOutcomeStatus.text")); + lblOutcomeStatus.setToolTipText(resources.getString("lblOutcomeStatus.toolTipText")); + lblOutcomeStatus.setName("lblOutcomeStatus"); + + setComboOutcomeStatus(new MMComboBox<>("comboOutcomeStatus", MissionStatus.values())); + getComboOutcomeStatus().setToolTipText(resources.getString("lblOutcomeStatus.toolTipText")); + getComboOutcomeStatus().setSelectedItem(MissionStatus.SUCCESS); + getComboOutcomeStatus().setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, @@ -84,44 +76,29 @@ public Component getListCellRendererComponent(final JList list, final Object return this; } }); - gridBagConstraints.gridx = gridx--; - getContentPane().add(choiceOutcome, gridBagConstraints); - JButton btnDone = new JButton(resourceMap.getString("btnDone.text")); - btnDone.setName("btnDone"); - btnDone.addActionListener(evt -> { - status = (MissionStatus) choiceOutcome.getSelectedItem(); - setVisible(false); - }); - gridBagConstraints.gridy = gridy++; - gridBagConstraints.gridx = gridx++; - gridBagConstraints.anchor = GridBagConstraints.CENTER; - getContentPane().add(btnDone, gridBagConstraints); + // Layout the Panel + final JPanel panel = new JPanel(); + panel.setName("completeMissionPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); - JButton btnCancel = new JButton(resourceMap.getString("btnCancel.text")); - btnCancel.setName("btnCancel"); - btnCancel.addActionListener(evt -> { - status = MissionStatus.ACTIVE; - setVisible(false); - }); - gridBagConstraints = new GridBagConstraints(); - gridBagConstraints.gridx = gridx; - getContentPane().add(btnCancel, gridBagConstraints); + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); - pack(); - } + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(lblOutcomeStatus) + .addComponent(getComboOutcomeStatus()) + ); - private void setUserPreferences() { - PreferencesNode preferences = MekHQ.getMHQPreferences().forClass(CompleteMissionDialog.class); + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(lblOutcomeStatus) + .addComponent(getComboOutcomeStatus()) + ); - this.setName("dialog"); - preferences.manage(new JWindowPreference(this)); + return panel; } //endregion Initialization - - //region Getters/Setters - public MissionStatus getStatus() { - return status; - } - //endregion Getters/Setters } diff --git a/MekHQ/src/mekhq/gui/dialog/CreateCampaignPresetDialog.java b/MekHQ/src/mekhq/gui/dialog/CreateCampaignPresetDialog.java index 711d578a6d..9a07074cce 100644 --- a/MekHQ/src/mekhq/gui/dialog/CreateCampaignPresetDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CreateCampaignPresetDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -41,6 +41,7 @@ import mekhq.campaign.universe.Factions; import mekhq.campaign.universe.Planet; import mekhq.campaign.universe.PlanetarySystem; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; import mekhq.gui.baseComponents.AbstractMHQValidationButtonDialog; import mekhq.gui.baseComponents.SortedComboBoxModel; import mekhq.gui.displayWrappers.FactionDisplay; @@ -55,6 +56,9 @@ import java.util.Hashtable; import java.util.stream.Collectors; +/** + * @author Justin "Windchild" Bowen + */ public class CreateCampaignPresetDialog extends AbstractMHQValidationButtonDialog { //region Variable Declarations private final Campaign campaign; @@ -75,6 +79,8 @@ public class CreateCampaignPresetDialog extends AbstractMHQValidationButtonDialo private JCheckBox chkSpecifyRankSystem; private MMComboBox comboRankSystem; private JSpinner spnContractCount; + private JCheckBox chkSpecifyCompanyGenerationOptions; + private CompanyGenerationOptions companyGenerationOptions; //endregion Startup //region Continuous @@ -95,6 +101,7 @@ public CreateCampaignPresetDialog(final JFrame frame, final Campaign campaign, this.campaign = campaign; setPreset(preset); setDate(campaign.getLocalDate()); + setCompanyGenerationOptions(null); this.gameOptions = ((preset == null) || (preset.getGameOptions() == null)) ? campaign.getGameOptions() : preset.getGameOptions(); this.campaignOptions = ((preset == null) || (preset.getCampaignOptions() == null)) @@ -244,6 +251,22 @@ public JSpinner getSpnContractCount() { public void setSpnContractCount(final JSpinner spnContractCount) { this.spnContractCount = spnContractCount; } + + public JCheckBox getChkSpecifyCompanyGenerationOptions() { + return chkSpecifyCompanyGenerationOptions; + } + + public void setChkSpecifyCompanyGenerationOptions(final JCheckBox chkSpecifyCompanyGenerationOptions) { + this.chkSpecifyCompanyGenerationOptions = chkSpecifyCompanyGenerationOptions; + } + + public @Nullable CompanyGenerationOptions getCompanyGenerationOptions() { + return companyGenerationOptions; + } + + public void setCompanyGenerationOptions(final @Nullable CompanyGenerationOptions companyGenerationOptions) { + this.companyGenerationOptions = companyGenerationOptions; + } //endregion Startup //region Continuous @@ -469,6 +492,16 @@ public Component getListCellRendererComponent(final JList list, final Object getSpnContractCount().setToolTipText(resources.getString("lblContractCount.toolTipText")); getSpnContractCount().setName("spnContractCount"); + setChkSpecifyCompanyGenerationOptions(new JCheckBox(resources.getString("chkSpecifyCompanyGenerationOptions.text"))); + getChkSpecifyCompanyGenerationOptions().setToolTipText(resources.getString("chkSpecifyCompanyGenerationOptions.toolTipText")); + getChkSpecifyCompanyGenerationOptions().setName("chkSpecifyCompanyGenerationOptions"); + + final JButton btnCompanyGenerationOptions = new MMButton("btnCompanyGenerationOptions", + resources, "btnCompanyGenerationOptions.text", + "btnCompanyGenerationOptions.toolTipText", evt -> setCompanyGenerationOptions( + new CompanyGenerationOptionsDialog(getFrame(), getCampaign(), + getCompanyGenerationOptions()).getSelectedItem())); + // Disable Panel Portions by Default getChkSpecifyDate().setSelected(true); getChkSpecifyDate().doClick(); @@ -510,6 +543,9 @@ public Component getListCellRendererComponent(final JList list, final Object .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(lblContractCount) .addComponent(getSpnContractCount(), GroupLayout.Alignment.LEADING)) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(getChkSpecifyCompanyGenerationOptions()) + .addComponent(btnCompanyGenerationOptions, GroupLayout.Alignment.LEADING)) ); layout.setHorizontalGroup( @@ -532,6 +568,9 @@ public Component getListCellRendererComponent(final JList list, final Object .addGroup(layout.createSequentialGroup() .addComponent(lblContractCount) .addComponent(getSpnContractCount())) + .addGroup(layout.createSequentialGroup() + .addComponent(getChkSpecifyCompanyGenerationOptions()) + .addComponent(btnCompanyGenerationOptions)) ); return panel; @@ -542,7 +581,6 @@ private JPanel createContinuousPanel() { setChkSpecifyGameOptions(new JCheckBox(resources.getString("chkSpecifyGameOptions.text"))); getChkSpecifyGameOptions().setToolTipText(resources.getString("chkSpecifyGameOptions.toolTipText")); getChkSpecifyGameOptions().setName("chkSpecifyGameOptions"); - getChkSpecifyRankSystem().addActionListener(evt -> getComboRankSystem().setEnabled(getChkSpecifyRankSystem().isSelected())); final JButton btnGameOptions = new MMButton("btnGameOptions", resources, "btnGameOptions.text", "btnGameOptions.toolTipText", evt -> { @@ -614,6 +652,7 @@ protected void setCustomPreferences(final PreferencesNode preferences) { preferences.manage(new JToggleButtonPreference(getChkSpecifyPlanet())); preferences.manage(new JToggleButtonPreference(getChkSpecifyRankSystem())); preferences.manage(new JIntNumberSpinnerPreference(getSpnContractCount())); + preferences.manage(new JToggleButtonPreference(getChkSpecifyCompanyGenerationOptions())); preferences.manage(new JToggleButtonPreference(getChkSpecifyGameOptions())); preferences.manage(new JToggleButtonPreference(getChkSpecifyCampaignOptions())); } @@ -622,7 +661,47 @@ protected void setCustomPreferences(final PreferencesNode preferences) { //region Button Actions @Override protected void okAction() { - updatePreset(); + if (!getState().isSuccess()) { + validateButtonActionPerformed(null); + } + + if (getState().isSuccess() || getState().isWarning()) { + setPreset(new CampaignPreset()); + + getPreset().setTitle(getTxtPresetName().getText().trim()); + getPreset().setDescription(getTxtPresetDescription().getText().trim()); + if (getChkSpecifyDate().isSelected()) { + getPreset().setDate(getDate()); + } + + if (getChkSpecifyFaction().isSelected()) { + final FactionDisplay factionDisplay = getComboFaction().getSelectedItem(); + getPreset().setFaction((factionDisplay == null) ? null : factionDisplay.getFaction()); + } + + if (getChkSpecifyPlanet().isSelected()) { + getPreset().setPlanet(getComboStartingPlanet().getSelectedItem()); + } + + if (getChkSpecifyRankSystem().isSelected()) { + getPreset().setRankSystem(getComboRankSystem().getSelectedItem()); + } + getPreset().setContractCount((int) getSpnContractCount().getValue()); + if (getChkSpecifyCompanyGenerationOptions().isSelected()) { + getPreset().setCompanyGenerationOptions(getCompanyGenerationOptions()); + } + + if (getChkSpecifyGameOptions().isSelected()) { + getPreset().setGameOptions(getGameOptions()); + } + + if (getChkSpecifyCampaignOptions().isSelected()) { + getPreset().setCampaignOptions(getCampaignOptions()); + getPreset().setRandomSkillPreferences(getRandomSkillPreferences()); + getPreset().setSkills(getSkills()); + getPreset().setSpecialAbilities(getSpecialAbilities()); + } + } } @Override @@ -688,46 +767,4 @@ private PlanetarySystem[] getPlanetarySystems(final @Nullable FactionDisplay fac .sorted(Comparator.comparing(p -> p.getName(getCampaign().getLocalDate()))) .collect(Collectors.toList()).toArray(new PlanetarySystem[]{}); } - - public void updatePreset() { - if (!getState().isSuccess()) { - validateButtonActionPerformed(null); - } - - if (getState().isSuccess() || getState().isWarning()) { - if (getPreset() == null) { - setPreset(new CampaignPreset()); - } - - getPreset().setTitle(getTxtPresetName().getText().trim()); - getPreset().setDescription(getTxtPresetDescription().getText().trim()); - if (getChkSpecifyDate().isSelected()) { - getPreset().setDate(getDate()); - } - - if (getChkSpecifyFaction().isSelected()) { - final FactionDisplay factionDisplay = getComboFaction().getSelectedItem(); - getPreset().setFaction((factionDisplay == null) ? null : factionDisplay.getFaction()); - } - - if (getChkSpecifyPlanet().isSelected()) { - getPreset().setPlanet(getComboStartingPlanet().getSelectedItem()); - } - - if (getChkSpecifyRankSystem().isSelected()) { - getPreset().setRankSystem(getComboRankSystem().getSelectedItem()); - } - getPreset().setContractCount((int) getSpnContractCount().getValue()); - if (getChkSpecifyGameOptions().isSelected()) { - getPreset().setGameOptions(getGameOptions()); - } - - if (getChkSpecifyCampaignOptions().isSelected()) { - getPreset().setCampaignOptions(getCampaignOptions()); - getPreset().setRandomSkillPreferences(getRandomSkillPreferences()); - getPreset().setSkills(getSkills()); - getPreset().setSpecialAbilities(getSpecialAbilities()); - } - } - } } diff --git a/MekHQ/src/mekhq/gui/dialog/CustomizeScenarioDialog.java b/MekHQ/src/mekhq/gui/dialog/CustomizeScenarioDialog.java index 1019dbe993..80b4e47c12 100644 --- a/MekHQ/src/mekhq/gui/dialog/CustomizeScenarioDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CustomizeScenarioDialog.java @@ -114,7 +114,7 @@ public CustomizeScenarioDialog(JFrame parent, boolean modal, Scenario s, Mission } private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; + java.awt.GridBagConstraints gridBagConstraints; txtName = new javax.swing.JTextField(); lblName = new javax.swing.JLabel(); diff --git a/MekHQ/src/mekhq/gui/dialog/MekHqOptionsDialog.java b/MekHQ/src/mekhq/gui/dialog/MekHqOptionsDialog.java index 4b8a74bacb..cb07af2333 100644 --- a/MekHQ/src/mekhq/gui/dialog/MekHqOptionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/MekHqOptionsDialog.java @@ -24,6 +24,7 @@ import mekhq.MekHQ; import mekhq.MHQConstants; import mekhq.campaign.event.MekHQOptionsChangedEvent; +import mekhq.campaign.universe.enums.CompanyGenerationMethod; import mekhq.gui.baseComponents.AbstractMHQButtonDialog; import mekhq.gui.enums.ForceIconOperationalStatusStyle; import mekhq.gui.enums.PersonnelFilterStyle; @@ -42,6 +43,8 @@ public class MekHqOptionsDialog extends AbstractMHQButtonDialog { private JTextField optionDisplayDateFormat; private JTextField optionLongDisplayDateFormat; private JCheckBox optionHistoricalDailyLog; + private JCheckBox chkCompanyGeneratorStartup; + private JCheckBox chkShowCompanyGenerator; //region Command Center Display private JCheckBox optionCommandCenterUseUnitMarket; @@ -124,9 +127,10 @@ public class MekHqOptionsDialog extends AbstractMHQButtonDialog { //endregion Nag Tab //region Miscellaneous - private JSpinner optionStartGameDelay; + private JSpinner spnStartGameDelay; + private MMComboBox comboDefaultCompanyGenerationMethod; //endregion Miscellaneous - //endregion Variable Declaration + //endregion Variable Declarations //region Constructors public MekHqOptionsDialog(final JFrame frame) { @@ -159,7 +163,7 @@ protected Container createCenterPane() { } private JPanel createDisplayTab() { - //region Create Graphical Segments + // Create Panel Components JLabel labelDisplayDateFormat = new JLabel(resources.getString("labelDisplayDateFormat.text")); JLabel labelDisplayDateFormatExample = new JLabel(); optionDisplayDateFormat = new JTextField(); @@ -181,6 +185,14 @@ private JPanel createDisplayTab() { optionHistoricalDailyLog = new JCheckBox(resources.getString("optionHistoricalDailyLog.text")); optionHistoricalDailyLog.setToolTipText(resources.getString("optionHistoricalDailyLog.toolTipText")); + chkCompanyGeneratorStartup = new JCheckBox(resources.getString("chkCompanyGeneratorStartup.text")); + chkCompanyGeneratorStartup.setToolTipText(resources.getString("chkCompanyGeneratorStartup.toolTipText")); + chkCompanyGeneratorStartup.setName("chkCompanyGeneratorStartup"); + + chkShowCompanyGenerator = new JCheckBox(resources.getString("chkShowCompanyGenerator.text")); + chkShowCompanyGenerator.setToolTipText(resources.getString("chkShowCompanyGenerator.toolTipText")); + chkShowCompanyGenerator.setName("chkShowCompanyGenerator"); + //region Command Center Display JLabel labelCommandCenterDisplay = new JLabel(resources.getString("labelCommandCenterDisplay.text")); @@ -213,9 +225,7 @@ public Component getListCellRendererComponent(final JList list, final Object optionPersonnelFilterOnPrimaryRole = new JCheckBox(resources.getString("optionPersonnelFilterOnPrimaryRole.text")); //endregion Personnel Tab Display Options - //endregion Create Graphical Components - //region Layout // Layout the UI JPanel body = new JPanel(); GroupLayout layout = new GroupLayout(body); @@ -235,6 +245,8 @@ public Component getListCellRendererComponent(final JList list, final Object .addComponent(optionLongDisplayDateFormat) .addComponent(labelLongDisplayDateFormatExample, GroupLayout.Alignment.TRAILING)) .addComponent(optionHistoricalDailyLog) + .addComponent(chkCompanyGeneratorStartup) + .addComponent(chkShowCompanyGenerator) .addComponent(labelCommandCenterDisplay) .addComponent(optionCommandCenterUseUnitMarket) .addComponent(optionCommandCenterMRMS) @@ -257,6 +269,8 @@ public Component getListCellRendererComponent(final JList list, final Object .addComponent(optionLongDisplayDateFormat) .addComponent(labelLongDisplayDateFormatExample)) .addComponent(optionHistoricalDailyLog) + .addComponent(chkCompanyGeneratorStartup) + .addComponent(chkShowCompanyGenerator) .addComponent(labelCommandCenterDisplay) .addComponent(optionCommandCenterUseUnitMarket) .addComponent(optionCommandCenterMRMS) @@ -266,7 +280,6 @@ public Component getListCellRendererComponent(final JList list, final Object .addComponent(optionPersonnelFilterStyle)) .addComponent(optionPersonnelFilterOnPrimaryRole) ); - //endregion Layout return body; } @@ -456,7 +469,7 @@ private JPanel createDisplayColourTab() { } private JPanel createAutosaveTab() { - //region Create Graphical Components + // Create Panel Components optionNoSave = new JRadioButton(resources.getString("optionNoSave.text")); optionNoSave.setMnemonic(KeyEvent.VK_N); @@ -485,9 +498,7 @@ private JPanel createAutosaveTab() { JLabel labelSavedGamesCount = new JLabel(resources.getString("labelSavedGamesCount.text")); spinnerSavedGamesCount = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1)); labelSavedGamesCount.setLabelFor(spinnerSavedGamesCount); - //endregion Create Graphical Components - //region Layout // Layout the UI JPanel body = new JPanel(); GroupLayout layout = new GroupLayout(body); @@ -522,7 +533,6 @@ private JPanel createAutosaveTab() { .addComponent(labelSavedGamesCount) .addComponent(spinnerSavedGamesCount)) ); - //endregion Layout return body; } @@ -615,7 +625,7 @@ public Component getListCellRendererComponent(final JList list, final Object } private JPanel createCampaignXMLSaveTab() { - //region Create Graphical Components + // Create Panel Components optionPreferGzippedOutput = new JCheckBox(resources.getString("optionPreferGzippedOutput.text")); optionPreferGzippedOutput.setToolTipText(resources.getString("optionPreferGzippedOutput.toolTipText")); @@ -625,9 +635,7 @@ private JPanel createCampaignXMLSaveTab() { optionSaveMothballState = new JCheckBox(resources.getString("optionSaveMothballState.text")); optionSaveMothballState.setToolTipText(resources.getString("optionSaveMothballState.toolTipText")); optionSaveMothballState.setMnemonic(KeyEvent.VK_U); - //endregion Create Graphical Components - //region Layout // Layout the UI JPanel body = new JPanel(); GroupLayout layout = new GroupLayout(body); @@ -649,7 +657,6 @@ private JPanel createCampaignXMLSaveTab() { .addComponent(optionWriteCustomsToXML) .addComponent(optionSaveMothballState) ); - //endregion Layout return body; } @@ -718,15 +725,31 @@ private JPanel createNagTab() { } private JPanel createMiscellaneousTab() { - //region Create Graphical Components - JLabel labelStartGameDelay = new JLabel(resources.getString("labelStartGameDelay.text")); - labelStartGameDelay.setToolTipText(resources.getString("optionStartGameDelay.toolTipText")); + // Create Panel Components + final JLabel lblStartGameDelay = new JLabel(resources.getString("lblStartGameDelay.text")); + lblStartGameDelay.setToolTipText(resources.getString("lblStartGameDelay.toolTipText")); - optionStartGameDelay = new JSpinner(new SpinnerNumberModel(0, 0, 2500, 25)); - optionStartGameDelay.setToolTipText(resources.getString("optionStartGameDelay.toolTipText")); - //endregion Create Graphical Components + spnStartGameDelay = new JSpinner(new SpinnerNumberModel(0, 0, 2500, 25)); + spnStartGameDelay.setToolTipText(resources.getString("lblStartGameDelay.toolTipText")); + + final JLabel lblDefaultCompanyGenerationMethod = new JLabel(resources.getString("lblDefaultCompanyGenerationMethod.text")); + lblDefaultCompanyGenerationMethod.setToolTipText(resources.getString("lblDefaultCompanyGenerationMethod.toolTipText")); + + comboDefaultCompanyGenerationMethod = new MMComboBox<>("comboDefaultCompanyGenerationMethod", CompanyGenerationMethod.values()); + comboDefaultCompanyGenerationMethod.setToolTipText(resources.getString("lblDefaultCompanyGenerationMethod.toolTipText")); + comboDefaultCompanyGenerationMethod.setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof CompanyGenerationMethod) { + list.setToolTipText(((CompanyGenerationMethod) value).getToolTipText()); + } + return this; + } + }); - //region Layout // Layout the UI JPanel body = new JPanel(); GroupLayout layout = new GroupLayout(body); @@ -738,18 +761,23 @@ private JPanel createMiscellaneousTab() { layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(labelStartGameDelay) - .addComponent(optionStartGameDelay, GroupLayout.DEFAULT_SIZE, + .addComponent(lblStartGameDelay) + .addComponent(spnStartGameDelay, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 40)) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(lblDefaultCompanyGenerationMethod) + .addComponent(comboDefaultCompanyGenerationMethod)) ); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(labelStartGameDelay) - .addComponent(optionStartGameDelay)) + .addComponent(lblStartGameDelay) + .addComponent(spnStartGameDelay)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblDefaultCompanyGenerationMethod) + .addComponent(comboDefaultCompanyGenerationMethod)) ); - //endregion Layout return body; } @@ -760,10 +788,13 @@ protected void okAction() { if (validateDateFormat(optionDisplayDateFormat.getText())) { MekHQ.getMHQOptions().setDisplayDateFormat(optionDisplayDateFormat.getText()); } + if (validateDateFormat(optionLongDisplayDateFormat.getText())) { MekHQ.getMHQOptions().setLongDisplayDateFormat(optionLongDisplayDateFormat.getText()); } MekHQ.getMHQOptions().setHistoricalDailyLog(optionHistoricalDailyLog.isSelected()); + MekHQ.getMHQOptions().setCompanyGeneratorStartup(chkCompanyGeneratorStartup.isSelected()); + MekHQ.getMHQOptions().setShowCompanyGenerator(chkShowCompanyGenerator.isSelected()); MekHQ.getMHQOptions().setCommandCenterUseUnitMarket(optionCommandCenterUseUnitMarket.isSelected()); MekHQ.getMHQOptions().setCommandCenterMRMS(optionCommandCenterMRMS.isSelected()); MekHQ.getMHQOptions().setPersonnelFilterStyle((PersonnelFilterStyle) Objects.requireNonNull(optionPersonnelFilterStyle.getSelectedItem())); @@ -828,7 +859,8 @@ protected void okAction() { MekHQ.getMHQOptions().setNagDialogIgnore(MHQConstants.NAG_UNRESOLVED_STRATCON_CONTACTS, optionUnresolvedStratConContactsNag.isSelected()); MekHQ.getMHQOptions().setNagDialogIgnore(MHQConstants.NAG_OUTSTANDING_SCENARIOS, optionOutstandingScenariosNag.isSelected()); - MekHQ.getMHQOptions().setStartGameDelay((Integer) optionStartGameDelay.getValue()); + MekHQ.getMHQOptions().setStartGameDelay((Integer) spnStartGameDelay.getValue()); + MekHQ.getMHQOptions().setDefaultCompanyGenerationMethod(Objects.requireNonNull(comboDefaultCompanyGenerationMethod.getSelectedItem())); MekHQ.triggerEvent(new MekHQOptionsChangedEvent()); } @@ -837,6 +869,8 @@ private void setInitialState() { optionDisplayDateFormat.setText(MekHQ.getMHQOptions().getDisplayDateFormat()); optionLongDisplayDateFormat.setText(MekHQ.getMHQOptions().getLongDisplayDateFormat()); optionHistoricalDailyLog.setSelected(MekHQ.getMHQOptions().getHistoricalDailyLog()); + chkCompanyGeneratorStartup.setSelected(MekHQ.getMHQOptions().getCompanyGeneratorStartup()); + chkShowCompanyGenerator.setSelected(MekHQ.getMHQOptions().getShowCompanyGenerator()); optionCommandCenterUseUnitMarket.setSelected(MekHQ.getMHQOptions().getCommandCenterUseUnitMarket()); optionCommandCenterMRMS.setSelected(MekHQ.getMHQOptions().getCommandCenterMRMS()); optionPersonnelFilterStyle.setSelectedItem(MekHQ.getMHQOptions().getPersonnelFilterStyle()); @@ -903,7 +937,8 @@ private void setInitialState() { optionUnresolvedStratConContactsNag.setSelected(MekHQ.getMHQOptions().getNagDialogIgnore(MHQConstants.NAG_UNRESOLVED_STRATCON_CONTACTS)); optionOutstandingScenariosNag.setSelected(MekHQ.getMHQOptions().getNagDialogIgnore(MHQConstants.NAG_OUTSTANDING_SCENARIOS)); - optionStartGameDelay.setValue(MekHQ.getMHQOptions().getStartGameDelay()); + spnStartGameDelay.setValue(MekHQ.getMHQOptions().getStartGameDelay()); + comboDefaultCompanyGenerationMethod.setSelectedItem(MekHQ.getMHQOptions().getDefaultCompanyGenerationMethod()); } //region Data Validation diff --git a/MekHQ/src/mekhq/gui/panels/CompanyGenerationOptionsPanel.java b/MekHQ/src/mekhq/gui/panels/CompanyGenerationOptionsPanel.java new file mode 100644 index 0000000000..bad72e5e86 --- /dev/null +++ b/MekHQ/src/mekhq/gui/panels/CompanyGenerationOptionsPanel.java @@ -0,0 +1,2196 @@ +/* + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.gui.panels; + +import megamek.client.ui.baseComponents.MMComboBox; +import megamek.client.ui.enums.ValidationState; +import megamek.common.EntityWeightClass; +import megamek.common.annotations.Nullable; +import mekhq.MekHQ; +import mekhq.campaign.Campaign; +import mekhq.campaign.personnel.enums.PersonnelRole; +import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; +import mekhq.campaign.universe.enums.*; +import mekhq.gui.FileDialogs; +import mekhq.gui.baseComponents.AbstractMHQPanel; +import mekhq.gui.baseComponents.JDisableablePanel; + +import javax.swing.*; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JSpinner.NumberEditor; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +/** + * @author Justin "Windchild" Bowen + */ +public class CompanyGenerationOptionsPanel extends AbstractMHQPanel { + //region Variable Declarations + private final Campaign campaign; + + // Base Information + private MMComboBox comboCompanyGenerationMethod; + private JCheckBox chkGenerateMercenaryCompanyCommandLance; + private JSpinner spnCompanyCount; + private JSpinner spnIndividualLanceCount; + private JSpinner spnLancesPerCompany; + private JSpinner spnLanceSize; + private JSpinner spnStarLeagueYear; + + // Personnel + private JLabel lblTotalSupportPersonnel; + private Map spnSupportPersonnelNumbers; + private JCheckBox chkPoolAssistants; + private JCheckBox chkGenerateCaptains; + private JCheckBox chkAssignCompanyCommanderFlag; + private JCheckBox chkApplyOfficerStatBonusToWorstSkill; + private JCheckBox chkAssignBestCompanyCommander; + private JCheckBox chkPrioritizeCompanyCommanderCombatSkills; + private JCheckBox chkAssignBestOfficers; + private JCheckBox chkPrioritizeOfficerCombatSkills; + private JCheckBox chkAssignMostSkilledToPrimaryLances; + private JCheckBox chkAutomaticallyAssignRanks; + private JCheckBox chkAssignFounderFlag; + + // Personnel Randomization + private RandomOriginOptionsPanel randomOriginOptionsPanel; + + // Starting Simulation + private JCheckBox chkRunStartingSimulation; + private JSpinner spnSimulationDuration; + private JCheckBox chkSimulateRandomMarriages; + private JCheckBox chkSimulateRandomProcreation; + + // Units + private MMComboBox comboBattleMechWeightClassGenerationMethod; + private MMComboBox comboBattleMechQualityGenerationMethod; + private JCheckBox chkNeverGenerateStarLeagueMechs; + private JCheckBox chkOnlyGenerateStarLeagueMechs; + private JCheckBox chkOnlyGenerateOmniMechs; + private JCheckBox chkGenerateUnitsAsAttached; + private JCheckBox chkAssignBestRollToCompanyCommander; + private JCheckBox chkSortStarLeagueUnitsFirst; + private JCheckBox chkGroupByWeight; + private JCheckBox chkGroupByQuality; + private JCheckBox chkKeepOfficerRollsSeparate; + private JCheckBox chkAssignTechsToUnits; + + // Unit + private MMComboBox comboForceNamingMethod; + private JCheckBox chkGenerateForceIcons; + private JCheckBox chkGenerateOriginNodeForceIcon; + private JCheckBox chkUseOriginNodeForceIconLogo; + private Map spnForceWeightLimits; + + // Spares + private JCheckBox chkGenerateMothballedSpareUnits; + private JSpinner spnSparesPercentOfActiveUnits; + private MMComboBox comboPartGenerationMethod; + private JSpinner spnStartingArmourWeight; + private JCheckBox chkGenerateSpareAmmunition; + private JSpinner spnNumberReloadsPerWeapon; + private JCheckBox chkGenerateFractionalMachineGunAmmunition; + + // Contracts + private JCheckBox chkSelectStartingContract; + private JCheckBox chkStartCourseToContractPlanet; + + // Finances + private JCheckBox chkProcessFinances; + private JSpinner spnStartingCash; + private JCheckBox chkRandomizeStartingCash; + private JSpinner spnRandomStartingCashDiceCount; + private JSpinner spnMinimumStartingFloat; + private JCheckBox chkIncludeInitialContractPayment; + private JCheckBox chkStartingLoan; + private JCheckBox chkPayForSetup; + private JCheckBox chkPayForPersonnel; + private JCheckBox chkPayForUnits; + private JCheckBox chkPayForParts; + private JCheckBox chkPayForArmour; + private JCheckBox chkPayForAmmunition; + + // Surprises + private JCheckBox chkGenerateSurprises; + private JCheckBox chkGenerateMysteryBoxes; + private Map chkGenerateMysteryBoxTypes; + //endregion Variable Declarations + + //region Constructors + public CompanyGenerationOptionsPanel(final JFrame frame, final Campaign campaign, + final @Nullable CompanyGenerationOptions companyGenerationOptions) { + super(frame, "CompanyGenerationOptionsPanel", new GridBagLayout()); + this.campaign = campaign; + + initialize(); + + if (companyGenerationOptions == null) { + setOptions(MekHQ.getMHQOptions().getDefaultCompanyGenerationMethod()); + } else { + setOptions(companyGenerationOptions); + } + } + //endregion Constructors + + //region Getters/Setters + public Campaign getCampaign() { + return campaign; + } + + //region Base Information + public MMComboBox getComboCompanyGenerationMethod() { + return comboCompanyGenerationMethod; + } + + public void setComboCompanyGenerationMethod(final MMComboBox comboCompanyGenerationMethod) { + this.comboCompanyGenerationMethod = comboCompanyGenerationMethod; + } + + public JCheckBox getChkGenerateMercenaryCompanyCommandLance() { + return chkGenerateMercenaryCompanyCommandLance; + } + + public void setChkGenerateMercenaryCompanyCommandLance(final JCheckBox chkGenerateMercenaryCompanyCommandLance) { + this.chkGenerateMercenaryCompanyCommandLance = chkGenerateMercenaryCompanyCommandLance; + } + + public JSpinner getSpnCompanyCount() { + return spnCompanyCount; + } + + public void setSpnCompanyCount(final JSpinner spnCompanyCount) { + this.spnCompanyCount = spnCompanyCount; + } + + public JSpinner getSpnIndividualLanceCount() { + return spnIndividualLanceCount; + } + + public void setSpnIndividualLanceCount(final JSpinner spnIndividualLanceCount) { + this.spnIndividualLanceCount = spnIndividualLanceCount; + } + + public JSpinner getSpnLancesPerCompany() { + return spnLancesPerCompany; + } + + public void setSpnLancesPerCompany(final JSpinner spnLancesPerCompany) { + this.spnLancesPerCompany = spnLancesPerCompany; + } + + public JSpinner getSpnLanceSize() { + return spnLanceSize; + } + + public void setSpnLanceSize(final JSpinner spnLanceSize) { + this.spnLanceSize = spnLanceSize; + } + + public JSpinner getSpnStarLeagueYear() { + return spnStarLeagueYear; + } + + public void setSpnStarLeagueYear(final JSpinner spnStarLeagueYear) { + this.spnStarLeagueYear = spnStarLeagueYear; + } + //endregion Base Information + + //region Personnel + public JLabel getLblTotalSupportPersonnel() { + return lblTotalSupportPersonnel; + } + + public void updateLblTotalSupportPersonnel(final int numSupportPersonnel) { + getLblTotalSupportPersonnel().setText(String.format( + resources.getString("lblTotalSupportPersonnel.text"), numSupportPersonnel)); + } + + public void setLblTotalSupportPersonnel(final JLabel lblTotalSupportPersonnel) { + this.lblTotalSupportPersonnel = lblTotalSupportPersonnel; + } + + public Map getSpnSupportPersonnelNumbers() { + return spnSupportPersonnelNumbers; + } + + public void setSpnSupportPersonnelNumbers(final Map spnSupportPersonnelNumbers) { + this.spnSupportPersonnelNumbers = spnSupportPersonnelNumbers; + } + + public JCheckBox getChkPoolAssistants() { + return chkPoolAssistants; + } + + public void setChkPoolAssistants(final JCheckBox chkPoolAssistants) { + this.chkPoolAssistants = chkPoolAssistants; + } + + public JCheckBox getChkGenerateCaptains() { + return chkGenerateCaptains; + } + + public void setChkGenerateCaptains(final JCheckBox chkGenerateCaptains) { + this.chkGenerateCaptains = chkGenerateCaptains; + } + + public JCheckBox getChkAssignCompanyCommanderFlag() { + return chkAssignCompanyCommanderFlag; + } + + public void setChkAssignCompanyCommanderFlag(final JCheckBox chkAssignCompanyCommanderFlag) { + this.chkAssignCompanyCommanderFlag = chkAssignCompanyCommanderFlag; + } + + public JCheckBox getChkApplyOfficerStatBonusToWorstSkill() { + return chkApplyOfficerStatBonusToWorstSkill; + } + + public void setChkApplyOfficerStatBonusToWorstSkill(final JCheckBox chkApplyOfficerStatBonusToWorstSkill) { + this.chkApplyOfficerStatBonusToWorstSkill = chkApplyOfficerStatBonusToWorstSkill; + } + + public JCheckBox getChkAssignBestCompanyCommander() { + return chkAssignBestCompanyCommander; + } + + public void setChkAssignBestCompanyCommander(final JCheckBox chkAssignBestCompanyCommander) { + this.chkAssignBestCompanyCommander = chkAssignBestCompanyCommander; + } + + public JCheckBox getChkPrioritizeCompanyCommanderCombatSkills() { + return chkPrioritizeCompanyCommanderCombatSkills; + } + + public void setChkPrioritizeCompanyCommanderCombatSkills(final JCheckBox chkPrioritizeCompanyCommanderCombatSkills) { + this.chkPrioritizeCompanyCommanderCombatSkills = chkPrioritizeCompanyCommanderCombatSkills; + } + + public JCheckBox getChkAssignBestOfficers() { + return chkAssignBestOfficers; + } + + public void setChkAssignBestOfficers(final JCheckBox chkAssignBestOfficers) { + this.chkAssignBestOfficers = chkAssignBestOfficers; + } + + public JCheckBox getChkPrioritizeOfficerCombatSkills() { + return chkPrioritizeOfficerCombatSkills; + } + + public void setChkPrioritizeOfficerCombatSkills(final JCheckBox chkPrioritizeOfficerCombatSkills) { + this.chkPrioritizeOfficerCombatSkills = chkPrioritizeOfficerCombatSkills; + } + + public JCheckBox getChkAssignMostSkilledToPrimaryLances() { + return chkAssignMostSkilledToPrimaryLances; + } + + public void setChkAssignMostSkilledToPrimaryLances(final JCheckBox chkAssignMostSkilledToPrimaryLances) { + this.chkAssignMostSkilledToPrimaryLances = chkAssignMostSkilledToPrimaryLances; + } + + public JCheckBox getChkAutomaticallyAssignRanks() { + return chkAutomaticallyAssignRanks; + } + + public void setChkAutomaticallyAssignRanks(final JCheckBox chkAutomaticallyAssignRanks) { + this.chkAutomaticallyAssignRanks = chkAutomaticallyAssignRanks; + } + + public JCheckBox getChkAssignFounderFlag() { + return chkAssignFounderFlag; + } + + public void setChkAssignFounderFlag(final JCheckBox chkAssignFounderFlag) { + this.chkAssignFounderFlag = chkAssignFounderFlag; + } + //endregion Personnel + + //region Personnel Randomization + public RandomOriginOptionsPanel getRandomOriginOptionsPanel() { + return randomOriginOptionsPanel; + } + + public void setRandomOriginOptionsPanel(final RandomOriginOptionsPanel randomOriginOptionsPanel) { + this.randomOriginOptionsPanel = randomOriginOptionsPanel; + } + //endregion Personnel Randomization + + //region Starting Simulation + public JCheckBox getChkRunStartingSimulation() { + return chkRunStartingSimulation; + } + + public void setChkRunStartingSimulation(final JCheckBox chkRunStartingSimulation) { + this.chkRunStartingSimulation = chkRunStartingSimulation; + } + + public JSpinner getSpnSimulationDuration() { + return spnSimulationDuration; + } + + public void setSpnSimulationDuration(final JSpinner spnSimulationDuration) { + this.spnSimulationDuration = spnSimulationDuration; + } + + public JCheckBox getChkSimulateRandomMarriages() { + return chkSimulateRandomMarriages; + } + + public void setChkSimulateRandomMarriages(final JCheckBox chkSimulateRandomMarriages) { + this.chkSimulateRandomMarriages = chkSimulateRandomMarriages; + } + + public JCheckBox getChkSimulateRandomProcreation() { + return chkSimulateRandomProcreation; + } + + public void setChkSimulateRandomProcreation(final JCheckBox chkSimulateRandomProcreation) { + this.chkSimulateRandomProcreation = chkSimulateRandomProcreation; + } + //endregion Starting Simulation + + //region Units + public MMComboBox getComboBattleMechWeightClassGenerationMethod() { + return comboBattleMechWeightClassGenerationMethod; + } + + public void setComboBattleMechWeightClassGenerationMethod( + final MMComboBox comboBattleMechWeightClassGenerationMethod) { + this.comboBattleMechWeightClassGenerationMethod = comboBattleMechWeightClassGenerationMethod; + } + + public MMComboBox getComboBattleMechQualityGenerationMethod() { + return comboBattleMechQualityGenerationMethod; + } + + public void setComboBattleMechQualityGenerationMethod( + final MMComboBox comboBattleMechQualityGenerationMethod) { + this.comboBattleMechQualityGenerationMethod = comboBattleMechQualityGenerationMethod; + } + + public JCheckBox getChkNeverGenerateStarLeagueMechs() { + return chkNeverGenerateStarLeagueMechs; + } + + public void setChkNeverGenerateStarLeagueMechs(final JCheckBox chkNeverGenerateStarLeagueMechs) { + this.chkNeverGenerateStarLeagueMechs = chkNeverGenerateStarLeagueMechs; + } + + public JCheckBox getChkOnlyGenerateStarLeagueMechs() { + return chkOnlyGenerateStarLeagueMechs; + } + + public void setChkOnlyGenerateStarLeagueMechs(JCheckBox chkOnlyGenerateStarLeagueMechs) { + this.chkOnlyGenerateStarLeagueMechs = chkOnlyGenerateStarLeagueMechs; + } + + public JCheckBox getChkOnlyGenerateOmniMechs() { + return chkOnlyGenerateOmniMechs; + } + + public void setChkOnlyGenerateOmniMechs(JCheckBox chkOnlyGenerateOmniMechs) { + this.chkOnlyGenerateOmniMechs = chkOnlyGenerateOmniMechs; + } + + public JCheckBox getChkGenerateUnitsAsAttached() { + return chkGenerateUnitsAsAttached; + } + + public void setChkGenerateUnitsAsAttached(final JCheckBox chkGenerateUnitsAsAttached) { + this.chkGenerateUnitsAsAttached = chkGenerateUnitsAsAttached; + } + + public JCheckBox getChkAssignBestRollToCompanyCommander() { + return chkAssignBestRollToCompanyCommander; + } + + public void setChkAssignBestRollToCompanyCommander(final JCheckBox chkAssignBestRollToCompanyCommander) { + this.chkAssignBestRollToCompanyCommander = chkAssignBestRollToCompanyCommander; + } + + public JCheckBox getChkSortStarLeagueUnitsFirst() { + return chkSortStarLeagueUnitsFirst; + } + + public void setChkSortStarLeagueUnitsFirst(final JCheckBox chkSortStarLeagueUnitsFirst) { + this.chkSortStarLeagueUnitsFirst = chkSortStarLeagueUnitsFirst; + } + + public JCheckBox getChkGroupByWeight() { + return chkGroupByWeight; + } + + public void setChkGroupByWeight(final JCheckBox chkGroupByWeight) { + this.chkGroupByWeight = chkGroupByWeight; + } + + public JCheckBox getChkGroupByQuality() { + return chkGroupByQuality; + } + + public void setChkGroupByQuality(final JCheckBox chkGroupByQuality) { + this.chkGroupByQuality = chkGroupByQuality; + } + + public JCheckBox getChkKeepOfficerRollsSeparate() { + return chkKeepOfficerRollsSeparate; + } + + public void setChkKeepOfficerRollsSeparate(final JCheckBox chkKeepOfficerRollsSeparate) { + this.chkKeepOfficerRollsSeparate = chkKeepOfficerRollsSeparate; + } + + public JCheckBox getChkAssignTechsToUnits() { + return chkAssignTechsToUnits; + } + + public void setChkAssignTechsToUnits(final JCheckBox chkAssignTechsToUnits) { + this.chkAssignTechsToUnits = chkAssignTechsToUnits; + } + //endregion Units + + //region Unit + public MMComboBox getComboForceNamingMethod() { + return comboForceNamingMethod; + } + + public void setComboForceNamingMethod(final MMComboBox comboForceNamingMethod) { + this.comboForceNamingMethod = comboForceNamingMethod; + } + + public JCheckBox getChkGenerateForceIcons() { + return chkGenerateForceIcons; + } + + public void setChkGenerateForceIcons(final JCheckBox chkGenerateForceIcons) { + this.chkGenerateForceIcons = chkGenerateForceIcons; + } + + public JCheckBox getChkGenerateOriginNodeForceIcon() { + return chkGenerateOriginNodeForceIcon; + } + + public void setChkGenerateOriginNodeForceIcon(final JCheckBox chkGenerateOriginNodeForceIcon) { + this.chkGenerateOriginNodeForceIcon = chkGenerateOriginNodeForceIcon; + } + + public JCheckBox getChkUseOriginNodeForceIconLogo() { + return chkUseOriginNodeForceIconLogo; + } + + public void setChkUseOriginNodeForceIconLogo(final JCheckBox chkUseOriginNodeForceIconLogo) { + this.chkUseOriginNodeForceIconLogo = chkUseOriginNodeForceIconLogo; + } + + public Map getSpnForceWeightLimits() { + return spnForceWeightLimits; + } + + public void setSpnForceWeightLimits(final Map spnForceWeightLimits) { + this.spnForceWeightLimits = spnForceWeightLimits; + } + //endregion Unit + + //region Spares + public JCheckBox getChkGenerateMothballedSpareUnits() { + return chkGenerateMothballedSpareUnits; + } + + public void setChkGenerateMothballedSpareUnits(final JCheckBox chkGenerateMothballedSpareUnits) { + this.chkGenerateMothballedSpareUnits = chkGenerateMothballedSpareUnits; + } + + public JSpinner getSpnSparesPercentOfActiveUnits() { + return spnSparesPercentOfActiveUnits; + } + + public void setSpnSparesPercentOfActiveUnits(final JSpinner spnSparesPercentOfActiveUnits) { + this.spnSparesPercentOfActiveUnits = spnSparesPercentOfActiveUnits; + } + + public MMComboBox getComboPartGenerationMethod() { + return comboPartGenerationMethod; + } + + public void setComboPartGenerationMethod(final MMComboBox comboPartGenerationMethod) { + this.comboPartGenerationMethod = comboPartGenerationMethod; + } + + public JSpinner getSpnStartingArmourWeight() { + return spnStartingArmourWeight; + } + + public void setSpnStartingArmourWeight(final JSpinner spnStartingArmourWeight) { + this.spnStartingArmourWeight = spnStartingArmourWeight; + } + + public JCheckBox getChkGenerateSpareAmmunition() { + return chkGenerateSpareAmmunition; + } + + public void setChkGenerateSpareAmmunition(final JCheckBox chkGenerateSpareAmmunition) { + this.chkGenerateSpareAmmunition = chkGenerateSpareAmmunition; + } + + public JSpinner getSpnNumberReloadsPerWeapon() { + return spnNumberReloadsPerWeapon; + } + + public void setSpnNumberReloadsPerWeapon(final JSpinner spnNumberReloadsPerWeapon) { + this.spnNumberReloadsPerWeapon = spnNumberReloadsPerWeapon; + } + + public JCheckBox getChkGenerateFractionalMachineGunAmmunition() { + return chkGenerateFractionalMachineGunAmmunition; + } + + public void setChkGenerateFractionalMachineGunAmmunition(final JCheckBox chkGenerateFractionalMachineGunAmmunition) { + this.chkGenerateFractionalMachineGunAmmunition = chkGenerateFractionalMachineGunAmmunition; + } + //endregion Spares + + //region Contracts + public JCheckBox getChkSelectStartingContract() { + return chkSelectStartingContract; + } + + public void setChkSelectStartingContract(final JCheckBox chkSelectStartingContract) { + this.chkSelectStartingContract = chkSelectStartingContract; + } + + public JCheckBox getChkStartCourseToContractPlanet() { + return chkStartCourseToContractPlanet; + } + + public void setChkStartCourseToContractPlanet(final JCheckBox chkStartCourseToContractPlanet) { + this.chkStartCourseToContractPlanet = chkStartCourseToContractPlanet; + } + //endregion Contracts + + //region Finances + public JCheckBox getChkProcessFinances() { + return chkProcessFinances; + } + + public void setChkProcessFinances(final JCheckBox chkProcessFinances) { + this.chkProcessFinances = chkProcessFinances; + } + + public JSpinner getSpnStartingCash() { + return spnStartingCash; + } + + public void setSpnStartingCash(final JSpinner spnStartingCash) { + this.spnStartingCash = spnStartingCash; + } + + public JCheckBox getChkRandomizeStartingCash() { + return chkRandomizeStartingCash; + } + + public void setChkRandomizeStartingCash(final JCheckBox chkRandomizeStartingCash) { + this.chkRandomizeStartingCash = chkRandomizeStartingCash; + } + + public JSpinner getSpnRandomStartingCashDiceCount() { + return spnRandomStartingCashDiceCount; + } + + public void setSpnRandomStartingCashDiceCount(final JSpinner spnRandomStartingCashDiceCount) { + this.spnRandomStartingCashDiceCount = spnRandomStartingCashDiceCount; + } + + public JSpinner getSpnMinimumStartingFloat() { + return spnMinimumStartingFloat; + } + + public void setSpnMinimumStartingFloat(final JSpinner spnMinimumStartingFloat) { + this.spnMinimumStartingFloat = spnMinimumStartingFloat; + } + + public JCheckBox getChkIncludeInitialContractPayment() { + return chkIncludeInitialContractPayment; + } + + public void setChkIncludeInitialContractPayment(final JCheckBox chkIncludeInitialContractPayment) { + this.chkIncludeInitialContractPayment = chkIncludeInitialContractPayment; + } + + public JCheckBox getChkStartingLoan() { + return chkStartingLoan; + } + + public void setChkStartingLoan(final JCheckBox chkStartingLoan) { + this.chkStartingLoan = chkStartingLoan; + } + + public JCheckBox getChkPayForSetup() { + return chkPayForSetup; + } + + public void setChkPayForSetup(final JCheckBox chkPayForSetup) { + this.chkPayForSetup = chkPayForSetup; + } + + public JCheckBox getChkPayForPersonnel() { + return chkPayForPersonnel; + } + + public void setChkPayForPersonnel(final JCheckBox chkPayForPersonnel) { + this.chkPayForPersonnel = chkPayForPersonnel; + } + + public JCheckBox getChkPayForUnits() { + return chkPayForUnits; + } + + public void setChkPayForUnits(final JCheckBox chkPayForUnits) { + this.chkPayForUnits = chkPayForUnits; + } + + public JCheckBox getChkPayForParts() { + return chkPayForParts; + } + + public void setChkPayForParts(final JCheckBox chkPayForParts) { + this.chkPayForParts = chkPayForParts; + } + + public JCheckBox getChkPayForArmour() { + return chkPayForArmour; + } + + public void setChkPayForArmour(final JCheckBox chkPayForArmour) { + this.chkPayForArmour = chkPayForArmour; + } + + public JCheckBox getChkPayForAmmunition() { + return chkPayForAmmunition; + } + + public void setChkPayForAmmunition(final JCheckBox chkPayForAmmunition) { + this.chkPayForAmmunition = chkPayForAmmunition; + } + //endregion Finances + + //region Surprises + public JCheckBox getChkGenerateSurprises() { + return chkGenerateSurprises; + } + + public void setChkGenerateSurprises(final JCheckBox chkGenerateSurprises) { + this.chkGenerateSurprises = chkGenerateSurprises; + } + + public JCheckBox getChkGenerateMysteryBoxes() { + return chkGenerateMysteryBoxes; + } + + public void setChkGenerateMysteryBoxes(final JCheckBox chkGenerateMysteryBoxes) { + this.chkGenerateMysteryBoxes = chkGenerateMysteryBoxes; + } + + public Map getChkGenerateMysteryBoxTypes() { + return chkGenerateMysteryBoxTypes; + } + + public void setChkGenerateMysteryBoxTypes(final Map chkGenerateMysteryBoxTypes) { + this.chkGenerateMysteryBoxTypes = chkGenerateMysteryBoxTypes; + } + //endregion Surprises + //endregion Getters/Setters + + //region Determination Methods + public int determineMaximumSupportPersonnel() { + return ((getChkGenerateMercenaryCompanyCommandLance().isSelected() ? 1 : 0) + + ((int) getSpnCompanyCount().getValue() * (int) getSpnLancesPerCompany().getValue()) + + (int) getSpnIndividualLanceCount().getValue()) * (int) getSpnLanceSize().getValue(); + } + //endregion Determination Methods + + //region Initialization + @Override + protected void initialize() { + final GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.fill = GridBagConstraints.HORIZONTAL; + add(createBaseInformationPanel(), gbc); + + gbc.gridx++; + add(createPersonnelPanel(), gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(createPersonnelRandomizationPanel(), gbc); + + gbc.gridx++; + add(createStartingSimulationPanel(), gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(createUnitsPanel(), gbc); + + gbc.gridx++; + add(createUnitPanel(), gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(createSparesPanel(), gbc); + + gbc.gridx++; + add(createContractsPanel(), gbc); + + gbc.gridx = 0; + gbc.gridy++; + add(createFinancesPanel(), gbc); + + gbc.gridx++; + add(createSurprisesPanel(), gbc); + } + + private JPanel createBaseInformationPanel() { + // Create Panel Components + final JLabel lblCompanyGenerationMethod = new JLabel(resources.getString("lblCompanyGenerationMethod.text")); + lblCompanyGenerationMethod.setToolTipText(resources.getString("lblCompanyGenerationMethod.toolTipText")); + lblCompanyGenerationMethod.setName("lblCompanyGenerationMethod"); + + setComboCompanyGenerationMethod(new MMComboBox<>("comboCompanyGenerationMethod", CompanyGenerationMethod.values())); + getComboCompanyGenerationMethod().setToolTipText(resources.getString("lblCompanyGenerationMethod.toolTipText")); + getComboCompanyGenerationMethod().setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof CompanyGenerationMethod) { + list.setToolTipText(((CompanyGenerationMethod) value).getToolTipText()); + } + return this; + } + }); + + setChkGenerateMercenaryCompanyCommandLance(new JCheckBox(resources.getString("chkGenerateMercenaryCompanyCommandLance.text"))); + getChkGenerateMercenaryCompanyCommandLance().setToolTipText(resources.getString("chkGenerateMercenaryCompanyCommandLance.toolTipText")); + getChkGenerateMercenaryCompanyCommandLance().setName("chkGenerateMercenaryCompanyCommandLance"); + + final JLabel lblCompanyCount = new JLabel(resources.getString("lblCompanyCount.text")); + lblCompanyCount.setToolTipText(resources.getString("lblCompanyCount.toolTipText")); + lblCompanyCount.setName("lblCompanyCount"); + + setSpnCompanyCount(new JSpinner(new SpinnerNumberModel(0, 0, 5, 1))); + getSpnCompanyCount().setToolTipText(resources.getString("lblCompanyCount.toolTipText")); + getSpnCompanyCount().setName("spnCompanyCount"); + + final JLabel lblIndividualLanceCount = new JLabel(resources.getString("lblIndividualLanceCount.text")); + lblIndividualLanceCount.setToolTipText(resources.getString("lblIndividualLanceCount.toolTipText")); + lblIndividualLanceCount.setName("lblIndividualLanceCount"); + + setSpnIndividualLanceCount(new JSpinner(new SpinnerNumberModel(0, 0, 2, 1))); + getSpnIndividualLanceCount().setToolTipText(resources.getString("lblIndividualLanceCount.toolTipText")); + getSpnIndividualLanceCount().setName("spnIndividualLanceCount"); + + final JLabel lblLancesPerCompany = new JLabel(resources.getString("lblLancesPerCompany.text")); + lblLancesPerCompany.setToolTipText(resources.getString("lblLancesPerCompany.toolTipText")); + lblLancesPerCompany.setName("lblLancesPerCompany"); + + setSpnLancesPerCompany(new JSpinner(new SpinnerNumberModel(3, 2, 6, 1))); + getSpnLancesPerCompany().setToolTipText(resources.getString("lblLancesPerCompany.toolTipText")); + getSpnLancesPerCompany().setName("spnLancesPerCompany"); + + final JLabel lblLanceSize = new JLabel(resources.getString("lblLanceSize.text")); + lblLanceSize.setToolTipText(resources.getString("lblLanceSize.toolTipText")); + lblLanceSize.setName("lblLanceSize"); + + setSpnLanceSize(new JSpinner(new SpinnerNumberModel(4, 3, 6, 1))); + getSpnLanceSize().setToolTipText(resources.getString("lblLanceSize.toolTipText")); + getSpnLanceSize().setName("spnLanceSize"); + + final JLabel lblStarLeagueYear = new JLabel(resources.getString("lblStarLeagueYear.text")); + lblStarLeagueYear.setToolTipText(resources.getString("lblStarLeagueYear.toolTipText")); + lblStarLeagueYear.setName("lblStarLeagueYear"); + + setSpnStarLeagueYear(new JSpinner(new SpinnerNumberModel(2765, 2571, 2780, 1))); + getSpnStarLeagueYear().setToolTipText(resources.getString("lblStarLeagueYear.toolTipText")); + getSpnStarLeagueYear().setName("spnStarLeagueYear"); + getSpnStarLeagueYear().setEditor(new NumberEditor(getSpnStarLeagueYear(), "#")); + + // Programmatically Assign Accessibility Labels + lblCompanyGenerationMethod.setLabelFor(getComboCompanyGenerationMethod()); + lblCompanyCount.setLabelFor(getSpnCompanyCount()); + lblIndividualLanceCount.setLabelFor(getSpnIndividualLanceCount()); + lblLancesPerCompany.setLabelFor(getSpnLancesPerCompany()); + lblLanceSize.setLabelFor(getSpnLanceSize()); + lblStarLeagueYear.setLabelFor(getSpnStarLeagueYear()); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("baseInformationPanel.title"))); + panel.setName("baseInformationPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblCompanyGenerationMethod) + .addComponent(getComboCompanyGenerationMethod(), Alignment.LEADING)) + .addComponent(getChkGenerateMercenaryCompanyCommandLance()) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblCompanyCount) + .addComponent(getSpnCompanyCount()) + .addComponent(lblIndividualLanceCount) + .addComponent(getSpnIndividualLanceCount(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblLancesPerCompany) + .addComponent(getSpnLancesPerCompany()) + .addComponent(lblLanceSize) + .addComponent(getSpnLanceSize(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblStarLeagueYear) + .addComponent(getSpnStarLeagueYear(), Alignment.LEADING)) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblCompanyGenerationMethod) + .addComponent(getComboCompanyGenerationMethod())) + .addComponent(getChkGenerateMercenaryCompanyCommandLance()) + .addGroup(layout.createSequentialGroup() + .addComponent(lblCompanyCount) + .addComponent(getSpnCompanyCount()) + .addComponent(lblIndividualLanceCount) + .addComponent(getSpnIndividualLanceCount())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblLancesPerCompany) + .addComponent(getSpnLancesPerCompany()) + .addComponent(lblLanceSize) + .addComponent(getSpnLanceSize())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblStarLeagueYear) + .addComponent(getSpnStarLeagueYear())) + ); + + return panel; + } + + private JPanel createPersonnelPanel() { + // Create Panel Components + setLblTotalSupportPersonnel(new JLabel()); + updateLblTotalSupportPersonnel(0); + getLblTotalSupportPersonnel().setToolTipText(resources.getString("lblTotalSupportPersonnel.toolTipText")); + getLblTotalSupportPersonnel().setName("lblTotalSupportPersonnel"); + + final JPanel supportPersonnelNumbersPanel = createSupportPersonnelNumbersPanel(); + + setChkPoolAssistants(new JCheckBox(resources.getString("chkPoolAssistants.text"))); + getChkPoolAssistants().setToolTipText(resources.getString("chkPoolAssistants.toolTipText")); + getChkPoolAssistants().setName("chkPoolAssistants"); + + setChkGenerateCaptains(new JCheckBox(resources.getString("chkGenerateCaptains.text"))); + getChkGenerateCaptains().setToolTipText(resources.getString("chkGenerateCaptains.toolTipText")); + getChkGenerateCaptains().setName("chkGenerateCaptains"); + + setChkAssignCompanyCommanderFlag(new JCheckBox(resources.getString("chkAssignCompanyCommanderFlag.text"))); + getChkAssignCompanyCommanderFlag().setToolTipText(resources.getString("chkAssignCompanyCommanderFlag.toolTipText")); + getChkAssignCompanyCommanderFlag().setName("chkAssignCompanyCommanderFlag"); + + setChkApplyOfficerStatBonusToWorstSkill(new JCheckBox(resources.getString("chkApplyOfficerStatBonusToWorstSkill.text"))); + getChkApplyOfficerStatBonusToWorstSkill().setToolTipText(resources.getString("chkApplyOfficerStatBonusToWorstSkill.toolTipText")); + getChkApplyOfficerStatBonusToWorstSkill().setName("chkApplyOfficerStatBonusToWorstSkill"); + + setChkAssignBestCompanyCommander(new JCheckBox(resources.getString("chkAssignBestCompanyCommander.text"))); + getChkAssignBestCompanyCommander().setToolTipText(resources.getString("chkAssignBestCompanyCommander.toolTipText")); + getChkAssignBestCompanyCommander().setName("chkAssignBestCompanyCommander"); + getChkAssignBestCompanyCommander().addActionListener(evt -> + getChkPrioritizeCompanyCommanderCombatSkills().setEnabled(getChkAssignBestCompanyCommander().isSelected())); + + setChkPrioritizeCompanyCommanderCombatSkills(new JCheckBox(resources.getString("chkPrioritizeCompanyCommanderCombatSkills.text"))); + getChkPrioritizeCompanyCommanderCombatSkills().setToolTipText(resources.getString("chkPrioritizeCompanyCommanderCombatSkills.toolTipText")); + getChkPrioritizeCompanyCommanderCombatSkills().setName("chkPrioritizeCompanyCommanderCombatSkills"); + + setChkAssignBestOfficers(new JCheckBox(resources.getString("chkAssignBestOfficers.text"))); + getChkAssignBestOfficers().setToolTipText(resources.getString("chkAssignBestOfficers.toolTipText")); + getChkAssignBestOfficers().setName("chkAssignBestOfficers"); + getChkAssignBestOfficers().addActionListener(evt -> + getChkPrioritizeOfficerCombatSkills().setEnabled(getChkAssignBestOfficers().isSelected())); + + setChkPrioritizeOfficerCombatSkills(new JCheckBox(resources.getString("chkPrioritizeOfficerCombatSkills.text"))); + getChkPrioritizeOfficerCombatSkills().setToolTipText(resources.getString("chkPrioritizeOfficerCombatSkills.toolTipText")); + getChkPrioritizeOfficerCombatSkills().setName("chkPrioritizeOfficerCombatSkills"); + + setChkAssignMostSkilledToPrimaryLances(new JCheckBox(resources.getString("chkAssignMostSkilledToPrimaryLances.text"))); + getChkAssignMostSkilledToPrimaryLances().setToolTipText(resources.getString("chkAssignMostSkilledToPrimaryLances.toolTipText")); + getChkAssignMostSkilledToPrimaryLances().setName("chkAssignMostSkilledToPrimaryLances"); + + setChkAutomaticallyAssignRanks(new JCheckBox(resources.getString("chkAutomaticallyAssignRanks.text"))); + getChkAutomaticallyAssignRanks().setToolTipText(resources.getString("chkAutomaticallyAssignRanks.toolTipText")); + getChkAutomaticallyAssignRanks().setName("chkAutomaticallyAssignRanks"); + + setChkAssignFounderFlag(new JCheckBox(resources.getString("chkAssignFounderFlag.text"))); + getChkAssignFounderFlag().setToolTipText(resources.getString("chkAssignFounderFlag.toolTipText")); + getChkAssignFounderFlag().setName("chkAssignFounderFlag"); + + // Disable Panel Portions by Default + getChkAssignBestCompanyCommander().setSelected(true); + getChkAssignBestCompanyCommander().doClick(); + getChkAssignBestOfficers().setSelected(true); + getChkAssignBestOfficers().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("personnelPanel.title"))); + panel.setName("personnelPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getLblTotalSupportPersonnel()) + .addComponent(supportPersonnelNumbersPanel) + .addComponent(getChkPoolAssistants()) + .addComponent(getChkGenerateCaptains()) + .addComponent(getChkAssignCompanyCommanderFlag()) + .addComponent(getChkApplyOfficerStatBonusToWorstSkill()) + .addComponent(getChkAssignBestCompanyCommander()) + .addComponent(getChkPrioritizeCompanyCommanderCombatSkills()) + .addComponent(getChkAssignBestOfficers()) + .addComponent(getChkPrioritizeOfficerCombatSkills()) + .addComponent(getChkAssignMostSkilledToPrimaryLances()) + .addComponent(getChkAutomaticallyAssignRanks()) + .addComponent(getChkAssignFounderFlag()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getLblTotalSupportPersonnel()) + .addComponent(supportPersonnelNumbersPanel) + .addComponent(getChkPoolAssistants()) + .addComponent(getChkGenerateCaptains()) + .addComponent(getChkAssignCompanyCommanderFlag()) + .addComponent(getChkApplyOfficerStatBonusToWorstSkill()) + .addComponent(getChkAssignBestCompanyCommander()) + .addComponent(getChkPrioritizeCompanyCommanderCombatSkills()) + .addComponent(getChkAssignBestOfficers()) + .addComponent(getChkPrioritizeOfficerCombatSkills()) + .addComponent(getChkAssignMostSkilledToPrimaryLances()) + .addComponent(getChkAutomaticallyAssignRanks()) + .addComponent(getChkAssignFounderFlag()) + ); + + return panel; + } + + private JPanel createSupportPersonnelNumbersPanel() { + final PersonnelRole[] personnelRoles = new PersonnelRole[] { + PersonnelRole.MECH_TECH, PersonnelRole.MECHANIC, PersonnelRole.AERO_TECH, + PersonnelRole.BA_TECH, PersonnelRole.DOCTOR, PersonnelRole.ADMINISTRATOR_COMMAND, + PersonnelRole.ADMINISTRATOR_LOGISTICS, PersonnelRole.ADMINISTRATOR_TRANSPORT, PersonnelRole.ADMINISTRATOR_HR + }; + + // Create Panel Components + setSpnSupportPersonnelNumbers(new HashMap<>()); + final Map labels = new HashMap<>(); + for (final PersonnelRole role : personnelRoles) { + final String name = role.getName(getCampaign().getFaction().isClan()); + final String toolTipText = String.format(resources.getString("supportPersonnelNumber.toolTipText"), name); + + labels.put(role, new JLabel(name)); + labels.get(role).setToolTipText(toolTipText); + labels.get(role).setName("lbl" + role.name()); + + getSpnSupportPersonnelNumbers().put(role, new JSpinner(new SpinnerNumberModel(0, 0, 100, 1))); + getSpnSupportPersonnelNumbers().get(role).setToolTipText(toolTipText); + getSpnSupportPersonnelNumbers().get(role).setName("spn" + role.name()); + + // Programmatically Assign Accessibility Labels + labels.get(role).setLabelFor(getSpnSupportPersonnelNumbers().get(role)); + } + + // Layout the UI + final JPanel panel = new JPanel(new GridLayout(0, 3)); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("supportPersonnelNumbersPanel.title"))); + panel.setName("supportPersonnelNumbersPanel"); + + // This puts the label above the spinner, separated into three columns. From the + // personnelRoles array declaration, the i tracks the line and the j tracks the + for (int i = 0; i < (personnelRoles.length / 3); i++) { + for (int j = 0; j < 3; j++) { + panel.add(labels.get(personnelRoles[j + (3 * i)])); + } + + for (int j = 0; j < 3; j++) { + panel.add(getSpnSupportPersonnelNumbers().get(personnelRoles[j + (3 * i)])); + } + } + + return panel; + } + + private JPanel createPersonnelRandomizationPanel() { + setRandomOriginOptionsPanel(new RandomOriginOptionsPanel(getFrame(), getCampaign(), + getCampaign().getFaction())); + return getRandomOriginOptionsPanel(); + } + + private JPanel createStartingSimulationPanel() { + // Initialize Labels Used in ActionListeners + final JLabel lblSimulationDuration = new JLabel(); + + // Create Panel Components + setChkRunStartingSimulation(new JCheckBox(resources.getString("chkRunStartingSimulation.text"))); + getChkRunStartingSimulation().setToolTipText(resources.getString("chkRunStartingSimulation.toolTipText")); + getChkRunStartingSimulation().setName("chkRunStartingSimulation"); + getChkRunStartingSimulation().addActionListener(evt -> { + final boolean selected = getChkRunStartingSimulation().isSelected(); + lblSimulationDuration.setEnabled(selected); + getSpnSimulationDuration().setEnabled(selected); + getChkSimulateRandomMarriages().setEnabled(selected); + getChkSimulateRandomProcreation().setEnabled(selected); + }); + + lblSimulationDuration.setText(resources.getString("lblSimulationDuration.text")); + lblSimulationDuration.setToolTipText(resources.getString("lblSimulationDuration.toolTipText")); + lblSimulationDuration.setName("lblSimulationDuration"); + + setSpnSimulationDuration(new JSpinner(new SpinnerNumberModel(0, 0, 25, 1))); + getSpnSimulationDuration().setToolTipText(resources.getString("lblSimulationDuration.toolTipText")); + getSpnSimulationDuration().setName("spnSimulationDuration"); + + setChkSimulateRandomMarriages(new JCheckBox(resources.getString("chkSimulateRandomMarriages.text"))); + getChkSimulateRandomMarriages().setToolTipText(resources.getString("chkSimulateRandomMarriages.toolTipText")); + getChkSimulateRandomMarriages().setName("chkSimulateRandomMarriages"); + + setChkSimulateRandomProcreation(new JCheckBox(resources.getString("chkSimulateRandomProcreation.text"))); + getChkSimulateRandomProcreation().setToolTipText(resources.getString("chkSimulateRandomProcreation.toolTipText")); + getChkSimulateRandomProcreation().setName("chkSimulateRandomProcreation"); + + // Programmatically Assign Accessibility Labels + lblSimulationDuration.setLabelFor(getSpnSimulationDuration()); + + // Disable Panel Portions by Default + getChkRunStartingSimulation().setSelected(true); + getChkRunStartingSimulation().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("startingSimulationPanel.title"))); + panel.setName("startingSimulationPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkRunStartingSimulation()) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblSimulationDuration) + .addComponent(getSpnSimulationDuration(), Alignment.LEADING)) + .addComponent(getChkSimulateRandomMarriages()) + .addComponent(getChkSimulateRandomProcreation()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkRunStartingSimulation()) + .addGroup(layout.createSequentialGroup() + .addComponent(lblSimulationDuration) + .addComponent(getSpnSimulationDuration())) + .addComponent(getChkSimulateRandomMarriages()) + .addComponent(getChkSimulateRandomProcreation()) + ); + + return panel; + } + + private JPanel createUnitsPanel() { + // Create Panel Components + final JLabel lblBattleMechWeightClassGenerationMethod = new JLabel(resources.getString("lblBattleMechWeightClassGenerationMethod.text")); + lblBattleMechWeightClassGenerationMethod.setToolTipText(resources.getString("lblBattleMechWeightClassGenerationMethod.toolTipText")); + lblBattleMechWeightClassGenerationMethod.setName("lblBattleMechWeightClassGenerationMethod"); + + setComboBattleMechWeightClassGenerationMethod(new MMComboBox<>("comboBattleMechWeightClassGenerationMethod", BattleMechWeightClassGenerationMethod.values())); + getComboBattleMechWeightClassGenerationMethod().setToolTipText(resources.getString("lblBattleMechWeightClassGenerationMethod.toolTipText")); + getComboBattleMechWeightClassGenerationMethod().setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof BattleMechWeightClassGenerationMethod) { + list.setToolTipText(((BattleMechWeightClassGenerationMethod) value).getToolTipText()); + } + return this; + } + }); + + final JLabel lblBattleMechQualityGenerationMethod = new JLabel(resources.getString("lblBattleMechQualityGenerationMethod.text")); + lblBattleMechQualityGenerationMethod.setToolTipText(resources.getString("lblBattleMechQualityGenerationMethod.toolTipText")); + lblBattleMechQualityGenerationMethod.setName("lblBattleMechQualityGenerationMethod"); + + setComboBattleMechQualityGenerationMethod(new MMComboBox<>("comboBattleMechQualityGenerationMethod", BattleMechQualityGenerationMethod.values())); + getComboBattleMechQualityGenerationMethod().setToolTipText(resources.getString("lblBattleMechQualityGenerationMethod.toolTipText")); + getComboBattleMechQualityGenerationMethod().setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof BattleMechQualityGenerationMethod) { + list.setToolTipText(((BattleMechQualityGenerationMethod) value).getToolTipText()); + } + return this; + } + }); + + setChkNeverGenerateStarLeagueMechs(new JCheckBox(resources.getString("chkNeverGenerateStarLeagueMechs.text"))); + getChkNeverGenerateStarLeagueMechs().setToolTipText(resources.getString("chkNeverGenerateStarLeagueMechs.toolTipText")); + getChkNeverGenerateStarLeagueMechs().setName("chkNeverGenerateStarLeagueMechs"); + getChkNeverGenerateStarLeagueMechs().addActionListener(evt -> + getChkOnlyGenerateStarLeagueMechs().setEnabled(!getChkNeverGenerateStarLeagueMechs().isSelected())); + + setChkOnlyGenerateStarLeagueMechs(new JCheckBox(resources.getString("chkOnlyGenerateStarLeagueMechs.text"))); + getChkOnlyGenerateStarLeagueMechs().setToolTipText(resources.getString("chkOnlyGenerateStarLeagueMechs.toolTipText")); + getChkOnlyGenerateStarLeagueMechs().setName("chkOnlyGenerateStarLeagueMechs"); + getChkOnlyGenerateStarLeagueMechs().addActionListener(evt -> + getChkNeverGenerateStarLeagueMechs().setEnabled(!getChkOnlyGenerateStarLeagueMechs().isSelected())); + + setChkOnlyGenerateOmniMechs(new JCheckBox(resources.getString("chkOnlyGenerateOmniMechs.text"))); + getChkOnlyGenerateOmniMechs().setToolTipText(resources.getString("chkOnlyGenerateOmniMechs.toolTipText")); + getChkOnlyGenerateOmniMechs().setName("chkOnlyGenerateOmniMechs"); + + setChkGenerateUnitsAsAttached(new JCheckBox(resources.getString("chkGenerateUnitsAsAttached.text"))); + getChkGenerateUnitsAsAttached().setToolTipText(resources.getString("chkGenerateUnitsAsAttached.toolTipText")); + getChkGenerateUnitsAsAttached().setName("chkGenerateUnitsAsAttached"); + + setChkAssignBestRollToCompanyCommander(new JCheckBox(resources.getString("chkAssignBestRollToCompanyCommander.text"))); + getChkAssignBestRollToCompanyCommander().setToolTipText(resources.getString("chkAssignBestRollToCompanyCommander.toolTipText")); + getChkAssignBestRollToCompanyCommander().setName("chkAssignBestRollToCompanyCommander"); + + setChkSortStarLeagueUnitsFirst(new JCheckBox(resources.getString("chkSortStarLeagueUnitsFirst.text"))); + getChkSortStarLeagueUnitsFirst().setToolTipText(resources.getString("chkSortStarLeagueUnitsFirst.toolTipText")); + getChkSortStarLeagueUnitsFirst().setName("chkSortStarLeagueUnitsFirst"); + + setChkGroupByWeight(new JCheckBox(resources.getString("chkGroupByWeight.text"))); + getChkGroupByWeight().setToolTipText(resources.getString("chkGroupByWeight.toolTipText")); + getChkGroupByWeight().setName("chkGroupByWeight"); + + setChkGroupByQuality(new JCheckBox(resources.getString("chkGroupByQuality.text"))); + getChkGroupByQuality().setToolTipText(resources.getString("chkGroupByQuality.toolTipText")); + getChkGroupByQuality().setName("chkGroupByQuality"); + + setChkKeepOfficerRollsSeparate(new JCheckBox(resources.getString("chkKeepOfficerRollsSeparate.text"))); + getChkKeepOfficerRollsSeparate().setToolTipText(resources.getString("chkKeepOfficerRollsSeparate.toolTipText")); + getChkKeepOfficerRollsSeparate().setName("chkKeepOfficerRollsSeparate"); + + setChkAssignTechsToUnits(new JCheckBox(resources.getString("chkAssignTechsToUnits.text"))); + getChkAssignTechsToUnits().setToolTipText(resources.getString("chkAssignTechsToUnits.toolTipText")); + getChkAssignTechsToUnits().setName("chkAssignTechsToUnits"); + + // Programmatically Assign Accessibility Labels + lblBattleMechWeightClassGenerationMethod.setLabelFor(getComboBattleMechWeightClassGenerationMethod()); + lblBattleMechQualityGenerationMethod.setLabelFor(getComboBattleMechQualityGenerationMethod()); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("unitsPanel.title"))); + panel.setName("unitsPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblBattleMechWeightClassGenerationMethod) + .addComponent(getComboBattleMechWeightClassGenerationMethod(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblBattleMechQualityGenerationMethod) + .addComponent(getComboBattleMechQualityGenerationMethod(), Alignment.LEADING)) + .addComponent(getChkNeverGenerateStarLeagueMechs()) + .addComponent(getChkOnlyGenerateStarLeagueMechs()) + .addComponent(getChkOnlyGenerateOmniMechs()) + .addComponent(getChkGenerateUnitsAsAttached()) + .addComponent(getChkAssignBestRollToCompanyCommander()) + .addComponent(getChkSortStarLeagueUnitsFirst()) + .addComponent(getChkGroupByWeight()) + .addComponent(getChkGroupByQuality()) + .addComponent(getChkKeepOfficerRollsSeparate()) + .addComponent(getChkAssignTechsToUnits()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblBattleMechWeightClassGenerationMethod) + .addComponent(getComboBattleMechWeightClassGenerationMethod())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblBattleMechQualityGenerationMethod) + .addComponent(getComboBattleMechQualityGenerationMethod())) + .addComponent(getChkNeverGenerateStarLeagueMechs()) + .addComponent(getChkOnlyGenerateStarLeagueMechs()) + .addComponent(getChkOnlyGenerateOmniMechs()) + .addComponent(getChkGenerateUnitsAsAttached()) + .addComponent(getChkAssignBestRollToCompanyCommander()) + .addComponent(getChkSortStarLeagueUnitsFirst()) + .addComponent(getChkGroupByWeight()) + .addComponent(getChkGroupByQuality()) + .addComponent(getChkKeepOfficerRollsSeparate()) + .addComponent(getChkAssignTechsToUnits()) + ); + + return panel; + } + + private JPanel createUnitPanel() { + // Initialize Components Used in ActionListeners + final JPanel forceWeightLimitsPanel = new JDisableablePanel("forceWeightLimitsPanel"); + + // Create Panel Components + final JLabel lblForceNamingMethod = new JLabel(resources.getString("lblForceNamingMethod.text")); + lblForceNamingMethod.setToolTipText(resources.getString("lblForceNamingMethod.toolTipText")); + lblForceNamingMethod.setName("lblForceNamingMethod"); + + setComboForceNamingMethod(new MMComboBox<>("comboForceNamingMethod", ForceNamingMethod.values())); + getComboForceNamingMethod().setToolTipText(resources.getString("lblForceNamingMethod.toolTipText")); + getComboForceNamingMethod().setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof ForceNamingMethod) { + list.setToolTipText(((ForceNamingMethod) value).getToolTipText()); + } + return this; + } + }); + + setChkGenerateForceIcons(new JCheckBox(resources.getString("chkGenerateForceIcons.text"))); + getChkGenerateForceIcons().setToolTipText(resources.getString("chkGenerateForceIcons.toolTipText")); + getChkGenerateForceIcons().setName("chkGenerateForceIcons"); + getChkGenerateForceIcons().addActionListener(evt -> { + final boolean selected = getChkGenerateForceIcons().isSelected(); + getChkGenerateOriginNodeForceIcon().setEnabled(selected); + getChkUseOriginNodeForceIconLogo().setEnabled(selected + && getChkGenerateOriginNodeForceIcon().isSelected()); + forceWeightLimitsPanel.setEnabled(selected); + }); + + setChkGenerateOriginNodeForceIcon(new JCheckBox(resources.getString("chkGenerateOriginNodeForceIcon.text"))); + getChkGenerateOriginNodeForceIcon().setToolTipText(resources.getString("chkGenerateOriginNodeForceIcon.toolTipText")); + getChkGenerateOriginNodeForceIcon().setName("chkGenerateOriginNodeForceIcon"); + getChkGenerateOriginNodeForceIcon().addActionListener(evt -> getChkUseOriginNodeForceIconLogo() + .setEnabled(getChkGenerateOriginNodeForceIcon().isEnabled() + && getChkGenerateOriginNodeForceIcon().isSelected())); + + setChkUseOriginNodeForceIconLogo(new JCheckBox(resources.getString("chkUseOriginNodeForceIconLogo.text"))); + getChkUseOriginNodeForceIconLogo().setToolTipText(resources.getString("chkUseOriginNodeForceIconLogo.toolTipText")); + getChkUseOriginNodeForceIconLogo().setName("chkUseOriginNodeForceIconLogo"); + + createForceWeightLimitsPanel(forceWeightLimitsPanel); + + // Programmatically Assign Accessibility Labels + lblForceNamingMethod.setLabelFor(getComboForceNamingMethod()); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("unitPanel.title"))); + panel.setName("unitPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblForceNamingMethod) + .addComponent(getComboForceNamingMethod(), Alignment.LEADING)) + .addComponent(getChkGenerateForceIcons()) + .addComponent(getChkGenerateOriginNodeForceIcon()) + .addComponent(getChkUseOriginNodeForceIconLogo()) + .addComponent(forceWeightLimitsPanel) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblForceNamingMethod) + .addComponent(getComboForceNamingMethod())) + .addComponent(getChkGenerateForceIcons()) + .addComponent(getChkGenerateOriginNodeForceIcon()) + .addComponent(getChkUseOriginNodeForceIconLogo()) + .addComponent(forceWeightLimitsPanel) + ); + return panel; + } + + private void createForceWeightLimitsPanel(final JPanel panel) { + // Create Panel + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("forceWeightLimitsPanel.title"))); + panel.setToolTipText(resources.getString("forceWeightLimitsPanel.toolTipText")); + panel.setLayout(new GridLayout(0, 2)); + + // Create Panel Components + setSpnForceWeightLimits(new HashMap<>()); + for (int i = EntityWeightClass.WEIGHT_ULTRA_LIGHT; i <= EntityWeightClass.WEIGHT_ASSAULT; i++) { + final String weightClass = EntityWeightClass.getClassName(i); + + final JLabel label = new JLabel(weightClass); + label.setToolTipText(resources.getString("forceWeightLimitsPanel.toolTipText")); + label.setName("lbl" + weightClass); + panel.add(label); + + getSpnForceWeightLimits().put(i, new JSpinner(new SpinnerNumberModel(0, 0, 10000, 10))); + getSpnForceWeightLimits().get(i).setToolTipText(resources.getString("forceWeightLimitsPanel.toolTipText")); + getSpnForceWeightLimits().get(i).setName("spn" + weightClass); + panel.add(getSpnForceWeightLimits().get(i)); + } + } + + private JPanel createSparesPanel() { + // Initialize Labels Used in ActionListeners + final JLabel lblSparesPercentOfActiveUnits = new JLabel(); + final JLabel lblNumberReloadsPerWeapon = new JLabel(); + + // Create Panel Components + setChkGenerateMothballedSpareUnits(new JCheckBox(resources.getString("chkGenerateMothballedSpareUnits.text"))); + getChkGenerateMothballedSpareUnits().setToolTipText(resources.getString("chkGenerateMothballedSpareUnits.toolTipText")); + getChkGenerateMothballedSpareUnits().setName("chkGenerateMothballedSpareUnits"); + getChkGenerateMothballedSpareUnits().addActionListener(evt -> { + final boolean selected = getChkGenerateMothballedSpareUnits().isSelected(); + lblSparesPercentOfActiveUnits.setEnabled(selected); + getSpnSparesPercentOfActiveUnits().setEnabled(selected); + }); + + lblSparesPercentOfActiveUnits.setText(resources.getString("lblSparesPercentOfActiveUnits.text")); + lblSparesPercentOfActiveUnits.setToolTipText(resources.getString("lblSparesPercentOfActiveUnits.toolTipText")); + lblSparesPercentOfActiveUnits.setName("lblSparesPercentOfActiveUnits"); + + setSpnSparesPercentOfActiveUnits(new JSpinner(new SpinnerNumberModel(0, 0, 100, 1))); + getSpnSparesPercentOfActiveUnits().setToolTipText(resources.getString("chkGenerateMothballedSpareUnits.toolTipText")); + getSpnSparesPercentOfActiveUnits().setName("spnGenerateMothballedSpareUnits"); + + final JLabel lblPartGenerationMethod = new JLabel(resources.getString("lblPartGenerationMethod.text")); + lblPartGenerationMethod.setToolTipText(resources.getString("lblPartGenerationMethod.toolTipText")); + lblPartGenerationMethod.setName("lblPartGenerationMethod"); + + setComboPartGenerationMethod(new MMComboBox<>("comboPartGenerationMethod", PartGenerationMethod.values())); + getComboPartGenerationMethod().setToolTipText(resources.getString("lblPartGenerationMethod.toolTipText")); + getComboPartGenerationMethod().setRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(final JList list, final Object value, + final int index, final boolean isSelected, + final boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof PartGenerationMethod) { + list.setToolTipText(((PartGenerationMethod) value).getToolTipText()); + } + return this; + } + }); + + final JLabel lblStartingArmourWeight = new JLabel(resources.getString("lblStartingArmourWeight.text")); + lblStartingArmourWeight.setToolTipText(resources.getString("lblStartingArmourWeight.toolTipText")); + lblStartingArmourWeight.setName("lblStartingArmourWeight"); + + setSpnStartingArmourWeight(new JSpinner(new SpinnerNumberModel(0, 0, 500, 1))); + getSpnStartingArmourWeight().setToolTipText(resources.getString("lblStartingArmourWeight.toolTipText")); + getSpnStartingArmourWeight().setName("spnStartingArmourWeight"); + + setChkGenerateSpareAmmunition(new JCheckBox(resources.getString("chkGenerateSpareAmmunition.text"))); + getChkGenerateSpareAmmunition().setToolTipText(resources.getString("chkGenerateSpareAmmunition.toolTipText")); + getChkGenerateSpareAmmunition().setName("chkGenerateSpareAmmunition"); + getChkGenerateSpareAmmunition().addActionListener(evt -> { + final boolean selected = getChkGenerateSpareAmmunition().isSelected(); + lblNumberReloadsPerWeapon.setEnabled(selected); + getSpnNumberReloadsPerWeapon().setEnabled(selected); + getChkGenerateFractionalMachineGunAmmunition().setEnabled(selected); + }); + + lblNumberReloadsPerWeapon.setText(resources.getString("lblNumberReloadsPerWeapon.text")); + lblNumberReloadsPerWeapon.setToolTipText(resources.getString("lblNumberReloadsPerWeapon.toolTipText")); + lblNumberReloadsPerWeapon.setName("lblNumberReloadsPerWeapon"); + + setSpnNumberReloadsPerWeapon(new JSpinner(new SpinnerNumberModel(0, 0, 25, 1))); + getSpnNumberReloadsPerWeapon().setToolTipText(resources.getString("lblNumberReloadsPerWeapon.toolTipText")); + getSpnNumberReloadsPerWeapon().setName("spnNumberReloadsPerWeapon"); + + setChkGenerateFractionalMachineGunAmmunition(new JCheckBox(resources.getString("chkGenerateFractionalMachineGunAmmunition.text"))); + getChkGenerateFractionalMachineGunAmmunition().setToolTipText(resources.getString("chkGenerateFractionalMachineGunAmmunition.toolTipText")); + getChkGenerateFractionalMachineGunAmmunition().setName("chkGenerateFractionalMachineGunAmmunition"); + + // Programmatically Assign Accessibility Labels + lblSparesPercentOfActiveUnits.setLabelFor(getSpnSparesPercentOfActiveUnits()); + lblPartGenerationMethod.setLabelFor(getComboPartGenerationMethod()); + lblStartingArmourWeight.setLabelFor(getSpnStartingArmourWeight()); + lblNumberReloadsPerWeapon.setLabelFor(getSpnNumberReloadsPerWeapon()); + + // Disable Panel Portions by Default + getChkGenerateMothballedSpareUnits().setSelected(true); + getChkGenerateMothballedSpareUnits().doClick(); + getChkGenerateSpareAmmunition().setSelected(true); + getChkGenerateSpareAmmunition().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("sparesPanel.title"))); + panel.setName("sparesPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkGenerateMothballedSpareUnits()) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblSparesPercentOfActiveUnits) + .addComponent(getSpnSparesPercentOfActiveUnits(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblPartGenerationMethod) + .addComponent(getComboPartGenerationMethod(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblStartingArmourWeight) + .addComponent(getSpnStartingArmourWeight(), Alignment.LEADING)) + .addComponent(getChkGenerateSpareAmmunition()) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblNumberReloadsPerWeapon) + .addComponent(getSpnNumberReloadsPerWeapon(), Alignment.LEADING)) + .addComponent(getChkGenerateFractionalMachineGunAmmunition()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkGenerateMothballedSpareUnits()) + .addGroup(layout.createSequentialGroup() + .addComponent(lblSparesPercentOfActiveUnits) + .addComponent(getSpnSparesPercentOfActiveUnits())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblPartGenerationMethod) + .addComponent(getComboPartGenerationMethod())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblStartingArmourWeight) + .addComponent(getSpnStartingArmourWeight())) + .addComponent(getChkGenerateSpareAmmunition()) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNumberReloadsPerWeapon) + .addComponent(getSpnNumberReloadsPerWeapon())) + .addComponent(getChkGenerateFractionalMachineGunAmmunition()) + ); + + return panel; + } + + private JPanel createContractsPanel() { + // Create Panel Components + setChkSelectStartingContract(new JCheckBox(resources.getString("chkSelectStartingContract.text"))); + getChkSelectStartingContract().setToolTipText(resources.getString("chkSelectStartingContract.toolTipText")); + getChkSelectStartingContract().setName("chkSelectStartingContract"); + getChkSelectStartingContract().addActionListener(evt -> { + final boolean selected = getChkSelectStartingContract().isSelected(); + getChkStartCourseToContractPlanet().setEnabled(selected); + if (getChkIncludeInitialContractPayment() != null) { + getChkIncludeInitialContractPayment().setEnabled(selected); + } + }); + + setChkStartCourseToContractPlanet(new JCheckBox(resources.getString("chkStartCourseToContractPlanet.text"))); + getChkStartCourseToContractPlanet().setToolTipText(resources.getString("chkStartCourseToContractPlanet.toolTipText")); + getChkStartCourseToContractPlanet().setName("chkStartCourseToContractPlanet"); + + // Disable Panel by Default + getChkSelectStartingContract().setSelected(true); + getChkSelectStartingContract().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("contractsPanel.title"))); + panel.setName("contractsPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkSelectStartingContract()) + .addComponent(getChkStartCourseToContractPlanet()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkSelectStartingContract()) + .addComponent(getChkStartCourseToContractPlanet()) + ); + + // TODO : Wave 5 : Company Generation GUI + panel.setEnabled(false); + getChkSelectStartingContract().setEnabled(false); + getChkStartCourseToContractPlanet().setEnabled(false); + + return panel; + } + + private JPanel createFinancesPanel() { + // Initialize Components Used in ActionListeners + final JPanel financialCreditsPanel = new JDisableablePanel("financialCreditsPanel"); + final JPanel financialDebitsPanel = new JDisableablePanel("financialDebitsPanel"); + + // Create Panel Components + setChkProcessFinances(new JCheckBox(resources.getString("chkProcessFinances.text"))); + getChkProcessFinances().setToolTipText(resources.getString("chkProcessFinances.toolTipText")); + getChkProcessFinances().setName("chkProcessFinances"); + getChkProcessFinances().addActionListener(evt -> { + final boolean selected = getChkProcessFinances().isSelected(); + financialCreditsPanel.setEnabled(selected); + financialDebitsPanel.setEnabled(selected); + + if (selected) { + getChkRandomizeStartingCash().setSelected(!getChkRandomizeStartingCash().isSelected()); + getChkRandomizeStartingCash().doClick(); + + getChkIncludeInitialContractPayment().setEnabled(getChkSelectStartingContract().isSelected()); + + getChkPayForSetup().setSelected(!getChkPayForSetup().isSelected()); + getChkPayForSetup().doClick(); + } + }); + + createFinancialCreditsPanel(financialCreditsPanel); + + createFinancialDebitsPanel(financialDebitsPanel); + + // Disable Panel Portions by Default + getChkProcessFinances().setSelected(true); + getChkProcessFinances().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("financesPanel.title"))); + panel.setName("financesPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkProcessFinances()) + .addComponent(financialCreditsPanel) + .addComponent(financialDebitsPanel) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkProcessFinances()) + .addComponent(financialCreditsPanel) + .addComponent(financialDebitsPanel) + ); + + return panel; + } + + private void createFinancialCreditsPanel(final JPanel panel) { + // Initialize Components Used in ActionListeners + final JLabel lblRandomStartingCashDiceCount = new JLabel(); + + // Create Panel Components + final JLabel lblStartingCash = new JLabel(resources.getString("lblStartingCash.text")); + lblStartingCash.setToolTipText(resources.getString("lblStartingCash.toolTipText")); + lblStartingCash.setName("lblStartingCash"); + + setSpnStartingCash(new JSpinner(new SpinnerNumberModel(0, 0, 200000000, 100000))); + getSpnStartingCash().setToolTipText(resources.getString("lblStartingCash.toolTipText")); + getSpnStartingCash().setName("spnStartingCash"); + + setChkRandomizeStartingCash(new JCheckBox(resources.getString("chkRandomizeStartingCash.text"))); + getChkRandomizeStartingCash().setToolTipText(resources.getString("chkRandomizeStartingCash.toolTipText")); + getChkRandomizeStartingCash().setName("chkRandomizeStartingCash"); + getChkRandomizeStartingCash().addActionListener(evt -> { + final boolean selected = getChkRandomizeStartingCash().isSelected(); + lblStartingCash.setEnabled(!selected); + getSpnStartingCash().setEnabled(!selected); + lblRandomStartingCashDiceCount.setEnabled(selected); + getSpnRandomStartingCashDiceCount().setEnabled(selected); + }); + + lblRandomStartingCashDiceCount.setText(resources.getString("lblRandomStartingCashDiceCount.text")); + lblRandomStartingCashDiceCount.setToolTipText(resources.getString("lblRandomStartingCashDiceCount.toolTipText")); + lblRandomStartingCashDiceCount.setName("lblRandomStartingCashDiceCount"); + + setSpnRandomStartingCashDiceCount(new JSpinner(new SpinnerNumberModel(8, 1, 100, 1))); + getSpnRandomStartingCashDiceCount().setToolTipText(resources.getString("lblRandomStartingCashDiceCount.toolTipText")); + getSpnRandomStartingCashDiceCount().setName("spnRandomStartingCashDiceCount"); + + final JLabel lblMinimumStartingFloat = new JLabel(resources.getString("lblMinimumStartingFloat.text")); + lblMinimumStartingFloat.setToolTipText(resources.getString("lblMinimumStartingFloat.toolTipText")); + lblMinimumStartingFloat.setName("lblMinimumStartingFloat"); + + setSpnMinimumStartingFloat(new JSpinner(new SpinnerNumberModel(0, 0, 10000000, 100000))); + getSpnMinimumStartingFloat().setToolTipText(resources.getString("lblMinimumStartingFloat.toolTipText")); + getSpnMinimumStartingFloat().setName("spnMinimumStartingFloat"); + + setChkIncludeInitialContractPayment(new JCheckBox(resources.getString("chkIncludeInitialContractPayment.text"))); + getChkIncludeInitialContractPayment().setToolTipText(resources.getString("chkIncludeInitialContractPayment.toolTipText")); + getChkIncludeInitialContractPayment().setName("chkIncludeInitialContractPayment"); + + setChkStartingLoan(new JCheckBox(resources.getString("chkStartingLoan.text"))); + getChkStartingLoan().setToolTipText(resources.getString("chkStartingLoan.toolTipText")); + getChkStartingLoan().setName("chkStartingLoan"); + + // Programmatically Assign Accessibility Labels + lblStartingCash.setLabelFor(getSpnStartingCash()); + lblRandomStartingCashDiceCount.setLabelFor(getSpnRandomStartingCashDiceCount()); + lblMinimumStartingFloat.setLabelFor(getSpnMinimumStartingFloat()); + + // Disable Panel Portions by Default + // This is handled by createFinancesPanel + + // Layout the UI + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("financialCreditsPanel.title"))); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblStartingCash) + .addComponent(getSpnStartingCash(), Alignment.LEADING)) + .addComponent(getChkRandomizeStartingCash()) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblRandomStartingCashDiceCount) + .addComponent(getSpnRandomStartingCashDiceCount(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblMinimumStartingFloat) + .addComponent(getSpnMinimumStartingFloat(), Alignment.LEADING)) + .addComponent(getChkIncludeInitialContractPayment()) + .addComponent(getChkStartingLoan()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblStartingCash) + .addComponent(getSpnStartingCash())) + .addComponent(getChkRandomizeStartingCash()) + .addGroup(layout.createSequentialGroup() + .addComponent(lblRandomStartingCashDiceCount) + .addComponent(getSpnRandomStartingCashDiceCount())) + .addGroup(layout.createSequentialGroup() + .addComponent(lblMinimumStartingFloat) + .addComponent(getSpnMinimumStartingFloat())) + .addComponent(getChkIncludeInitialContractPayment()) + .addComponent(getChkStartingLoan()) + ); + } + + private void createFinancialDebitsPanel(final JPanel panel) { + // Create Panel Components + setChkPayForSetup(new JCheckBox(resources.getString("chkPayForSetup.text"))); + getChkPayForSetup().setToolTipText(resources.getString("chkPayForSetup.toolTipText")); + getChkPayForSetup().setName("chkPayForSetup"); + getChkPayForSetup().addActionListener(evt -> { + final boolean enabled = getChkPayForSetup().isEnabled() && getChkPayForSetup().isSelected(); + getChkPayForPersonnel().setEnabled(enabled); + getChkPayForUnits().setEnabled(enabled); + getChkPayForParts().setEnabled(enabled); + getChkPayForArmour().setEnabled(enabled); + getChkPayForAmmunition().setEnabled(enabled); + }); + + setChkPayForPersonnel(new JCheckBox(resources.getString("chkPayForPersonnel.text"))); + getChkPayForPersonnel().setToolTipText(resources.getString("chkPayForPersonnel.toolTipText")); + getChkPayForPersonnel().setName("chkPayForPersonnel"); + + setChkPayForUnits(new JCheckBox(resources.getString("chkPayForUnits.text"))); + getChkPayForUnits().setToolTipText(resources.getString("chkPayForUnits.toolTipText")); + getChkPayForUnits().setName("chkPayForUnits"); + + setChkPayForParts(new JCheckBox(resources.getString("chkPayForParts.text"))); + getChkPayForParts().setToolTipText(resources.getString("chkPayForParts.toolTipText")); + getChkPayForParts().setName("chkPayForParts"); + + setChkPayForArmour(new JCheckBox(resources.getString("chkPayForArmour.text"))); + getChkPayForArmour().setToolTipText(resources.getString("chkPayForArmour.toolTipText")); + getChkPayForArmour().setName("chkPayForArmour"); + + setChkPayForAmmunition(new JCheckBox(resources.getString("chkPayForAmmunition.text"))); + getChkPayForAmmunition().setToolTipText(resources.getString("chkPayForAmmunition.toolTipText")); + getChkPayForAmmunition().setName("chkPayForAmmunition"); + + // Disable Panel Portions by Default + // This is handled by createFinancesPanel + + // Layout the UI + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("financialDebitsPanel.title"))); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkPayForSetup()) + .addComponent(getChkPayForPersonnel()) + .addComponent(getChkPayForUnits()) + .addComponent(getChkPayForParts()) + .addComponent(getChkPayForArmour()) + .addComponent(getChkPayForAmmunition()) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkPayForSetup()) + .addComponent(getChkPayForPersonnel()) + .addComponent(getChkPayForUnits()) + .addComponent(getChkPayForParts()) + .addComponent(getChkPayForArmour()) + .addComponent(getChkPayForAmmunition()) + ); + } + + private JPanel createSurprisesPanel() { + // Initialize Components Used in ActionListeners + final JPanel mysteryBoxPanel = new JDisableablePanel("mysteryBoxPanel"); + + // Create Panel Components + setChkGenerateSurprises(new JCheckBox(resources.getString("chkGenerateSurprises.text"))); + getChkGenerateSurprises().setToolTipText(resources.getString("chkGenerateSurprises.toolTipText")); + getChkGenerateSurprises().setName("chkGenerateSurprises"); + getChkGenerateSurprises().addActionListener(evt -> { + final boolean selected = getChkGenerateSurprises().isSelected(); + getChkGenerateMysteryBoxes().setEnabled(selected); + mysteryBoxPanel.setEnabled(selected && getChkGenerateMysteryBoxes().isSelected()); + }); + + setChkGenerateMysteryBoxes(new JCheckBox(resources.getString("chkGenerateMysteryBoxes.text"))); + getChkGenerateMysteryBoxes().setToolTipText(resources.getString("chkGenerateMysteryBoxes.toolTipText")); + getChkGenerateMysteryBoxes().setName("chkGenerateMysteryBoxes"); + getChkGenerateMysteryBoxes().addActionListener(evt -> mysteryBoxPanel.setEnabled( + getChkGenerateMysteryBoxes().isSelected())); + + createMysteryBoxPanel(mysteryBoxPanel); + + // Disable Panel by Default + getChkGenerateSurprises().setSelected(true); + getChkGenerateSurprises().doClick(); + + // Layout the UI + final JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("surprisesPanel.title"))); + panel.setToolTipText(resources.getString("surprisesPanel.toolTipText")); + panel.setName("surprisesPanel"); + final GroupLayout layout = new GroupLayout(panel); + panel.setLayout(layout); + + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(getChkGenerateSurprises()) + .addComponent(getChkGenerateMysteryBoxes()) + .addComponent(mysteryBoxPanel) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(getChkGenerateSurprises()) + .addComponent(getChkGenerateMysteryBoxes()) + .addComponent(mysteryBoxPanel) + ); + + // TODO : Wave 7 : Surprises + panel.setEnabled(false); + getChkGenerateSurprises().setEnabled(false); + getChkGenerateMysteryBoxes().setEnabled(false); + mysteryBoxPanel.setEnabled(false); + + return panel; + } + + private void createMysteryBoxPanel(final JPanel panel) { + // Create Panel + panel.setBorder(BorderFactory.createTitledBorder(resources.getString("mysteryBoxPanel.title"))); + panel.setToolTipText(resources.getString("mysteryBoxPanel.toolTipText")); + panel.setLayout(new GridLayout(0, 1)); + + // Create Panel Components + setChkGenerateMysteryBoxTypes(new HashMap<>()); + for (final MysteryBoxType type : MysteryBoxType.values()) { + getChkGenerateMysteryBoxTypes().put(type, new JCheckBox(type.toString())); + getChkGenerateMysteryBoxTypes().get(type).setToolTipText(type.getToolTipText()); + getChkGenerateMysteryBoxTypes().get(type).setName("chk" + type.name()); + panel.add(getChkGenerateMysteryBoxTypes().get(type)); + } + } + //endregion Initialization + + //region Options + /** + * Sets the options for this panel to the default for the selected CompanyGenerationMethod + */ + public void setOptions() { + setOptions(getComboCompanyGenerationMethod().getSelectedItem()); + } + + /** + * Sets the options for this panel to the default for the provided CompanyGenerationMethod + * @param method the CompanyGenerationOptions to create the CompanyGenerationOptions from + */ + public void setOptions(final CompanyGenerationMethod method) { + setOptions(new CompanyGenerationOptions(method)); + } + + /** + * Sets the options for this panel based on the provided CompanyGenerationOptions + * @param options the CompanyGenerationOptions to use + */ + public void setOptions(final CompanyGenerationOptions options) { + // Base Information + getComboCompanyGenerationMethod().setSelectedItem(options.getMethod()); + getChkGenerateMercenaryCompanyCommandLance().setSelected(options.isGenerateMercenaryCompanyCommandLance()); + getSpnCompanyCount().setValue(options.getCompanyCount()); + getSpnIndividualLanceCount().setValue(options.getIndividualLanceCount()); + getSpnLancesPerCompany().setValue(options.getLancesPerCompany()); + getSpnLanceSize().setValue(options.getLanceSize()); + getSpnStarLeagueYear().setValue(options.getStarLeagueYear()); + + // Personnel + updateLblTotalSupportPersonnel(determineMaximumSupportPersonnel()); + for (final Entry entry : getSpnSupportPersonnelNumbers().entrySet()) { + entry.getValue().setValue(options.getSupportPersonnel().getOrDefault(entry.getKey(), 0)); + } + getChkPoolAssistants().setSelected(options.isPoolAssistants()); + getChkGenerateCaptains().setSelected(options.isGenerateCaptains()); + getChkAssignCompanyCommanderFlag().setSelected(options.isAssignCompanyCommanderFlag()); + getChkApplyOfficerStatBonusToWorstSkill().setSelected(options.isApplyOfficerStatBonusToWorstSkill()); + if (getChkAssignBestCompanyCommander().isSelected() != options.isAssignBestCompanyCommander()) { + getChkAssignBestCompanyCommander().doClick(); + } + getChkPrioritizeCompanyCommanderCombatSkills().setSelected(options.isPrioritizeCompanyCommanderCombatSkills()); + if (getChkAssignBestOfficers().isSelected() != options.isAssignBestOfficers()) { + getChkAssignBestOfficers().doClick(); + } + getChkPrioritizeOfficerCombatSkills().setSelected(options.isPrioritizeOfficerCombatSkills()); + getChkAssignMostSkilledToPrimaryLances().setSelected(options.isAssignMostSkilledToPrimaryLances()); + getChkAutomaticallyAssignRanks().setSelected(options.isAutomaticallyAssignRanks()); + getChkAssignFounderFlag().setSelected(options.isAssignFounderFlag()); + + // Personnel Randomization + getRandomOriginOptionsPanel().setOptions(options.getRandomOriginOptions()); + + // Starting Simulation + if (getChkRunStartingSimulation().isSelected() != options.isRunStartingSimulation()) { + getChkRunStartingSimulation().doClick(); + } + getSpnSimulationDuration().setValue(options.getSimulationDuration()); + getChkSimulateRandomMarriages().setSelected(options.isSimulateRandomMarriages()); + getChkSimulateRandomProcreation().setSelected(options.isSimulateRandomProcreation()); + + // Units + getComboBattleMechWeightClassGenerationMethod().setSelectedItem(options.getBattleMechWeightClassGenerationMethod()); + getComboBattleMechQualityGenerationMethod().setSelectedItem(options.getBattleMechQualityGenerationMethod()); + getChkNeverGenerateStarLeagueMechs().setSelected(options.isNeverGenerateStarLeagueMechs()); + getChkOnlyGenerateStarLeagueMechs().setSelected(options.isOnlyGenerateStarLeagueMechs()); + getChkOnlyGenerateOmniMechs().setSelected(options.isOnlyGenerateOmniMechs()); + getChkGenerateUnitsAsAttached().setSelected(options.isGenerateUnitsAsAttached()); + getChkAssignBestRollToCompanyCommander().setSelected(options.isAssignBestRollToCompanyCommander()); + getChkSortStarLeagueUnitsFirst().setSelected(options.isSortStarLeagueUnitsFirst()); + getChkGroupByWeight().setSelected(options.isGroupByWeight()); + getChkGroupByQuality().setSelected(options.isGroupByQuality()); + getChkKeepOfficerRollsSeparate().setSelected(options.isKeepOfficerRollsSeparate()); + getChkAssignTechsToUnits().setSelected(options.isAssignTechsToUnits()); + + // Unit + getComboForceNamingMethod().setSelectedItem(options.getForceNamingMethod()); + if (getChkGenerateForceIcons().isSelected() != options.isGenerateForceIcons()) { + getChkGenerateForceIcons().doClick(); + } + + if (getChkGenerateOriginNodeForceIcon().isSelected() != options.isGenerateOriginNodeForceIcon()) { + getChkGenerateOriginNodeForceIcon().doClick(); + } + getChkUseOriginNodeForceIconLogo().setSelected(options.isUseOriginNodeForceIconLogo()); + for (final Entry entry : options.getForceWeightLimits().entrySet()) { + getSpnForceWeightLimits().get(entry.getValue()).setValue(entry.getKey()); + } + + // Spares + if (getChkGenerateMothballedSpareUnits().isSelected() != options.isGenerateMothballedSpareUnits()) { + getChkGenerateMothballedSpareUnits().doClick(); + } + getSpnSparesPercentOfActiveUnits().setValue(options.getSparesPercentOfActiveUnits()); + getComboPartGenerationMethod().setSelectedItem(options.getPartGenerationMethod()); + getSpnStartingArmourWeight().setValue(options.getStartingArmourWeight()); + if (getChkGenerateSpareAmmunition().isSelected() != options.isGenerateSpareAmmunition()) { + getChkGenerateSpareAmmunition().doClick(); + } + getSpnNumberReloadsPerWeapon().setValue(options.getNumberReloadsPerWeapon()); + getChkGenerateFractionalMachineGunAmmunition().setSelected(options.isGenerateFractionalMachineGunAmmunition()); + + // Contracts + if (getChkSelectStartingContract().isSelected() != options.isSelectStartingContract()) { + getChkSelectStartingContract().doClick(); + } + getChkStartCourseToContractPlanet().setSelected(options.isStartCourseToContractPlanet()); + + // Finances + if (getChkProcessFinances().isSelected() != options.isProcessFinances()) { + getChkProcessFinances().doClick(); + } + getSpnStartingCash().setValue(options.getStartingCash()); + if (getChkRandomizeStartingCash().isSelected() != options.isRandomizeStartingCash()) { + getChkRandomizeStartingCash().doClick(); + } + getSpnRandomStartingCashDiceCount().setValue(options.getRandomStartingCashDiceCount()); + getSpnMinimumStartingFloat().setValue(options.getMinimumStartingFloat()); + getChkIncludeInitialContractPayment().setSelected(options.isIncludeInitialContractPayment()); + getChkStartingLoan().setSelected(options.isStartingLoan()); + if (getChkPayForSetup().isSelected() != options.isPayForSetup()) { + getChkPayForSetup().doClick(); + } + getChkPayForPersonnel().setSelected(options.isPayForPersonnel()); + getChkPayForUnits().setSelected(options.isPayForUnits()); + getChkPayForParts().setSelected(options.isPayForParts()); + getChkPayForArmour().setSelected(options.isPayForArmour()); + getChkPayForAmmunition().setSelected(options.isPayForAmmunition()); + + // Surprises + if (getChkGenerateSurprises().isSelected() != options.isGenerateSurprises()) { + getChkGenerateSurprises().doClick(); + } + + if (getChkGenerateMysteryBoxes().isSelected() != options.isGenerateMysteryBoxes()) { + getChkGenerateMysteryBoxes().doClick(); + } + + for (final Entry entry : getChkGenerateMysteryBoxTypes().entrySet()) { + entry.getValue().setSelected(options.getGenerateMysteryBoxTypes().getOrDefault(entry.getKey(), false)); + } + } + + /** + * @return the CompanyGenerationOptions created from the current panel + */ + public CompanyGenerationOptions createOptionsFromPanel() { + final CompanyGenerationOptions options = new CompanyGenerationOptions( + getComboCompanyGenerationMethod().getSelectedItem()); + + // Base Information + options.setGenerateMercenaryCompanyCommandLance(getChkGenerateMercenaryCompanyCommandLance().isSelected()); + options.setCompanyCount((Integer) getSpnCompanyCount().getValue()); + options.setIndividualLanceCount((Integer) getSpnIndividualLanceCount().getValue()); + options.setLancesPerCompany((Integer) getSpnLancesPerCompany().getValue()); + options.setLanceSize((Integer) getSpnLanceSize().getValue()); + options.setStarLeagueYear((Integer) getSpnStarLeagueYear().getValue()); + + // Personnel + options.setSupportPersonnel(new HashMap<>()); + for (final Entry entry : getSpnSupportPersonnelNumbers().entrySet()) { + final int value = (int) entry.getValue().getValue(); + if (value <= 0) { + continue; + } + options.getSupportPersonnel().put(entry.getKey(), value); + } + options.setPoolAssistants(getChkPoolAssistants().isSelected()); + options.setGenerateCaptains(getChkGenerateCaptains().isSelected()); + options.setAssignCompanyCommanderFlag(getChkAssignCompanyCommanderFlag().isSelected()); + options.setApplyOfficerStatBonusToWorstSkill(getChkApplyOfficerStatBonusToWorstSkill().isSelected()); + options.setAssignBestCompanyCommander(getChkAssignBestCompanyCommander().isSelected()); + options.setPrioritizeCompanyCommanderCombatSkills(getChkPrioritizeCompanyCommanderCombatSkills().isSelected()); + options.setAssignBestOfficers(getChkAssignBestOfficers().isSelected()); + options.setPrioritizeOfficerCombatSkills(getChkPrioritizeOfficerCombatSkills().isSelected()); + options.setAssignMostSkilledToPrimaryLances(getChkAssignMostSkilledToPrimaryLances().isSelected()); + options.setAutomaticallyAssignRanks(getChkAutomaticallyAssignRanks().isSelected()); + options.setAssignFounderFlag(getChkAssignFounderFlag().isSelected()); + + // Personnel Randomization + options.setRandomOriginOptions(getRandomOriginOptionsPanel().createOptionsFromPanel()); + + // Starting Simulation + options.setRunStartingSimulation(getChkRunStartingSimulation().isSelected()); + options.setSimulationDuration((Integer) getSpnSimulationDuration().getValue()); + options.setSimulateRandomMarriages(getChkSimulateRandomMarriages().isSelected()); + options.setSimulateRandomProcreation(getChkSimulateRandomProcreation().isSelected()); + + // Units + options.setBattleMechWeightClassGenerationMethod(getComboBattleMechWeightClassGenerationMethod().getSelectedItem()); + options.setBattleMechQualityGenerationMethod(getComboBattleMechQualityGenerationMethod().getSelectedItem()); + options.setNeverGenerateStarLeagueMechs(getChkNeverGenerateStarLeagueMechs().isSelected()); + options.setOnlyGenerateStarLeagueMechs(getChkOnlyGenerateStarLeagueMechs().isSelected()); + options.setOnlyGenerateOmniMechs(getChkOnlyGenerateOmniMechs().isSelected()); + options.setGenerateUnitsAsAttached(getChkGenerateUnitsAsAttached().isSelected()); + options.setAssignBestRollToCompanyCommander(getChkAssignBestRollToCompanyCommander().isSelected()); + options.setSortStarLeagueUnitsFirst(getChkSortStarLeagueUnitsFirst().isSelected()); + options.setGroupByWeight(getChkGroupByWeight().isSelected()); + options.setGroupByQuality(getChkGroupByQuality().isSelected()); + options.setKeepOfficerRollsSeparate(getChkKeepOfficerRollsSeparate().isSelected()); + options.setAssignTechsToUnits(getChkAssignTechsToUnits().isSelected()); + + // Unit + options.setForceNamingMethod(getComboForceNamingMethod().getSelectedItem()); + options.setGenerateForceIcons(getChkGenerateForceIcons().isSelected()); + options.setGenerateOriginNodeForceIcon(getChkGenerateOriginNodeForceIcon().isSelected()); + options.setUseOriginNodeForceIconLogo(getChkUseOriginNodeForceIconLogo().isSelected()); + options.setForceWeightLimits(new TreeMap<>()); + for (final Entry entry : getSpnForceWeightLimits().entrySet()) { + options.getForceWeightLimits().put((int) entry.getValue().getValue(), entry.getKey()); + } + + // Spares + options.setGenerateMothballedSpareUnits(getChkGenerateMothballedSpareUnits().isSelected()); + options.setSparesPercentOfActiveUnits((Integer) getSpnSparesPercentOfActiveUnits().getValue()); + options.setPartGenerationMethod(getComboPartGenerationMethod().getSelectedItem()); + options.setStartingArmourWeight((Integer) getSpnStartingArmourWeight().getValue()); + options.setGenerateSpareAmmunition(getChkGenerateSpareAmmunition().isSelected()); + options.setNumberReloadsPerWeapon((Integer) getSpnNumberReloadsPerWeapon().getValue()); + options.setGenerateFractionalMachineGunAmmunition(getChkGenerateFractionalMachineGunAmmunition().isSelected()); + + // Contracts + options.setSelectStartingContract(getChkSelectStartingContract().isSelected()); + options.setStartCourseToContractPlanet(getChkStartCourseToContractPlanet().isSelected()); + + // Finances + options.setProcessFinances(getChkProcessFinances().isSelected()); + options.setStartingCash((Integer) getSpnStartingCash().getValue()); + options.setRandomizeStartingCash(getChkRandomizeStartingCash().isSelected()); + options.setRandomStartingCashDiceCount((Integer) getSpnRandomStartingCashDiceCount().getValue()); + options.setMinimumStartingFloat((Integer) getSpnMinimumStartingFloat().getValue()); + options.setIncludeInitialContractPayment(getChkIncludeInitialContractPayment().isSelected()); + options.setStartingLoan(getChkStartingLoan().isSelected()); + options.setPayForSetup(getChkPayForSetup().isSelected()); + options.setPayForPersonnel(getChkPayForPersonnel().isSelected()); + options.setPayForUnits(getChkPayForUnits().isSelected()); + options.setPayForParts(getChkPayForParts().isSelected()); + options.setPayForArmour(getChkPayForArmour().isSelected()); + options.setPayForAmmunition(getChkPayForAmmunition().isSelected()); + + // Surprises + options.setGenerateSurprises(getChkGenerateSurprises().isSelected()); + options.setGenerateMysteryBoxes(getChkGenerateMysteryBoxes().isSelected()); + options.setGenerateMysteryBoxTypes(new HashMap<>()); + for (final Entry entry : getChkGenerateMysteryBoxTypes().entrySet()) { + options.getGenerateMysteryBoxTypes().put(entry.getKey(), entry.getValue().isSelected()); + } + + return options; + } + + /** + * Validates the data contained in this panel, returning the current state of validation. + * @param display to display dialogs containing the messages or not + * @return true if the data validates successfully, otherwise false + */ + public ValidationState validateOptions(final boolean display) { + //region Errors + // Minimum Generation Size Validation + // Minimum Generation Parameter of 1 Company or Lance, the Company Command Lance Doesn't Count + if (((int) getSpnCompanyCount().getValue() <= 0) + && ((int) getSpnIndividualLanceCount().getValue() <= 0)) { + if (display) { + JOptionPane.showMessageDialog(getFrame(), + resources.getString("CompanyGenerationOptionsPanel.InvalidGenerationSize.text"), + resources.getString("InvalidOptions.title"), + JOptionPane.ERROR_MESSAGE); + } + return ValidationState.FAILURE; + } + + // Random Origin Options Validation + if (getRandomOriginOptionsPanel().validateOptions(display).isFailure()) { + return ValidationState.FAILURE; + } + //endregion Errors + + //region Warnings + // Only need to check these if they are to be displayed + if (display) { + // Support Personnel Count: + // 1) Above Recommended Maximum Support Personnel Count + // 2) Below Half of Recommended Maximum Support Personnel Count + final int maximumSupportPersonnelCount = determineMaximumSupportPersonnel(); + final int currentSupportPersonnelCount = getSpnSupportPersonnelNumbers().values().stream() + .mapToInt(spinner -> (int) spinner.getValue()).sum(); + if ((maximumSupportPersonnelCount < currentSupportPersonnelCount) + && (JOptionPane.showConfirmDialog(getFrame(), + resources.getString("CompanyGenerationOptionsPanel.OverMaximumSupportPersonnel.text"), + resources.getString("CompanyGenerationOptionsPanel.OverMaximumSupportPersonnel.title"), + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.NO_OPTION)) { + return ValidationState.WARNING; + } else if ((currentSupportPersonnelCount < (maximumSupportPersonnelCount / 2.0)) + && (JOptionPane.showConfirmDialog(getFrame(), + resources.getString("CompanyGenerationOptionsPanel.UnderHalfMaximumSupportPersonnel.text"), + resources.getString("CompanyGenerationOptionsPanel.UnderHalfMaximumSupportPersonnel.title"), + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.NO_OPTION)) { + return ValidationState.WARNING; + } + } + //endregion Warnings + + // The options specified are correct, and thus can be saved + return ValidationState.SUCCESS; + } + //endregion Options + + //region File I/O + /** + * Imports CompanyGenerationOptions from an XML file + */ + public void importOptionsFromXML() { + FileDialogs.openCompanyGenerationOptions(getFrame()) + .ifPresent(file -> setOptions(CompanyGenerationOptions.parseFromXML(file))); + } + + /** + * Exports the CompanyGenerationOptions displayed on this panel to an XML file. + */ + public void exportOptionsToXML() { + FileDialogs.saveCompanyGenerationOptions(getFrame()) + .ifPresent(file -> createOptionsFromPanel().writeToFile(file)); + } + //endregion File I/O +} diff --git a/MekHQ/src/mekhq/gui/panels/RandomOriginOptionsPanel.java b/MekHQ/src/mekhq/gui/panels/RandomOriginOptionsPanel.java index 0822eefcc0..1b23e00b5d 100644 --- a/MekHQ/src/mekhq/gui/panels/RandomOriginOptionsPanel.java +++ b/MekHQ/src/mekhq/gui/panels/RandomOriginOptionsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * Copyright (c) 2021-2022 - The MegaMek Team. All Rights Reserved. * * This file is part of MekHQ. * @@ -19,6 +19,7 @@ package mekhq.gui.panels; import megamek.client.ui.baseComponents.MMComboBox; +import megamek.client.ui.enums.ValidationState; import megamek.common.annotations.Nullable; import mekhq.campaign.Campaign; import mekhq.campaign.RandomOriginOptions; @@ -30,22 +31,31 @@ import org.apache.logging.log4j.LogManager; import javax.swing.*; +import javax.swing.GroupLayout.Alignment; import java.awt.*; import java.util.Comparator; import java.util.Objects; import java.util.stream.Collectors; +/** + * This is used to select a set of RandomOriginOptions. It requires either the faction or the + * ComboBox from which a faction is selected, the former when the faction is constant and the + * latter when it can change after this panel is initialized. + * + * @author Justin "Windchild" Bowen + */ public class RandomOriginOptionsPanel extends AbstractMHQPanel { //region Variable Declarations private final Campaign campaign; + private final Faction faction; private final MMComboBox comboFaction; private JCheckBox chkRandomizeOrigin; private JCheckBox chkRandomizeDependentsOrigin; private JCheckBox chkRandomizeAroundSpecifiedPlanet; private JCheckBox chkSpecifiedSystemFactionSpecific; - private JComboBox comboSpecifiedSystem; - private JComboBox comboSpecifiedPlanet; + private MMComboBox comboSpecifiedSystem; + private MMComboBox comboSpecifiedPlanet; private JSpinner spnOriginSearchRadius; private JSpinner spnOriginDistanceScale; private JCheckBox chkAllowClanOrigins; @@ -53,10 +63,22 @@ public class RandomOriginOptionsPanel extends AbstractMHQPanel { //endregion Variable Declarations //region Constructors + public RandomOriginOptionsPanel(final JFrame frame, final Campaign campaign, + final Faction faction) { + this(frame, campaign, faction, null); + } + public RandomOriginOptionsPanel(final JFrame frame, final Campaign campaign, final MMComboBox comboFaction) { + this(frame, campaign, null, comboFaction); + } + + private RandomOriginOptionsPanel(final JFrame frame, final Campaign campaign, + final @Nullable Faction faction, + final @Nullable MMComboBox comboFaction) { super(frame, "RandomOriginOptionsPanel"); this.campaign = campaign; + this.faction = faction; this.comboFaction = comboFaction; initialize(); } @@ -67,12 +89,17 @@ public Campaign getCampaign() { return campaign; } - public MMComboBox getComboFaction() { - return comboFaction; + public Faction getFaction() { + return (getComboFaction() == null) ? getFactionDirect() + : Objects.requireNonNull(getComboFaction().getSelectedItem()).getFaction(); } - public Faction getFaction() { - return Objects.requireNonNull(getComboFaction().getSelectedItem()).getFaction(); + private @Nullable Faction getFactionDirect() { + return faction; + } + + public @Nullable MMComboBox getComboFaction() { + return comboFaction; } public JCheckBox getChkRandomizeOrigin() { @@ -107,15 +134,11 @@ public void setChkSpecifiedSystemFactionSpecific(final JCheckBox chkSpecifiedSys this.chkSpecifiedSystemFactionSpecific = chkSpecifiedSystemFactionSpecific; } - public JComboBox getComboSpecifiedSystem() { + public MMComboBox getComboSpecifiedSystem() { return comboSpecifiedSystem; } - public @Nullable PlanetarySystem getSpecifiedSystem() { - return (PlanetarySystem) getComboSpecifiedSystem().getSelectedItem(); - } - - public void setComboSpecifiedSystem(final JComboBox comboSpecifiedSystem) { + public void setComboSpecifiedSystem(final MMComboBox comboSpecifiedSystem) { this.comboSpecifiedSystem = comboSpecifiedSystem; } @@ -126,25 +149,22 @@ private void restoreComboSpecifiedSystem() { restoreComboSpecifiedPlanet(); } - public JComboBox getComboSpecifiedPlanet() { + public MMComboBox getComboSpecifiedPlanet() { return comboSpecifiedPlanet; } - public @Nullable Planet getSpecifiedPlanet() { - return (Planet) getComboSpecifiedPlanet().getSelectedItem(); - } - - public void setComboSpecifiedPlanet(final JComboBox comboSpecifiedPlanet) { + public void setComboSpecifiedPlanet(final MMComboBox comboSpecifiedPlanet) { this.comboSpecifiedPlanet = comboSpecifiedPlanet; } private void restoreComboSpecifiedPlanet() { - if (getSpecifiedSystem() != null) { - getComboSpecifiedPlanet().setModel(new DefaultComboBoxModel<>( - getSpecifiedSystem().getPlanets().toArray(new Planet[]{}))); - getComboSpecifiedPlanet().setSelectedItem(getSpecifiedSystem().getPrimaryPlanet()); - } else { + final PlanetarySystem planetarySystem = getComboSpecifiedSystem().getSelectedItem(); + if (planetarySystem == null) { getComboSpecifiedPlanet().removeAllItems(); + } else { + getComboSpecifiedPlanet().setModel(new DefaultComboBoxModel<>( + planetarySystem.getPlanets().toArray(new Planet[]{}))); + getComboSpecifiedPlanet().setSelectedItem(planetarySystem.getPrimaryPlanet()); } } @@ -227,8 +247,9 @@ protected void initialize() { getChkSpecifiedSystemFactionSpecific().setToolTipText(resources.getString("chkSpecifiedSystemFactionSpecific.toolTipText")); getChkSpecifiedSystemFactionSpecific().setName("chkSpecifiedSystemFactionSpecific"); getChkSpecifiedSystemFactionSpecific().addActionListener(evt -> { - if ((getSpecifiedSystem() == null) || ((getSpecifiedSystem() != null) - && !getSpecifiedSystem().getFactionSet(getCampaign().getLocalDate()).contains(getFaction()))) { + final PlanetarySystem planetarySystem = getComboSpecifiedSystem().getSelectedItem(); + if ((planetarySystem == null) + || !planetarySystem.getFactionSet(getCampaign().getLocalDate()).contains(getFaction())) { restoreComboSpecifiedSystem(); } }); @@ -237,9 +258,8 @@ protected void initialize() { lblSpecifiedPlanet.setToolTipText(resources.getString("lblSpecifiedPlanet.toolTipText")); lblSpecifiedPlanet.setName("lblSpecifiedPlanet"); - setComboSpecifiedSystem(new JComboBox<>()); + setComboSpecifiedSystem(new MMComboBox<>("comboSpecifiedSystem")); getComboSpecifiedSystem().setToolTipText(resources.getString("comboSpecifiedSystem.toolTipText")); - getComboSpecifiedSystem().setName("comboSpecifiedSystem"); getComboSpecifiedSystem().setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(final JList list, final Object value, @@ -253,15 +273,16 @@ public Component getListCellRendererComponent(final JList list, final Object } }); getComboSpecifiedSystem().addActionListener(evt -> { - if ((getSpecifiedSystem() == null) || ((getSpecifiedSystem() != null) && (getSpecifiedPlanet() != null) - && !getSpecifiedPlanet().getParentSystem().equals(getSpecifiedSystem()))) { + final PlanetarySystem planetarySystem = getComboSpecifiedSystem().getSelectedItem(); + final Planet planet = getComboSpecifiedPlanet().getSelectedItem(); + if ((planetarySystem == null) + || ((planet != null) && !planet.getParentSystem().equals(planetarySystem))) { restoreComboSpecifiedPlanet(); } }); - setComboSpecifiedPlanet(new JComboBox<>()); + setComboSpecifiedPlanet(new MMComboBox<>("comboSpecifiedPlanet")); getComboSpecifiedPlanet().setToolTipText(resources.getString("lblSpecifiedPlanet.toolTipText")); - getComboSpecifiedPlanet().setName("comboSpecifiedPlanet"); getComboSpecifiedPlanet().setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(final JList list, final Object value, @@ -321,25 +342,25 @@ public Component getListCellRendererComponent(final JList list, final Object layout.createSequentialGroup() .addComponent(getChkRandomizeOrigin()) .addComponent(getChkRandomizeDependentsOrigin()) - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(getChkRandomizeAroundSpecifiedPlanet()) - .addComponent(getChkSpecifiedSystemFactionSpecific(), GroupLayout.Alignment.LEADING)) - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(getChkSpecifiedSystemFactionSpecific(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(lblSpecifiedPlanet) .addComponent(getComboSpecifiedSystem()) - .addComponent(getComboSpecifiedPlanet(), GroupLayout.Alignment.LEADING)) - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(getComboSpecifiedPlanet(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(lblOriginSearchRadius) - .addComponent(getSpnOriginSearchRadius(), GroupLayout.Alignment.LEADING)) - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(getSpnOriginSearchRadius(), Alignment.LEADING)) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(lblOriginDistanceScale) - .addComponent(getSpnOriginDistanceScale(), GroupLayout.Alignment.LEADING)) + .addComponent(getSpnOriginDistanceScale(), Alignment.LEADING)) .addComponent(getChkAllowClanOrigins()) .addComponent(getChkExtraRandomOrigin()) ); layout.setHorizontalGroup( - layout.createParallelGroup(GroupLayout.Alignment.LEADING) + layout.createParallelGroup(Alignment.LEADING) .addComponent(getChkRandomizeOrigin()) .addComponent(getChkRandomizeDependentsOrigin()) .addGroup(layout.createSequentialGroup() @@ -368,6 +389,7 @@ private PlanetarySystem[] getPlanetarySystems(final @Nullable Faction faction) { } //endregion Initialization + //region Options public void setOptions(final RandomOriginOptions options) { if (getChkRandomizeOrigin().isSelected() != options.isRandomizeOrigin()) { getChkRandomizeOrigin().doClick(); @@ -392,7 +414,7 @@ public RandomOriginOptions createOptionsFromPanel() { options.setRandomizeOrigin(getChkRandomizeOrigin().isSelected()); options.setRandomizeDependentOrigin(getChkRandomizeDependentsOrigin().isSelected()); options.setRandomizeAroundSpecifiedPlanet(getChkRandomizeAroundSpecifiedPlanet().isSelected()); - options.setSpecifiedPlanet(getSpecifiedPlanet()); + options.setSpecifiedPlanet(getComboSpecifiedPlanet().getSelectedItem()); options.setOriginSearchRadius((Integer) getSpnOriginSearchRadius().getValue()); options.setOriginDistanceScale((Double) getSpnOriginDistanceScale().getValue()); options.setAllowClanOrigins(getChkAllowClanOrigins().isSelected()); @@ -402,4 +424,30 @@ public RandomOriginOptions createOptionsFromPanel() { } return options; } + + /** + * Validates the data contained in this panel, returning the current state of validation. + * @param display to display dialogs containing the messages or not + * @return ValidationState.SUCCESS if the data validates successfully, ValidationState.WARNING + * if a warning was issued, or ValidationState.FAILURE if validation fails + */ + public ValidationState validateOptions(final boolean display) { + //region Errors + // Specified System/Planet Validation + if ((getComboSpecifiedSystem().getSelectedItem() == null) + || (getComboSpecifiedPlanet().getSelectedItem() == null)) { + if (display) { + JOptionPane.showMessageDialog(getFrame(), + resources.getString("RandomOriginOptionsPanel.InvalidSpecifiedPlanet.text"), + resources.getString("InvalidOptions.title"), + JOptionPane.ERROR_MESSAGE); + } + return ValidationState.FAILURE; + } + //endregion Errors + + // The options specified are correct, and thus can be saved + return ValidationState.SUCCESS; + } + //endregion Options } diff --git a/MekHQ/src/mekhq/gui/renderers/CampaignPresetRenderer.java b/MekHQ/src/mekhq/gui/renderers/CampaignPresetRenderer.java index 0537e3dd00..25b81fe3d7 100644 --- a/MekHQ/src/mekhq/gui/renderers/CampaignPresetRenderer.java +++ b/MekHQ/src/mekhq/gui/renderers/CampaignPresetRenderer.java @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MekHQ. - * - * MekHQ is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MekHQ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with MekHQ. If not, see . - */ -package mekhq.gui.renderers; - -import mekhq.campaign.CampaignPreset; -import mekhq.gui.panels.CampaignPresetPanel; - -import javax.swing.*; -import java.awt.*; - -public class CampaignPresetRenderer extends CampaignPresetPanel implements ListCellRenderer { - //region Constructors - public CampaignPresetRenderer(final JFrame frame) { - super(frame, null, null); - } - //endregion Constructors - - @Override - public Component getListCellRendererComponent(final JList list, - final CampaignPreset value, final int index, - final boolean isSelected, - final boolean cellHasFocus) { - // JTextArea::setForeground and JTextArea::setBackground don't work properly with the - // default return, but by recreating the colour it works properly - final Color foreground = new Color((isSelected - ? list.getSelectionForeground() : list.getForeground()).getRGB()); - final Color background = new Color((isSelected - ? list.getSelectionBackground() : list.getBackground()).getRGB()); - setForeground(foreground); - setBackground(background); - - getTxtDescription().setForeground(foreground); - getTxtDescription().setBackground(background); - - updateFromPreset(value); - this.revalidate(); - - return this; - } - - @Override - public Dimension getMinimumSize() { - return new Dimension(300, 100); - } - - @Override - public Dimension getPreferredSize() { - return new Dimension(400, 120); - } -} +/* + * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MekHQ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MekHQ. If not, see . + */ +package mekhq.gui.renderers; + +import mekhq.campaign.CampaignPreset; +import mekhq.gui.panels.CampaignPresetPanel; + +import javax.swing.*; +import java.awt.*; + +public class CampaignPresetRenderer extends CampaignPresetPanel implements ListCellRenderer { + //region Constructors + public CampaignPresetRenderer(final JFrame frame) { + super(frame, null, null); + } + //endregion Constructors + + @Override + public Component getListCellRendererComponent(final JList list, + final CampaignPreset value, final int index, + final boolean isSelected, + final boolean cellHasFocus) { + // JTextArea::setForeground and JTextArea::setBackground don't work properly with the + // default return, but by recreating the colour it works properly + final Color foreground = new Color((isSelected + ? list.getSelectionForeground() : list.getForeground()).getRGB()); + final Color background = new Color((isSelected + ? list.getSelectionBackground() : list.getBackground()).getRGB()); + setForeground(foreground); + setBackground(background); + + getTxtDescription().setForeground(foreground); + getTxtDescription().setBackground(background); + + updateFromPreset(value); + this.revalidate(); + + return this; + } + + @Override + public Dimension getMinimumSize() { + return new Dimension(300, 100); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(400, 120); + } +}