From 680d1d07030b56aa61689ed4b20559751c1cd076 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 12:41:43 -0500 Subject: [PATCH 01/12] Refactored education checks in EducationController The education checks in EducationController.java were refactored for improved readability and maintainability. The code was broken down into individual methods each handling a specific type of check: weekly, monthly, and yearly. --- .../education/EducationController.java | 109 ++++++++++++------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 21764675c6..72f3bf1ca8 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -348,24 +348,22 @@ private static boolean ongoingEducation(Campaign campaign, Person person, Academ person.setEduEducationStage(EducationStage.GRADUATING); - if (campaign.getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY) { - processNewWeekChecks(campaign, academy, person, resources); + // if the person is graduating at the beginning of a month, + // they are still entitled to random xp + if (campaign.getLocalDate().getDayOfMonth() == 1) { + processNewMonthChecks(campaign, academy, person); } return true; } - if (campaign.getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY) { - processNewWeekChecks(campaign, academy, person, resources); - } + checkForEvents(campaign, person, academy, resources); return false; } else { person.setEduEducationTime(daysOfEducation - 1); - if (campaign.getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY) { - processNewWeekChecks(campaign, academy, person, resources); - } + checkForEvents(campaign, person, academy, resources); // we use 2 as that would be the value prior the day's decrement if (daysOfEducation < 2) { @@ -380,6 +378,28 @@ private static boolean ongoingEducation(Campaign campaign, Person person, Academ return false; } + /** + * Checks for any events based on the current date of the campaign. + * + * @param campaign the campaign to check events for + * @param person the person involved in the campaign + * @param academy the academy related to the campaign + * @param resources the resource bundle for localized messages + */ + private static void checkForEvents(Campaign campaign, Person person, Academy academy, ResourceBundle resources) { + if (campaign.getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY) { + processNewWeekChecks(campaign, academy, person, resources); + } + + if (campaign.getLocalDate().getDayOfMonth() == 1) { + processNewMonthChecks(campaign, academy, person); + } + + if (campaign.getLocalDate().getDayOfYear() == 1) { + processNewYearChecks(campaign, academy, person, resources); + } + } + /** * Picks the appropriate graduation method based on the given campaign, person, academy, and resources. * @@ -466,46 +486,61 @@ public static Academy getAcademy(String academySetName, String academyNameInSet) * @param resources The resource bundle used for localized strings. */ private static void processNewWeekChecks(Campaign campaign, Academy academy, Person person, ResourceBundle resources) { - if ((campaign.getCampaignOptions().isEnableRandomXp()) && (campaign.getLocalDate().getDayOfMonth() == 1)) { - if (Compute.d6(2) >= academy.getFacultySkill()) { - person.awardXP(campaign, campaign.getCampaignOptions().getRandomXpRate()); + // has the system been depopulated? Nominally similar to destruction, but here we use actual system data, so it's more dynamic. + if (campaign.getSystemById(person.getEduAcademySystem()).getPopulation(campaign.getLocalDate()) == 0) { + if (checkForAcademyDestruction(campaign, academy, person, resources)) { + return; } } - if (!person.getEduEducationStage().isGraduating()) { - // It's unlikely we'll ever get canonical destruction or closure dates for all the academies, - // so no need to check these more than once a year - if (campaign.getLocalDate().getDayOfYear() == 1) { - // time to check whether the academy is still standing. - if (checkForAcademyDestruction(campaign, academy, person, resources)) { - return; - } + // is the academy faction at war with person faction, or the campaign faction? + if (checkForAcademyFactionConflict(campaign, academy, person, resources)) { + return; + } - // is the academy still open? - if (checkForAcademyClosure(campaign, academy, person, resources)) { - return; - } - } + // does person want to drop out? + if (checkForDropout(campaign, academy, person, resources)) { + return; + } - // has the system been depopulated? Nominally similar to the above, but here we use actual system data, so it's more dynamic. - if (campaign.getSystemById(person.getEduAcademySystem()).getPopulation(campaign.getLocalDate()) == 0) { - if (checkForAcademyDestruction(campaign, academy, person, resources)) { - return; - } - } + // was there a training accident? + checkForTrainingAccidents(campaign, academy, person, resources); + } - // is the academy faction at war with person faction, or the campaign faction? - if (checkForAcademyFactionConflict(campaign, academy, person, resources)) { - return; + /** + * Processes the new month checks for a specific person in a campaign. + * + * @param campaign The campaign in which the person is participating. + * @param academy The academy where the person is receiving education. + * @param person The person whose new month checks need to be processed. + */ + private static void processNewMonthChecks(Campaign campaign, Academy academy, Person person) { + if (campaign.getCampaignOptions().isEnableRandomXp()) { + if (Compute.d6(2) >= academy.getFacultySkill()) { + person.awardXP(campaign, campaign.getCampaignOptions().getRandomXpRate()); } + } + } - // does person want to drop out? - if (checkForDropout(campaign, academy, person, resources)) { + /** + * Processes the new year checks for a specific person in a campaign. + * + * @param campaign The campaign in which the person is participating. + * @param academy The academy where the person is receiving education. + * @param person The person whose new month checks need to be processed. + * @param resources The resource bundle used for localized strings. + */ + private static void processNewYearChecks(Campaign campaign, Academy academy, Person person, ResourceBundle resources) { + // It's unlikely we'll ever get canonical destruction or closure dates for all the academies, + // so no need to check these more than once a year + if (campaign.getLocalDate().getDayOfYear() == 1) { + // time to check whether the academy is still standing. + if (checkForAcademyDestruction(campaign, academy, person, resources)) { return; } - // was there a training accident? - checkForTrainingAccidents(campaign, academy, person, resources); + // is the academy still open? + checkForAcademyClosure(campaign, academy, person, resources); } } From 7f65bafd4a98c3c690baca804dda7ce28886afd3 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 13:46:49 -0500 Subject: [PATCH 02/12] Updated text for barely graduated education status The text for the "barely graduated" education status in the Education.properties file was updated. The revised version provides a more specific phrase that includes the name of the institution from which the individual has barely graduated. --- MekHQ/resources/mekhq/resources/Education.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MekHQ/resources/mekhq/resources/Education.properties b/MekHQ/resources/mekhq/resources/Education.properties index de9713e140..91a4cdf489 100644 --- a/MekHQ/resources/mekhq/resources/Education.properties +++ b/MekHQ/resources/mekhq/resources/Education.properties @@ -63,7 +63,7 @@ eventTrainingAccidentKilled.text=has suffered a serious training accident. Sadly dropOut.text=has dropped out of their education or training. Tomorrow they will begin their journey back to the unit. dropOutRejected.text=wanted to drop out of their education or training, but was convinced to stick it out. graduatedFailed.text=has failed to graduate. Tomorrow they will begin their journey back to the unit. -graduatedBarely.text=has barely graduated. Tomorrow they will begin their journey back to the unit. +graduatedBarely.text=has barely graduated from %s. Tomorrow they will begin their journey back to the unit. graduatedClassNeeded.text=still needs to complete one or more classes, and is unable to graduate. %s days have been added to their education. graduated.text=has attended their graduation ceremony%s. Tomorrow they will begin their journey back to the unit. graduatedHonors.text=has attended their graduation ceremony%s. They have graduated with honors. Tomorrow they will begin their journey back to the unit. From 38d891e4c76b4337c95effdaea998467ce5ec174 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 13:47:39 -0500 Subject: [PATCH 03/12] Refactored EducationController and removed unnecessary checks Refactored the EducationController class, specifically the methods which generate prefixes, suffixes, and types. Switch-case statements were refactored for quick assignment of strings. Removed code that checked for the start of a new month to allocate training XP, which is no longer required. Improvements were also made to add bonus XP. The "graduatedBarely" and "graduatedChild" conditions were streamlined, thus removing duplicated code. Finally, removed the redundant use of Collectors.toList(). --- .../education/EducationController.java | 158 +++++++----------- 1 file changed, 57 insertions(+), 101 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 72f3bf1ca8..38a392f755 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -32,7 +32,6 @@ import java.time.DayOfWeek; import java.util.*; -import java.util.stream.Collectors; /** * The EducationController class is responsible for managing the education process. @@ -175,22 +174,15 @@ public static String generateName(Academy academy, String campus) { * @throws IllegalStateException if an unexpected roll occurs */ private static String generateMilitaryPrefix(ResourceBundle resources) { - switch (Compute.d6(1)) { - case 1: - return resources.getString("prefixCombinedArms.text"); - case 2: - return resources.getString("prefixCombinedForces.text"); - case 3: - return resources.getString("prefixMilitary.text"); - case 4: - return resources.getString("prefixWar.text"); - case 5: - return resources.getString("prefixWarFighting.text"); - case 6: - return resources.getString("prefixCombat.text"); - default: - throw new IllegalStateException("Unexpected roll in generateMilitaryPrefix"); - } + return switch (Compute.d6(1)) { + case 1 -> resources.getString("prefixCombinedArms.text"); + case 2 -> resources.getString("prefixCombinedForces.text"); + case 3 -> resources.getString("prefixMilitary.text"); + case 4 -> resources.getString("prefixWar.text"); + case 5 -> resources.getString("prefixWarFighting.text"); + case 6 -> resources.getString("prefixCombat.text"); + default -> throw new IllegalStateException("Unexpected roll in generateMilitaryPrefix"); + }; } /** @@ -201,22 +193,15 @@ private static String generateMilitaryPrefix(ResourceBundle resources) { * @throws IllegalStateException if the random roll is unexpected. */ private static String generateSuffix(ResourceBundle resources) { - switch (Compute.d6(1)) { - case 1: - return resources.getString("suffixTechnology.text"); - case 2: - return resources.getString("suffixTechnologyAdvanced.text"); - case 3: - return resources.getString("suffixScience.text"); - case 4: - return resources.getString("suffixScienceAdvanced.text"); - case 5: - return resources.getString("suffixStudies.text"); - case 6: - return resources.getString("suffixHigherLearning.text"); - default: - throw new IllegalStateException("Unexpected roll in generateSuffix()"); - } + return switch (Compute.d6(1)) { + case 1 -> resources.getString("suffixTechnology.text"); + case 2 -> resources.getString("suffixTechnologyAdvanced.text"); + case 3 -> resources.getString("suffixScience.text"); + case 4 -> resources.getString("suffixScienceAdvanced.text"); + case 5 -> resources.getString("suffixStudies.text"); + case 6 -> resources.getString("suffixHigherLearning.text"); + default -> throw new IllegalStateException("Unexpected roll in generateSuffix()"); + }; } /** @@ -227,22 +212,15 @@ private static String generateSuffix(ResourceBundle resources) { * @throws IllegalStateException if the generated roll is unexpected */ private static String generateTypeAdult(ResourceBundle resources) { - switch (Compute.d6(1)) { - case 1: - return resources.getString("typeAcademy.text"); - case 2: - return resources.getString("typeCollege.text"); - case 3: - return resources.getString("typeInstitute.text"); - case 4: - return resources.getString("typeUniversity.text"); - case 5: - return resources.getString("typePolytechnic.text"); - case 6: - return resources.getString("typeSchool.text"); - default: - throw new IllegalStateException("Unexpected roll in generateTypeAdult"); - } + return switch (Compute.d6(1)) { + case 1 -> resources.getString("typeAcademy.text"); + case 2 -> resources.getString("typeCollege.text"); + case 3 -> resources.getString("typeInstitute.text"); + case 4 -> resources.getString("typeUniversity.text"); + case 5 -> resources.getString("typePolytechnic.text"); + case 6 -> resources.getString("typeSchool.text"); + default -> throw new IllegalStateException("Unexpected roll in generateTypeAdult"); + }; } @@ -254,22 +232,15 @@ private static String generateTypeAdult(ResourceBundle resources) { * @throws IllegalStateException if the generated roll is unexpected */ private static String generateTypeChild(ResourceBundle resources) { - switch (Compute.d6(1)) { - case 1: - return resources.getString("typeAcademy.text"); - case 2: - return resources.getString("typePreparatorySchool.text"); - case 3: - return resources.getString("typeInstitute.text"); - case 4: - return resources.getString("typeSchoolBoarding.text"); - case 5: - return resources.getString("typeFinishingSchool.text"); - case 6: - return resources.getString("typeSchool.text"); - default: - throw new IllegalStateException("Unexpected roll in generateTypeAdult"); - } + return switch (Compute.d6(1)) { + case 1 -> resources.getString("typeAcademy.text"); + case 2 -> resources.getString("typePreparatorySchool.text"); + case 3 -> resources.getString("typeInstitute.text"); + case 4 -> resources.getString("typeSchoolBoarding.text"); + case 5 -> resources.getString("typeFinishingSchool.text"); + case 6 -> resources.getString("typeSchool.text"); + default -> throw new IllegalStateException("Unexpected roll in generateTypeChild"); + }; } /** @@ -348,12 +319,6 @@ private static boolean ongoingEducation(Campaign campaign, Person person, Academ person.setEduEducationStage(EducationStage.GRADUATING); - // if the person is graduating at the beginning of a month, - // they are still entitled to random xp - if (campaign.getLocalDate().getDayOfMonth() == 1) { - processNewMonthChecks(campaign, academy, person); - } - return true; } @@ -391,10 +356,6 @@ private static void checkForEvents(Campaign campaign, Person person, Academy aca processNewWeekChecks(campaign, academy, person, resources); } - if (campaign.getLocalDate().getDayOfMonth() == 1) { - processNewMonthChecks(campaign, academy, person); - } - if (campaign.getLocalDate().getDayOfYear() == 1) { processNewYearChecks(campaign, academy, person, resources); } @@ -507,21 +468,6 @@ private static void processNewWeekChecks(Campaign campaign, Academy academy, Per checkForTrainingAccidents(campaign, academy, person, resources); } - /** - * Processes the new month checks for a specific person in a campaign. - * - * @param campaign The campaign in which the person is participating. - * @param academy The academy where the person is receiving education. - * @param person The person whose new month checks need to be processed. - */ - private static void processNewMonthChecks(Campaign campaign, Academy academy, Person person) { - if (campaign.getCampaignOptions().isEnableRandomXp()) { - if (Compute.d6(2) >= academy.getFacultySkill()) { - person.awardXP(campaign, campaign.getCampaignOptions().getRandomXpRate()); - } - } - } - /** * Processes the new year checks for a specific person in a campaign. * @@ -740,6 +686,7 @@ private static boolean graduateAdult(Campaign campaign, Person person, Academy a ServiceLogger.eduFailed(person, campaign.getLocalDate(), person.getEduAcademyName(), academy.getQualifications().get(person.getEduCourseIndex())); improveSkills(campaign, person, academy, false); + addBonusXp(campaign, person, academy, 0); person.setEduEducationStage(EducationStage.DROPPING_OUT); @@ -855,19 +802,12 @@ private static void reportMastersOrDoctorateGain(Campaign campaign, Person perso private static void graduateChild(Campaign campaign, Person person, Academy academy, ResourceBundle resources) { int graduationRoll = Compute.randomInt(100); - // qualification failed if (graduationRoll < 30) { - campaign.addReport(person.getHyperlinkedName() + ' ' + resources.getString("graduatedBarely.text")); - ServiceLogger.eduFailed(person, campaign.getLocalDate(), person.getEduAcademyName(), academy.getQualifications().get(person.getEduCourseIndex())); - - improveSkills(campaign, person, academy, false); - - return; + campaign.addReport(person.getHyperlinkedName() + ' ' + String.format(resources.getString("graduatedBarely.text"), person.getEduAcademyName())); + } else { + campaign.addReport(person.getHyperlinkedName() + ' ' + String.format(resources.getString("graduatedChild.text"), person.getEduAcademyName())); } - // default graduation - campaign.addReport(person.getHyperlinkedName() + ' ' + String.format(resources.getString("graduatedChild.text"), person.getEduAcademyName())); - ServiceLogger.eduGraduated(person, campaign.getLocalDate(), person.getEduAcademyName(), academy.getQualifications().get(person.getEduCourseIndex())); processGraduation(campaign, person, academy, 0, resources); @@ -902,6 +842,8 @@ private static void adjustLoyalty(Person person) { private static void processGraduation(Campaign campaign, Person person, Academy academy, Integer bonusCount, ResourceBundle resources) { improveSkills(campaign, person, academy, true); + addBonusXp(campaign, person, academy, bonusCount); + if ((campaign.getCampaignOptions().isEnableBonuses()) && (bonusCount > 0)) { addBonus(campaign, person, academy, bonusCount, resources); } @@ -991,6 +933,20 @@ private static void improveSkills(Campaign campaign, Person person, Academy acad } } + /** + * Adds bonus XP to a person based on faculty skill and academy duration. + * + * @param campaign the campaign the person is participating in + * @param person the person receiving the bonus XP + * @param academy the academy attended by the person + * @param bonusCount the number of extra bonus XP to be added (based on graduation level) + */ + private static void addBonusXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { + int xpRate = Math.max(0, (academy.getDurationDays() - person.getEduEducationTime()) / 150 - academy.getFacultySkill()); + + person.awardXP(campaign, xpRate + bonusCount); + } + /** * Adds bonus to a number of skills based on the course curriculum. * @@ -1004,7 +960,7 @@ private static void addBonus(Campaign campaign, Person person, Academy academy, curriculum = curriculum.stream() .map(String::trim) - .collect(Collectors.toList()); + .toList(); for (int i = 0; i < bonusCount; i++) { int roll = Compute.randomInt(curriculum.size()); From 78a38af4f14647224d52c730a60d28c583ece099 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 14:05:04 -0500 Subject: [PATCH 04/12] Added condition to bonus XP awarding in EducationController The code now checks if the person's highest education level is less than the academy's education level before awarding bonus XP. This prevents a potential exploit in XP distribution. --- .../campaign/personnel/education/EducationController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 38a392f755..7662d2d1b7 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -942,9 +942,11 @@ private static void improveSkills(Campaign campaign, Person person, Academy acad * @param bonusCount the number of extra bonus XP to be added (based on graduation level) */ private static void addBonusXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { - int xpRate = Math.max(0, (academy.getDurationDays() - person.getEduEducationTime()) / 150 - academy.getFacultySkill()); + if (EducationLevel.parseToInt(person.getEduHighestEducation()) < academy.getEducationLevel(person)) { + int xpRate = Math.max(0, (academy.getDurationDays() - person.getEduEducationTime()) / 150 - academy.getFacultySkill()); - person.awardXP(campaign, xpRate + bonusCount); + person.awardXP(campaign, xpRate + bonusCount); + } } /** From cdd184c1f566b9abe7a990a0c3f3f254ff7afa12 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 14:06:42 -0500 Subject: [PATCH 05/12] Refactored checkForAcademyClosure method in EducationController The method 'checkForAcademyClosure' in EducationController was refactored. The return type was changed from boolean to void as the returned boolean value was not used elsewhere in the code. --- .../campaign/personnel/education/EducationController.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 7662d2d1b7..e26939675e 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -624,16 +624,12 @@ private static boolean checkForAcademyFactionConflict(Campaign campaign, Academy * @param academy the academy being checked for closure * @param person the person enrolled in the academy * @param resources the resource bundle for localization. - * @return true if the academy has been closed, false otherwise */ - private static boolean checkForAcademyClosure(Campaign campaign, Academy academy, Person person, ResourceBundle resources) { + private static void checkForAcademyClosure(Campaign campaign, Academy academy, Person person, ResourceBundle resources) { if (campaign.getLocalDate().getYear() >= academy.getClosureYear()) { campaign.addReport(person.getHyperlinkedName() + ' ' + resources.getString("eventClosure.text")); person.setEduEducationStage(EducationStage.DROPPING_OUT); - - return true; } - return false; } /** From bd5e574710b0607362c09590ab6e3d48ffc39231 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 14:54:31 -0500 Subject: [PATCH 06/12] Refactored switch statements and updated XP options The random XP option in the campaign was replaced with a more flexible bonus XP multiplier. Furthermore, all references to the old system were removed from the UI and the underlying codebase. --- .../CampaignOptionsDialog.properties | 8 +-- MekHQ/src/mekhq/campaign/CampaignOptions.java | 69 +++++++------------ .../mekhq/gui/panes/CampaignOptionsPane.java | 59 +++++----------- 3 files changed, 43 insertions(+), 93 deletions(-) diff --git a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties index 4a6c805780..0f7f685d26 100644 --- a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties +++ b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties @@ -568,11 +568,9 @@ chkEnableLocalAcademies.toolTip=Allows personnel to enroll in local, planet-side chkEnablePrestigiousAcademies.text=Enable Prestigious Academies chkEnablePrestigiousAcademies.toolTip=Allows personnel to enroll in named, canonical, academies. -xpAndSkillBonuses.title=Random XP and Skill Bonuses -chkEnableRandomXp.text=Random Monthly XP -chkEnableRandomXp.toolTip=Enables the per-month chance for students to gain additional xp (based on Faculty Skill). -lblRandomXpRate.text=Random XP Rate -lblRandomXpRate.toolTip=The amount of random xp gained per success. +xpAndSkillBonuses.title=XP and Skill Bonuses +lblBonusXpRate.text=Bonus XP Multiplier +lblBonusXpRate.toolTip=This value multiplies the number of XP gained when completing (or partially completing) a qualification. Setting this to 0 disabled bonus XP. chkEnableBonuses.text=Graduation Bonuses chkEnableBonuses.toolTip=Enables the chance of gaining a permanent skill bonus when graduating. diff --git a/MekHQ/src/mekhq/campaign/CampaignOptions.java b/MekHQ/src/mekhq/campaign/CampaignOptions.java index 4c9f556678..46c2bf314e 100644 --- a/MekHQ/src/mekhq/campaign/CampaignOptions.java +++ b/MekHQ/src/mekhq/campaign/CampaignOptions.java @@ -75,33 +75,23 @@ public class CampaignOptions { public static final double MAXIMUM_WARSHIP_EQUIPMENT_PERCENT = 1.0; public static String getTechLevelName(final int techLevel) { - switch (techLevel) { - case TECH_INTRO: - return TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_INTRO]; - case TECH_STANDARD: - return TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_STANDARD]; - case TECH_ADVANCED: - return TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_ADVANCED]; - case TECH_EXPERIMENTAL: - return TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_EXPERIMENTAL]; - case TECH_UNOFFICIAL: - return TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_UNOFFICIAL]; - default: - return "Unknown"; - } + return switch (techLevel) { + case TECH_INTRO -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_INTRO]; + case TECH_STANDARD -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_STANDARD]; + case TECH_ADVANCED -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_ADVANCED]; + case TECH_EXPERIMENTAL -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_EXPERIMENTAL]; + case TECH_UNOFFICIAL -> TechConstants.T_SIMPLE_NAMES[TechConstants.T_SIMPLE_UNOFFICIAL]; + default -> "Unknown"; + }; } public static String getTransitUnitName(final int unit) { - switch (unit) { - case TRANSIT_UNIT_DAY: - return "Days"; - case TRANSIT_UNIT_WEEK: - return "Weeks"; - case TRANSIT_UNIT_MONTH: - return "Months"; - default: - return "Unknown"; - } + return switch (unit) { + case TRANSIT_UNIT_DAY -> "Days"; + case TRANSIT_UNIT_WEEK -> "Weeks"; + case TRANSIT_UNIT_MONTH -> "Months"; + default -> "Unknown"; + }; } //endregion Magic Numbers @@ -391,8 +381,7 @@ public static String getTransitUnitName(final int unit) { private boolean enablePrestigiousAcademies; private boolean enableOverrideRequirements; private boolean enableShowIneligibleAcademies; - private boolean enableRandomXp; - private Integer randomXpRate; + private Double bonusXpRate; private boolean enableBonuses; private Integer adultDropoutChance; private Integer childrenDropoutChance; @@ -898,8 +887,7 @@ public CampaignOptions() { setEnablePrestigiousAcademies(true); setEnableOverrideRequirements(false); setEnableShowIneligibleAcademies(true); - setEnableRandomXp(true); - setRandomXpRate(1); + setBonusXpRate(1.00); setEnableBonuses(true); setAdultDropoutChance(1000); setChildrenDropoutChance(10000); @@ -2740,20 +2728,12 @@ public void setEnableShowIneligibleAcademies(boolean enableShowIneligibleAcademi this.enableShowIneligibleAcademies = enableShowIneligibleAcademies; } - public boolean isEnableRandomXp() { - return enableRandomXp; - } - - public void setEnableRandomXp(boolean enableRandomXp) { - this.enableRandomXp = enableRandomXp; - } - - public Integer getRandomXpRate() { - return randomXpRate; + public Double getBonusXpRate() { + return bonusXpRate; } - public void setRandomXpRate(Integer randomXpRate) { - this.randomXpRate = randomXpRate; + public void setBonusXpRate(Double bonusXpRate) { + this.bonusXpRate = bonusXpRate; } public boolean isEnableBonuses() { @@ -4706,8 +4686,7 @@ public void writeToXml(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enablePrestigiousAcademies", isEnablePrestigiousAcademies()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableOverrideRequirements", isEnableOverrideRequirements()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableShowIneligibleAcademies", isEnableShowIneligibleAcademies()); - MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableRandomXp", isEnableRandomXp()); - MHQXMLUtility.writeSimpleXMLTag(pw, indent, "randomXpRate", getRandomXpRate()); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "bonusXpRate", getBonusXpRate()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableBonuses", isEnableBonuses()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "adultDropoutChance", getAdultDropoutChance()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "childrenDropoutChance", getChildrenDropoutChance()); @@ -5459,10 +5438,8 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve retVal.setEnableOverrideRequirements(Boolean.parseBoolean(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("enableShowIneligibleAcademies")) { retVal.setEnableShowIneligibleAcademies(Boolean.parseBoolean(wn2.getTextContent().trim())); - } else if (wn2.getNodeName().equalsIgnoreCase("enableRandomXp")) { - retVal.setEnableRandomXp(Boolean.parseBoolean(wn2.getTextContent().trim())); - } else if (wn2.getNodeName().equalsIgnoreCase("randomXpRate")) { - retVal.setRandomXpRate(Integer.parseInt(wn2.getTextContent().trim())); + } else if (wn2.getNodeName().equalsIgnoreCase("bonusXpRate")) { + retVal.setBonusXpRate(Double.parseDouble(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("enableBonuses")) { retVal.setEnableBonuses(Boolean.parseBoolean(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("adultDropoutChance")) { diff --git a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java index 1fa171b5ce..a8a44af76c 100644 --- a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java +++ b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java @@ -454,10 +454,9 @@ public class CampaignOptionsPane extends AbstractMHQTabbedPane { private JCheckBox chkEnablePrestigiousAcademies; private JCheckBox chkShowIneligibleAcademies; private JCheckBox chkEnableOverrideRequirements; - private JCheckBox chkEnableRandomXp; private JCheckBox chkEnableBonuses; - private JLabel lblRandomXpRate; - private JSpinner spnRandomXpRate; + private JLabel lblBonusXpRate; + private JSpinner spnBonusXpRate; private JLabel lblAdultDropoutChance; private JSpinner spnAdultDropoutChance; private JLabel lblChildrenDropoutChance; @@ -6107,9 +6106,8 @@ private JPanel createEducationPanel() { xpAndSkillBonusesPanel.setEnabled(isEnabled); chkEnableBonuses.setEnabled(isEnabled); - lblRandomXpRate.setEnabled(isEnabled); - spnRandomXpRate.setEnabled(isEnabled); - chkEnableRandomXp.setEnabled(isEnabled); + lblBonusXpRate.setEnabled(isEnabled); + spnBonusXpRate.setEnabled(isEnabled); dropoutChancePanel.setEnabled(isEnabled); lblAdultDropoutChance.setEnabled(isEnabled); @@ -6231,33 +6229,15 @@ private JPanel createXpAndSkillBonusesPanel() { chkEnableBonuses.setToolTipText(resources.getString("chkEnableBonuses.toolTip")); chkEnableBonuses.setName("chkEnableBonuses"); - lblRandomXpRate = new JLabel(resources.getString("lblRandomXpRate.text")); - lblRandomXpRate.setToolTipText(resources.getString("lblRandomXpRate.toolTip")); - lblRandomXpRate.setName("lblRandomXpRate"); - spnRandomXpRate = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1)); - spnRandomXpRate.setToolTipText(resources.getString("lblRandomXpRate.toolTip")); - spnRandomXpRate.setName("spnRandomXpRate"); + lblBonusXpRate = new JLabel(resources.getString("lblBonusXpRate.text")); + lblBonusXpRate.setToolTipText(resources.getString("lblBonusXpRate.toolTip")); + lblBonusXpRate.setName("lblBonusXpRate"); - chkEnableRandomXp = new JCheckBox(resources.getString("chkEnableRandomXp.text")); - chkEnableRandomXp.setToolTipText(resources.getString("chkEnableRandomXp.toolTip")); - chkEnableRandomXp.setName("chkEnableRandomXp"); - chkEnableRandomXp.addActionListener(evt -> { - final boolean isEnabled = chkEnableRandomXp.isSelected(); + spnBonusXpRate = new JSpinner(new SpinnerNumberModel(1.00, 0.00, 10.00, 0.01)); + spnBonusXpRate.setToolTipText(resources.getString("lblBonusXpRate.toolTip")); + spnBonusXpRate.setName("spnBonusXpRate"); - lblRandomXpRate.setEnabled(isEnabled); - }); - - // These prevent a really annoying bug where disabled options don't stay disabled when - // reloading Campaign Options - if ((campaign.getCampaignOptions().isEnableRandomXp()) && (campaign.getCampaignOptions().isUseEducationModule())) { - lblRandomXpRate.setEnabled(true); - spnRandomXpRate.setEnabled(true); - } else { - lblRandomXpRate.setEnabled(false); - spnRandomXpRate.setEnabled(false); - } chkEnableBonuses.setEnabled(campaign.getCampaignOptions().isUseEducationModule()); - chkEnableRandomXp.setEnabled(campaign.getCampaignOptions().isUseEducationModule()); // creating the layout final JPanel panel = new JPanel(); @@ -6272,19 +6252,17 @@ private JPanel createXpAndSkillBonusesPanel() { layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(chkEnableBonuses) - .addComponent(chkEnableRandomXp) .addGroup(layout.createParallelGroup(Alignment.BASELINE) - .addComponent(lblRandomXpRate) - .addComponent(spnRandomXpRate, Alignment.LEADING)) + .addComponent(lblBonusXpRate) + .addComponent(spnBonusXpRate, Alignment.LEADING)) ); layout.setHorizontalGroup( layout.createParallelGroup(Alignment.LEADING) .addComponent(chkEnableBonuses) - .addComponent(chkEnableRandomXp) .addGroup(layout.createSequentialGroup() - .addComponent(lblRandomXpRate) - .addComponent(spnRandomXpRate)) + .addComponent(lblBonusXpRate) + .addComponent(spnBonusXpRate)) ); return panel; @@ -8162,8 +8140,7 @@ public void setOptions(@Nullable CampaignOptions options, chkEnablePrestigiousAcademies.setSelected(options.isEnablePrestigiousAcademies()); chkEnableOverrideRequirements.setSelected(options.isEnableOverrideRequirements()); chkShowIneligibleAcademies.setSelected(options.isEnableShowIneligibleAcademies()); - chkEnableRandomXp.setSelected(options.isEnableRandomXp()); - spnRandomXpRate.setValue(options.getRandomXpRate()); + spnBonusXpRate.setValue(options.getBonusXpRate()); chkEnableBonuses.setSelected(options.isEnableBonuses()); spnAdultDropoutChance.setValue(options.getAdultDropoutChance()); spnChildrenDropoutChance.setValue(options.getChildrenDropoutChance()); @@ -8824,8 +8801,7 @@ public void updateOptions() { options.setEnablePrestigiousAcademies(chkEnablePrestigiousAcademies.isSelected()); options.setEnableOverrideRequirements(chkEnableOverrideRequirements.isSelected()); options.setEnableShowIneligibleAcademies(chkShowIneligibleAcademies.isSelected()); - options.setEnableRandomXp(chkEnableRandomXp.isSelected()); - options.setRandomXpRate((Integer) spnRandomXpRate.getValue()); + options.setBonusXpRate((Double) spnBonusXpRate.getValue()); options.setEnableBonuses(chkEnableBonuses.isSelected()); options.setAdultDropoutChance((Integer) spnAdultDropoutChance.getValue()); options.setChildrenDropoutChance((Integer) spnChildrenDropoutChance.getValue()); @@ -9397,8 +9373,7 @@ public void addNotify() { super.addNotify(); Component c = getParent(); // Keep scrolling of the row table in sync with the main table. - if (c instanceof JViewport) { - JViewport viewport = (JViewport) c; + if (c instanceof JViewport viewport) { viewport.addChangeListener(this); } } From 591b73f301331cd446a6b6e167fa72096e0682fe Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 14:58:00 -0500 Subject: [PATCH 07/12] Updated XP rate calculation in EducationController The calculation for xpRate in the addBonusXp method of EducationController was updated. The formula was adjusted to factor in the faculty skill level and operate over a different range by dividing the time spent in education by 600, rather than 150. --- .../campaign/personnel/education/EducationController.java | 4 +++- MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index e26939675e..126bd907f0 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -939,7 +939,9 @@ private static void improveSkills(Campaign campaign, Person person, Academy acad */ private static void addBonusXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { if (EducationLevel.parseToInt(person.getEduHighestEducation()) < academy.getEducationLevel(person)) { - int xpRate = Math.max(0, (academy.getDurationDays() - person.getEduEducationTime()) / 150 - academy.getFacultySkill()); + int xpRate = Math.max(0, (12 - academy.getFacultySkill()) * ((academy.getDurationDays() - person.getEduEducationTime()) / 600)); + + xpRate *= campaign.getCampaignOptions().getBonusXpRate(); person.awardXP(campaign, xpRate + bonusCount); } diff --git a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java index a8a44af76c..d0eda08d24 100644 --- a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java +++ b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java @@ -1081,9 +1081,7 @@ private JScrollPane createRepairAndMaintenanceTab() { gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; panSubMaintenance.add(chkUseRandomUnitQualities, gridBagConstraints); - reverseQualityNames.addActionListener(evt -> { - recreateFinancesPanel(reverseQualityNames.isSelected()); - }); + reverseQualityNames.addActionListener(evt -> recreateFinancesPanel(reverseQualityNames.isSelected())); useUnofficialMaintenance = new JCheckBox(resources.getString("useUnofficialMaintenance.text")); useUnofficialMaintenance.setToolTipText(resources.getString("useUnofficialMaintenance.toolTipText")); From 9b523a74d13fd464ad7c92a8b7ac28c22dd457dd Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 15:32:29 -0500 Subject: [PATCH 08/12] Renamed "bonusXpRate" to "facultyXpRate" The variable "bonusXpRate" used in different places in CampaignOptions class was renamed to "facultyXpRate". Accompanying changes were made in labels, Spinner and other related methods and comments as well to maintain consistency. This refactoring was made to provide more clarity in identifying the purpose of the variable. --- .../CampaignOptionsDialog.properties | 6 ++-- MekHQ/src/mekhq/campaign/CampaignOptions.java | 18 +++++------ .../mekhq/gui/panes/CampaignOptionsPane.java | 32 +++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties index 0f7f685d26..aa530b1b65 100644 --- a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties +++ b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties @@ -568,9 +568,9 @@ chkEnableLocalAcademies.toolTip=Allows personnel to enroll in local, planet-side chkEnablePrestigiousAcademies.text=Enable Prestigious Academies chkEnablePrestigiousAcademies.toolTip=Allows personnel to enroll in named, canonical, academies. -xpAndSkillBonuses.title=XP and Skill Bonuses -lblBonusXpRate.text=Bonus XP Multiplier -lblBonusXpRate.toolTip=This value multiplies the number of XP gained when completing (or partially completing) a qualification. Setting this to 0 disabled bonus XP. +xpAndSkillBonuses.title=Faculty XP and Skill Bonuses +lblFacultyXPMultiplier.text=Faculty XP Multiplier +lblFacultyXPMultiplier.toolTip=This value multiplies the number of XP gained when completing (or partially completing) a qualification. Setting this to 0 disabled faculty XP. chkEnableBonuses.text=Graduation Bonuses chkEnableBonuses.toolTip=Enables the chance of gaining a permanent skill bonus when graduating. diff --git a/MekHQ/src/mekhq/campaign/CampaignOptions.java b/MekHQ/src/mekhq/campaign/CampaignOptions.java index 46c2bf314e..9fbc2c092d 100644 --- a/MekHQ/src/mekhq/campaign/CampaignOptions.java +++ b/MekHQ/src/mekhq/campaign/CampaignOptions.java @@ -381,7 +381,7 @@ public static String getTransitUnitName(final int unit) { private boolean enablePrestigiousAcademies; private boolean enableOverrideRequirements; private boolean enableShowIneligibleAcademies; - private Double bonusXpRate; + private Double facultyXpRate; private boolean enableBonuses; private Integer adultDropoutChance; private Integer childrenDropoutChance; @@ -887,7 +887,7 @@ public CampaignOptions() { setEnablePrestigiousAcademies(true); setEnableOverrideRequirements(false); setEnableShowIneligibleAcademies(true); - setBonusXpRate(1.00); + setFacultyXpRate(1.00); setEnableBonuses(true); setAdultDropoutChance(1000); setChildrenDropoutChance(10000); @@ -2728,12 +2728,12 @@ public void setEnableShowIneligibleAcademies(boolean enableShowIneligibleAcademi this.enableShowIneligibleAcademies = enableShowIneligibleAcademies; } - public Double getBonusXpRate() { - return bonusXpRate; + public Double getFacultyXpRate() { + return facultyXpRate; } - public void setBonusXpRate(Double bonusXpRate) { - this.bonusXpRate = bonusXpRate; + public void setFacultyXpRate(Double facultyXpRate) { + this.facultyXpRate = facultyXpRate; } public boolean isEnableBonuses() { @@ -4686,7 +4686,7 @@ public void writeToXml(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enablePrestigiousAcademies", isEnablePrestigiousAcademies()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableOverrideRequirements", isEnableOverrideRequirements()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableShowIneligibleAcademies", isEnableShowIneligibleAcademies()); - MHQXMLUtility.writeSimpleXMLTag(pw, indent, "bonusXpRate", getBonusXpRate()); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "facultyXpRate", getFacultyXpRate()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "enableBonuses", isEnableBonuses()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "adultDropoutChance", getAdultDropoutChance()); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "childrenDropoutChance", getChildrenDropoutChance()); @@ -5438,8 +5438,8 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve retVal.setEnableOverrideRequirements(Boolean.parseBoolean(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("enableShowIneligibleAcademies")) { retVal.setEnableShowIneligibleAcademies(Boolean.parseBoolean(wn2.getTextContent().trim())); - } else if (wn2.getNodeName().equalsIgnoreCase("bonusXpRate")) { - retVal.setBonusXpRate(Double.parseDouble(wn2.getTextContent().trim())); + } else if (wn2.getNodeName().equalsIgnoreCase("facultyXpRate")) { + retVal.setFacultyXpRate(Double.parseDouble(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("enableBonuses")) { retVal.setEnableBonuses(Boolean.parseBoolean(wn2.getTextContent().trim())); } else if (wn2.getNodeName().equalsIgnoreCase("adultDropoutChance")) { diff --git a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java index d0eda08d24..68001fb46d 100644 --- a/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java +++ b/MekHQ/src/mekhq/gui/panes/CampaignOptionsPane.java @@ -455,8 +455,8 @@ public class CampaignOptionsPane extends AbstractMHQTabbedPane { private JCheckBox chkShowIneligibleAcademies; private JCheckBox chkEnableOverrideRequirements; private JCheckBox chkEnableBonuses; - private JLabel lblBonusXpRate; - private JSpinner spnBonusXpRate; + private JLabel lblFacultyXpMultiplier; + private JSpinner spnFacultyXpMultiplier; private JLabel lblAdultDropoutChance; private JSpinner spnAdultDropoutChance; private JLabel lblChildrenDropoutChance; @@ -6104,8 +6104,8 @@ private JPanel createEducationPanel() { xpAndSkillBonusesPanel.setEnabled(isEnabled); chkEnableBonuses.setEnabled(isEnabled); - lblBonusXpRate.setEnabled(isEnabled); - spnBonusXpRate.setEnabled(isEnabled); + lblFacultyXpMultiplier.setEnabled(isEnabled); + spnFacultyXpMultiplier.setEnabled(isEnabled); dropoutChancePanel.setEnabled(isEnabled); lblAdultDropoutChance.setEnabled(isEnabled); @@ -6227,13 +6227,13 @@ private JPanel createXpAndSkillBonusesPanel() { chkEnableBonuses.setToolTipText(resources.getString("chkEnableBonuses.toolTip")); chkEnableBonuses.setName("chkEnableBonuses"); - lblBonusXpRate = new JLabel(resources.getString("lblBonusXpRate.text")); - lblBonusXpRate.setToolTipText(resources.getString("lblBonusXpRate.toolTip")); - lblBonusXpRate.setName("lblBonusXpRate"); + lblFacultyXpMultiplier = new JLabel(resources.getString("lblFacultyXPMultiplier.text")); + lblFacultyXpMultiplier.setToolTipText(resources.getString("lblFacultyXPMultiplier.toolTip")); + lblFacultyXpMultiplier.setName("lblFacultyXpMultiplier"); - spnBonusXpRate = new JSpinner(new SpinnerNumberModel(1.00, 0.00, 10.00, 0.01)); - spnBonusXpRate.setToolTipText(resources.getString("lblBonusXpRate.toolTip")); - spnBonusXpRate.setName("spnBonusXpRate"); + spnFacultyXpMultiplier = new JSpinner(new SpinnerNumberModel(1.00, 0.00, 10.00, 0.01)); + spnFacultyXpMultiplier.setToolTipText(resources.getString("lblFacultyXPMultiplier.toolTip")); + spnFacultyXpMultiplier.setName("spnFacultyXpMultiplier"); chkEnableBonuses.setEnabled(campaign.getCampaignOptions().isUseEducationModule()); @@ -6251,16 +6251,16 @@ private JPanel createXpAndSkillBonusesPanel() { layout.createSequentialGroup() .addComponent(chkEnableBonuses) .addGroup(layout.createParallelGroup(Alignment.BASELINE) - .addComponent(lblBonusXpRate) - .addComponent(spnBonusXpRate, Alignment.LEADING)) + .addComponent(lblFacultyXpMultiplier) + .addComponent(spnFacultyXpMultiplier, Alignment.LEADING)) ); layout.setHorizontalGroup( layout.createParallelGroup(Alignment.LEADING) .addComponent(chkEnableBonuses) .addGroup(layout.createSequentialGroup() - .addComponent(lblBonusXpRate) - .addComponent(spnBonusXpRate)) + .addComponent(lblFacultyXpMultiplier) + .addComponent(spnFacultyXpMultiplier)) ); return panel; @@ -8138,7 +8138,7 @@ public void setOptions(@Nullable CampaignOptions options, chkEnablePrestigiousAcademies.setSelected(options.isEnablePrestigiousAcademies()); chkEnableOverrideRequirements.setSelected(options.isEnableOverrideRequirements()); chkShowIneligibleAcademies.setSelected(options.isEnableShowIneligibleAcademies()); - spnBonusXpRate.setValue(options.getBonusXpRate()); + spnFacultyXpMultiplier.setValue(options.getFacultyXpRate()); chkEnableBonuses.setSelected(options.isEnableBonuses()); spnAdultDropoutChance.setValue(options.getAdultDropoutChance()); spnChildrenDropoutChance.setValue(options.getChildrenDropoutChance()); @@ -8799,7 +8799,7 @@ public void updateOptions() { options.setEnablePrestigiousAcademies(chkEnablePrestigiousAcademies.isSelected()); options.setEnableOverrideRequirements(chkEnableOverrideRequirements.isSelected()); options.setEnableShowIneligibleAcademies(chkShowIneligibleAcademies.isSelected()); - options.setBonusXpRate((Double) spnBonusXpRate.getValue()); + options.setFacultyXpRate((Double) spnFacultyXpMultiplier.getValue()); options.setEnableBonuses(chkEnableBonuses.isSelected()); options.setAdultDropoutChance((Integer) spnAdultDropoutChance.getValue()); options.setChildrenDropoutChance((Integer) spnChildrenDropoutChance.getValue()); From 70699c45ba9d68fb7f16d0b33dd119fd9efbf5ec Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 15:35:32 -0500 Subject: [PATCH 09/12] Renamed bonus XP to faculty XP in EducationController The method 'addBonusXp' was renamed to 'addFacultyXp' to more accurately reflect its functionality. The related variable and calculations were updated accordingly. Moreover, a base XP rate is now also awarded when the person's highest education level is equal or greater than the academy's education level. --- .../personnel/education/EducationController.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 126bd907f0..344bf97441 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -682,7 +682,7 @@ private static boolean graduateAdult(Campaign campaign, Person person, Academy a ServiceLogger.eduFailed(person, campaign.getLocalDate(), person.getEduAcademyName(), academy.getQualifications().get(person.getEduCourseIndex())); improveSkills(campaign, person, academy, false); - addBonusXp(campaign, person, academy, 0); + addFacultyXp(campaign, person, academy, 0); person.setEduEducationStage(EducationStage.DROPPING_OUT); @@ -838,7 +838,7 @@ private static void adjustLoyalty(Person person) { private static void processGraduation(Campaign campaign, Person person, Academy academy, Integer bonusCount, ResourceBundle resources) { improveSkills(campaign, person, academy, true); - addBonusXp(campaign, person, academy, bonusCount); + addFacultyXp(campaign, person, academy, bonusCount); if ((campaign.getCampaignOptions().isEnableBonuses()) && (bonusCount > 0)) { addBonus(campaign, person, academy, bonusCount, resources); @@ -930,20 +930,22 @@ private static void improveSkills(Campaign campaign, Person person, Academy acad } /** - * Adds bonus XP to a person based on faculty skill and academy duration. + * Adds faculty XP to a person based on faculty skill and academy duration. * * @param campaign the campaign the person is participating in * @param person the person receiving the bonus XP * @param academy the academy attended by the person * @param bonusCount the number of extra bonus XP to be added (based on graduation level) */ - private static void addBonusXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { + private static void addFacultyXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { if (EducationLevel.parseToInt(person.getEduHighestEducation()) < academy.getEducationLevel(person)) { - int xpRate = Math.max(0, (12 - academy.getFacultySkill()) * ((academy.getDurationDays() - person.getEduEducationTime()) / 600)); + int xpRate = Math.max(1, (12 - academy.getFacultySkill()) * ((academy.getDurationDays() - person.getEduEducationTime()) / 600)); - xpRate *= campaign.getCampaignOptions().getBonusXpRate(); + xpRate *= campaign.getCampaignOptions().getFacultyXpRate(); person.awardXP(campaign, xpRate + bonusCount); + } else { + person.awardXP(campaign, 1 + bonusCount); } } From 62e45e8100107203fabea85f6763752f9aff132d Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Wed, 10 Jul 2024 15:50:08 -0500 Subject: [PATCH 10/12] Added faculty XP on education drop out In the EducationController class, a line of code has been added for granting faculty XP when a person drops out of education. --- .../mekhq/campaign/personnel/education/EducationController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 344bf97441..75d12c1b1d 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -582,6 +582,7 @@ private static boolean checkForDropout(Campaign campaign, Academy academy, Perso campaign.addReport(person.getHyperlinkedName() + ' ' + resources.getString("dropOut.text")); ServiceLogger.eduFailed(person, campaign.getLocalDate(), person.getEduAcademyName(), academy.getQualifications().get(person.getEduCourseIndex())); person.setEduEducationStage(EducationStage.DROPPING_OUT); + addFacultyXp(campaign, person, academy, 0); } } else { campaign.addReport(person.getHyperlinkedName() + ' ' + resources.getString("dropOutRejected.text")); From 1200751ab41364ccf5be4254a4969bf0f6ac7a19 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Thu, 11 Jul 2024 11:32:41 -0500 Subject: [PATCH 11/12] Update XP calculation in EducationController Implemented additional checks in the addFacultyXp method to account for an academy's type when calculating experience points. Specifically, logic now differentiates whether the academy is a PrepSchool or not. --- .../personnel/education/EducationController.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 75d12c1b1d..6ed1843103 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -939,8 +939,16 @@ private static void improveSkills(Campaign campaign, Person person, Academy acad * @param bonusCount the number of extra bonus XP to be added (based on graduation level) */ private static void addFacultyXp(Campaign campaign, Person person, Academy academy, Integer bonusCount) { + int academyDuration; + + if (academy.isPrepSchool()) { + academyDuration = (person.getAge(campaign.getLocalDate()) - academy.getAgeMin()) * 300; + } else { + academyDuration = academy.getDurationDays() - person.getEduEducationTime(); + } + if (EducationLevel.parseToInt(person.getEduHighestEducation()) < academy.getEducationLevel(person)) { - int xpRate = Math.max(1, (12 - academy.getFacultySkill()) * ((academy.getDurationDays() - person.getEduEducationTime()) / 600)); + int xpRate = Math.max(1, (12 - academy.getFacultySkill()) * (academyDuration / 600)); xpRate *= campaign.getCampaignOptions().getFacultyXpRate(); From 12d1683aa1af8d3c22d90af57518ca38b174189c Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Thu, 11 Jul 2024 11:47:16 -0500 Subject: [PATCH 12/12] Refactor bonus calculation in EducationController The bonus calculation has been refactored in the EducationController. Specifically, we've introduced a bonusPercentage that is determined by the bonusCount divided by 5. Then, this bonusPercentage is utilized to calculate the bonusAmount, which gets factored into the final XP award. --- .../campaign/personnel/education/EducationController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java index 6ed1843103..10810974e3 100644 --- a/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java +++ b/MekHQ/src/mekhq/campaign/personnel/education/EducationController.java @@ -947,14 +947,18 @@ private static void addFacultyXp(Campaign campaign, Person person, Academy acade academyDuration = academy.getDurationDays() - person.getEduEducationTime(); } + double bonusPercentage = (double) bonusCount / 5; + if (EducationLevel.parseToInt(person.getEduHighestEducation()) < academy.getEducationLevel(person)) { int xpRate = Math.max(1, (12 - academy.getFacultySkill()) * (academyDuration / 600)); xpRate *= campaign.getCampaignOptions().getFacultyXpRate(); - person.awardXP(campaign, xpRate + bonusCount); + int bonusAmount = (int) Math.max(bonusCount, xpRate * bonusPercentage); + person.awardXP(campaign, xpRate + bonusAmount); } else { - person.awardXP(campaign, 1 + bonusCount); + int bonusAmount = (int) Math.max(bonusCount, 1 * bonusPercentage); + person.awardXP(campaign, 1 + bonusAmount); } }