Skip to content

Commit

Permalink
Merge pull request #1451 from sixlettervariables/continue-to-refine-a…
Browse files Browse the repository at this point in the history
…cquisitions

Refine shopping to avoid indefinitely loops #1447
  • Loading branch information
sixlettervariables authored Feb 6, 2020
2 parents fc2eb73 + 2893c19 commit cce74f9
Showing 1 changed file with 122 additions and 43 deletions.
165 changes: 122 additions & 43 deletions MekHQ/src/mekhq/campaign/Campaign.java
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,51 @@ public Person getLogisticsPerson() {
return admin;
}

/**
* Gets a list of applicable logistics personnel, or an empty list
* if acquisitions automatically succeed.
* @return A {@see List} of personnel who can perform logistical actions.
*/
public List<Person> getLogisticsPersonnel() {
String skill = getCampaignOptions().getAcquisitionSkill();
if (skill.equals(CampaignOptions.S_AUTO)) {
return Collections.emptyList();
} else {
List<Person> logisticsPersonnel = new ArrayList<>();
int maxAcquisitions = getCampaignOptions().getMaxAcquisitions();
for (Person p : getPersonnel()) {
if (!p.isActive()) {
continue;
}
if (getCampaignOptions().isAcquisitionSupportStaffOnly()
&& !p.isSupport()) {
continue;
}
if (maxAcquisitions > 0 && p.getAcquisitions() >= maxAcquisitions) {
continue;
}
if (skill.equals(CampaignOptions.S_TECH)) {
if (null != p.getBestTechSkill()) {
logisticsPersonnel.add(p);
}
} else if (p.hasSkill(skill)) {
logisticsPersonnel.add(p);
}
}

// Sort by their skill level, descending.
logisticsPersonnel.sort((a, b) -> {
if (skill.equals(CampaignOptions.S_TECH)) {
return Integer.compare(b.getBestTechSkill().getLevel(), a.getBestTechSkill().getLevel());
} else {
return Integer.compare(b.getSkill(skill).getLevel(), a.getSkill(skill).getLevel());
}
});

return logisticsPersonnel;
}
}

/***
* This is the main function for getting stuff (parts, units, etc.) All non-GM
* acquisition should go through this function to ensure the campaign rules for
Expand All @@ -2119,35 +2164,70 @@ public ShoppingList goShopping(ShoppingList sList) {
shoppingItem.decrementDaysToWait();
}

if (!getCampaignOptions().usesPlanetaryAcquisition()) {
if (getCampaignOptions().getAcquisitionSkill().equals(CampaignOptions.S_AUTO)) {
return goShoppingAutomatically(sList);
} else if (!getCampaignOptions().usesPlanetaryAcquisition()) {
return goShoppingStandard(sList);
} else {
return goShoppingByPlanet(sList);
}
}

private ShoppingList goShoppingStandard(ShoppingList sList) {
// loop through shopping list. If its time to check, then check as appropriate.
// Items not found get added to the remaining item list
/**
* Shops for items on the {@link ShoppingList}, where each acquisition
* automatically succeeds.
*
* @param sList The shopping list to use when shopping.
* @return The new shopping list containing the items that were not
* acquired.
*/
private ShoppingList goShoppingAutomatically(ShoppingList sList) {
List<IAcquisitionWork> currentList = new ArrayList<>(sList.getAllShoppingItems());

Set<Person> seen = new HashSet<>();
while (!currentList.isEmpty()) {
Person person = getLogisticsPerson();
if (null == person && !getCampaignOptions().getAcquisitionSkill().equals(CampaignOptions.S_AUTO)) {
addReport("Your force has no one capable of acquiring equipment.");
break;
} else if (null != person && !seen.add(person)) {
// if we've already tried with this logistics person
// don't try again; they won't succeed.
List<IAcquisitionWork> remainingItems = new ArrayList<>(currentList.size());
for (IAcquisitionWork shoppingItem : currentList) {
if (shoppingItem.getDaysToWait() <= 0) {
while (shoppingItem.getQuantity() > 0) {
if (!acquireEquipment(shoppingItem, null)) {
shoppingItem.resetDaysToWait();
break;
}
}
}
if (shoppingItem.getQuantity() > 0 || shoppingItem.getDaysToWait() > 0) {
remainingItems.add(shoppingItem);
}
}

return new ShoppingList(remainingItems);
}

/**
* Shops for items on the {@link ShoppingList}, where each acquisition
* is performed by available logistics personnel.
*
* @param sList The shopping list to use when shopping.
* @return The new shopping list containing the items that were not
* acquired.
*/
private ShoppingList goShoppingStandard(ShoppingList sList) {
List<Person> logisticsPersonnel = getLogisticsPersonnel();
if (logisticsPersonnel.isEmpty()) {
addReport("Your force has no one capable of acquiring equipment.");
return sList;
}

List<IAcquisitionWork> currentList = new ArrayList<>(sList.getAllShoppingItems());
for (Person person : logisticsPersonnel) {
if (currentList.isEmpty()) {
// Nothing left to shop for!
break;
}

List<IAcquisitionWork> remainingItems = new ArrayList<>();
List<IAcquisitionWork> remainingItems = new ArrayList<>(currentList.size());
for (IAcquisitionWork shoppingItem : currentList) {
if (shoppingItem.getDaysToWait() <= 0) {
while (canAcquireParts(person)
&& shoppingItem.getQuantity() > 0) {
while (canAcquireParts(person) && shoppingItem.getQuantity() > 0) {
if (!acquireEquipment(shoppingItem, person)) {
shoppingItem.resetDaysToWait();
break;
Expand All @@ -2160,17 +2240,26 @@ private ShoppingList goShoppingStandard(ShoppingList sList) {
}

currentList = remainingItems;

if (null == person) {
// If we have no logistics person make no attempt to loop
break;
}
}

return new ShoppingList(currentList);
}

/**
* Shops for items on the {@link ShoppingList}, where each acquisition
* is attempted on nearby planets by available logistics personnel.
*
* @param sList The shopping list to use when shopping.
* @return The new shopping list containing the items that were not
* acquired.
*/
private ShoppingList goShoppingByPlanet(ShoppingList sList) {
List<Person> logisticsPersonnel = getLogisticsPersonnel();
if (logisticsPersonnel.isEmpty()) {
addReport("Your force has no one capable of acquiring equipment.");
return sList;
}

// we are shopping by planets, so more involved
List<IAcquisitionWork> currentList = sList.getAllShoppingItems();
DateTime currentDate = Utilities.getDateTimeDay(getCalendar());
Expand All @@ -2184,22 +2273,13 @@ private ShoppingList goShoppingByPlanet(ShoppingList sList) {
getCampaignOptions().getMaxJumpsPlanetaryAcquisition(),
currentDate);

Set<Person> seen = new HashSet<>();
while (!currentList.isEmpty()) {
Person person = getLogisticsPerson();
if (null == person && !getCampaignOptions().getAcquisitionSkill().equals(CampaignOptions.S_AUTO)) {
addReport("Your force has no one capable of acquiring equipment.");
break;
} else if (null != person && !seen.add(person)) {
// if we've already tried with this logistics person
// don't try again; they won't succeed.
for (Person person : logisticsPersonnel) {
if (currentList.isEmpty()) {
// Nothing left to shop for!
break;
}

String personTitle = "";
if (null != person) {
personTitle = person.getHyperlinkedFullTitle() + " ";
}
String personTitle = person.getHyperlinkedFullTitle() + " ";

for (PlanetarySystem system: systems) {
List<IAcquisitionWork> remainingItems = new ArrayList<>();
Expand All @@ -2224,7 +2304,11 @@ && acquireEquipment(shoppingItem, person, system, transitTime)) {
totalQuantity++;
}
if (totalQuantity > 0) {
addReport(personTitle + "<font color='green'><b> found " + shoppingItem.getQuantityName(totalQuantity) + " on " + system.getPrintableName(currentDate) + ". Delivery in " + transitTime + " days.</b></font>");
addReport(personTitle + "<font color='green'><b> found "
+ shoppingItem.getQuantityName(totalQuantity)
+ " on "
+ system.getPrintableName(currentDate)
+ ". Delivery in " + transitTime + " days.</b></font>");
}
}
}
Expand All @@ -2250,11 +2334,6 @@ && acquireEquipment(shoppingItem, person, system, transitTime)) {
break;
}
}

if (null == person) {
// If we have no logistics person make no attempt to loop
break;
}
}

// add shelved items back to the currentlist
Expand Down Expand Up @@ -7906,16 +7985,16 @@ public void doMaintenance(Unit u) {
astechPoolMinutes -= astechsUsed * minutesUsed;
}
u.incrementDaysSinceMaintenance(maintained, astechsUsed);

int ruggedMultiplier = 1;
if(u.getEntity().hasQuirk(OptionsConstants.QUIRK_POS_RUGGED_1)) {
ruggedMultiplier = 2;
}

if(u.getEntity().hasQuirk(OptionsConstants.QUIRK_POS_RUGGED_2)) {
ruggedMultiplier = 3;
}

if (u.getDaysSinceMaintenance() >= getCampaignOptions().getMaintenanceCycleDays() * ruggedMultiplier) {
// maybe use the money
if (campaignOptions.payForMaintain()) {
Expand Down

0 comments on commit cce74f9

Please sign in to comment.