Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Personality Revamp #5998

Merged
merged 35 commits into from
Feb 25, 2025
Merged

Personality Revamp #5998

merged 35 commits into from
Feb 25, 2025

Conversation

IllianiCBT
Copy link
Collaborator

@IllianiCBT IllianiCBT commented Feb 7, 2025

  • Fixed bug that was causing characters to get negative and major personality traits more often than intended. This may result in some personality changes between <50.04 and 50.04.
  • Fixed a bug where personality would be generated twice.
  • Moved getPersonalityValue method out of Reputation class and into Personality Controller, as it made more sense for it to live there.
  • Refactored folder organization in RandomEvents folder. No functionality change.
  • Rewrote all personality descriptions. All personality descriptions now come in three flavors, effectively tripling the number of personality traits we support without actually increasing their number. What flavor a character will get is determined at character creation and cannot be changed, those individual traits can be changed as normal. This is true for the next two points, also.
  • Rewrote all intelligence descriptions. All intelligence descriptions also come in three flavors.
  • Rewrote all personality quirks. All personality quirks now come in six flavors. Three flavors for combat professions. Three flavors for support professions. Dependents no longer show personality quirks. Description will update whenever a character's primary role is changed, ensuring things are kept consistent. Quirk descriptions should mirror each other across the Combatant:Support divide.
  • Added a handful of new personality quirks.
  • Added unit tests to test the personality enums. This will ensure we can never end up in a situation where an enum has incomplete information.
  • Converted personality traits, quirks, and intelligence to use MHQInternationalization, without which this PR wouldn't be possible.

Taking everything into consideration we have gone from 120 individual personality characteristics to 360. Intelligence has gone from 24 to 350. And personality quirks have gone from 217 quirks (with one description each) to 229 individual quirks and 1,374 descriptions.

And for anyone wondering what the difference looks like, we go from this...
image

To this...
image

Fix #5715

Moved personality-related classes and controllers from the "personnel.randomEvents" package to the "randomEvents.personalities" package. Updated all affected imports and references across various files to align with the new structure. Added a helper method to `PersonalityController` for calculating personality values.
Replaced ordinal-based traits with name-based handling for better readability, removing outdated compatibility logic. Centralized resource management for personality descriptions using properties files, improving maintainability and localization support. Streamlined enum trait methods and added descriptive accessors for consistency.
This update introduced new fields for personality trait description indices and initialized them with random values using `randomInt(3)`. The changes enable more detailed and randomized personality descriptions and extended XML handling for saving and loading these indices. Additionally, personality description property files were updated to support multiple descriptions per trait.
Revised character trait descriptions to use gender-neutral pronouns and phrasing, enhancing inclusivity. This applies to both Aggression and Ambition property files across multiple traits.
Added ".regexp" suffix to resource keys in personality enums to align with expected format. This ensures proper localization lookup and resolves potential inconsistencies in description retrieval.
Replaced existing description keys with `.regexp` counterparts for better consistency and potential adaptability. This change aligns the property structure to a more standardized format across the file.
Revised and expanded intelligence and greed property descriptions to use regex for enhanced flexibility and customization. Corrected terminology inconsistencies, replacing 'Mech with 'Mek across multiple entries to ensure alignment with proper usage.
…rals

Adjusted the personality description logic to include proper paragraph formatting. Fixed single-quote escaping in resource files to ensure consistency and prevent errors.
Replaced hardcoded names and pronouns with dynamic placeholders in Social.properties. This improves reusability and allows descriptions to adapt to different characters automatically.
Simplified property key structure by removing ".regexp" suffix in Intelligence and Aggression property files. This ensures consistency and reduces redundancy in key naming while maintaining the same functional content.
Expanded the descriptions for all Personality Quirks, adding nuance and depth through multiple detailed variants. This enhances the context and characterization, creating more immersive and relatable attributes for each quirk.
…descriptions.

Updated descriptions in resource files for better narrative depth and clarity, distinguishing between combatant and civilian personas. This improves immersion and contextual storytelling for characters.
Expanded the descriptions of various personality quirks in the `PersonalityQuirk.properties` file. Each quirk now includes nuanced backstories and motivations tailored to both combatant and civilian contexts, enhancing depth and character immersion.
Removed "DEBRIS_SLINGER" from quirks, updated civilian roles to support roles, and added numerous new personality quirks to enhance diversity. Adjusted descriptions to align with the support role context for consistency.
Added campaign context to personality generation and description logic, enabling context-sensitive behavior for factions and roles. Updated related classes and methods to support this refactor, ensuring accurate generation and descriptions based on campaign information.
# Conflicts:
#	MekHQ/src/mekhq/campaign/personnel/Person.java
#	MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java
Moved the `getPersonalityValue` method from `CommandRating` to `PersonalityController` to centralize personality-related logic. Updated imports and documentation to align with the refactor. Consolidated copyright year updates across multiple files.
Added test classes for personality-related enums (Greed, Aggression, Social, Intelligence, Ambition, and PersonalityQuirk). These include validation for string parsing, labels, and descriptions to ensure proper functionality.
Replaced redundant calls to PersonalityController with a static import for writeDescription. Ensured consistent usage of writeDescription during role updates and name changes for improved code clarity and maintainability.
@IllianiCBT IllianiCBT added Bug Personnel Personnel-related Issues Tests Issues or Pull Requests related to the project tests labels Feb 7, 2025
@IllianiCBT IllianiCBT self-assigned this Feb 7, 2025
@codecov-commenter
Copy link

codecov-commenter commented Feb 7, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 11.13%. Comparing base (e7a4c86) to head (537c20f).
Report is 100 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #5998      +/-   ##
============================================
+ Coverage     10.92%   11.13%   +0.21%     
- Complexity     6357     6419      +62     
============================================
  Files          1059     1062       +3     
  Lines        140086   140380     +294     
  Branches      20884    20878       -6     
============================================
+ Hits          15301    15632     +331     
+ Misses       123192   123128      -64     
- Partials       1593     1620      +27     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Replaced numerical keys with descriptive "lance" keys for Inner Sphere terminology in PersonalityQuirk.properties. This enhances clarity and improves maintainability of resource definitions.
@IllianiCBT IllianiCBT marked this pull request as draft February 7, 2025 21:47
@IllianiCBT IllianiCBT marked this pull request as ready for review February 7, 2025 21:47
@IllianiCBT IllianiCBT marked this pull request as draft February 9, 2025 20:19
@HammerGS HammerGS added the Draft Work in Progress label Feb 9, 2025
@IllianiCBT
Copy link
Collaborator Author

This PR has been marked as a Draft as it shouldn't be merged until I return from vacation due to the likelihood of it needing post-launch support.

However, this PR is feature complete and ready for review.

The Personalities.properties file has been deleted as it was no longer in use. This cleanup reduces unnecessary clutter and improves maintainability of the codebase.
Standardized intelligence labels, descriptions, and tiers for clarity and consistency. Expanded descriptions to provide richer characterization for various levels while improving differentiation across the scale.
Updated the copyright header to include 2025, reflecting maintenance or contributions made this year. This change ensures proper representation of the project's timeline and legal accuracy.
This refactor simplifies method signatures by removing the unused `campaign` parameter from personality-related methods in `PersonalityController` and related calls. This enhances clarity and ensures consistency across the application.
@IllianiCBT IllianiCBT added Documentation and removed Draft Work in Progress labels Feb 23, 2025
@IllianiCBT IllianiCBT marked this pull request as ready for review February 23, 2025 03:48
@IllianiCBT
Copy link
Collaborator Author

Taking this off draft, it's now ready to be reviewed and merged.

Introduced a chance for re-educated personnel to gain personality quirks. Made personality quirk generation configurable via the static `PERSONALITY_QUIRK_CHANCE` field for better control. Also exposed `generatePersonalityQuirk` for broader use within the campaign logic.
Ensure the first trait description is appended without unnecessary `<p>` tags to prevent spacing issues. Adjust the loop to handle subsequent traits starting from the second entry. This improves the clarity and formatting of personality descriptions.
Changed the modifier of PERSONALITY_QUIRK_CHANCE to "final" to ensure its value remains unaltered throughout the codebase. This improves code clarity and enforces immutability for this constant.
Corrected a placeholder error in the 'INDIFFERENT.description.1' property, replacing an incorrect reference to {4} with {0} for consistency and accuracy. This ensures proper formatting and coherent descriptor functionality.
@Algebro7 Algebro7 self-requested a review February 23, 2025 23:20
Copy link
Collaborator

@Algebro7 Algebro7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good, nice work! I left a handful of questions/suggestions that you can feel free to address or ignore. The latter won't hurt my feelings a bit :)

return aggressionDescriptionIndex;
}

public void setAggressionDescriptionIndex(final int aggressionDescriptionIndex) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest adding Javadocs for these even though they're technically a trivial getters and setters. I worry that the consumers of this API might not know that this should be an integer between 0 and 3 or bigger ranges if they change in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I have a better idea. I'll clamp them and add a static variable so that it's not possible to input invalid entries. While also killing a few magic numbers. Thanks for the inspiration!

@@ -2616,65 +2695,29 @@ public static Person generateInstanceFromXML(Node wn, Campaign c, Version versio
} else if (wn2.getNodeName().equalsIgnoreCase("eduEducationTime")) {
retVal.eduEducationTime = Integer.parseInt(wn2.getTextContent());
} else if (wn2.getNodeName().equalsIgnoreCase("aggression")) {
try {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just confirming that these compatibility handlers should be removed since I don't have the full context

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I rewrote the parser so they're no longer necessary. Now it will just accept both ordinal and name without issue.


public class PersonalityController {
public final static int PERSONALITY_QUIRK_CHANCE = 10;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add tests for the PersonalityController class? It looks like there is a lot of logic involving a good bit of randomness here so I think it would be good to have test coverage for it if we don't. Spies will let you control the randomInt() calls to return values you want, if that's any help.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I really don't wanna write tests for code that wasn't designed for testing. But I guess it wouldn't hurt.

* @param person the person to calculate the personality value for
* @return the total personality value of the person in the campaign
*/
public static int getPersonalityValue(Campaign campaign, Person person) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way this could be adjusted to work without taking an entire campaign object? It only seems to care about two specific campaign options right? Could we pass those as booleans instead? Just looking for ways to reduce coupling/dependencies on Campaigns.

import static org.mockito.Mockito.mock;

public class GreedTest {
@Test
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out @ParameterizedTest--you could basically condense most of these into a single test case I think with CsvSource or MethodSource. I have an open PR that does this (AtBContract tests) if you need help


public class AmbitionTest {
@Test
public void testFromString_ValidStatus() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommending parameterization

import static org.mockito.Mockito.mock;

public class AggressionTest {
@Test
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommending parameterization

import static mekhq.campaign.personnel.enums.GenderDescriptors.HIS_HER_THEIR;
import static mekhq.utilities.MHQInternationalization.getFormattedTextAt;

public enum Aggression {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think a class-level docstring is warranted here?

* <p>The label is determined based on the resource bundle for the application,
* utilizing the enum name combined with a specific key suffix to fetch the
* relevant localized string.</p>
*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest documenting the Person parameter in this docstring

*
* @return the description associated with this enumeration value
*/
public String getDescription(Person person) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it make sense to pass in the index, first name, and gender instead of a whole person to reduce the coupling with that class? Doesn't seem like a major concern here but the fewer things you have to mock in tests the better usually.

@IllianiCBT
Copy link
Collaborator Author

These are all good feedback. I'll pop this back on draft till I have time to refactor the personality controller for testing.

@IllianiCBT IllianiCBT marked this pull request as draft February 24, 2025 01:31
# Conflicts:
#	MekHQ/src/mekhq/campaign/rating/CamOpsReputation/CommandRating.java
#	MekHQ/src/mekhq/gui/adapter/PersonnelTableMouseAdapter.java
#	MekHQ/src/mekhq/gui/dialog/ResolveScenarioWizardDialog.java
Introduced modular methods and constants to simplify personality generation and enhance extensibility. Added new fallback logic, improved trait description localization with gender and name support, and clamped indexes for defined ranges to ensure consistency. Refactored enum traits to include metadata for better trait management, improving maintainability and readability.
Updated to use `PersonalityController.getPersonalityValue` with explicit parameters for clarity and to align with campaign options. This improves modularity and ensures better maintainability of the personality evaluation logic.
Renamed `writeDescription` to `writePersonalityDescription` for better clarity and consistency. Updated related method calls and tests accordingly. Also changed `generateAndApplyPersonalityQuirk` to public for broader usability.
@IllianiCBT IllianiCBT marked this pull request as ready for review February 24, 2025 21:27
@IllianiCBT
Copy link
Collaborator Author

Did some refactoring to personality controller. However, it's not going to be easy to test because of it's a utility class not initialized so it can't be easily spy'd or for the random elements to be overridden by creating an override class in the test suite.

Somebody more learned on unit tests might be able to figure it, but I'm not there yet. I also chose not to implement parameterization testing at this time as I want to be able to look into that properly and I really need to move onto post-50.03 bug support, so at this time the test suite passes and I don't want to take the time to rewrite it.

I did, however, update javadocs and do some additional polish and safeguards so I don't anticipate any issues.

Flipping this to live: once more with feeling.

Person person = new Person(campaign);

for (Aggression trait : Aggression.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Constant loop condition Warning

Loop
might not terminate, as this loop condition is constant within the loop.
Person person = new Person(campaign);

for (Aggression trait : Aggression.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Useless comparison test Warning

Test is always true.
Person person = new Person(campaign);

for (Ambition trait : Ambition.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Constant loop condition Warning

Loop
might not terminate, as this loop condition is constant within the loop.
Person person = new Person(campaign);

for (Ambition trait : Ambition.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Useless comparison test Warning

Test is always true.
Person person = new Person(campaign);

for (Greed trait : Greed.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Constant loop condition Warning

Loop
might not terminate, as this loop condition is constant within the loop.
public void testGetDescription_notInvalid_Combatant() {
Faction originFaction = Factions.getInstance().getFaction("MERC");
for (PersonalityQuirk trait : PersonalityQuirk.values()) {
for (int i = 0; i < 3; i++) {

Check warning

Code scanning / CodeQL

Useless comparison test Warning

Test is always true.
public void testGetDescription_notInvalid_Support() {
Faction originFaction = Factions.getInstance().getFaction("MERC");
for (PersonalityQuirk trait : PersonalityQuirk.values()) {
for (int i = 0; i < 3; i++) {

Check warning

Code scanning / CodeQL

Constant loop condition Warning

Loop
might not terminate, as this loop condition is constant within the loop.
public void testGetDescription_notInvalid_Support() {
Faction originFaction = Factions.getInstance().getFaction("MERC");
for (PersonalityQuirk trait : PersonalityQuirk.values()) {
for (int i = 0; i < 3; i++) {

Check warning

Code scanning / CodeQL

Useless comparison test Warning

Test is always true.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it isn't

Person person = new Person(campaign);

for (Social trait : Social.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Constant loop condition Warning

Loop
might not terminate, as this loop condition is constant within the loop.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it won't

Person person = new Person(campaign);

for (Social trait : Social.values()) {
for (int i = 0; i < MAXIMUM_VARIATIONS; i++) {

Check warning

Code scanning / CodeQL

Useless comparison test Warning

Test is always true.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it isn't

@IllianiCBT IllianiCBT requested a review from Algebro7 February 24, 2025 21:33
@IllianiCBT IllianiCBT mentioned this pull request Feb 25, 2025
Copy link
Member

@HammerGS HammerGS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with Co-Pilot and IDEA AI no issues detected

@HammerGS HammerGS merged commit ef29961 into MegaMek:master Feb 25, 2025
4 checks passed
@IllianiCBT IllianiCBT deleted the personality_revamp branch March 23, 2025 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Documentation Personnel Personnel-related Issues Tests Issues or Pull Requests related to the project tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Issue] Typo/better grammar possible on personnel blurb
4 participants