// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.gameManager.ChatManager; import engine.gameManager.DbManager; import engine.gameManager.DispatchManager; import engine.loot.WorkOrder; import engine.mbEnums; import engine.net.Dispatch; import engine.net.client.ClientConnection; import engine.net.client.msg.*; import engine.server.MBServerStatics; import org.joda.time.DateTime; import org.json.JSONArray; import org.json.JSONObject; import org.pmw.tinylog.Logger; import java.sql.SQLException; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; public class Warehouse { public EnumSet locked = EnumSet.noneOf(mbEnums.ResourceType.class); public Building building; public City city; public ArrayList transactions = new ArrayList<>(); public ConcurrentHashMap resources = new ConcurrentHashMap<>(); public Warehouse(Building building) { this.building = building; this.city = building.getCity(); // New empty warehouse for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) this.resources.put(resourceType, 0); // With no locks this.locked = EnumSet.noneOf(mbEnums.ResourceType.class); } public Warehouse(JSONObject warehouse) throws SQLException { JSONObject resources = (JSONObject) warehouse.get("resources"); for (String key : resources.keySet()) { mbEnums.ResourceType resourceType = mbEnums.ResourceType.valueOf(key); int value = resources.getInt(key); this.resources.put(resourceType, value); } JSONArray lockedResources = (JSONArray) warehouse.get("locked"); if (lockedResources.isEmpty() == false) for (Object o : lockedResources) this.locked.add(mbEnums.ResourceType.valueOf((String) o)); } public static void warehouseDeposit(MerchantMsg msg, PlayerCharacter playerCharacter, NPC npc) { Building warehouseBuilding; Warehouse warehouse; int depositAmount; Dispatch dispatch; Item resource = Item.getFromCache(msg.getItemID()); if (resource == null) return; depositAmount = msg.getAmount(); CharacterItemManager itemMan = playerCharacter.charItemManager; if (!itemMan.doesCharOwnThisItem(resource.getObjectUUID())) return; warehouseBuilding = npc.getBuilding(); if (warehouseBuilding == null) return; City city = warehouseBuilding.getCity(); if (city == null) return; warehouse = city.warehouse; if (warehouse == null) return; if (!deposit(playerCharacter, resource, depositAmount, true, true, warehouse)) return; ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter); vrm.setGuild(playerCharacter.getGuild()); vrm.setWarehouseBuilding(warehouseBuilding); vrm.configure(); dispatch = Dispatch.borrow(playerCharacter, vrm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } public static void warehouseWithdraw(MerchantMsg msg, PlayerCharacter playerCharacter, NPC npc) { int withdrawAmount; Building warehouseBuilding; Warehouse warehouse; Dispatch dispatch; withdrawAmount = msg.getAmount(); warehouseBuilding = npc.getBuilding(); if (warehouseBuilding == null) return; if (playerCharacter.getGuild() != warehouseBuilding.getGuild() || !GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus())) return; City city = warehouseBuilding.getCity(); if (city == null) return; warehouse = city.warehouse; if (warehouse == null) return; mbEnums.ResourceType resourceType = mbEnums.ResourceType.templateHashLookup.get(msg.getHashID()); if (isResourceLocked(warehouse, resourceType)) { ChatManager.chatSystemInfo(playerCharacter, "You cannot withdrawl a locked resource."); return; } if (!withdraw(warehouse, playerCharacter, resourceType, withdrawAmount, true, true)) { ChatManager.chatGuildError(playerCharacter, "Failed to withdrawl " + resourceType.name() + '.'); Logger.debug(playerCharacter.getName() + " Failed to withdrawl =" + resourceType.name() + " from Warehouse With ID = " + warehouseBuilding.getObjectUUID()); return; } ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter); vrm.setGuild(playerCharacter.getGuild()); vrm.setWarehouseBuilding(warehouseBuilding); vrm.configure(); dispatch = Dispatch.borrow(playerCharacter, vrm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } public static void warehouseLock(MerchantMsg msg, PlayerCharacter playerCharacter, NPC npc) { Building warehouseBuilding; Warehouse warehouse; int hashID; Dispatch dispatch; hashID = msg.getHashID(); warehouseBuilding = npc.getBuilding(); if (warehouseBuilding == null) return; if (playerCharacter.getGuild() != warehouseBuilding.getGuild() || !GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus())) return; City city = warehouseBuilding.getCity(); if (city == null) return; warehouse = city.warehouse; mbEnums.ResourceType resourceType = mbEnums.ResourceType.templateHashLookup.get(hashID); // toggle lock if (warehouse.locked.contains(resourceType)) { boolean worked; warehouse.locked.remove(resourceType); worked = DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse); if (worked) { ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter); vrm.setGuild(playerCharacter.getGuild()); vrm.setWarehouseBuilding(warehouseBuilding); vrm.configure(); dispatch = Dispatch.borrow(playerCharacter, vrm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } else warehouse.locked.add(resourceType); return; } boolean worked; warehouse.locked.add(resourceType); worked = DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse); if (worked) { ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter); vrm.setGuild(playerCharacter.getGuild()); vrm.setWarehouseBuilding(warehouseBuilding); vrm.configure(); dispatch = Dispatch.borrow(playerCharacter, vrm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } else warehouse.locked.remove(resourceType); } public static synchronized boolean deposit(PlayerCharacter playerCharacter, Item resource, int amount, boolean removeFromInventory, boolean transaction, Warehouse warehouse) { ClientConnection origin = playerCharacter.getClientConnection(); if (origin == null) return false; if (amount < 0) { Logger.info(playerCharacter.getFirstName() + " Attempting to Dupe!!!!!!"); return false; } mbEnums.ResourceType resourceType = mbEnums.ResourceType.templateLookup.get(resource.templateID); if (warehouse.resources.get(resourceType) == null) return false; CharacterItemManager itemMan = playerCharacter.charItemManager; if (itemMan == null) return false; if (itemMan.getGoldTrading() > 0) { ErrorPopupMsg.sendErrorPopup(playerCharacter, 195); return false; } if (!itemMan.doesCharOwnThisItem(resource.getObjectUUID())) return false; if (!resource.validForInventory(origin, playerCharacter, itemMan)) return false; if (resource.getNumOfItems() < amount) return false; int oldAmount = warehouse.resources.get(resourceType); int newAmount = oldAmount + amount; if (newAmount > mbEnums.ResourceType.templateLookup.get(resource.templateID).deposit_limit) return false; if (removeFromInventory) { if (resourceType.equals(mbEnums.ResourceType.GOLD)) { if (itemMan.getGoldInventory().getNumOfItems() - amount < 0) return false; if (itemMan.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT) return false; if (!itemMan.modifyInventoryGold(-amount)) return false; UpdateGoldMsg ugm = new UpdateGoldMsg(playerCharacter); ugm.configure(); Dispatch dispatch = Dispatch.borrow(playerCharacter, ugm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); itemMan.updateInventory(); } else { itemMan.delete(resource); itemMan.updateInventory(); } } itemMan.updateInventory(); if (newAmount > resourceType.deposit_limit) return false; warehouse.resources.put(resourceType, newAmount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { warehouse.resources.put(resourceType, oldAmount); return false; } if (resource.template.item_type.equals(mbEnums.ItemType.GOLD)) resourceType = mbEnums.ResourceType.GOLD; else resourceType = mbEnums.ResourceType.valueOf(ItemTemplate.templates.get(resource.templateID).item_base_name.toUpperCase()); if (transaction) AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount); return true; } public static synchronized boolean depositFromMine(Mine mine, mbEnums.ResourceType resourceType, int amount, Warehouse warehouse) { int oldAmount = warehouse.resources.get(resourceType); int newAmount = oldAmount + amount; if (newAmount > resourceType.deposit_limit) return false; warehouse.resources.put(resourceType, newAmount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { warehouse.resources.put(resourceType, oldAmount); return false; } if (mine != null) AddTransactionToWarehouse(warehouse, mbEnums.GameObjectType.Building, mine.getBuildingID(), mbEnums.TransactionType.MINE, resourceType, amount); return true; } public static synchronized void depositRealmTaxes(PlayerCharacter taxer, mbEnums.ResourceType resourceType, int amount, Warehouse warehouse) { int oldAmount = warehouse.resources.get(resourceType); int newAmount = oldAmount + amount; warehouse.resources.put(resourceType, newAmount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { warehouse.resources.put(resourceType, oldAmount); return; } AddTransactionToWarehouse(warehouse, taxer.getObjectType(), taxer.getObjectUUID(), mbEnums.TransactionType.TAXRESOURCEDEPOSIT, resourceType, amount); } public static synchronized void depositProfitTax(mbEnums.ResourceType resourceType, int amount, Building building, Warehouse warehouse) { if (warehouse.resources.get(resourceType) == null) return; int oldAmount = warehouse.resources.get(resourceType); int newAmount = oldAmount + amount; if (newAmount > resourceType.deposit_limit) return; warehouse.resources.put(resourceType, newAmount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { warehouse.resources.put(resourceType, oldAmount); return; } if (building != null) AddTransactionToWarehouse(warehouse, mbEnums.GameObjectType.Building, building.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount); } public static synchronized void transferResources(Warehouse warehouse, PlayerCharacter taxer, TaxResourcesMsg msg, ArrayList realmResources, float taxPercent) { for (mbEnums.ResourceType resourceType : realmResources) { if (warehouse.resources.get(resourceType) == null) return; int amount = (int) (warehouse.resources.get(resourceType) * taxPercent); if (amount <= 0) { msg.getResources().put(resourceType.resourceHash, 0); continue; } int oldAmount = warehouse.resources.get(resourceType); if (oldAmount < amount) amount = oldAmount; int newAmount = oldAmount - amount; if (newAmount < amount) continue; msg.getResources().put(resourceType.resourceHash, amount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { msg.getResources().put(resourceType.resourceHash, 0); warehouse.resources.put(resourceType, oldAmount); continue; } warehouse.resources.put(resourceType, newAmount); depositRealmTaxes(taxer, resourceType, amount, warehouse); AddTransactionToWarehouse(warehouse, taxer.getObjectType(), taxer.getObjectUUID(), mbEnums.TransactionType.TAXRESOURCE, resourceType, amount); } } public static synchronized boolean withdraw(Warehouse warehouse, PlayerCharacter playerCharacter, mbEnums.ResourceType resourceType, int amount, boolean addToInventory, boolean transaction) { if (playerCharacter == null) return false; ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID); if (warehouse.resources.get(resourceType) == null) return false; if (amount <= 0) return false; CharacterItemManager itemMan = playerCharacter.charItemManager; if (itemMan == null) return false; if (addToInventory) if (!itemMan.hasRoomInventory(template.item_wt)) { ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); return false; } if (addToInventory && resourceType.equals(mbEnums.ResourceType.GOLD)) { if (playerCharacter.charItemManager.getGoldInventory().getNumOfItems() + amount > MBServerStatics.PLAYER_GOLD_LIMIT) return false; if (playerCharacter.charItemManager.getGoldInventory().getNumOfItems() + amount < 0) return false; } int oldAmount = warehouse.resources.get(resourceType); if (oldAmount < amount) return false; int newAmount = oldAmount - amount; warehouse.resources.put(resourceType, newAmount); if (!DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse)) { warehouse.resources.put(resourceType, oldAmount); return false; } if (addToInventory) { if (resourceType.equals(mbEnums.ResourceType.GOLD)) { itemMan.addGoldToInventory(amount, false); UpdateGoldMsg ugm = new UpdateGoldMsg(playerCharacter); ugm.configure(); Dispatch dispatch = Dispatch.borrow(playerCharacter, ugm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); itemMan.updateInventory(); } else { boolean itemWorked = false; Item item = new Item(resourceType.templateID); item.ownerID = playerCharacter.getObjectUUID(); item.ownerType = mbEnums.OwnerType.PlayerCharacter; item.containerType = mbEnums.ItemContainerType.INVENTORY; item.numberOfItems = amount; try { item = DbManager.ItemQueries.PERSIST(item); itemWorked = true; } catch (Exception e) { Logger.error(e); } if (itemWorked) { itemMan.addItemToInventory(item); itemMan.updateInventory(); } } } if (transaction) AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.WITHDRAWL, resourceType, amount); return true; } public static synchronized boolean loot(Warehouse warehouse, PlayerCharacter playerCharacter, mbEnums.ResourceType resourceType, int amount, boolean addToInventory) { if (playerCharacter == null) return false; ItemTemplate template = ItemTemplate.templates.get(resourceType); if (template == null) return false; if (warehouse.resources.get(resourceType) == null) return false; if (amount <= 0) return false; CharacterItemManager itemMan = playerCharacter.charItemManager; if (itemMan == null) return false; if (!itemMan.hasRoomInventory(template.item_wt)) { ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item."); return false; } int oldAmount = warehouse.resources.get(resourceType); if (oldAmount < amount) return false; int newAmount = oldAmount - amount; warehouse.resources.put(resourceType, newAmount); if (addToInventory) { if (resourceType.equals(mbEnums.ResourceType.GOLD)) { itemMan.addGoldToInventory(amount, false); UpdateGoldMsg ugm = new UpdateGoldMsg(playerCharacter); ugm.configure(); Dispatch dispatch = Dispatch.borrow(playerCharacter, ugm); DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); itemMan.updateInventory(); } else { boolean itemWorked = false; Item item = new Item(resourceType.templateID); item.ownerID = playerCharacter.getObjectUUID(); item.ownerType = mbEnums.OwnerType.PlayerCharacter; item.containerType = mbEnums.ItemContainerType.INVENTORY; item.numberOfItems = amount; try { item = DbManager.ItemQueries.PERSIST(item); itemWorked = true; } catch (Exception e) { Logger.error(e); } if (itemWorked) { itemMan.addItemToInventory(item); itemMan.updateInventory(); } } } return true; } public static boolean isEmpty(Warehouse warehouse) { int amount = 0; for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) { amount += warehouse.resources.get(resourceType); if (amount > 0) return false; } return true; } public static void AddTransactionToWarehouse(Warehouse warehouse, mbEnums.GameObjectType targetType, int targetUUID, mbEnums.TransactionType transactionType, mbEnums.ResourceType resource, int amount) { if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now())) return; Transaction transaction = new Transaction(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now()); warehouse.transactions.add(transaction); } public static boolean isAboveCap(Warehouse warehouse, mbEnums.ResourceType resourceType, int deposit) { int newAmount = warehouse.resources.get(resourceType) + deposit; return newAmount > resourceType.deposit_limit; } public static boolean isResourceLocked(Warehouse warehouse, mbEnums.ResourceType resourceType) { return warehouse.locked.contains(resourceType); } public static HashMap calcCostOverrun(WorkOrder workOrder) { HashMap costMap = new HashMap<>(); Warehouse warehouse; // See if we can meet gold only requirements and early exit if (workOrder.production_cost_total.size() == 1) { if (workOrder.vendor.building.getStrongboxValue() > workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD)) return costMap; } // Gold deficit exists so a warehouse is required warehouse = workOrder.vendor.building.getCity() == null ? null : workOrder.vendor.building.getCity().warehouse; if (warehouse == null) return workOrder.production_cost_total; // Method returns a map of resourceType that a transaction overdrafts. HashMap overflowMap = new HashMap<>(); for (mbEnums.ResourceType resourceType : workOrder.production_cost_total.keySet()) { int debit = warehouse.resources.get(resourceType) - workOrder.production_cost_total.get(resourceType); // Locked resources are always unavailable if (debit < 0 || warehouse.locked.contains(resourceType)) overflowMap.put(resourceType, debit); } return overflowMap; } }