diff --git a/src/engine/net/client/ClientMessagePump.java b/src/engine/net/client/ClientMessagePump.java index 32765679..56ec074b 100644 --- a/src/engine/net/client/ClientMessagePump.java +++ b/src/engine/net/client/ClientMessagePump.java @@ -12,7 +12,6 @@ package engine.net.client; import engine.Enum.DispatchChannel; import engine.Enum.GameObjectType; import engine.Enum.ItemContainerType; -import engine.Enum.ProtectionState; import engine.InterestManagement.WorldGrid; import engine.exception.MsgSendException; import engine.gameManager.*; @@ -36,7 +35,6 @@ import engine.util.StringUtils; import org.pmw.tinylog.Logger; import java.sql.SQLException; -import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; @@ -1026,172 +1024,6 @@ public class ClientMessagePump implements NetMsgHandler { dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); - - } - - private static void sellToNPC(SellToNPCMsg msg, ClientConnection origin) { - - PlayerCharacter player = SessionManager.getPlayerCharacter(origin); - Dispatch dispatch; - - if (player == null) - return; - - CharacterItemManager itemMan = player.charItemManager; - - if (itemMan == null) - return; - - NPC npc = NPC.getFromCache(msg.getNPCID()); - - if (npc == null) - return; - - Item gold = itemMan.getGoldInventory(); - - if (gold == null) - return; - - if (origin.sellLock.tryLock()) { - try { - Item sell; - int cost = 0; - - - if (npc.charItemManager.getInventoryCount() > 150) { - if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID == 0) { - ArrayList inv = npc.getInventory(); - for (int i = 0; i < 20; i++) { - try { - Item toRemove = inv.get(i); - if (toRemove != null) - npc.charItemManager.delete(toRemove); - } catch (Exception e) { - break; - } - - } - } - - } - - // Early exit sanity check - - if (msg.getItemType() == GameObjectType.Item.ordinal() == false) - return; - - sell = Item.getFromCache(msg.getItemID()); - - if (sell == null) - return; - - //get item to sell - - if (sell.template == null) - return; - - if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0) - if (!npc.charItemManager.hasRoomInventory(sell.template.item_wt)) { - - ErrorPopupMsg.sendErrorPopup(player, 21); - return; - } - - if (!sell.validForInventory(origin, player, itemMan)) - return; - - //get goldItem cost to sell - - - cost = sell.template.item_value; - - //apply damaged value reduction - float durabilityCurrent = (short) sell.durabilityCurrent; - float durabilityMax = sell.template.item_health_full; - float damagedModifier = durabilityCurrent / durabilityMax; - cost *= damagedModifier; - float bargain = player.getBargain(); - - float profit = npc.getBuyPercent(player) + bargain; - - if (profit > 1) - profit = 1; - - - cost *= profit; - - if (gold.getNumOfItems() + cost > 10000000) { - return; - } - - if (gold.getNumOfItems() + cost < 0) - return; - - //TODO make sure npc can buy item type - //test room available for item on npc - - // if (!npc.isStatic() && npc.getCharItemManager().getInventoryCount() > 150) { - // // chatMan.chatSystemInfo(pc, "This vendor's inventory is full"); - // return; - // } - - //make sure item is in player inventory - - Building building = (!npc.isStatic()) ? npc.getBuilding() : null; - - if (building != null && building.getProtectionState().equals(ProtectionState.NPC)) - building = null; - if (npc.getParentZone().playerCityUUID == 0) - building = null; - - //make sure npc can afford item - - if (building != null && !building.hasFunds(cost)) { - ErrorPopupMsg.sendErrorPopup(player, 17); - return; - } - if (building != null && (building.getStrongboxValue() - cost) < 0) { - ErrorPopupMsg.sendErrorPopup(player, 17); - return; - } - - //TODO transfer item and goldItem transfer should be handled together incase failure - //transfer the item - - if (!itemMan.sellToNPC(sell, npc)) - return; - - if (!itemMan.sellToNPC(building, cost, sell)) - return; - - //handle goldItem transfer - - if (sell == null) - return; - - // ***REFACTOR: SellToNpc sends this message, is this a duplicate? - - //update player's goldItem count - UpdateGoldMsg ugm = new UpdateGoldMsg(player); - ugm.configure(); - - dispatch = Dispatch.borrow(player, ugm); - DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); - - //send the sell message back to update player - msg.setItemType(sell.getObjectType().ordinal()); - msg.setItemID(sell.getObjectUUID()); - msg.setUnknown01(cost); //not sure if this is correct - - dispatch = Dispatch.borrow(player, msg); - DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); - - } finally { - origin.sellLock.unlock(); - } - } else { - ErrorPopupMsg.sendErrorPopup(player, 12); - } } private static void openBuyFromNPCWindow(BuyFromNPCWindowMsg msg, ClientConnection origin) { @@ -1542,9 +1374,6 @@ public class ClientMessagePump implements NetMsgHandler { case SHOPINFO: openSellToNPCWindow((SellToNPCWindowMsg) msg, origin); break; - case SELLOBJECT: - sellToNPC((SellToNPCMsg) msg, origin); - break; case TRAINERLIST: WorldServer.trainerInfo((TrainerInfoMsg) msg, origin); break; diff --git a/src/engine/net/client/Protocol.java b/src/engine/net/client/Protocol.java index 42e2d62a..cf40b61f 100644 --- a/src/engine/net/client/Protocol.java +++ b/src/engine/net/client/Protocol.java @@ -185,7 +185,7 @@ public enum Protocol { SELECTCHAR(0x7E6A9338, GameServerIPRequestMsg.class, null), // Game Server IP Request SELECTCITY(0x7E6BE630, null, null), SELECTSERVER(0x440D28B7, ServerInfoMsg.class, null), // Server Info Request/Response - SELLOBJECT(0x57111C67, SellToNPCMsg.class, null), //Sell to NPC + SELLOBJECT(0x57111C67, SellToNPCMsg.class, SellToNPCMsgHandler.class), //Sell to NPC SENDCITYENTRY(0xBC3B5E72, null, null), //Send Teleport/Repledge List SENDGUILDENTRY(0x6D5EF164, null, null), SENDMEMBERENTRY(0x6949C720, GuildListMsg.class, GuildListHandler.class), // ShowCombatInfo guild members list, I think diff --git a/src/engine/net/client/handlers/SellToNPCMsgHandler.java b/src/engine/net/client/handlers/SellToNPCMsgHandler.java new file mode 100644 index 00000000..0eda5721 --- /dev/null +++ b/src/engine/net/client/handlers/SellToNPCMsgHandler.java @@ -0,0 +1,208 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2022 +// www.magicbane.com + +package engine.net.client.handlers; + +import engine.Enum; +import engine.Enum.DispatchChannel; +import engine.exception.MsgSendException; +import engine.gameManager.SessionManager; +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.SellToNPCMsg; +import engine.net.client.msg.UpdateGoldMsg; +import engine.objects.*; + +import java.util.ArrayList; + +public class SellToNPCMsgHandler extends AbstractClientMsgHandler { + + public SellToNPCMsgHandler() { + super(SellToNPCMsg.class); + } + + @Override + protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException { + + PlayerCharacter pc = origin.getPlayerCharacter(); + PlayerCharacter player = SessionManager.getPlayerCharacter(origin); + Dispatch dispatch; + + if (player == null) + return true; + + CharacterItemManager itemMan = player.charItemManager; + + if (itemMan == null) + return true; + + SellToNPCMsg sellToNPCMsg = (SellToNPCMsg) baseMsg; + + NPC npc = NPC.getFromCache(sellToNPCMsg.getNPCID()); + + if (npc == null) + return true; + + Item gold = itemMan.getGoldInventory(); + + if (gold == null) + return true; + + if (origin.sellLock.tryLock()) { + try { + Item sell; + int cost = 0; + + + if (npc.charItemManager.getInventoryCount() > 150) { + if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID == 0) { + ArrayList inv = npc.getInventory(); + for (int i = 0; i < 20; i++) { + try { + Item toRemove = inv.get(i); + if (toRemove != null) + npc.charItemManager.delete(toRemove); + } catch (Exception e) { + break; + } + + } + } + + } + + // Early exit sanity check + + if (sellToNPCMsg.getItemType() == Enum.GameObjectType.Item.ordinal() == false) + return true; + + sell = Item.getFromCache(sellToNPCMsg.getItemID()); + + if (sell == null) + return true; + + //get item to sell + + if (sell.template == null) + return true; + + if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0) + if (!npc.charItemManager.hasRoomInventory(sell.template.item_wt)) { + ErrorPopupMsg.sendErrorPopup(player, 21); + return true; + } + + if (!sell.validForInventory(origin, player, itemMan)) + return true; + + //get goldItem cost to sell + + + cost = sell.template.item_value; + + //apply damaged value reduction + float durabilityCurrent = (short) sell.durabilityCurrent; + float durabilityMax = sell.template.item_health_full; + float damagedModifier = durabilityCurrent / durabilityMax; + cost *= damagedModifier; + float bargain = player.getBargain(); + + float profit = npc.getBuyPercent(player) + bargain; + + if (profit > 1) + profit = 1; + + + cost *= profit; + + if (gold.getNumOfItems() + cost > 10000000) + return true; + + if (gold.getNumOfItems() + cost < 0) + return true; + + //TODO make sure npc can buy item type + //test room available for item on npc + + // if (!npc.isStatic() && npc.getCharItemManager().getInventoryCount() > 150) { + // // chatMan.chatSystemInfo(pc, "This vendor's inventory is full"); + // return; + // } + + //make sure item is in player inventory + + Building building = (!npc.isStatic()) ? npc.getBuilding() : null; + + if (building != null && building.getProtectionState().equals(Enum.ProtectionState.NPC)) + building = null; + + if (npc.getParentZone().playerCityUUID == 0) + building = null; + + //make sure npc can afford item + + if (building != null && !building.hasFunds(cost)) { + ErrorPopupMsg.sendErrorPopup(player, 17); + return true; + } + + if (building != null && (building.getStrongboxValue() - cost) < 0) { + ErrorPopupMsg.sendErrorPopup(player, 17); + return true; + } + + //TODO transfer item and goldItem transfer should be handled together incase failure + //transfer the item + + if (!itemMan.sellToNPC(sell, npc)) + return true; + + if (!itemMan.sellToNPC(building, cost, sell)) + return true; + + //handle goldItem transfer + + if (sell == null) + return true; + + // ***REFACTOR: SellToNpc sends this message, is this a duplicate? + + //update player's goldItem count + UpdateGoldMsg ugm = new UpdateGoldMsg(player); + ugm.configure(); + + dispatch = Dispatch.borrow(player, ugm); + DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); + + //send the sell message back to update player + sellToNPCMsg.setItemType(sell.getObjectType().ordinal()); + sellToNPCMsg.setItemID(sell.getObjectUUID()); + sellToNPCMsg.setUnknown01(cost); //not sure if this is correct + + dispatch = Dispatch.borrow(player, sellToNPCMsg); + DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); + + } finally { + origin.sellLock.unlock(); + } + } else { + ErrorPopupMsg.sendErrorPopup(player, 12); + } + + // Send ping to client + + dispatch = Dispatch.borrow(pc, sellToNPCMsg); + DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); + + return true; + } + +} \ No newline at end of file diff --git a/src/engine/objects/CharacterItemManager.java b/src/engine/objects/CharacterItemManager.java index 7b41a1fc..58a12766 100644 --- a/src/engine/objects/CharacterItemManager.java +++ b/src/engine/objects/CharacterItemManager.java @@ -1315,8 +1315,8 @@ public class CharacterItemManager { } finally { buildingCity.transactionLock.writeLock().unlock(); } - } else if (!vendorBuilding.transferGold(buildingDeposit, true)) - return false; + } else + return vendorBuilding.transferGold(buildingDeposit, true); return true; } @@ -1382,8 +1382,10 @@ public class CharacterItemManager { synchronized (this) { synchronized (itemMan) { + if (!this.doesCharOwnThisItem(itemToSell.getObjectUUID())) return false; + // attempt to transfer item in db boolean sdrMerchant = false; @@ -1398,13 +1400,14 @@ public class CharacterItemManager { } else if (!itemToSell.moveItemToInventory(npc)) return false; - // db transfer successfull, remove from this character // skip this check if this is a mobLoot item (which is not in any inventory) + if (!sdrMerchant) if (!removeItemFromInventory(itemToSell)) return false; - // add item to looter. + // add item to vendor + if (!sdrMerchant) if (!itemMan.addItemToInventory(itemToSell)) return false;