Skip to content

Commit d0e1ed6

Browse files
committed
Simplify delivery transit time calculation logic
Removed redundant margin of success (MoS) and minimum delivery time configuration for transit calculations. Standardized transit time determination using item availability, campaign settings, and a random roll. Updated the UI and campaign options to align with the simplified calculation method.
1 parent 60328bb commit d0e1ed6

File tree

5 files changed

+70
-247
lines changed

5 files changed

+70
-247
lines changed

MekHQ/resources/mekhq/resources/CampaignOptionsDialog.properties

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,9 @@ lblAutoLogisticsOther.tooltip=autoLogistics counts each part in use, that is not
236236

237237
# createDeliveryPanel
238238
lblDeliveryPanel.text=Deliveries
239-
lblNDiceTransitTime.text=Delivery Time
240-
lblNDiceTransitTime.tooltip=How many dice are rolled to determine delivery time?
241-
lblConstantTransitTime.text=d6+
242-
lblConstantTransitTime.tooltip=How long is added to the delivery time roll?
243-
lblAcquireMosBonus.text=Delivery Time Reduction
244-
lblAcquireMosBonus.tooltip=How much should the delivery time be reduced per margin of success?
245-
lblAcquireMinimum.text=Minimum Delivery Time
246-
lblAcquireMinimum.tooltip=What is the minimum delivery duration?
239+
lblTransitTimeUnits.text=Delivery Scale
240+
lblTransitTimeUnits.tooltip=Should deliveries be scaled using days, weeks, or months? Campaign\
241+
\ Operations uses months.
247242
transitUnitNamesDays.text=Days
248243
transitUnitNamesWeeks.text=Weeks
249244
transitUnitNamesMonths.text=Months

MekHQ/src/mekhq/campaign/Campaign.java

Lines changed: 53 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@
152152
import static java.lang.Math.floor;
153153
import static java.lang.Math.max;
154154
import static java.lang.Math.round;
155+
import static megamek.common.Compute.d6;
156+
import static mekhq.campaign.CampaignOptions.TRANSIT_UNIT_MONTH;
157+
import static mekhq.campaign.CampaignOptions.TRANSIT_UNIT_WEEK;
155158
import static mekhq.campaign.enums.CampaignTransportType.SHIP_TRANSPORT;
156159
import static mekhq.campaign.enums.CampaignTransportType.TACTICAL_TRANSPORT;
157160
import static mekhq.campaign.force.CombatTeam.getStandardForceSize;
@@ -816,7 +819,7 @@ private void processShipSearch() {
816819

817820
long numDays = ChronoUnit.DAYS.between(getShipSearchStart(), getLocalDate());
818821
if (numDays > 21) {
819-
int roll = Compute.d6(2);
822+
int roll = d6(2);
820823
TargetRoll target = getAtBConfig().shipSearchTargetRoll(shipSearchType, this);
821824
setShipSearchStart(null);
822825
report.append("<br/>Ship search target: ").append(target.getValueAsString()).append(" roll: ")
@@ -877,7 +880,7 @@ public void purchaseShipSearchResult() {
877880
Entity en = mekFileParser.getEntity();
878881

879882
int transitDays = getCampaignOptions().isInstantUnitMarketDelivery() ? 0
880-
: calculatePartTransitTime(Compute.d6(2) - 2);
883+
: calculatePartTransitTime(en.calcYearAvailability(getGameYear(), useClanTechBase(), getTechFaction()));
881884

882885
getFinances().debit(TransactionType.UNIT_PURCHASE, getLocalDate(), cost, "Purchased " + en.getShortName());
883886
PartQuality quality = PartQuality.QUALITY_D;
@@ -2002,11 +2005,11 @@ private void simulateRelationshipHistory(Person person) {
20022005

20032006
// set loyalty
20042007
if (experienceLevel <= 0) {
2005-
person.setLoyalty(Compute.d6(3) + 2);
2008+
person.setLoyalty(d6(3) + 2);
20062009
} else if (experienceLevel == 1) {
2007-
person.setLoyalty(Compute.d6(3) + 1);
2010+
person.setLoyalty(d6(3) + 1);
20082011
} else {
2009-
person.setLoyalty(Compute.d6(3));
2012+
person.setLoyalty(d6(3));
20102013
}
20112014

20122015
if (experienceLevel >= 0) {
@@ -2180,7 +2183,7 @@ public void checkBloodnameAdd(Person person, boolean ignoreDice) {
21802183
bloodnameTarget += Math.min(0, getRankSystem().getOfficerCut() - person.getRankNumeric());
21812184
}
21822185

2183-
if (ignoreDice || (Compute.d6(2) >= bloodnameTarget)) {
2186+
if (ignoreDice || (d6(2) >= bloodnameTarget)) {
21842187
final Phenotype phenotype = person.getPhenotype().isNone() ? Phenotype.GENERAL : person.getPhenotype();
21852188

21862189
final Bloodname bloodname = Bloodname.randomBloodname(
@@ -2840,7 +2843,7 @@ public String healPerson(Person medWork, Person doctor) {
28402843
report += doctor.getHyperlinkedFullTitle() + " attempts to heal "
28412844
+ medWork.getFullName();
28422845
TargetRoll target = getTargetFor(medWork, doctor);
2843-
int roll = Compute.d6(2);
2846+
int roll = d6(2);
28442847
report = report + ", needs " + target.getValueAsString()
28452848
+ " and rolls " + roll + ':';
28462849
int xpGained = 0;
@@ -2850,7 +2853,7 @@ public String healPerson(Person medWork, Person doctor) {
28502853
&& doctor.getOptions().booleanOption(PersonnelOptions.EDGE_MEDICAL)) {
28512854
if ((roll == 2) && (doctor.getCurrentEdge() > 0) && (target.getValue() != TargetRoll.AUTOMATIC_SUCCESS)) {
28522855
doctor.changeCurrentEdge(-1);
2853-
roll = Compute.d6(2);
2856+
roll = d6(2);
28542857
report += medWork.fail() + '\n' + doctor.getHyperlinkedFullTitle() + " uses Edge to reroll:"
28552858
+ " rolls " + roll + ':';
28562859
}
@@ -3365,7 +3368,7 @@ public PartAcquisitionResult findContactForAcquisition(IAcquisitionWork acquisit
33653368
}
33663369
return PartAcquisitionResult.PlanetSpecificFailure;
33673370
}
3368-
if (Compute.d6(2) < target.getValue()) {
3371+
if (d6(2) < target.getValue()) {
33693372
// no contacts on this planet, move along
33703373
if (getCampaignOptions().isPlanetAcquisitionVerbose()) {
33713374
addReport("<font color='" + MekHQ.getMHQOptions().getFontColorNegativeHexColor() + "'><b>"
@@ -3448,25 +3451,21 @@ private boolean acquireEquipment(IAcquisitionWork acquisition, Person person, Pl
34483451
return false;
34493452
}
34503453

3451-
int roll = Compute.d6(2);
3454+
int roll = d6(2);
34523455
report += " needs " + target.getValueAsString();
34533456
report += " and rolls " + roll + ':';
34543457
// Edge reroll, if applicable
34553458
if (getCampaignOptions().isUseSupportEdge() && (roll < target.getValue()) && (person != null)
34563459
&& person.getOptions().booleanOption(PersonnelOptions.EDGE_ADMIN_ACQUIRE_FAIL)
34573460
&& (person.getCurrentEdge() > 0)) {
34583461
person.changeCurrentEdge(-1);
3459-
roll = Compute.d6(2);
3462+
roll = d6(2);
34603463
report += " <b>failed!</b> but uses Edge to reroll...getting a " + roll + ": ";
34613464
}
3462-
int mos = roll - target.getValue();
3463-
if (target.getValue() == TargetRoll.AUTOMATIC_SUCCESS) {
3464-
mos = roll - 2;
3465-
}
34663465
int xpGained = 0;
34673466
if (roll >= target.getValue()) {
34683467
if (transitDays < 0) {
3469-
transitDays = calculatePartTransitTime(mos);
3468+
transitDays = calculatePartTransitTime(acquisition.getAvailability());
34703469
}
34713470
report = report + acquisition.find(transitDays);
34723471
found = true;
@@ -3656,7 +3655,7 @@ public void refit(Refit theRefit) {
36563655
int roll;
36573656
String wrongType = "";
36583657
if (tech.isRightTechTypeFor(theRefit)) {
3659-
roll = Compute.d6(2);
3658+
roll = d6(2);
36603659
} else {
36613660
roll = Utilities.roll3d6();
36623661
wrongType = " <b>Warning: wrong tech type for this refit.</b>";
@@ -3666,7 +3665,7 @@ public void refit(Refit theRefit) {
36663665
&& tech.getOptions().booleanOption(PersonnelOptions.EDGE_REPAIR_FAILED_REFIT)
36673666
&& (tech.getCurrentEdge() > 0)) {
36683667
tech.changeCurrentEdge(-1);
3669-
roll = tech.isRightTechTypeFor(theRefit) ? Compute.d6(2) : Utilities.roll3d6();
3668+
roll = tech.isRightTechTypeFor(theRefit) ? d6(2) : Utilities.roll3d6();
36703669
// This is needed to update the edge values of individual crewmen
36713670
if (tech.isEngineer()) {
36723671
tech.setEdgeUsed(tech.getEdgeUsed() - 1);
@@ -3857,7 +3856,7 @@ public String fixPart(IPartWork partWork, Person tech) {
38573856
int roll;
38583857
String wrongType = "";
38593858
if (tech.isRightTechTypeFor(partWork)) {
3860-
roll = Compute.d6(2);
3859+
roll = d6(2);
38613860
} else {
38623861
roll = Utilities.roll3d6();
38633862
wrongType = " <b>Warning: wrong tech type for this repair.</b>";
@@ -3879,7 +3878,7 @@ public String fixPart(IPartWork partWork, Person tech) {
38793878
|| tech.getPrimaryRole().isVehicleCrew())) // For vessel crews
38803879
&& (roll < target.getValue())) {
38813880
tech.changeCurrentEdge(-1);
3882-
roll = tech.isRightTechTypeFor(partWork) ? Compute.d6(2) : Utilities.roll3d6();
3881+
roll = tech.isRightTechTypeFor(partWork) ? d6(2) : Utilities.roll3d6();
38833882
// This is needed to update the edge values of individual crewmen
38843883
if (tech.isEngineer()) {
38853884
tech.setEdgeUsed(tech.getEdgeUsed() + 1);
@@ -4058,7 +4057,7 @@ && getLocation().getJumpPath().getLastSystem().getId().equals(contract.getSystem
40584057

40594058
if (campaignOptions.isUseStratCon() && contract.getMoraleLevel().isRouted()) {
40604059
LocalDate newRoutEndDate = contract.getStartDate()
4061-
.plusMonths(max(1, Compute.d6() - 3))
4060+
.plusMonths(max(1, d6() - 3))
40624061
.minusDays(1);
40634062
contract.setRoutEndDate(newRoutEndDate);
40644063
}
@@ -4273,7 +4272,7 @@ private void processNewDayATB() {
42734272
private void processResupply(AtBContract contract) {
42744273
boolean isGuerrilla = contract.getContractType().isGuerrillaWarfare();
42754274

4276-
if (!isGuerrilla || Compute.d6(1) > 4) {
4275+
if (!isGuerrilla || d6(1) > 4) {
42774276
ResupplyType resupplyType = isGuerrilla ? ResupplyType.RESUPPLY_SMUGGLER : ResupplyType.RESUPPLY_NORMAL;
42784277
Resupply resupply = new Resupply(this, contract, resupplyType);
42794278
performResupply(resupply, contract);
@@ -4460,7 +4459,7 @@ private boolean processMonthlyVocationalXp(Person person, int vocationalXpRate)
44604459

44614460
person.setVocationalXPTimer(person.getVocationalXPTimer() + 1);
44624461
if (person.getVocationalXPTimer() >= checkFrequency) {
4463-
if (Compute.d6(2) >= targetNumber) {
4462+
if (d6(2) >= targetNumber) {
44644463
person.awardXP(this, vocationalXpRate);
44654464
person.setVocationalXPTimer(0);
44664465
return true;
@@ -4540,7 +4539,7 @@ private void processMonthlyAutoAwards(Person person) {
45404539
int dice = person.getExperienceLevel(this, false);
45414540

45424541
if (dice > 0) {
4543-
score = Compute.d6(dice);
4542+
score = d6(dice);
45444543
}
45454544

45464545
multiplier += 0.5;
@@ -4550,7 +4549,7 @@ private void processMonthlyAutoAwards(Person person) {
45504549
int dice = person.getExperienceLevel(this, true);
45514550

45524551
if (dice > 0) {
4553-
score += Compute.d6(dice);
4552+
score += d6(dice);
45544553
}
45554554

45564555
multiplier += 0.5;
@@ -8135,55 +8134,42 @@ public int calculatePartTransitTime(PlanetarySystem system) {
81358134
// if you are delivering from the same planet then no transit times
81368135
int currentTransitTime = (distance > 0) ? (int) Math.ceil(getCurrentSystem().getTimeToJumpPoint(1.0)) : 0;
81378136
int originTransitTime = (distance > 0) ? (int) Math.ceil(system.getTimeToJumpPoint(1.0)) : 0;
8138-
int amazonFreeShipping = Compute.d6(1 + jumps);
8137+
int amazonFreeShipping = d6(1 + jumps);
81398138
return (recharges * 7) + currentTransitTime + originTransitTime + amazonFreeShipping;
81408139
}
81418140

8142-
/***
8143-
* Calculate transit times based on the margin of success from an acquisition
8144-
* roll. The values here
8145-
* are all based on what the user entered for the campaign options.
8141+
/**
8142+
* Calculates the transit time for the arrival of parts or supplies based on the availability
8143+
* of the item, a random roll, and campaign-specific transit time settings.
81468144
*
8147-
* @param mos - an integer of the margin of success of an acquisition roll
8148-
* @return the number of days that supplies will take to arrive.
8145+
* <p>The transit time is calculated using the following factors:
8146+
* <ul>
8147+
* <li>A fixed base modifier value defined by campaign rules.</li>
8148+
* <li>A random roll of 1d6 to add variability to the calculation.</li>
8149+
* <li>The availability value of the requested parts or supplies from the acquisition details.</li>
8150+
* </ul>
8151+
*
8152+
* <p>The calculated duration is applied in units (days, weeks, or months) based on the campaign's
8153+
* configuration for transit time.</p>
8154+
*
8155+
* @param availability the availability code of the part or unit being acquired as an integer.
8156+
* @return the number of days required for the parts or units to arrive based on the
8157+
* calculated transit time.
81498158
*/
8150-
public int calculatePartTransitTime(int mos) {
8151-
int nDice = getCampaignOptions().getNDiceTransitTime();
8152-
int time = getCampaignOptions().getConstantTransitTime();
8153-
if (nDice > 0) {
8154-
time += Compute.d6(nDice);
8155-
}
8156-
// now step forward through the calendar
8157-
LocalDate arrivalDate = getLocalDate();
8158-
arrivalDate = switch (getCampaignOptions().getUnitTransitTime()) {
8159-
case CampaignOptions.TRANSIT_UNIT_MONTH -> arrivalDate.plusMonths(time);
8160-
case CampaignOptions.TRANSIT_UNIT_WEEK -> arrivalDate.plusWeeks(time);
8161-
default -> arrivalDate.plusDays(time);
8162-
};
8163-
8164-
// now adjust for MoS and minimums
8165-
int mosBonus = getCampaignOptions().getAcquireMosBonus() * mos;
8166-
arrivalDate = switch (getCampaignOptions().getAcquireMosUnit()) {
8167-
case CampaignOptions.TRANSIT_UNIT_MONTH -> arrivalDate.minusMonths(mosBonus);
8168-
case CampaignOptions.TRANSIT_UNIT_WEEK -> arrivalDate.minusWeeks(mosBonus);
8169-
default -> arrivalDate.minusDays(mosBonus);
8170-
};
8159+
public int calculatePartTransitTime(int availability) {
8160+
final int BASE_MODIFIER = 7; // CamOps p51
8161+
final int roll = d6(1);
8162+
final int total = max(1, (BASE_MODIFIER + roll + availability) / 4); // CamOps p51
81718163

8172-
// now establish minimum date and if this is before
8173-
LocalDate minimumDate = getLocalDate();
8174-
minimumDate = switch (getCampaignOptions().getAcquireMinimumTimeUnit()) {
8175-
case CampaignOptions.TRANSIT_UNIT_MONTH ->
8176-
minimumDate.plusMonths(getCampaignOptions().getAcquireMinimumTime());
8177-
case CampaignOptions.TRANSIT_UNIT_WEEK ->
8178-
minimumDate.plusWeeks(getCampaignOptions().getAcquireMinimumTime());
8179-
default -> minimumDate.plusDays(getCampaignOptions().getAcquireMinimumTime());
8164+
// now step forward through the calendar
8165+
LocalDate arrivalDate = currentDay;
8166+
arrivalDate = switch (campaignOptions.getUnitTransitTime()) {
8167+
case TRANSIT_UNIT_MONTH -> arrivalDate.plusMonths(total);
8168+
case TRANSIT_UNIT_WEEK -> arrivalDate.plusWeeks(total);
8169+
default -> arrivalDate.plusDays(total);
81808170
};
81818171

8182-
if (arrivalDate.isBefore(minimumDate)) {
8183-
return Math.toIntExact(ChronoUnit.DAYS.between(getLocalDate(), minimumDate));
8184-
} else {
8185-
return Math.toIntExact(ChronoUnit.DAYS.between(getLocalDate(), arrivalDate));
8186-
}
8172+
return Math.toIntExact(ChronoUnit.DAYS.between(getLocalDate(), arrivalDate));
81878173
}
81888174

81898175
/**
@@ -8524,7 +8510,7 @@ private String doMaintenanceOnUnitPart(Unit u, Part p, Map<Part, Integer> partsT
85248510
}
85258511

85268512
partReport += ", TN " + target.getValue() + '[' + target.getDesc() + ']';
8527-
int roll = Compute.d6(2);
8513+
int roll = d6(2);
85288514
int margin = roll - target.getValue();
85298515
partReport += " rolled a " + roll + ", margin of " + margin;
85308516

0 commit comments

Comments
 (0)