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.

512 lines
18 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net.client.handlers;
import engine.Enum;
import engine.Enum.GameObjectType;
import engine.Enum.ItemType;
import engine.exception.MsgSendException;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
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 {
private static final int ACTION_PRODUCE = 1;
private static final int ACTION_JUNK = 2;
private static final int ACTION_RECYCLE = 3;
private static final int ACTION_COMPLETE = 4;
private static final int ACTION_DEPOSIT = 6;
private static final int ACTION_SETPRICE = 5;
private static final int ACTION_TAKE = 7;
private static final int ACTION_CONFIRM_SETPRICE = 9; // Unsure. Sent by client
private static final int ACTION_CONFIRM_DEPOSIT = 10; // Unsure. Sent by client
private static final int ACTION_CONFIRM_TAKE = 11; // Unsure. Sent by client
public ItemProductionMsgHandler() {
super(ItemProductionMsg.class);
}
private static void setItemPrice(int itemType, int itemUUID, int itemPrice, NPC vendor, ClientConnection origin) {
Item targetItem;
ItemProductionMsg outMsg;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
if (itemType == GameObjectType.Item.ordinal())
targetItem = Item.getFromCache(itemUUID);
else if (itemType == GameObjectType.MobLoot.ordinal())
targetItem = MobLoot.getFromCache(itemUUID);
else
targetItem = null;
if (targetItem == null)
return;
if (targetItem.getObjectType() == GameObjectType.Item) {
if (!DbManager.ItemQueries.UPDATE_VALUE(targetItem, itemPrice)) {
ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help.");
return;
}
targetItem.setValue(itemPrice);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_SETPRICE, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
} else if (targetItem.getObjectType() == GameObjectType.MobLoot) {
MobLoot mobLoot = (MobLoot) targetItem;
if (!DbManager.NPCQueries.UPDATE_ITEM_PRICE(mobLoot.getObjectUUID(), vendor.getObjectUUID(), itemPrice)) {
ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help.");
return;
}
targetItem.setValue(itemPrice);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_SETPRICE, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
}
// Set item's price
}
// 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.getItemBase().getType() == ItemType.GOLD)
return;
if (!vendor.getCharItemManager().hasRoomInventory(targetItem.template.item_wt)) {
ErrorPopupMsg.sendErrorPopup(player, 21);
return;
}
itemMan = origin.getPlayerCharacter().getCharItemManager();
if (itemMan == null)
return;
if (vendor.getCharItemManager().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, ACTION_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_CONFIRM_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
origin.getPlayerCharacter().getCharItemManager().updateInventory();
} catch (Exception e) {
Logger.error(e);
} finally {
origin.sellLock.unlock();
}
}
}
// Method adds an item from the players inventory to the vendor.
private static void completeItem(int itemUUID, NPC vendor, ClientConnection origin, ItemProductionMsg msg) {
Item targetItem;
ManageNPCMsg outMsg;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
if (origin.buyLock.tryLock()) {
try {
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
return;
if (!vendor.getCharItemManager().forgeContains(targetItem, vendor))
return;
boolean worked = DbManager.ItemQueries.UPDATE_FORGE_TO_INVENTORY(targetItem);
if (!worked) {
Guild guild = vendor.getGuild();
if (guild == null)
return;
//ChatManager.chatGuildInfo(guild, "Failed to complete Item " + targetItem.getName());
return;
}
targetItem.containerType = Enum.ItemContainerType.INVENTORY;
targetItem.setOwner(vendor);
vendor.getCharItemManager().addItemToInventory(targetItem);
vendor.removeItemFromForge(targetItem);
outMsg = new ManageNPCMsg(vendor);
outMsg.setMessageType(ACTION_PRODUCE);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
} finally {
origin.buyLock.unlock();
}
}
}
// Method completes an item that has been previously rolled
// adding it to the NPC's inventory
private static void recycleItem(HashMap<Integer, Integer> itemList, NPC vendor, ClientConnection origin) {
Item targetItem;
ItemProductionMsg outMsg;
int totalValue = 0;
int currentStrongbox;
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;
int type = itemList.get(itemUUID);
if (type == GameObjectType.Item.ordinal())
targetItem = Item.getFromCache(itemUUID);
else
targetItem = MobLoot.getFromCache(itemUUID);
if (targetItem == null)
continue;
if (targetItem.getItemBase().getType() == ItemType.GOLD)
return;
if (!vendor.getCharItemManager().doesCharOwnThisItem(targetItem.getObjectUUID()))
continue;
if (vendor.getCharItemManager().inventoryContains(targetItem) == false)
continue;
itemValue = targetItem.template.item_value;
if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(player, 201);
break;
}
switch (targetItem.getItemBase().getType()) {
case CONTRACT:
case GUILDCHARTER:
case DEED:
case REALMCHARTER:
case SCROLL:
case TEARS:
itemValue = 0;
continue;
}
totalValue += itemValue;
long start = System.currentTimeMillis();
vendor.getCharItemManager().recycle(targetItem);
long end = System.currentTimeMillis();
long timetook = end - start;
// ChatManager.chatSystemInfo(player, "Took " + timetook + " ms to finish");
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_TAKE, true);
dispatch = Dispatch.borrow(origin.getPlayerCharacter(), outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
}
// Refund a portion of the gold
if (!vendor.getBuilding().transferGold(totalValue, false))
return;
} catch (Exception e) {
Logger.error(e);
} finally {
origin.sellLock.unlock();
}
}
// Refresh vendor's inventory to client
}
// Method handles recycling of an item
private static void junkItem(int itemUUID, NPC vendor, ClientConnection origin) {
MobLoot targetItem;
ManageNPCMsg outMsg;
Dispatch dispatch;
if (origin.sellLock.tryLock()) {
try {
targetItem = MobLoot.getFromCache(itemUUID);
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
// Can't junk nothing!
if (targetItem == null)
return;
if (!vendor.getCharItemManager().forgeContains(targetItem, vendor))
return;
// Cannot junk items without a forge!
if (vendor.getBuilding() == null)
return;
// Delete the item and cancel any pending rolling timer jobs
targetItem.recycle(vendor);
vendor.removeItemFromForge(targetItem);
// Refresh vendor's inventory to client
outMsg = new ManageNPCMsg(vendor);
outMsg.setMessageType(1);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
;
} finally {
origin.sellLock.unlock();
}
}
}
// Method junks an item that has been rolled but not completed
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()) {
int type = itemList.get(itemUUID);
if (type == GameObjectType.Item.ordinal()) {
targetItem = Item.getFromCache(itemUUID);
} else {
targetItem = MobLoot.getFromCache(itemUUID);
}
if (targetItem == null)
return;
if (targetItem.getItemBase().getType() == ItemType.GOLD)
return;
if (vendor.getCharItemManager().inventoryContains(targetItem) == false)
return;
if (player.getCharItemManager().hasRoomInventory(targetItem.template.item_wt) == false)
return;
player.getCharItemManager().buyFromNPC(targetItem, vendor);
}
player.getCharItemManager().updateInventory();
// Update NPC inventory to client
}
// Method removes item from an NPC's inventory and transferes it to a player
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {
// Member variable declaration
PlayerCharacter player;
NPC vendorNPC;
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
vendorNPC = (NPC) DbManager.getObject(engine.Enum.GameObjectType.NPC, msg.getNpcUUID());
// Oops?
if (vendorNPC == null)
return true;
// Process Request
switch (msg.getActionType()) {
case ACTION_PRODUCE:
boolean isRandom = false;
if (msg.getUnknown03() != 0 && msg.getpToken() == 0 && msg.getsToken() == 0)
isRandom = true;
//Create Multiple Item Function.. Fill all empty slots
if (msg.isMultiple()) {
int emptySlots = vendorNPC.getRank() - vendorNPC.getRolling().size();
if (emptySlots > 0) {
for (int i = 0; i < emptySlots; i++) {
vendorNPC.produceItem(player.getObjectUUID(), msg.getTotalProduction(), isRandom, msg.getpToken(), msg.getsToken(), msg.getName(), msg.getItemUUID());
}
}
} else
vendorNPC.produceItem(player.getObjectUUID(), msg.getTotalProduction(), isRandom, msg.getpToken(), msg.getsToken(), msg.getName(), msg.getItemUUID());
break;
case ACTION_JUNK:
junkItem(msg.getItemUUID(), vendorNPC, origin);
break;
case ACTION_RECYCLE:
recycleItem(msg.getItemIDtoTypeMap(), vendorNPC, origin);
msg.setActionType(7);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
break;
case ACTION_COMPLETE:
vendorNPC.completeItem(msg.getItemUUID());
// ManageNPCMsg outMsg = new ManageNPCMsg(vendorNPC);
// outMsg.setMessageType(1);
//
// dispatch = Dispatch.borrow(player, outMsg);
// DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
break;
case ACTION_DEPOSIT:
depositItem(msg.getItemUUID(), vendorNPC, origin);
break;
case ACTION_SETPRICE:
setItemPrice(msg.getItemType(), msg.getItemUUID(), msg.getItemPrice(), vendorNPC, origin);
break;
case ACTION_TAKE:
takeItem(msg.getItemIDtoTypeMap(), vendorNPC, origin);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
break;
}
return true;
}
// Method handles rolling item requests from the client
}