Files
prestonbane/src/engine/loot/WorkOrder.java
T

283 lines
12 KiB
Java
Raw Normal View History

2024-04-05 20:13:16 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.loot;
2024-04-25 08:42:20 -04:00
import engine.gameManager.DbManager;
2024-04-22 16:07:25 -04:00
import engine.gameManager.ForgeManager;
2024-04-10 16:06:09 -04:00
import engine.mbEnums;
2024-04-14 16:29:17 -04:00
import engine.objects.Item;
2024-04-23 15:11:56 -04:00
import engine.objects.ItemTemplate;
2024-04-05 20:13:16 -04:00
import engine.objects.NPC;
2024-04-23 15:11:56 -04:00
import engine.objects.Warehouse;
2024-04-22 16:02:22 -04:00
import org.json.JSONArray;
2024-04-22 09:21:46 -04:00
import org.json.JSONObject;
2024-04-05 20:13:16 -04:00
2024-04-13 07:18:55 -04:00
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
2024-04-22 08:53:33 -04:00
import java.util.ArrayList;
2024-04-23 15:14:43 -04:00
import java.util.EnumSet;
2024-04-10 16:06:09 -04:00
import java.util.HashMap;
2024-05-11 08:57:26 -04:00
import java.util.Objects;
2024-04-22 00:46:59 -04:00
import java.util.concurrent.ConcurrentHashMap;
2024-04-05 20:13:16 -04:00
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
2024-05-11 09:15:11 -04:00
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
2024-04-05 20:13:16 -04:00
public class WorkOrder implements Delayed {
2024-04-25 09:22:50 -04:00
// MB Dev notes:
2024-04-27 08:53:50 -04:00
// Class defines a Forge rolling request made through a vendor
// interaction; submitted to the ForgeManager singleton for completion.
2024-04-25 09:22:50 -04:00
//
2024-04-27 08:53:50 -04:00
// A workOrder once created will last until all items are either
// completed or junked. They are persisted in the table dyn_workorders.
2024-04-25 09:22:50 -04:00
2024-04-07 22:15:06 -04:00
public int workOrderID;
2024-04-05 20:13:16 -04:00
public NPC vendor;
2024-05-11 09:15:11 -04:00
public AtomicInteger slots_used = new AtomicInteger(0);
2024-04-07 22:31:58 -04:00
public int total_to_produce;
2024-04-08 13:06:22 -04:00
public int total_produced;
public boolean multiple_slot_request;
2024-04-10 16:06:09 -04:00
public HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>();
2024-04-10 16:47:02 -04:00
public HashMap<mbEnums.ResourceType, Integer> production_cost_total = new HashMap<>();
2024-04-05 20:14:29 -04:00
public int templateID;
2024-04-13 07:54:26 -04:00
public String item_name_override;
2024-04-05 20:13:16 -04:00
public int prefixToken;
public int suffixToken;
2024-04-07 23:21:35 -04:00
public long rollingDuration;
2024-04-05 20:13:16 -04:00
public long completionTime;
2024-05-11 09:15:11 -04:00
public AtomicBoolean runCompleted = new AtomicBoolean(false);
2024-04-25 10:03:37 -04:00
// This collection is serialized to the vendor rolling window in ManageNPCMsg.
2024-04-22 00:46:59 -04:00
public ConcurrentHashMap.KeySetView<Item, Boolean> cooking = ConcurrentHashMap.newKeySet();
2024-04-08 04:46:54 -04:00
2024-04-05 20:13:16 -04:00
public WorkOrder() {
}
2024-04-22 15:34:57 -04:00
public WorkOrder(JSONObject jsonWorkOrder) {
2024-04-20 15:58:01 -04:00
2024-04-25 10:03:37 -04:00
// This constructor is used to load workOrders from disk
// during bootstrap. (dyn_workorders)
2024-04-22 15:49:57 -04:00
this.workOrderID = jsonWorkOrder.getInt("workOrderID");
2024-04-22 15:34:57 -04:00
this.vendor = NPC.getNPC(jsonWorkOrder.getInt("vendor"));
2024-05-11 09:15:11 -04:00
this.slots_used.set(jsonWorkOrder.getInt("slots_used"));
2024-04-22 15:34:57 -04:00
this.total_to_produce = jsonWorkOrder.getInt("total_to_produce");
this.total_produced = jsonWorkOrder.getInt("total_produced");
this.multiple_slot_request = jsonWorkOrder.getBoolean("multiple_slot_request");
this.templateID = jsonWorkOrder.getInt("templateID");
this.item_name_override = jsonWorkOrder.getString("item_name_override");
this.prefixToken = jsonWorkOrder.getInt("prefixToken");
this.suffixToken = jsonWorkOrder.getInt("suffixToken");
this.rollingDuration = jsonWorkOrder.getLong("rollingDuration");
this.completionTime = jsonWorkOrder.getLong("completionTime");
2024-05-11 09:15:11 -04:00
this.runCompleted.set(jsonWorkOrder.getBoolean("runCompleted"));
2024-04-22 15:34:57 -04:00
2024-06-12 14:04:19 -04:00
// Vendor sanity check. Might have been deleted
if (this.vendor == null)
return;
2024-04-22 15:34:57 -04:00
JSONObject productionCostMap = jsonWorkOrder.getJSONObject("production_cost");
for (String key : productionCostMap.keySet()) {
mbEnums.ResourceType resourceType = mbEnums.ResourceType.valueOf(key);
int value = productionCostMap.getInt(key);
this.production_cost.put(resourceType, value);
}
2024-04-25 09:39:03 -04:00
JSONObject productionTotalCostMap = jsonWorkOrder.getJSONObject("production_cost_total");
2024-04-22 15:34:57 -04:00
for (String key : productionTotalCostMap.keySet()) {
mbEnums.ResourceType resourceType = mbEnums.ResourceType.valueOf(key);
int value = productionTotalCostMap.getInt(key);
this.production_cost_total.put(resourceType, value);
}
2024-04-22 16:02:22 -04:00
// Reconstruct cooking items
JSONArray tokenList = jsonWorkOrder.getJSONArray("cookingTokens");
for (Object o : tokenList) {
2024-04-22 16:28:02 -04:00
int prefix = ((JSONArray) o).getInt(0);
int suffix = ((JSONArray) o).getInt(1);
2024-06-12 14:04:19 -04:00
2024-04-22 16:07:25 -04:00
Item cookingItem = ForgeManager.forgeItem(this);
cookingItem.prefixToken = prefix;
cookingItem.suffixToken = suffix;
2024-04-22 16:14:10 -04:00
cookingItem.setDateToUpgrade(this.completionTime);
2024-04-22 16:02:22 -04:00
}
2024-04-20 15:58:01 -04:00
}
2024-04-23 15:11:56 -04:00
public static int validate(WorkOrder workOrder) {
2024-04-25 09:22:50 -04:00
// Validate that a workOrder can be completed by both
// the vendor and the forge.
2024-04-23 15:11:56 -04:00
int validation_result = 0;
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
if (workOrder.vendor.getBuilding() == null)
return 58; //58: The formula is beyond the means of this facility
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.item_wt))
return 30; //30: That person cannot carry that item
2024-07-22 16:37:27 -04:00
if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) &&
!workOrder.vendor.getItemModTable().contains((template.modTable)))
2024-04-23 15:11:56 -04:00
return 59; //59: This hireling does not have this formula
if (!Warehouse.calcCostOverrun(workOrder).isEmpty())
return 10; //18: You can't really afford that
// Forge must be protected in order to access warehouse.
if (ForgeManager.calcProductionCost(workOrder).size() > 1)
2024-04-23 15:14:43 -04:00
if (!EnumSet.of(mbEnums.ProtectionState.PROTECTED, mbEnums.ProtectionState.CONTRACT).contains(workOrder.vendor.building.protectionState))
2024-04-23 15:11:56 -04:00
return 193; //193: Production denied: This building must be protected to gain access to warehouse
return validation_result;
}
2024-04-25 09:22:50 -04:00
public static boolean withdrawWorkOrderCost(WorkOrder workOrder) {
2024-04-25 08:42:20 -04:00
2024-05-09 14:04:19 -04:00
HashMap<mbEnums.ResourceType, Integer> modified_production_cost = new HashMap<>(workOrder.production_cost_total);
2024-04-25 08:42:20 -04:00
if (workOrder.vendor.building.getCity() == null)
return false;
int strongbox = workOrder.vendor.building.getStrongboxValue();
2024-05-09 11:31:12 -04:00
// Early exit if strongbox can cover gold only roll.
2024-04-25 08:42:20 -04:00
2024-05-09 11:31:12 -04:00
if (workOrder.production_cost_total.size() == 1 && workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) <= strongbox) {
2024-04-25 08:42:20 -04:00
workOrder.vendor.building.setStrongboxValue(strongbox - workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD));
2024-05-09 11:31:12 -04:00
return true;
2024-04-25 08:42:20 -04:00
}
2024-05-09 11:31:12 -04:00
// Warehouse is required after this point
2024-04-25 08:42:20 -04:00
Warehouse warehouse = workOrder.vendor.building.getCity().warehouse;
if (warehouse == null)
return false;
2024-05-09 14:04:19 -04:00
// Take from strongbox first and deduct from production cost total
if (workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) <= strongbox) {
workOrder.vendor.building.setStrongboxValue(strongbox - workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD));
modified_production_cost.put(mbEnums.ResourceType.GOLD, 0);
} else {
int overflowAmount = workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) - strongbox;
workOrder.vendor.building.setStrongboxValue(0);
2024-05-09 14:40:40 -04:00
modified_production_cost.put(mbEnums.ResourceType.GOLD, overflowAmount);
2024-05-09 14:04:19 -04:00
}
2024-05-09 11:31:12 -04:00
2024-04-25 08:42:20 -04:00
// Deduct total production cost from warehouse
2024-05-09 14:04:19 -04:00
modified_production_cost.forEach((key, value) -> warehouse.resources.put(key, warehouse.resources.get(key) - value));
2024-04-25 08:42:20 -04:00
DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse);
return true;
}
2024-04-08 16:42:44 -04:00
2024-04-25 09:39:03 -04:00
public static JSONObject toJson(WorkOrder workOrder) {
2024-04-25 10:03:37 -04:00
// Workorders are persisted in JSON format.
2024-04-25 09:39:03 -04:00
JSONObject jsonWorkOrder = new JSONObject();
jsonWorkOrder.put("workOrderID", workOrder.workOrderID);
jsonWorkOrder.put("vendor", workOrder.vendor.getObjectUUID());
2024-05-11 09:19:29 -04:00
jsonWorkOrder.put("slots_used", workOrder.slots_used.get());
2024-04-25 09:39:03 -04:00
jsonWorkOrder.put("total_to_produce", workOrder.total_to_produce);
jsonWorkOrder.put("total_produced", workOrder.total_produced);
jsonWorkOrder.put("multiple_slot_request", workOrder.multiple_slot_request);
jsonWorkOrder.put("production_cost", workOrder.production_cost);
jsonWorkOrder.put("production_cost_total", workOrder.production_cost_total);
jsonWorkOrder.put("templateID", workOrder.templateID);
jsonWorkOrder.put("item_name_override", workOrder.item_name_override);
jsonWorkOrder.put("prefixToken", workOrder.prefixToken);
jsonWorkOrder.put("suffixToken", workOrder.suffixToken);
jsonWorkOrder.put("rollingDuration", workOrder.rollingDuration);
jsonWorkOrder.put("completionTime", workOrder.completionTime);
2024-05-11 09:19:29 -04:00
jsonWorkOrder.put("runCompleted", workOrder.runCompleted.get());
2024-04-25 09:39:03 -04:00
ArrayList<Integer[]> cookingTokens = new ArrayList<>();
for (Item item : workOrder.cooking)
cookingTokens.add(new Integer[]{item.prefixToken, item.suffixToken});
jsonWorkOrder.put("cookingTokens", cookingTokens);
return jsonWorkOrder;
}
2024-04-08 16:42:44 -04:00
public String toString() {
2024-04-13 07:18:55 -04:00
LocalDateTime localDateTime = Instant.ofEpochMilli(this.completionTime)
.atZone(ZoneId.systemDefault()).toLocalDateTime();
2024-04-13 07:26:39 -04:00
Duration duration = Duration.ofMillis(this.rollingDuration);
2024-04-13 07:18:55 -04:00
2024-04-08 16:58:07 -04:00
String outSTring = "\r\nwordOrderID: " + this.workOrderID + "\r\n" +
2024-04-08 16:49:19 -04:00
"vendor: " + this.vendor.getObjectUUID() + "\r\n" +
2024-05-11 09:19:29 -04:00
"slots_used: " + this.slots_used.get() + "\r\n" +
2024-04-08 16:49:19 -04:00
"total_to_produce: " + this.total_to_produce + "\r\n" +
"total_produced: " + this.total_produced + "\r\n" +
"templateID: " + this.templateID + "\r\n" +
2024-04-13 07:54:26 -04:00
"item_name_override: " + this.item_name_override + "\r\n" +
2024-04-08 16:49:19 -04:00
"prefixToken: " + this.prefixToken + "\r\n" +
"suffixToken: " + this.suffixToken + "\r\n" +
2024-04-13 07:18:55 -04:00
"rollingDuration: " + duration + "\r\n" +
"completionTime: " + localDateTime + "\r\n" +
2024-05-11 09:19:29 -04:00
"runCompleted: " + this.runCompleted.get() + "\r\n" +
2024-04-23 13:15:15 -04:00
"productionCost: " + this.production_cost.toString() + "\r\n" +
"totalProductionCost:: " + this.production_cost_total.toString();
2024-04-08 16:42:44 -04:00
return outSTring;
}
2024-05-11 08:57:26 -04:00
@Override
public long getDelay(TimeUnit unit) {
long timeRemaining = completionTime - System.currentTimeMillis();
return unit.convert(timeRemaining, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.completionTime, ((WorkOrder) o).completionTime);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
WorkOrder otherWorkOrder = (WorkOrder) obj;
return workOrderID == otherWorkOrder.workOrderID;
}
@Override
public int hashCode() {
return Objects.hash(workOrderID);
}
2024-04-05 20:13:16 -04:00
}