Files
Server/src/engine/net/client/handlers/VendorSellMsgHandler.java
T
MagicBotandClaude Opus 5.5 6b4e9815e0 Switch Item.template and MobLoot to CObjectTemplate
Item.template is now the cache template from CObjectTemplate.lookup
instead of the legacy DB ItemTemplate, so item.template.cacheTemplate.X
becomes item.template.X. MobLoot, LootManager, ItemManager.isTwoHanded/
isShield and CombatManager.getSwingAnimation take a CObjectTemplate.

No value changes: every getter already read the cache template through
the bridge, and the lookup resolves the same 7586 ids as
static_item_templates with the same item_type (offline parity p17.py,
0 differences).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:55:28 -04:00

199 lines
7.1 KiB
Java

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.net.client.handlers;
import engine.gameManager.DispatchManager;
import engine.gameManager.SessionManager;
import engine.mbEnums;
import engine.mbEnums.DispatchChannel;
import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.UpdateGoldMsg;
import engine.net.client.msg.VendorSellMsg;
import engine.objects.*;
import java.util.ArrayList;
public class VendorSellMsgHandler extends AbstractClientMsgHandler {
public VendorSellMsgHandler() {
super();
}
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) {
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;
VendorSellMsg vendorSellMsg = (VendorSellMsg) baseMsg;
NPC npc = NPC.getFromCache(vendorSellMsg.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<Item> 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 (vendorSellMsg.getItemType() == mbEnums.GameObjectType.Item.ordinal() == false)
return true;
sell = Item.getFromCache(vendorSellMsg.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.getItemWt())) {
ErrorPopupMsg.sendErrorPopup(player, 21);
return true;
}
if (!sell.validForInventory(origin, player, itemMan))
return true;
//get goldItem cost to sell
cost = (int) (sell.template.getItemValue() * (sell.combat_health_current / sell.template.getCombatHealthFull()));
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(mbEnums.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);
DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
//send the sell message back to update player
vendorSellMsg.setItemType(sell.getObjectType().ordinal());
vendorSellMsg.setItemID(sell.getObjectUUID());
vendorSellMsg.setUnknown01(cost); //not sure if this is correct
dispatch = Dispatch.borrow(player, vendorSellMsg);
DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
} finally {
origin.sellLock.unlock();
}
} else {
ErrorPopupMsg.sendErrorPopup(player, 12);
}
// Send ping to client
dispatch = Dispatch.borrow(pc, vendorSellMsg);
DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
return true;
}
}