Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
17 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net.client.handlers;
import engine.exception.MsgSendException;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager;
import engine.gameManager.ItemManager;
import engine.loot.WorkOrder;
import engine.mbEnums;
import engine.mbEnums.ItemType;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.ItemProductionMsg;
import engine.net.client.msg.ManageNPCMsg;
import engine.objects.*;
import org.pmw.tinylog.Logger;
import java.util.HashMap;
/*
* @Summary: Processes application protocol message which modifies
* hireling inventory through rolling, junking or depositing.
*/
public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
public ItemProductionMsgHandler() {
super();
}
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {
// Member variable declaration
PlayerCharacter player;
NPC vendor;
ItemProductionMsg msg;
Dispatch dispatch;
// Member variable assignment
msg = (ItemProductionMsg) baseMsg;
player = origin.getPlayerCharacter();
if (player == null)
return true;
// Grab reference to vendor we are interacting with
vendor = (NPC) DbManager.getObject(mbEnums.GameObjectType.NPC, msg.npcUUID);
// Oops?
if (vendor == null)
return true;
// Process Request
switch (msg.actionType) {
case PRODUCE:
// Create new work order
WorkOrder workOrder = new WorkOrder();
workOrder.total_to_produce = msg.total_to_produce;
workOrder.vendor = vendor;
workOrder.templateID = msg.itemUUID;
workOrder.prefixToken = msg.pToken;
workOrder.suffixToken = msg.sToken;
workOrder.item_name_override = msg.name;
workOrder.multiple_slot_request = (msg.size != 0);
// Submit workOder to begin rolling items
int validation_result = ForgeManager.submit(workOrder);
// workOrder could not be completed
// Report back to the user the reason why
if (validation_result != 0) {
ErrorPopupMsg.sendErrorPopup(player, validation_result);
return true;
}
break;
case JUNK:
junkItem(msg.itemUUID, vendor, origin);
break;
case RECYCLE:
recycleItem(msg.items, vendor, origin);
msg.actionType = mbEnums.ProductionActionType.TAKE;
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
case COMPLETE:
completeItem(msg.itemUUID, vendor);
break;
case DEPOSIT:
depositItem(msg.itemUUID, vendor, origin);
break;
case SETPRICE:
setItemPrice(msg.itemUUID, msg.itemPrice, vendor, origin);
break;
case TAKE:
takeItem(msg.items, vendor, origin);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
}
return true;
}
private static void completeItem(int itemUUID, NPC vendor) {
Item virtualItem = Item.getFromCache(itemUUID);
WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(virtualItem);
City city = workOrder.vendor.building.getCity();
if (city == null)
return;
city.transactionLock.writeLock().lock();
try {
// Remove virtual item from the vendor rolling window
// (Add / Completed / Remove)
ItemProductionMsg outMsg = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, virtualItem, mbEnums.ProductionActionType.CONFIRM_SETPRICE, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
// Remove virtualItem from collections
workOrder.cooking.remove(virtualItem);
ForgeManager.itemWorkOrderLookup.remove(virtualItem);
DbManager.removeFromCache(virtualItem);
workOrder.slots_used.decrementAndGet();
// Update workOrder on disk
if (workOrder.cooking.isEmpty()) {
ForgeManager.vendorWorkOrderLookup.get(vendor).remove(workOrder);
DbManager.WarehouseQueries.DELETE_WORKORDER(workOrder);
} else
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
// Persist item and add to vendor inventory
virtualItem.containerType = mbEnums.ItemContainerType.INVENTORY;
Item completedItem = DbManager.ItemQueries.PERSIST(virtualItem);
// Apply Item effects for Prefix and Suffix tokens
completedItem.prefixToken = virtualItem.prefixToken;
completedItem.suffixToken = virtualItem.suffixToken;
ItemManager.applyItemEffects(completedItem);
vendor.charItemManager.addItemToInventory(completedItem);
// Add persisted items to the vendor inventory window
ItemProductionMsg outMsg1 = new ItemProductionMsg(vendor.building, vendor, completedItem, mbEnums.ProductionActionType.DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(vendor, outMsg1, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
ItemProductionMsg outMsg2 = new ItemProductionMsg(vendor.building, vendor, completedItem, mbEnums.ProductionActionType.CONFIRM_DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(vendor, outMsg2, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
} catch (Exception e) {
Logger.error(e);
} finally {
city.transactionLock.writeLock().unlock();
}
}
private static void setItemPrice(int itemUUID, int itemPrice, NPC vendor, ClientConnection origin) {
Item targetItem;
ItemProductionMsg outMsg;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
return;
if (!DbManager.ItemQueries.UPDATE_VALUE(targetItem, itemPrice)) {
ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help.");
return;
}
targetItem.setValue(itemPrice);
targetItem.magicValue = targetItem.value;
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.SETPRICE, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
}
// Method sets the price on an item in the vendor inventory
private static void depositItem(int itemUUID, NPC vendor, ClientConnection origin) {
Item targetItem;
ItemProductionMsg outMsg;
CharacterItemManager itemMan;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
if (origin.sellLock.tryLock()) {
try {
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
return;
if (targetItem.template.item_type.equals(ItemType.GOLD))
return;
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) {
ErrorPopupMsg.sendErrorPopup(player, 21);
return;
}
itemMan = origin.getPlayerCharacter().charItemManager;
if (itemMan == null)
return;
if (vendor.charItemManager.getInventoryWeight() > 500) {
ErrorPopupMsg.sendErrorPopup(player, 21);
return;
}
if (!targetItem.validForInventory(origin, player, itemMan)) {
ErrorPopupMsg.sendErrorPopup(player, 19);
return;
}
// Transfer item from player to vendor's inventory
if (!itemMan.sellToNPC(targetItem, vendor)) {
ErrorPopupMsg.sendErrorPopup(player, 109);
return;
}
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.CONFIRM_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
origin.getPlayerCharacter().charItemManager.updateInventory();
} catch (Exception e) {
Logger.error(e);
} finally {
origin.sellLock.unlock();
}
}
}
// Method completes an item that has been previously rolled
// adding it to the Vendor inventory
private static void recycleItem(HashMap<Integer, Integer> itemList, NPC vendor, ClientConnection origin) {
Item targetItem;
ItemProductionMsg outMsg;
int totalValue = 0;
Dispatch dispatch;
if (vendor.getBuilding() == null)
return;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
if (itemList == null)
return;
if (origin.sellLock.tryLock()) {
try {
for (int itemUUID : itemList.keySet()) {
int itemValue = 0;
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
continue;
if (targetItem.template.item_type.equals(ItemType.GOLD))
return;
if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID()))
continue;
if (!vendor.charItemManager.inventoryContains(targetItem))
continue;
itemValue = targetItem.template.item_value;
if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(player, 201);
break;
}
switch (targetItem.template.item_type) {
case EMPLOYMENTCONTRACT:
case CHARTER:
case DEED:
case REALMCHARTER:
case SCROLL:
case POTION:
continue;
}
totalValue += itemValue;
vendor.charItemManager.recycle(targetItem);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.TAKE, true);
dispatch = Dispatch.borrow(origin.getPlayerCharacter(), outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
}
// Refund a portion of the gold
vendor.getBuilding().transferGold(totalValue, false);
} catch (Exception e) {
Logger.error(e);
} finally {
origin.sellLock.unlock();
}
}
}
// Method handles recycling of an item
private static void junkItem(int itemUUID, NPC vendor, ClientConnection origin) {
Item virtualItem;
ManageNPCMsg outMsg;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
// Cannot junk items without a forge!
if (vendor.getBuilding() == null)
return;
// junk nothing?
virtualItem = Item.getFromCache(itemUUID);
if (virtualItem == null)
return;
WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(virtualItem);
// If this virtual item was already processed then
// it will have been removed from the workOrder.
if (workOrder == null)
return;
if (!workOrder.cooking.contains(virtualItem))
return;
City city = workOrder.vendor.building.getCity();
if (city == null)
return;
city.transactionLock.writeLock().lock();
try {
workOrder.cooking.remove(virtualItem);
DbManager.removeFromCache(virtualItem);
ForgeManager.itemWorkOrderLookup.remove(virtualItem);
// Update total_to_produce accounting for the slot being
// removed while workOrder is not completed.
if (!workOrder.runCompleted.get())
if (workOrder.multiple_slot_request && workOrder.slots_used.get() > 1) {
int itemsPerSlot = workOrder.total_to_produce / workOrder.slots_used.get();
workOrder.total_to_produce = workOrder.total_to_produce - itemsPerSlot;
}
// Slot is no longer allocated to this workOrder.
workOrder.slots_used.decrementAndGet();
// Update workOrder on disk
if (workOrder.cooking.isEmpty()) {
ForgeManager.vendorWorkOrderLookup.get(vendor).remove(workOrder);
DbManager.WarehouseQueries.DELETE_WORKORDER(workOrder);
} else
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
// Refresh vendor's inventory to client
outMsg = new ManageNPCMsg(vendor);
outMsg.setMessageType(1);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
} catch (Exception e) {
Logger.error(e);
} finally {
city.transactionLock.writeLock().unlock();
}
}
private static void takeItem(HashMap<Integer, Integer> itemList, NPC vendor, ClientConnection origin) {
Item targetItem;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
for (int itemUUID : itemList.keySet()) {
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
return;
if (targetItem.template.item_type.equals(ItemType.GOLD))
return;
if (!vendor.charItemManager.inventoryContains(targetItem))
return;
if (!player.charItemManager.hasRoomInventory(targetItem.template.item_wt))
return;
player.charItemManager.buyFromNPC(targetItem, vendor);
}
player.charItemManager.updateInventory();
}
}