From 1d803627df4ac5ca6c9688c029c783f906f6bf85 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Sun, 6 Apr 2025 15:33:38 -0500 Subject: [PATCH 1/2] dded Randomize Traits Option For Character Creation - Introduced a new option to randomize traits during character creation, including Connections, Reputation, Wealth, and Unlucky scores. - Updated `CampaignOptionsDialog.properties` with labels and tooltips for the new setting. - Extended `RandomSkillPreferences` to support `randomizeTraits` with default settings and XML integration. - Modified personnel generators to calculate and assign random trait values when the option is enabled. - Added methods to the `Person` class for modifying traits with proper clamping to ensure values remain within defined limits. - Updated `AdvancementTab` to include a checkbox for enabling or disabling the new randomization feature. --- .../CampaignOptionsDialog.properties | 11 ++++ .../campaign/RandomSkillPreferences.java | 13 +++++ .../src/mekhq/campaign/personnel/Person.java | 52 +++++++++++++++++-- .../generator/AbstractSkillGenerator.java | 10 ++-- .../generator/DefaultPersonnelGenerator.java | 1 + .../generator/DefaultSkillGenerator.java | 45 ++++++++++++++-- .../contents/AdvancementTab.java | 13 +++-- 7 files changed, 130 insertions(+), 15 deletions(-) diff --git a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties index efaccbeb82..2a9c935954 100644 --- a/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties +++ b/MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties @@ -1796,6 +1796,17 @@ lblExtraRandomness.tooltip=If checked, an additional 1d6 will be rolled per skil
\
Warning: Due to the way experience levels are calculated, enabling this option will\ \ more frequently have characters created with slightly lower than normal experience levels. +lblRandomizeTraits.text=Randomize Traits \u26A0 \uD83C\uDF1F +lblRandomizeTraits.tooltip=If checked, a newly created character's Connections, Wealth, Reputation, and Unlucky scores\ + \ are randomized.\ +
\ +
For Connections a d6 is rolled, on a roll of 6 the character's Connections score becomes 1.\ +
\ +
For Wealth and Reputation a d6 is rolled (for each), on a roll of 6 the character's score becomes 1.\ + \ While a roll of 1 causes their score to become -1.\ +
\ +
For Unlucky a d20 is rolled, on a roll of 1 the character's score becomes 1. A high Unlucky score is a bad\ + \ thing. lblPhenotypesPanel.text=Clan Trueborn Percentages lblMekWarrior.text=MekWarrior lblMekWarrior.tooltip=What percentage of Clan MekWarriors should have a Trueborn phenotype? diff --git a/MekHQ/src/mekhq/campaign/RandomSkillPreferences.java b/MekHQ/src/mekhq/campaign/RandomSkillPreferences.java index 58f7c6a3b9..8b2124164b 100644 --- a/MekHQ/src/mekhq/campaign/RandomSkillPreferences.java +++ b/MekHQ/src/mekhq/campaign/RandomSkillPreferences.java @@ -52,6 +52,7 @@ public class RandomSkillPreferences { private int overallRecruitBonus; Map recruitmentBonuses; private boolean randomizeSkill; + private boolean randomizeTraits; private boolean useClanBonuses; private int antiMekProb; private int[] specialAbilityBonus; @@ -68,6 +69,7 @@ public RandomSkillPreferences() { overallRecruitBonus = 0; recruitmentBonuses = new HashMap<>(); randomizeSkill = true; + randomizeTraits = false; useClanBonuses = true; antiMekProb = 10; combatSmallArmsBonus = -3; @@ -173,6 +175,14 @@ public boolean randomizeSkill() { return randomizeSkill; } + public boolean isRandomizeTraits() { + return randomizeTraits; + } + + public void setRandomizeTraits(boolean randomizeTraits) { + this.randomizeTraits = randomizeTraits; + } + public void setUseClanBonuses(boolean b) { this.useClanBonuses = b; } @@ -269,6 +279,7 @@ public void writeToXML(final PrintWriter pw, int indent) { MHQXMLUtility.writeSimpleXMLTag(pw, indent, "commandSkillsModifier", commandSkillsModifier); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "roleplaySkillsModifier", roleplaySkillsModifier); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "randomizeSkill", randomizeSkill); + MHQXMLUtility.writeSimpleXMLTag(pw, indent, "randomizeTraits", randomizeTraits); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useClanBonuses", useClanBonuses); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "antiMekProb", antiMekProb); MHQXMLUtility.writeSimpleXMLTag(pw, indent, "combatSmallArmsBonus", combatSmallArmsBonus); @@ -303,6 +314,8 @@ public static RandomSkillPreferences generateRandomSkillPreferencesFromXml(Node retVal.overallRecruitBonus = Integer.parseInt(wn2.getTextContent().trim()); } else if (wn2.getNodeName().equalsIgnoreCase("randomizeSkill")) { retVal.randomizeSkill = wn2.getTextContent().equalsIgnoreCase("true"); + } else if (wn2.getNodeName().equalsIgnoreCase("randomizeTraits")) { + retVal.randomizeTraits = wn2.getTextContent().equalsIgnoreCase("true"); } else if (wn2.getNodeName().equalsIgnoreCase("useClanBonuses")) { retVal.useClanBonuses = wn2.getTextContent().equalsIgnoreCase("true"); } else if (wn2.getNodeName().equalsIgnoreCase("antiMekProb")) { diff --git a/MekHQ/src/mekhq/campaign/personnel/Person.java b/MekHQ/src/mekhq/campaign/personnel/Person.java index b233c0645d..463dfc4584 100644 --- a/MekHQ/src/mekhq/campaign/personnel/Person.java +++ b/MekHQ/src/mekhq/campaign/personnel/Person.java @@ -4916,7 +4916,20 @@ public int getConnections() { } public void setConnections(final int connections) { - this.connections = connections; + this.connections = clamp(connections, MINIMUM_CONNECTIONS, MAXIMUM_CONNECTIONS); + } + + /** + * Adjusts the person's Connections score by the specified amount. + * + *

The change in connections can be positive or negative, depending on the provided delta value.

+ * + * @param delta The amount by which to adjust the number of connections. A positive value increases the connections, + * while a negative value decreases them. + */ + public void changeConnections(final int delta) { + int newValue = connections + delta; + connections = clamp(newValue, MINIMUM_CONNECTIONS, MAXIMUM_CONNECTIONS); } public int getWealth() { @@ -4924,7 +4937,20 @@ public int getWealth() { } public void setWealth(final int wealth) { - this.wealth = wealth; + this.wealth = clamp(wealth, MINIMUM_REPUTATION, MAXIMUM_REPUTATION); + } + + /** + * Adjusts the person's wealth by the specified amount. + * + *

The change in wealth can be positive or negative, depending on the provided delta value.

+ * + * @param delta The amount by which to adjust the wealth. A positive value increases the wealth, while a negative + * value decreases it. + */ + public void changeWealth(final int delta) { + int newValue = wealth + delta; + wealth = clamp(newValue, MINIMUM_WEALTH, MAXIMUM_WEALTH); } public int getReputation() { @@ -4932,7 +4958,20 @@ public int getReputation() { } public void setReputation(final int reputation) { - this.reputation = reputation; + this.reputation = clamp(reputation, MINIMUM_REPUTATION, MAXIMUM_REPUTATION); + } + + /** + * Adjusts the person's reputation by the specified amount. + * + *

The change in reputation can be positive or negative, depending on the provided delta value.

+ * + * @param delta The amount by which to adjust the reputation. A positive value increases the reputation, while a + * negative value decreases it. + */ + public void changeReputation(final int delta) { + int newValue = reputation + delta; + reputation = clamp(newValue, MINIMUM_REPUTATION, MAXIMUM_REPUTATION); } public int getUnlucky() { @@ -4940,7 +4979,12 @@ public int getUnlucky() { } public void setUnlucky(final int unlucky) { - this.unlucky = unlucky; + this.unlucky = clamp(unlucky, MINIMUM_UNLUCKY, MAXIMUM_UNLUCKY); + } + + public void changeUnlucky(final int delta) { + int newValue = unlucky + delta; + unlucky = clamp(newValue, MINIMUM_UNLUCKY, MAXIMUM_UNLUCKY); } /** diff --git a/MekHQ/src/mekhq/campaign/personnel/generator/AbstractSkillGenerator.java b/MekHQ/src/mekhq/campaign/personnel/generator/AbstractSkillGenerator.java index 36e822de29..6b30ba6bac 100644 --- a/MekHQ/src/mekhq/campaign/personnel/generator/AbstractSkillGenerator.java +++ b/MekHQ/src/mekhq/campaign/personnel/generator/AbstractSkillGenerator.java @@ -35,8 +35,6 @@ import mekhq.campaign.Campaign; import mekhq.campaign.RandomSkillPreferences; import mekhq.campaign.personnel.Person; -import mekhq.campaign.personnel.skills.Skill; -import mekhq.campaign.personnel.skills.SkillType; import mekhq.campaign.personnel.enums.PersonnelRole; import mekhq.campaign.personnel.skills.Skill; import mekhq.campaign.personnel.skills.SkillType; @@ -78,6 +76,8 @@ public void setSkillPreferences(RandomSkillPreferences skillPreferences) { */ public abstract void generateSkills(Campaign campaign, Person person, int expLvl); + public abstract void generateTraits(Person person); + /** * Generates the default skills for a {@link Person} based on their primary role. * @@ -88,7 +88,7 @@ public void setSkillPreferences(RandomSkillPreferences skillPreferences) { * @param rollModifier A roll modifier to apply to any randomizations. */ protected void generateDefaultSkills(Person person, PersonnelRole primaryRole, int expLvl, int bonus, - int rollModifier) { + int rollModifier) { switch (primaryRole) { case MEKWARRIOR: addSkill(person, SkillType.S_PILOT_MEK, expLvl, rskillPrefs.randomizeSkill(), bonus, rollModifier); @@ -209,12 +209,12 @@ public static void addSkill(Person person, String skillName, int level, int bonu } protected static void addSkill(Person person, String skillName, int experienceLevel, boolean randomizeLevel, - int bonus) { + int bonus) { addSkill(person, skillName, experienceLevel, randomizeLevel, bonus, 0); } protected static void addSkill(Person person, String skillName, int experienceLevel, boolean randomizeLevel, - int bonus, int rollMod) { + int bonus, int rollMod) { if (randomizeLevel) { person.addSkill(skillName, Skill.randomizeLevel(skillName, experienceLevel, bonus, rollMod)); } else { diff --git a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultPersonnelGenerator.java b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultPersonnelGenerator.java index 407a38ed3c..b08b6283e5 100644 --- a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultPersonnelGenerator.java +++ b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultPersonnelGenerator.java @@ -103,6 +103,7 @@ public Person generate(Campaign campaign, PersonnelRole primaryRole, PersonnelRo AbstractSkillGenerator skillGenerator = new DefaultSkillGenerator(getSkillPreferences()); skillGenerator.generateSkills(campaign, person, expLvl); + skillGenerator.generateTraits(person); // Limit skills by age for children and adolescents int age = person.getAge(campaign.getLocalDate()); diff --git a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java index 04fdc07443..1d4c1cffce 100644 --- a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java +++ b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java @@ -27,19 +27,19 @@ */ package mekhq.campaign.personnel.generator; +import static megamek.common.Compute.d6; +import static megamek.common.Compute.randomInt; import static mekhq.campaign.personnel.skills.SkillDeprecationTool.DEPRECATED_SKILLS; import static mekhq.campaign.personnel.skills.enums.SkillSubType.SUPPORT_COMMAND; import java.util.ArrayList; import java.util.List; -import megamek.common.Compute; import mekhq.Utilities; import mekhq.campaign.Campaign; import mekhq.campaign.CampaignOptions; import mekhq.campaign.RandomSkillPreferences; import mekhq.campaign.personnel.Person; -import mekhq.campaign.personnel.skills.SkillType; import mekhq.campaign.personnel.enums.PersonnelRole; import mekhq.campaign.personnel.skills.SkillType; @@ -147,9 +147,48 @@ public void generateSkills(final Campaign campaign, final Person person, final i } } - String selSkill = possibleSkills.get(Compute.randomInt(possibleSkills.size())); + String selSkill = possibleSkills.get(randomInt(possibleSkills.size())); int secondLvl = Utilities.generateExpLevel(rskillPrefs.getSecondSkillBonus()); addSkill(person, selSkill, secondLvl, rskillPrefs.randomizeSkill(), 0); } } + + /** + * Generates traits for the specified person based on random or pre-determined criteria. + * + *

When randomization is enabled, this method calculates and assigns specific traits such as connections, + * reputation, wealth, and bad luck using random rolls. Each trait has its own set of rules for adjustment.

+ * + * @param person The person whose traits will be updated. Traits are adjusted based on random rolls when + * randomization is enabled. + */ + @Override + public void generateTraits(Person person) { + if (!getSkillPreferences().isRandomizeTraits()) { + return; + } + + // Connections + if (d6() == 6) { + person.changeConnections(1); + } + + // Reputation + int roll = d6(); + if (roll == 6 || roll == 1) { + person.changeReputation(roll == 6 ? 1 : -1); + } + + // Wealth + roll = d6(); + if (roll == 6 || roll == 1) { + person.changeWealth(roll == 6 ? 1 : -1); + } + + // Unlucky + roll = randomInt(20); + if (roll == 0) { + person.changeUnlucky(1); + } + } } diff --git a/MekHQ/src/mekhq/gui/campaignOptions/contents/AdvancementTab.java b/MekHQ/src/mekhq/gui/campaignOptions/contents/AdvancementTab.java index 53492cfed3..3e1ee3b6e3 100644 --- a/MekHQ/src/mekhq/gui/campaignOptions/contents/AdvancementTab.java +++ b/MekHQ/src/mekhq/gui/campaignOptions/contents/AdvancementTab.java @@ -43,7 +43,6 @@ import mekhq.campaign.Campaign; import mekhq.campaign.CampaignOptions; import mekhq.campaign.RandomSkillPreferences; -import mekhq.campaign.personnel.skills.SkillType; import mekhq.campaign.personnel.enums.PersonnelRole; import mekhq.campaign.personnel.enums.Phenotype; import mekhq.campaign.personnel.skills.SkillType; @@ -114,6 +113,7 @@ public class AdvancementTab { //start Skill Randomization Tab private JCheckBox chkExtraRandomness; + private JCheckBox chkRandomizeTraits; private JPanel pnlPhenotype; private JLabel[] phenotypeLabels; @@ -520,6 +520,7 @@ private JPanel createAdministratorsPanel() { */ private void initializeSkillRandomizationTab() { chkExtraRandomness = new JCheckBox(); + chkRandomizeTraits = new JCheckBox(); pnlPhenotype = new JPanel(); phenotypeLabels = new JLabel[] {}; // This will be initialized properly later @@ -604,6 +605,7 @@ public JPanel skillRandomizationTab() { // Contents chkExtraRandomness = new CampaignOptionsCheckBox("ExtraRandomness"); + chkRandomizeTraits = new CampaignOptionsCheckBox("RandomizeTraits"); pnlPhenotype = createPhenotypePanel(); pnlRandomAbilities = createAbilityPanel(); @@ -621,6 +623,9 @@ public JPanel skillRandomizationTab() { layout.gridwidth = 1; panel.add(chkExtraRandomness, layout); + layout.gridy++; + panel.add(chkRandomizeTraits, layout); + layout.gridx = 0; layout.gridy++; panel.add(pnlPhenotype, layout); @@ -1100,7 +1105,7 @@ public void loadValuesFromCampaignOptions() { * {@code null}, values are loaded from the current skill preferences. */ public void loadValuesFromCampaignOptions(@Nullable CampaignOptions presetCampaignOptions, - @Nullable RandomSkillPreferences presetRandomSkillPreferences) { + @Nullable RandomSkillPreferences presetRandomSkillPreferences) { CampaignOptions options = presetCampaignOptions; if (presetCampaignOptions == null) { options = this.campaignOptions; @@ -1132,6 +1137,7 @@ public void loadValuesFromCampaignOptions(@Nullable CampaignOptions presetCampai //start Skill Randomization Tab chkExtraRandomness.setSelected(skillPreferences.randomizeSkill()); + chkRandomizeTraits.setSelected(skillPreferences.isRandomizeTraits()); final int[] phenotypeProbabilities = options.getPhenotypeProbabilities(); for (int i = 0; i < phenotypeSpinners.length; i++) { phenotypeSpinners[i].setValue(phenotypeProbabilities[i]); @@ -1184,7 +1190,7 @@ public void loadValuesFromCampaignOptions(@Nullable CampaignOptions presetCampai * {@code null}, values are applied to the current skill preferences. */ public void applyCampaignOptionsToCampaign(@Nullable CampaignOptions presetCampaignOptions, - @Nullable RandomSkillPreferences presetRandomSkillPreferences) { + @Nullable RandomSkillPreferences presetRandomSkillPreferences) { CampaignOptions options = presetCampaignOptions; if (presetCampaignOptions == null) { options = this.campaignOptions; @@ -1216,6 +1222,7 @@ public void applyCampaignOptionsToCampaign(@Nullable CampaignOptions presetCampa //start Skill Randomization Tab skillPreferences.setRandomizeSkill(chkExtraRandomness.isSelected()); + skillPreferences.setRandomizeTraits(chkRandomizeTraits.isSelected()); for (int i = 0; i < phenotypeSpinners.length; i++) { options.setPhenotypeProbability(i, (int) phenotypeSpinners[i].getValue()); } From ecbfe75110aa75f87c6277b350337b7ce296f17f Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Sun, 6 Apr 2025 18:09:16 -0500 Subject: [PATCH 2/2] - Introduced `CMD_GENERATE_ROLEPLAY_TRAITS` for resetting roleplay traits in `PersonnelTableMouseAdapter`. --- MekHQ/resources/mekhq/resources/GUI.properties | 1 + .../generator/DefaultSkillGenerator.java | 16 ++++++++++++---- .../gui/adapter/PersonnelTableMouseAdapter.java | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/MekHQ/resources/mekhq/resources/GUI.properties b/MekHQ/resources/mekhq/resources/GUI.properties index daa9dde448..10f237705c 100644 --- a/MekHQ/resources/mekhq/resources/GUI.properties +++ b/MekHQ/resources/mekhq/resources/GUI.properties @@ -282,6 +282,7 @@ regenerateLoyalty.text=Regenerate Loyalty regeneratePersonality.text=Regenerate Personality addRandomSPA.text=Add Random SPA generateRoleplaySkills.text=Generate Roleplay Skills +generateRoleplayTraits.text=Reset Roleplay Traits addMinimumComplement.text=Add minimum complement addMinimumComplementRandom.text=Random addMinimumComplementElite.text=Elite diff --git a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java index 1d4c1cffce..084c7cbb9b 100644 --- a/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java +++ b/MekHQ/src/mekhq/campaign/personnel/generator/DefaultSkillGenerator.java @@ -170,25 +170,33 @@ public void generateTraits(Person person) { // Connections if (d6() == 6) { - person.changeConnections(1); + person.setConnections(1); + } else { + person.setConnections(0); } // Reputation int roll = d6(); if (roll == 6 || roll == 1) { - person.changeReputation(roll == 6 ? 1 : -1); + person.setReputation(roll == 6 ? 1 : -1); + } else { + person.setReputation(0); } // Wealth roll = d6(); if (roll == 6 || roll == 1) { - person.changeWealth(roll == 6 ? 1 : -1); + person.setWealth(roll == 6 ? 1 : -1); + } else { + person.setWealth(0); } // Unlucky roll = randomInt(20); if (roll == 0) { - person.changeUnlucky(1); + person.setUnlucky(1); + } else { + person.setUnlucky(0); } } } diff --git a/MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java b/MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java index 5e02956fd2..1508f0ac15 100644 --- a/MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java +++ b/MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java @@ -213,6 +213,7 @@ public class PersonnelTableMouseAdapter extends JPopupMenuAdapter { private static final String CMD_PERSONALITY = "PERSONALITY"; private static final String CMD_ADD_RANDOM_ABILITY = "ADD_RANDOM_ABILITY"; private static final String CMD_GENERATE_ROLEPLAY_SKILLS = "GENERATE_ROLEPLAY_SKILLS"; + private static final String CMD_GENERATE_ROLEPLAY_TRAITS = "GENERATE_ROLEPLAY_TRAITS"; private static final String CMD_FREE = "FREE"; private static final String CMD_EXECUTE = "EXECUTE"; @@ -1367,6 +1368,15 @@ public void actionPerformed(ActionEvent action) { } break; } + case CMD_GENERATE_ROLEPLAY_TRAITS: { + RandomSkillPreferences skillPreferences = getCampaign().getRandomSkillPreferences(); + AbstractSkillGenerator skillGenerator = new DefaultSkillGenerator(skillPreferences); + for (Person person : people) { + skillGenerator.generateTraits(person); + MekHQ.triggerEvent(new PersonChangedEvent(person)); + } + break; + } // region Randomization Menu case CMD_RANDOM_NAME: { @@ -3631,6 +3641,13 @@ protected Optional createPopupMenu() { menuItem.addActionListener(this); menu.add(menuItem); + if (getCampaign().getRandomSkillPreferences().isRandomizeTraits()) { + menuItem = new JMenuItem(resources.getString("generateRoleplayTraits.text")); + menuItem.setActionCommand(CMD_GENERATE_ROLEPLAY_TRAITS); + menuItem.addActionListener(this); + menu.add(menuItem); + } + JMenu attributesMenu = new JMenu(resources.getString("spendOnAttributes.set")); for (SkillAttribute attribute : SkillAttribute.values()) {