Skip to content

Commit fbc6005

Browse files
authored
Merge pull request #5850 from IllianiCBT/vocationalXP
Rebranded Idle XP into Vocational XP
2 parents d65f60f + 899ef61 commit fbc6005

File tree

6 files changed

+230
-175
lines changed

6 files changed

+230
-175
lines changed

MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,14 +1838,16 @@ lblKills.tooltip=How many kills need to be scored before experience is awarded?\
18381838

18391839
# createMissionsPanel
18401840
lblMissionsPanel.text=Missions
1841-
lblIdleXP.text=Milestone XP per
1842-
lblIdleXP.tooltip=How much experience should be awarded per milestone?
1843-
lblMonthsIdleXP.text=Months
1844-
lblMonthsIdleXP.tooltip=How many months are in each experience milestone? Characters will make a\
1845-
\ milestone experience check every time this many months has passed.
1846-
lblTargetIdleXP.text=Milestone XP Target Number
1847-
lblTargetIdleXP.tooltip=What is the 2d6 target number a character must beat to be awarded milestone\
1848-
\ experience?
1841+
lblVocationalXP.text=Vocational XP per \u26A0
1842+
lblVocationalXP.tooltip=How much experience should be awarded per vocational experience check? This\
1843+
\ value is doubled while on any contract not classified as 'Garrison Type' (any contract that\
1844+
\ ends in 'Duty').
1845+
lblVocationalXPFrequency.text=Months
1846+
lblVocationalXPFrequency.tooltip=How many months occur between vocational experience checks?\
1847+
\ Characters will make a vocational experience check every time this many months has passed.
1848+
lblVocationalXPTargetNumber.text=Vocational XP Target Number
1849+
lblVocationalXPTargetNumber.tooltip=What is the 2d6 target number a character must beat to be\
1850+
\ awarded vocational experience?
18491851
lblMissionXpFail.text=Failure
18501852
lblMissionXpFail.tooltip=How much experience is awarded for a failed contract? This is granted to\
18511853
\ all active personnel.

MekHQ/src/mekhq/campaign/Campaign.java

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4318,34 +4318,57 @@ public void processNewDayPersonnel() {
43184318
// This list ensures we don't hit a concurrent modification error
43194319
List<Person> personnel = getPersonnelFilteringOutDeparted();
43204320

4321+
// Prep some data for vocational xp
4322+
int vocationalXpRate = campaignOptions.getVocationalXP();
4323+
if (hasActiveContract) {
4324+
if (campaignOptions.isUseAtB()) {
4325+
for (AtBContract contract : getActiveAtBContracts()) {
4326+
if (!contract.getContractType().isGarrisonType()) {
4327+
vocationalXpRate *= 2;
4328+
break;
4329+
}
4330+
}
4331+
} else {
4332+
vocationalXpRate *= 2;
4333+
}
4334+
}
4335+
4336+
// Process personnel
43214337
for (Person person : personnel) {
43224338
if (person.getStatus().isDepartedUnit()) {
43234339
continue;
43244340
}
43254341

4342+
// Daily events
43264343
if (getDeath().processNewDay(this, getLocalDate(), person)) {
43274344
// The person has died, so don't continue to process the dead
43284345
continue;
43294346
}
43304347

4331-
processWeeklyRelationshipEvents(person);
4332-
43334348
person.resetMinutesLeft();
43344349
person.setAcquisition(0);
43354350

43364351
processAdvancedMedicalEvents(person);
43374352

4338-
// Reset edge points to the purchased value each week. This should only
4339-
// apply for support personnel - combat troops reset with each new mm game
4340-
processWeeklyEdgeResets(person);
4353+
processAnniversaries(person);
4354+
4355+
// Weekly events
4356+
if (currentDay.getDayOfWeek() == DayOfWeek.MONDAY) {
4357+
processWeeklyRelationshipEvents(person);
43414358

4342-
if (processMonthlyVocationalXp(person)) {
4343-
personnelWhoAdvancedInXP.add(person);
4359+
processWeeklyEdgeResets(person);
43444360
}
43454361

4346-
processAnniversaries(person);
4362+
// Monthly events
4363+
if (currentDay.getDayOfMonth() == 1) {
4364+
processMonthlyAutoAwards(person);
43474365

4348-
processMonthlyAutoAwards(person);
4366+
if (vocationalXpRate > 0) {
4367+
if (processMonthlyVocationalXp(person, vocationalXpRate)) {
4368+
personnelWhoAdvancedInXP.add(person);
4369+
}
4370+
}
4371+
}
43494372
}
43504373

43514374
if (!personnelWhoAdvancedInXP.isEmpty()) {
@@ -4392,45 +4415,29 @@ private void processAdvancedMedicalEvents(Person person) {
43924415
* @param person the person for whom weekly Edge resets will be processed
43934416
*/
43944417
private void processWeeklyEdgeResets(Person person) {
4395-
if ((person.hasSupportRole(true) || person.isEngineer())
4396-
&& (getLocalDate().getDayOfWeek() == DayOfWeek.MONDAY)) {
4418+
if ((person.hasSupportRole(true) || person.isEngineer())) {
43974419
person.resetCurrentEdge();
43984420
}
43994421
}
44004422

44014423
/**
4402-
* Processes the monthly vocational experience (XP) gain for a given person based on specific
4403-
* eligibility criteria. If the person meets the conditions, XP is awarded and their progress
4404-
* is tracked.
4405-
*
4406-
* <p>The method checks the following conditions to determine eligibility for XP gain:
4407-
* <ul>
4408-
* <li>The person must have an active status (e.g., not retired, deceased, or in education).</li>
4409-
* <li>The person must not be a child on the current date.</li>
4410-
* <li>The person must not be categorized as a dependent.</li>
4411-
* <li>The campaign must enable idle XP, and the current date must be the first day of the month.</li>
4412-
* <li>The person must not have the status of a prisoner (Bondsmen are exempt from this
4413-
* and remain eligible for XP).</li>
4414-
* </ul>
4424+
* Processes the monthly vocational experience (XP) gain for a given person based on their
4425+
* eligibility and the vocational experience rules defined in campaign options.
44154426
*
4416-
* <p>If all of these conditions are satisfied:
4427+
* <p>Eligibility for receiving vocational XP is determined by checking the following conditions:
44174428
* <ul>
4418-
* <li>The person’s idle month count is incremented.</li>
4419-
* <li>If the accumulated idle months reach the threshold defined in the campaign options,
4420-
* an idle XP roll (2d6) is performed.</li>
4421-
* <li>If the roll result meets or exceeds the target threshold:
4422-
* <ul>
4423-
* <li>XP is awarded to the person based on the campaign's idle XP configuration.</li>
4424-
* <li>The idle month count is reset.</li>
4425-
* </ul>
4426-
* </li>
4427-
* <li>If the roll is unsuccessful, the idle month count is still reset.</li>
4429+
* <li>The person must have an <b>active status</b> (e.g., not retired, deceased, or in education).</li>
4430+
* <li>The person must not be a <b>child</b> as of the current date.</li>
4431+
* <li>The person must not be categorized as a <b>dependent</b>.</li>
4432+
* <li>The person must not have the status of a <b>prisoner</b>.</li>
4433+
* <b>Note:</b> Bondsmen are exempt from this restriction and are eligible for vocational XP.
44284434
* </ul>
44294435
*
44304436
* @param person the {@link Person} whose monthly vocational XP is to be processed
4437+
* @param vocationalXpRate the amount of XP awarded on a successful roll
44314438
* @return {@code true} if XP was successfully awarded during the process, {@code false} otherwise
44324439
*/
4433-
private boolean processMonthlyVocationalXp(Person person) {
4440+
private boolean processMonthlyVocationalXp(Person person, int vocationalXpRate) {
44344441
if (!person.getStatus().isActive()) {
44354442
return false;
44364443
}
@@ -4443,16 +4450,22 @@ private boolean processMonthlyVocationalXp(Person person) {
44434450
return false;
44444451
}
44454452

4446-
if ((getCampaignOptions().getIdleXP() > 0) && (getLocalDate().getDayOfMonth() == 1)
4447-
&& !person.getPrisonerStatus().isCurrentPrisoner()) { // Prisoners can't gain XP, while Bondsmen can
4448-
person.setIdleMonths(person.getIdleMonths() + 1);
4449-
if (person.getIdleMonths() >= getCampaignOptions().getMonthsIdleXP()) {
4450-
if (Compute.d6(2) >= getCampaignOptions().getTargetIdleXP()) {
4451-
person.awardXP(this, getCampaignOptions().getIdleXP());
4452-
person.setIdleMonths(0);
4453-
return true;
4454-
}
4455-
person.setIdleMonths(0);
4453+
if (person.getPrisonerStatus().isCurrentPrisoner()) {
4454+
// Prisoners can't gain vocational XP, while Bondsmen can
4455+
return false;
4456+
}
4457+
4458+
int checkFrequency = campaignOptions.getVocationalXPCheckFrequency();
4459+
int targetNumber = campaignOptions.getVocationalXPTargetNumber();
4460+
4461+
person.setVocationalXPTimer(person.getVocationalXPTimer() + 1);
4462+
if (person.getVocationalXPTimer() >= checkFrequency) {
4463+
if (Compute.d6(2) >= targetNumber) {
4464+
person.awardXP(this, vocationalXpRate);
4465+
person.setVocationalXPTimer(0);
4466+
return true;
4467+
} else {
4468+
person.setVocationalXPTimer(0);
44564469
}
44574470
}
44584471

@@ -4519,35 +4532,33 @@ private void processAnniversaries(Person person) {
45194532
* @param person the person for whom the monthly auto awards are being processed
45204533
*/
45214534
private void processMonthlyAutoAwards(Person person) {
4522-
if (getLocalDate().getDayOfMonth() == 1) {
4523-
double multiplier = 0;
4535+
double multiplier = 0;
45244536

4525-
int score = 0;
4537+
int score = 0;
45264538

4527-
if (person.getPrimaryRole().isSupport(true)) {
4528-
int dice = person.getExperienceLevel(this, false);
4529-
4530-
if (dice > 0) {
4531-
score = Compute.d6(dice);
4532-
}
4539+
if (person.getPrimaryRole().isSupport(true)) {
4540+
int dice = person.getExperienceLevel(this, false);
45334541

4534-
multiplier += 0.5;
4542+
if (dice > 0) {
4543+
score = Compute.d6(dice);
45354544
}
45364545

4537-
if (person.getSecondaryRole().isSupport(true)) {
4538-
int dice = person.getExperienceLevel(this, true);
4546+
multiplier += 0.5;
4547+
}
45394548

4540-
if (dice > 0) {
4541-
score += Compute.d6(dice);
4542-
}
4549+
if (person.getSecondaryRole().isSupport(true)) {
4550+
int dice = person.getExperienceLevel(this, true);
45434551

4544-
multiplier += 0.5;
4545-
} else if (person.getSecondaryRole().isNone()) {
4546-
multiplier += 0.5;
4552+
if (dice > 0) {
4553+
score += Compute.d6(dice);
45474554
}
45484555

4549-
person.changeAutoAwardSupportPoints((int) (score * multiplier));
4556+
multiplier += 0.5;
4557+
} else if (person.getSecondaryRole().isNone()) {
4558+
multiplier += 0.5;
45504559
}
4560+
4561+
person.changeAutoAwardSupportPoints((int) (score * multiplier));
45514562
}
45524563

45534564
/**

MekHQ/src/mekhq/campaign/CampaignOptions.java

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,9 @@ public static String getTransitUnitName(final int unit) {
497497
private int nTasksXP;
498498
private int successXP;
499499
private int mistakeXP;
500-
private int idleXP;
501-
private int monthsIdleXP;
502-
private int targetIdleXP;
500+
private int vocationalXP;
501+
private int vocationalXPCheckFrequency;
502+
private int vocationalXPTargetNumber;
503503
private int contractNegotiationXP;
504504
private int adminXP;
505505
private int adminXPPeriod;
@@ -1123,9 +1123,9 @@ public CampaignOptions() {
11231123
nTasksXP = 25;
11241124
successXP = 0;
11251125
mistakeXP = 0;
1126-
idleXP = 0;
1127-
monthsIdleXP = 2;
1128-
targetIdleXP = 10;
1126+
vocationalXP = 1;
1127+
vocationalXPCheckFrequency = 1;
1128+
vocationalXPTargetNumber = 7;
11291129
contractNegotiationXP = 0;
11301130
adminXP = 0;
11311131
adminXPPeriod = 1;
@@ -3903,28 +3903,28 @@ public void setAssignPortraitOnRoleChange(final boolean assignPortraitOnRoleChan
39033903
this.assignPortraitOnRoleChange = assignPortraitOnRoleChange;
39043904
}
39053905

3906-
public int getIdleXP() {
3907-
return idleXP;
3906+
public int getVocationalXP() {
3907+
return vocationalXP;
39083908
}
39093909

3910-
public void setIdleXP(final int idleXP) {
3911-
this.idleXP = idleXP;
3910+
public void setVocationalXP(final int vocationalXP) {
3911+
this.vocationalXP = vocationalXP;
39123912
}
39133913

3914-
public int getTargetIdleXP() {
3915-
return targetIdleXP;
3914+
public int getVocationalXPTargetNumber() {
3915+
return vocationalXPTargetNumber;
39163916
}
39173917

3918-
public void setTargetIdleXP(final int targetIdleXP) {
3919-
this.targetIdleXP = targetIdleXP;
3918+
public void setVocationalXPTargetNumber(final int vocationalXPTargetNumber) {
3919+
this.vocationalXPTargetNumber = vocationalXPTargetNumber;
39203920
}
39213921

3922-
public int getMonthsIdleXP() {
3923-
return monthsIdleXP;
3922+
public int getVocationalXPCheckFrequency() {
3923+
return vocationalXPCheckFrequency;
39243924
}
39253925

3926-
public void setMonthsIdleXP(final int monthsIdleXP) {
3927-
this.monthsIdleXP = monthsIdleXP;
3926+
public void setVocationalXPCheckFrequency(final int vocationalXPCheckFrequency) {
3927+
this.vocationalXPCheckFrequency = vocationalXPCheckFrequency;
39283928
}
39293929

39303930
public int getContractNegotiationXP() {
@@ -4792,9 +4792,9 @@ public void writeToXml(final PrintWriter pw, int indent) {
47924792
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "tasksXP", tasksXP);
47934793
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "mistakeXP", mistakeXP);
47944794
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "successXP", successXP);
4795-
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "idleXP", idleXP);
4796-
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "targetIdleXP", targetIdleXP);
4797-
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "monthsIdleXP", monthsIdleXP);
4795+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "vocationalXP", vocationalXP);
4796+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "vocationalXPTargetNumber", vocationalXPTargetNumber);
4797+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "vocationalXPCheckFrequency", vocationalXPCheckFrequency);
47984798
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "contractNegotiationXP", contractNegotiationXP);
47994799
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "adminWeeklyXP", adminXP);
48004800
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "adminXPPeriod", adminXPPeriod);
@@ -5395,12 +5395,18 @@ public static CampaignOptions generateCampaignOptionsFromXml(Node wn, Version ve
53955395
retVal.successXP = Integer.parseInt(wn2.getTextContent().trim());
53965396
} else if (wn2.getNodeName().equalsIgnoreCase("mistakeXP")) {
53975397
retVal.mistakeXP = Integer.parseInt(wn2.getTextContent().trim());
5398-
} else if (wn2.getNodeName().equalsIgnoreCase("idleXP")) {
5399-
retVal.idleXP = Integer.parseInt(wn2.getTextContent().trim());
5400-
} else if (wn2.getNodeName().equalsIgnoreCase("targetIdleXP")) {
5401-
retVal.targetIdleXP = Integer.parseInt(wn2.getTextContent().trim());
5402-
} else if (wn2.getNodeName().equalsIgnoreCase("monthsIdleXP")) {
5403-
retVal.monthsIdleXP = Integer.parseInt(wn2.getTextContent().trim());
5398+
} else if (wn2.getNodeName().equalsIgnoreCase("vocationalXP")
5399+
// <50.03 compatibility handler
5400+
|| wn2.getNodeName().equalsIgnoreCase("idleXP")) {
5401+
retVal.vocationalXP = Integer.parseInt(wn2.getTextContent().trim());
5402+
} else if (wn2.getNodeName().equalsIgnoreCase("vocationalXPTargetNumber")
5403+
// <50.03 compatibility handler
5404+
|| wn2.getNodeName().equalsIgnoreCase("targetIdleXP")) {
5405+
retVal.vocationalXPTargetNumber = Integer.parseInt(wn2.getTextContent().trim());
5406+
} else if (wn2.getNodeName().equalsIgnoreCase("vocationalXPCheckFrequency")
5407+
// <50.03 compatibility handler
5408+
|| wn2.getNodeName().equalsIgnoreCase("monthsIdleXP")) {
5409+
retVal.vocationalXPCheckFrequency = Integer.parseInt(wn2.getTextContent().trim());
54045410
} else if (wn2.getNodeName().equalsIgnoreCase("contractNegotiationXP")) {
54055411
retVal.contractNegotiationXP = Integer.parseInt(wn2.getTextContent().trim());
54065412
} else if (wn2.getNodeName().equalsIgnoreCase("adminWeeklyXP")) {

MekHQ/src/mekhq/campaign/personnel/Person.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ public class Person {
167167
private UUID doctorId;
168168
private List<Unit> techUnits;
169169

170+
private int vocationalXPTimer;
171+
170172
// days of rest
171-
private int idleMonths;
172173
private int daysToWaitForHealing;
173174

174175
// Our rank
@@ -1307,12 +1308,12 @@ public void setStatus(final PersonnelStatus status) {
13071308
this.status = status;
13081309
}
13091310

1310-
public int getIdleMonths() {
1311-
return idleMonths;
1311+
public int getVocationalXPTimer() {
1312+
return vocationalXPTimer;
13121313
}
13131314

1314-
public void setIdleMonths(final int idleMonths) {
1315-
this.idleMonths = idleMonths;
1315+
public void setVocationalXPTimer(final int vocationalXPTimer) {
1316+
this.vocationalXPTimer = vocationalXPTimer;
13161317
}
13171318

13181319
public int getDaysToWaitForHealing() {
@@ -1974,8 +1975,8 @@ public void writeToXML(final PrintWriter pw, int indent, final Campaign campaign
19741975
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "biography", biography);
19751976
}
19761977

1977-
if (idleMonths > 0) {
1978-
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "idleMonths", idleMonths);
1978+
if (vocationalXPTimer > 0) {
1979+
MHQXMLUtility.writeSimpleXMLTag(pw, indent, "vocationalXPTimer", vocationalXPTimer);
19791980
}
19801981

19811982
if (!genealogy.isEmpty()) {
@@ -2336,8 +2337,10 @@ public static Person generateInstanceFromXML(Node wn, Campaign c, Version versio
23362337
retVal.secondaryDesignator = ROMDesignation.parseFromString(wn2.getTextContent().trim());
23372338
} else if (wn2.getNodeName().equalsIgnoreCase("daysToWaitForHealing")) {
23382339
retVal.daysToWaitForHealing = Integer.parseInt(wn2.getTextContent());
2339-
} else if (wn2.getNodeName().equalsIgnoreCase("idleMonths")) {
2340-
retVal.idleMonths = Integer.parseInt(wn2.getTextContent());
2340+
} else if (wn2.getNodeName().equalsIgnoreCase("vocationalXPTimer")
2341+
// <50.03 compatibility handler
2342+
|| wn2.getNodeName().equalsIgnoreCase("idleMonths")) {
2343+
retVal.vocationalXPTimer = Integer.parseInt(wn2.getTextContent());
23412344
} else if (wn2.getNodeName().equalsIgnoreCase("id")) {
23422345
retVal.id = UUID.fromString(wn2.getTextContent());
23432346
} else if (wn2.getNodeName().equalsIgnoreCase("genealogy")) {

0 commit comments

Comments
 (0)