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

Added Randomized Relationship History for Personnel #4512

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,25 @@ lifePathsPanel.title=Life Paths
personnelRandomizationPanel.title=Personnel Randomization
chkUseDylansRandomXP.text=Use Dylan's Random XP (Unofficial)
chkUseDylansRandomXP.toolTipText=Use Dylan's optional random XP on creation of a new person (20% chance each of 0, 1, 2, 3, and randomized between 1 and 8 XP)

# Random Histories
randomHistoriesPanel.title=Random Histories
chkUseRandomPersonalities.text=Use Random Personalities
chkUseRandomPersonalities.toolTipText=<html>Personnel are generated with random personality traits, quirks and intelligence.\
<br>\
<br>Intelligence affects a characters ability to graduate from education module academies.\
<br>Intelligence affects a character's ability to graduate from education module academies.\
<br>\
<br>While traits and quirks do not currently have a mechanical effect, they will be used by the upcoming Random Events module.</html>
chkUseSimulatedRelationships.text=Simulate Relationship History
chkUseSimulatedRelationships.toolTipText=<html>Personnel are generated with a random relationship history.\
<br>\
<br>If randomized marriages are enabled the various marriage settings (including chance) will be used to determine whether new personnel have been previously married.\
<br>\
<br>If randomized procreation is enabled the various procreation settings (including chance) will be used to determine whether new personnel have children traveling with them.\
<br>\
<br>If randomized divorce is enabled the various divorce settings (including chance) will be used to determine whether any marriages have ended in divorce.\
<br>\
<br>Any children and current spouses will travel alongside the unit.</html>

# Family
familyPanel.title=Family (Unofficial)
Expand Down
322 changes: 276 additions & 46 deletions MekHQ/src/mekhq/campaign/Campaign.java

Large diffs are not rendered by default.

133 changes: 80 additions & 53 deletions MekHQ/src/mekhq/campaign/CampaignOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -272,58 +272,11 @@ public static String getTransitUnitName(final int unit) {
// Personnel Randomization
private boolean useDylansRandomXP; // Unofficial
private RandomOriginOptions randomOriginOptions;
private boolean useRandomPersonalities;

// Retirement
private boolean useRandomRetirement;

private TurnoverTargetNumberMethod turnoverTargetNumberMethod;
private SkillLevel turnoverDifficulty;
private int turnoverFixedTargetNumber;
private boolean aeroRecruitsHaveUnits;
private boolean trackOriginalUnit;
private TurnoverFrequency turnoverFrequency;
private boolean useContractCompletionRandomRetirement;
private boolean useRandomFounderTurnover;
private boolean useFounderRetirement;
private boolean useSubContractSoldiers;
private int serviceContractDuration;
private int serviceContractModifier;
private boolean payBonusDefault;
private int payBonusDefaultThreshold;

private boolean useCustomRetirementModifiers;
private boolean useFatigueModifiers;
private boolean useSkillModifiers;
private boolean useAgeModifiers;
private boolean useUnitRatingModifiers;
private boolean useFactionModifiers;
private boolean useHostileTerritoryModifiers;
private boolean useMissionStatusModifiers;
private boolean useFamilyModifiers;
private boolean useLoyaltyModifiers;
private boolean useHideLoyalty;

private int payoutRateOfficer;
private int payoutRateEnlisted;
private int payoutRetirementMultiplier;
private boolean usePayoutServiceBonus;
private int payoutServiceBonusRate;

private boolean useAdministrativeStrain;
private int administrativeCapacity;
private int multiCrewStrainDivider;

private boolean useManagementSkill;
private boolean useCommanderLeadershipOnly;
private int managementSkillPenalty;
// Random Histories
private boolean useRandomPersonalities;
private boolean useSimulatedRelationships;

private boolean useFatigue;
private int fatigueRate;
private boolean useInjuryFatigue;
private int fieldKitchenCapacity;
private boolean fieldKitchenIgnoreNonCombatants;
private int fatigueLeaveThreshold;

// Family
private FamilialRelationshipDisplayLevel familyDisplayLevel;
Expand Down Expand Up @@ -411,6 +364,58 @@ public static String getTransitUnitName(final int unit) {
private Map<TenYearAgeRange, Double> ageRangeRandomDeathFemaleValues;
//endregion Life Paths Tab

//region Turnover and Retention
private boolean useRandomRetirement;

private TurnoverTargetNumberMethod turnoverTargetNumberMethod;
private SkillLevel turnoverDifficulty;
private int turnoverFixedTargetNumber;
private boolean aeroRecruitsHaveUnits;
private boolean trackOriginalUnit;
private TurnoverFrequency turnoverFrequency;
private boolean useContractCompletionRandomRetirement;
private boolean useRandomFounderTurnover;
private boolean useFounderRetirement;
private boolean useSubContractSoldiers;
private int serviceContractDuration;
private int serviceContractModifier;
private boolean payBonusDefault;
private int payBonusDefaultThreshold;

private boolean useCustomRetirementModifiers;
private boolean useFatigueModifiers;
private boolean useSkillModifiers;
private boolean useAgeModifiers;
private boolean useUnitRatingModifiers;
private boolean useFactionModifiers;
private boolean useHostileTerritoryModifiers;
private boolean useMissionStatusModifiers;
private boolean useFamilyModifiers;
private boolean useLoyaltyModifiers;
private boolean useHideLoyalty;

private int payoutRateOfficer;
private int payoutRateEnlisted;
private int payoutRetirementMultiplier;
private boolean usePayoutServiceBonus;
private int payoutServiceBonusRate;

private boolean useAdministrativeStrain;
private int administrativeCapacity;
private int multiCrewStrainDivider;

private boolean useManagementSkill;
private boolean useCommanderLeadershipOnly;
private int managementSkillPenalty;

private boolean useFatigue;
private int fatigueRate;
private boolean useInjuryFatigue;
private int fieldKitchenCapacity;
private boolean fieldKitchenIgnoreNonCombatants;
private int fatigueLeaveThreshold;
//endregion Turnover and Retention

//region Finance tab
private boolean payForParts;
private boolean payForRepairs;
Expand Down Expand Up @@ -820,7 +825,10 @@ public CampaignOptions() {
// Personnel Randomization
setUseDylansRandomXP(false);
setRandomOriginOptions(new RandomOriginOptions(true));

// Random Histories
setUseRandomPersonalities(false);
setUseSimulatedRelationships(false);

// Family
setFamilyDisplayLevel(FamilialRelationshipDisplayLevel.SPOUSE);
Expand Down Expand Up @@ -1825,15 +1833,25 @@ public RandomOriginOptions getRandomOriginOptions() {
public void setRandomOriginOptions(final RandomOriginOptions randomOriginOptions) {
this.randomOriginOptions = randomOriginOptions;
}
//endregion Personnel Randomization

//region Random Histories
public boolean isUseRandomPersonalities() {
return useRandomPersonalities;
}

public void setUseRandomPersonalities(final boolean useRandomPersonalities) {
this.useRandomPersonalities = useRandomPersonalities;
}
//endregion Personnel Randomization

public boolean isUseSimulatedRelationships() {
return useSimulatedRelationships;
}

public void setUseSimulatedRelationships(final boolean useSimulatedRelationships) {
this.useSimulatedRelationships = useSimulatedRelationships;
}
//endregion Random Histories

//region Retirement
public boolean isUseRandomRetirement() {
Expand Down Expand Up @@ -4633,9 +4651,13 @@ public void writeToXml(final PrintWriter pw, int indent) {
//region Personnel Randomization
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useDylansRandomXP", isUseDylansRandomXP());
getRandomOriginOptions().writeToXML(pw, indent);
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useRandomPersonalities", isUseRandomPersonalities());
//endregion Personnel Randomization

//region Random Histories
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useRandomPersonalities", isUseRandomPersonalities());
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useSimulatedRelationships", isUseSimulatedRelationships());
//endregion Random Histories

//region Retirement
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "useRandomRetirement", isUseRandomRetirement());
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "turnoverTargetNumberMethod", getTurnoverTargetNumberMethod().name());
Expand Down Expand Up @@ -5374,9 +5396,14 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve
continue;
}
retVal.setRandomOriginOptions(randomOriginOptions);
//endregion Personnel Randomization

//region Random Histories
} else if (wn2.getNodeName().equalsIgnoreCase("useRandomPersonalities")) {
retVal.setUseRandomPersonalities(Boolean.parseBoolean(wn2.getTextContent().trim()));
//endregion Personnel Randomization
} else if (wn2.getNodeName().equalsIgnoreCase("useSimulatedRelationships")) {
retVal.setUseSimulatedRelationships(Boolean.parseBoolean(wn2.getTextContent().trim()));
//endregion Random Histories

//region Family
} else if (wn2.getNodeName().equalsIgnoreCase("familyDisplayLevel")
Expand Down
9 changes: 5 additions & 4 deletions MekHQ/src/mekhq/campaign/mission/AtBContract.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import megamek.client.generator.RandomUnitGenerator;
import megamek.client.ui.swing.util.PlayerColour;
import megamek.common.*;
import megamek.common.enums.Gender;
import megamek.common.enums.SkillLevel;
import megamek.common.icons.Camouflage;
import megamek.common.loaders.EntityLoadingException;
Expand Down Expand Up @@ -480,12 +481,12 @@ public void doBonusRoll(Campaign c) {
int roll = Compute.d6();
switch (roll) {
case 1: /* 1d6 dependents */
if (c.getCampaignOptions().getRandomDependentMethod().isAgainstTheBot()
&& c.getCampaignOptions().isUseRandomDependentAddition()) {
if (c.getCampaignOptions().isUseRandomDependentAddition()) {
number = Compute.d6();
c.addReport("Bonus: " + number + " dependent" + ((number > 1) ? "s" : ""));

for (int i = 0; i < number; i++) {
Person p = c.newDependent(false);
Person p = c.newDependent(false, Gender.RANDOMIZE);
c.recruitPerson(p);
}
}
Expand Down Expand Up @@ -974,7 +975,7 @@ public void setEmployerCode(String code, int year) {
}

public String getEmployerName(int year) {
return isMercSubcontract() ? "Mercenary (" + getEmployerFaction().getFullName(year) + ")"
return isMercSubcontract() ? "Mercenary (" + getEmployerFaction().getFullName(year) + ')'
: getEmployerFaction().getFullName(year);
}

Expand Down
27 changes: 27 additions & 0 deletions MekHQ/src/mekhq/campaign/personnel/divorce/AbstractDivorce.java
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,33 @@ public void divorce(final Campaign campaign, final LocalDate today, final Person
MekHQ.triggerEvent(new PersonChangedEvent(origin));
}

/**
* This divorces two married people.
* This version is meant to be used to log historic divorces that occur during a characters' random background.
* It is a watered down version of divorce()
*
* @param campaign the campaign the two people are a part of
* @param today the current date
* @param origin the origin person being divorced
*/
public void divorceHistoric(final Campaign campaign, final LocalDate today, final Person origin) {
final Person spouse = origin.getGenealogy().getSpouse();

SplittingSurnameStyle.WEIGHTED.apply(campaign, origin, spouse);

PersonalLogger.divorcedFrom(origin, spouse, today);
PersonalLogger.divorcedFrom(spouse, origin, today);

spouse.setMaidenName(null);
origin.setMaidenName(null);

spouse.getGenealogy().setSpouse(null);
origin.getGenealogy().setSpouse(null);

spouse.getGenealogy().addFormerSpouse(new FormerSpouse(origin, today, FormerSpouseReason.DIVORCE));
origin.getGenealogy().addFormerSpouse(new FormerSpouse(spouse, today, FormerSpouseReason.DIVORCE));
}

//region New Day
/**
* Processes new day random divorce for an individual.
Expand Down
8 changes: 8 additions & 0 deletions MekHQ/src/mekhq/campaign/personnel/familyTree/Genealogy.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.w3c.dom.NodeList;

import java.io.PrintWriter;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -194,6 +195,13 @@ public boolean hasChildren() {
return getFamily().get(FamilialRelationshipType.CHILD) != null;
}

/**
* @return true if the person has at least one kid, false otherwise
*/
public boolean hasNonAdultChildren(LocalDate localDate) {
return getChildren().stream().anyMatch(child -> child.isChild(localDate));
}

/**
* @return true if the Person has any parents, otherwise false
*/
Expand Down
26 changes: 26 additions & 0 deletions MekHQ/src/mekhq/campaign/personnel/marriage/AbstractMarriage.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,32 @@ public void marry(final Campaign campaign, final LocalDate today, final Person o
return;
}

performMarriageChanges(campaign, today, origin, spouse, surnameStyle);

campaign.addReport(String.format(resources.getString("marriage.report"), origin.getHyperlinkedName(),
spouse.getHyperlinkedName()));

// Process the loyalty change
if (campaign.getCampaignOptions().isUseLoyaltyModifiers()) {
origin.performRandomizedLoyaltyChange(campaign, false, true);
spouse.performRandomizedLoyaltyChange(campaign, false, true);
}

// And finally we trigger person changed events
MekHQ.triggerEvent(new PersonChangedEvent(origin));
MekHQ.triggerEvent(new PersonChangedEvent(spouse));
}

/**
* Updates the necessary information to perform a marriage between two individuals.
*
* @param campaign the campaign in which the marriage is taking place
* @param today the current date of the marriage
* @param origin the first person getting married
* @param spouse the second person getting married
* @param surnameStyle the style of surname changes to be applied
*/
public static void performMarriageChanges(Campaign campaign, LocalDate today, Person origin, Person spouse, MergingSurnameStyle surnameStyle) {
// Immediately set both Maiden Names, to avoid any divorce bugs (as the default is now an empty string)
origin.setMaidenName(origin.getSurname());
spouse.setMaidenName(spouse.getSurname());
Expand Down
Loading