forked from MagicBane/Server
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.
2630 lines
74 KiB
2630 lines
74 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
|
|
package engine.objects; |
|
|
|
import engine.Enum; |
|
import engine.Enum.GameObjectType; |
|
import engine.Enum.ItemType; |
|
import engine.gameManager.BuildingManager; |
|
import engine.gameManager.ChatManager; |
|
import engine.gameManager.ConfigManager; |
|
import engine.gameManager.DbManager; |
|
import engine.math.Vector3fImmutable; |
|
import engine.net.Dispatch; |
|
import engine.net.DispatchMessage; |
|
import engine.net.client.ClientConnection; |
|
import engine.net.client.ClientMessagePump; |
|
import engine.net.client.msg.*; |
|
import engine.server.MBServerStatics; |
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Collection; |
|
import java.util.HashSet; |
|
import java.util.Iterator; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
import java.util.concurrent.ThreadLocalRandom; |
|
|
|
import static engine.math.FastMath.sqr; |
|
import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup; |
|
|
|
|
|
|
|
public class CharacterItemManager { |
|
|
|
private final AbstractCharacter absCharacter; |
|
private Account account; |
|
|
|
// Mapping of all the items associated with this Manager |
|
private final ConcurrentHashMap<Integer, Integer> itemIDtoType = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
|
|
// Mapping of all items equipped in this Manager |
|
// Key = Item Slot |
|
private final ConcurrentHashMap<Integer, Item> equipped = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
|
|
private final HashSet<Item> inventory = new HashSet<>(); |
|
private final HashSet<Item> bank = new HashSet<>(); |
|
private final HashSet<Item> vault = new HashSet<>(); |
|
|
|
private Item goldInventory; |
|
private Item goldBank; |
|
public Item goldVault; |
|
|
|
private boolean bankOpened; |
|
private boolean vaultOpened; |
|
|
|
private short bankWeight; |
|
private short inventoryWeight; |
|
private short equipWeight; |
|
private short vaultWeight; |
|
|
|
private ClientConnection tradingWith; |
|
private byte tradeCommitted; |
|
private boolean tradeSuccess; |
|
private HashSet<Integer> trading; |
|
private int goldTradingAmount; |
|
private int tradeID = 0; |
|
private final HashSet<Integer> equipOrder = new HashSet<>(); |
|
|
|
/* |
|
* Item Manager Version data |
|
*/ |
|
private byte equipVer = (byte) 0; |
|
private static final byte inventoryVer = (byte) 0; |
|
private static final byte bankVer = (byte) 0; |
|
private static final byte vaultVer = (byte) 0; |
|
|
|
public CharacterItemManager(AbstractCharacter ac) { |
|
super(); |
|
this.absCharacter = ac; |
|
} |
|
|
|
public void load() { |
|
loadForGeneric(); |
|
|
|
if (this.absCharacter .getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
loadForPlayerCharacter(); |
|
else if (this.absCharacter.getObjectType().equals(GameObjectType.NPC)) |
|
loadForNPC(); |
|
|
|
} |
|
|
|
public void loadGoldItems() { |
|
|
|
if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER)) { |
|
//other server, just make generic |
|
this.goldInventory = new MobLoot(this.absCharacter, 0); |
|
this.goldBank = new MobLoot(this.absCharacter, 0); |
|
this.goldVault = new MobLoot(this.absCharacter, 0); |
|
return; |
|
} |
|
|
|
//create inventory gold if needed |
|
if (this.goldInventory == null) |
|
if (this.absCharacter != null && (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) || this.absCharacter.getObjectType().equals(GameObjectType.NPC))) |
|
this.goldInventory = Item.newGoldItem(this.absCharacter, ItemBase.getItemBase(7), Enum.ItemContainerType.INVENTORY); |
|
else |
|
this.goldInventory = new MobLoot(this.absCharacter, 0); |
|
|
|
//create bank gold if needed |
|
if (this.goldBank == null) |
|
if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
this.goldBank = Item.newGoldItem(this.absCharacter, ItemBase.getItemBase(7), Enum.ItemContainerType.BANK); |
|
else |
|
this.goldBank = new MobLoot(this.absCharacter, 0); |
|
|
|
//create vault gold if needed |
|
if (this.goldVault == null) |
|
if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)){ |
|
this.goldVault = this.account.vaultGold; |
|
} |
|
|
|
else |
|
this.goldVault = new MobLoot(this.absCharacter, 0); |
|
|
|
this.itemIDtoType.put(this.goldInventory.getObjectUUID(), this.goldInventory.getObjectType().ordinal()); |
|
this.itemIDtoType.put(this.goldBank.getObjectUUID(), this.goldBank.getObjectType().ordinal()); |
|
this.itemIDtoType.put(this.goldVault.getObjectUUID(), this.goldVault.getObjectType().ordinal()); |
|
|
|
} |
|
|
|
private void loadForPlayerCharacter() { |
|
ArrayList<Item> al = null; |
|
|
|
// TODO Verify this is an actual account. |
|
this.account = ((PlayerCharacter) this.absCharacter).getAccount(); |
|
|
|
// Get Items for player and vault |
|
if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER)) //login, only need equipped items |
|
al = DbManager.ItemQueries.GET_EQUIPPED_ITEMS(this.absCharacter.getObjectUUID()); |
|
else |
|
al = DbManager.ItemQueries.GET_ITEMS_FOR_PC(this.absCharacter.getObjectUUID()); |
|
|
|
for (Item i : al) { |
|
|
|
i.validateItemContainer(); |
|
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); |
|
|
|
switch (i.containerType) { |
|
case EQUIPPED: |
|
if (this.equipped.containsValue(i) == false) { |
|
this.equipped.put((int) i.getEquipSlot(), i); |
|
addEquipOrder((int) i.getEquipSlot()); |
|
} |
|
break; |
|
case BANK: |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
this.goldBank = i; |
|
else if (this.bank.contains(i) == false) |
|
this.bank.add(i); |
|
break; |
|
case INVENTORY: |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
this.goldInventory = i; |
|
else if (this.inventory.contains(i) == false) |
|
this.inventory.add(i); |
|
break; |
|
case VAULT: |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
this.goldVault = i; |
|
else if (this.vault.contains(i) == false) |
|
this.vault.add(i); |
|
break; |
|
default: |
|
i.junk(); |
|
break; |
|
} |
|
|
|
} |
|
|
|
this.goldVault = this.account.vaultGold; |
|
|
|
//check all gold is created |
|
//loadGoldItems(); |
|
calculateWeights(); |
|
} |
|
|
|
private void loadForNPC() { |
|
ArrayList<Item> al = null; |
|
|
|
// Get all items related to this NPC: |
|
al = DbManager.ItemQueries.GET_ITEMS_FOR_NPC(this.absCharacter.getObjectUUID()); |
|
|
|
for (Item i : al) { |
|
i.validateItemContainer(); |
|
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); |
|
|
|
switch (i.containerType) { |
|
case EQUIPPED: |
|
if (this.equipped.containsValue(i) == false) |
|
this.equipped.put((int) i.getEquipSlot(), i); |
|
break; |
|
case BANK: |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
this.goldBank = i; |
|
else if (this.bank.contains(i) == false) |
|
this.bank.add(i); |
|
break; |
|
case INVENTORY: |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
this.goldInventory = i; |
|
else if (this.inventory.contains(i) == false) |
|
this.inventory.add(i); |
|
break; |
|
default: |
|
i.junk(); |
|
break; |
|
} |
|
} |
|
|
|
//check all gold is created |
|
//loadGoldItems(); |
|
} |
|
|
|
private void loadForGeneric() { |
|
this.bankWeight = 0; |
|
this.inventoryWeight = 0; |
|
this.equipWeight = 0; |
|
this.vaultWeight = 0; |
|
|
|
//check all gold is created |
|
//loadGoldItems(); |
|
// Always initialize with bank and vault closed |
|
bankOpened = false; |
|
vaultOpened = false; |
|
} |
|
|
|
//Positve Amount = TO BUILDING; Negative Amount = FROM BUILDING. flip signs for Player inventory. |
|
public synchronized boolean transferGoldToFromBuilding(int amount, AbstractWorldObject object){ |
|
if (this.absCharacter.getObjectType() != GameObjectType.PlayerCharacter) |
|
return false; |
|
|
|
PlayerCharacter player = (PlayerCharacter) this.absCharacter; |
|
|
|
switch (object.getObjectType()){ |
|
case Building: |
|
Building building = (Building)object; |
|
|
|
if (!this.getGoldInventory().validForInventory(player.getClientConnection(), player, this)) |
|
return false; |
|
|
|
if (amount <0 && amount > building.getStrongboxValue()) |
|
return false; |
|
|
|
// Not enough gold in inventory to transfer to tree |
|
|
|
if ((amount > 0) && |
|
(this.getGoldInventory().getNumOfItems() - amount < 0)) { |
|
sendErrorPopup(player, 28); |
|
return false; |
|
} |
|
|
|
if (this.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT){ |
|
ErrorPopupMsg.sendErrorPopup(player, 202); |
|
return false; |
|
} |
|
|
|
|
|
|
|
// Not enough gold to transfer to inventory from tree |
|
|
|
if ((amount < 0) && |
|
(building.getStrongboxValue() + amount < 0)) { |
|
sendErrorPopup(player, 127); |
|
return false; |
|
} |
|
|
|
if (amount < 0) |
|
if (!building.hasFunds(-amount)) |
|
return false; |
|
|
|
//Verify player can access building to transfer goldItem |
|
|
|
if (!BuildingManager.playerCanManage(player, building)) |
|
return false; |
|
|
|
if (building.getStrongboxValue() + amount > building.getMaxGold()){ |
|
ErrorPopupMsg.sendErrorPopup(player, 201); |
|
return false; |
|
} |
|
|
|
if (this.getOwner().getCharItemManager().getGoldTrading() > 0){ |
|
if (this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
ErrorPopupMsg.sendErrorPopup((PlayerCharacter)this.getOwner(), 195); |
|
return false; |
|
} |
|
|
|
if (!this.modifyInventoryGold(-amount)){ |
|
|
|
Logger.error(player.getName() + " transfer amount = " + amount +" ; Gold Inventory = " + this.getGoldInventory().getNumOfItems()); |
|
|
|
// ChatManager.chatSystemError(player, "You do not have this Gold."); |
|
return false; |
|
} |
|
|
|
if (!building.transferGold(amount,false)){ |
|
|
|
Logger.error(player.getName() + " transfer amount = " + amount +" ; Gold Inventory = " + this.getGoldInventory().getNumOfItems() + "; Building Strongbox = " + building.getStrongboxValue()); |
|
|
|
//ChatManager.chatSystemError(player, "Something went terribly wrong. Contact CCR."); |
|
return false; |
|
} |
|
|
|
break; |
|
case Warehouse: |
|
|
|
Warehouse warehouse = (Warehouse)object; |
|
|
|
if (amount < 0){ |
|
if (!warehouse.deposit((PlayerCharacter) this.absCharacter, this.getGoldInventory(), amount*-1, true,true)){ |
|
|
|
ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.absCharacter, 203); |
|
return false; |
|
} |
|
}else{ |
|
if (!warehouse.withdraw((PlayerCharacter) this.absCharacter, this.getGoldInventory().getItemBase(), amount*-1, true,true)){ |
|
|
|
ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.absCharacter, 203); |
|
return false; |
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
return true; |
|
} |
|
|
|
/* |
|
* Item Controls |
|
*/ |
|
public synchronized boolean modifyInventoryGold(int modifyValue) { |
|
|
|
Item goldItem; |
|
PlayerCharacter player; |
|
boolean success = false; |
|
|
|
goldItem = getGoldInventory(); |
|
|
|
if (goldItem == null) { |
|
Logger.error("ModifyInventoryGold", "Could not create gold item"); |
|
return success; |
|
} |
|
|
|
if (this.getGoldInventory().getNumOfItems() + modifyValue > MBServerStatics.PLAYER_GOLD_LIMIT){ |
|
return false; |
|
} |
|
|
|
if (this.getGoldInventory().getNumOfItems() + modifyValue < 0) |
|
return false; |
|
|
|
// No database update for npc's gold values so we use the player object |
|
// for flow control later on. |
|
|
|
if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) |
|
player = (PlayerCharacter) this.absCharacter; |
|
else |
|
player = null; |
|
|
|
// If this is an update for a player character update the database |
|
|
|
if (player != null) |
|
try { |
|
if (!DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + modifyValue)){ |
|
return false; |
|
} |
|
|
|
|
|
success = true; |
|
} catch (Exception e) { |
|
Logger.error("ModifyInventoryGold", "Error writing to database"); |
|
} |
|
|
|
// Update in-game gold values for character |
|
goldItem.setNumOfItems(goldItem.getNumOfItems() + modifyValue); |
|
UpdateGoldMsg ugm = new UpdateGoldMsg(this.absCharacter); |
|
ugm.configure(); |
|
|
|
Dispatch dispatch = Dispatch.borrow(player, ugm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
return success; |
|
} |
|
|
|
public synchronized boolean tradeRequest(TradeRequestMsg msg) { |
|
|
|
PlayerCharacter source = (PlayerCharacter) this.getOwner(); |
|
PlayerCharacter target = PlayerCharacter.getFromCache(msg.getPlayerID()); |
|
Dispatch dispatch; |
|
|
|
if (!canTrade(source, target)) { |
|
ChatManager.chatSystemError(source, "Can't currently trade with target player"); |
|
return false; |
|
} |
|
|
|
// TODO uncomment this block after we determine when we |
|
// setBankOpen(false) and setVaultOpen(false) |
|
CharacterItemManager cim1 = source.getCharItemManager(); |
|
CharacterItemManager cim2 = target.getCharItemManager(); |
|
|
|
if (cim1 == null) |
|
return false; |
|
|
|
if (cim2 == null) |
|
return false; |
|
|
|
dispatch = Dispatch.borrow(target, msg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
return true; |
|
|
|
} |
|
|
|
public synchronized boolean invalidTradeRequest(InvalidTradeRequestMsg msg) { |
|
PlayerCharacter requester = PlayerCharacter.getFromCache(msg.getRequesterID()); |
|
Dispatch dispatch; |
|
|
|
dispatch = Dispatch.borrow(requester, msg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
return true; |
|
|
|
} |
|
|
|
public synchronized boolean canTrade(PlayerCharacter playerA, PlayerCharacter playerB) { |
|
|
|
if (playerA == null || playerB == null) |
|
return false; |
|
|
|
//make sure both are alive |
|
if (!playerA.isAlive() || !playerB.isAlive()) |
|
return false; |
|
|
|
//distance check |
|
Vector3fImmutable aLoc = playerA.getLoc(); |
|
Vector3fImmutable bLoc = playerB.getLoc(); |
|
|
|
if (aLoc.distanceSquared2D(bLoc) > sqr(MBServerStatics.TRADE_RANGE)) |
|
return false; |
|
|
|
//visibility check |
|
if (!playerA.canSee(playerB) || !playerB.canSee(playerA)) |
|
return false; |
|
|
|
if (playerA.lastBuildingAccessed != 0) { |
|
ManageCityAssetsMsg mca = new ManageCityAssetsMsg(); |
|
mca.actionType = 4; |
|
mca.setTargetType(Enum.GameObjectType.Building.ordinal()); |
|
mca.setTargetID(playerA.lastBuildingAccessed); |
|
Dispatch dispatch = Dispatch.borrow(playerA, mca); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
playerA.lastBuildingAccessed = 0; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean acceptTradeRequest(AcceptTradeRequestMsg msg) { |
|
|
|
PlayerCharacter source = (PlayerCharacter)this.getOwner(); |
|
PlayerCharacter target = PlayerCharacter.getFromCache(msg.getTargetID()); |
|
|
|
Dispatch dispatch; |
|
|
|
if (source == null || !source.isAlive()) |
|
return false; |
|
|
|
if (target == null || !target.isAlive()) |
|
return false; |
|
|
|
if (this.tradingWith != null) |
|
return false; |
|
|
|
if (!canTrade(source, target)) |
|
return false; |
|
|
|
// verify characterTarget is in range |
|
if (source.getLoc().distanceSquared2D(target.getLoc()) > sqr(MBServerStatics.TRADE_RANGE)) |
|
return false; |
|
|
|
// TODO uncomment this block after we determine when we |
|
// setBankOpen(false) and setVaultOpen(false) |
|
/* |
|
* CharacterItemManager cim1 = source.getCharItemManager(); |
|
* CharacterItemManager cim2 = characterTarget.getCharItemManager(); if (cim1 == |
|
* null) return false; if (cim2 == null) return false; if (cim1.isBankOpen()) |
|
* return false; if (cim2.isVaultOpen()) return false; |
|
*/ |
|
ClientConnection sourceConn = source.getClientConnection(); |
|
ClientConnection targetConn = target.getClientConnection(); |
|
|
|
if (sourceConn == null) |
|
return false; |
|
|
|
if (targetConn == null) |
|
return false; |
|
|
|
|
|
CharacterItemManager toTradeWith = target.getCharItemManager(); |
|
|
|
if (toTradeWith == null) |
|
return false; |
|
|
|
Account sourceAccount = source.getAccount(); |
|
Account targetAccount = target.getAccount(); |
|
|
|
UpdateVaultMsg uvmSource = new UpdateVaultMsg(sourceAccount); |
|
UpdateVaultMsg uvmTarget = new UpdateVaultMsg(targetAccount); |
|
|
|
dispatch = Dispatch.borrow(source, uvmSource); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
|
|
dispatch = Dispatch.borrow(target, uvmTarget); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
|
|
this.setVaultOpen(false); |
|
toTradeWith.setVaultOpen(false); |
|
this.setBankOpen(false); |
|
toTradeWith.setBankOpen(false); |
|
|
|
OpenTradeWindowMsg otwm = new OpenTradeWindowMsg(msg.getUnknown01(), source, target); |
|
|
|
// Only start trade if both players aren't already trading with |
|
// someone |
|
|
|
if (this.getTradingWith() != null || toTradeWith.getTradingWith() != null) |
|
return false; |
|
|
|
this.initializeTrade(); |
|
toTradeWith.initializeTrade(); |
|
this.setTradingWith(targetConn); |
|
toTradeWith.setTradingWith(sourceConn); |
|
this.tradeID = msg.getUnknown01(); |
|
toTradeWith.tradeID = msg.getUnknown01(); |
|
|
|
dispatch = Dispatch.borrow(source, otwm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
|
|
dispatch = Dispatch.borrow(target, otwm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean addItemToTradeWindow(AddItemToTradeWindowMsg msg) { |
|
PlayerCharacter source =(PlayerCharacter)this.getOwner(); |
|
Dispatch dispatch; |
|
|
|
if (source == null || !source.isAlive()) |
|
return false; |
|
|
|
|
|
|
|
|
|
ClientConnection ccOther = this.getTradingWith(); |
|
|
|
if (ccOther == null) |
|
return false; |
|
|
|
PlayerCharacter other = ccOther.getPlayerCharacter(); |
|
|
|
if (other == null || !other.isAlive()) |
|
return false; |
|
|
|
CharacterItemManager tradingWith = other.getCharItemManager(); |
|
|
|
if (tradingWith == null) |
|
return false; |
|
|
|
if (!canTrade(source, other)) |
|
return false; |
|
|
|
Item i = Item.getFromCache(msg.getItemID()); |
|
|
|
if (i == null) |
|
return false; |
|
|
|
if (!this.doesCharOwnThisItem(i.getObjectUUID())) |
|
return false; |
|
|
|
//can't add item to trade window twice |
|
if (this.tradingContains(i)) |
|
return false; |
|
|
|
//dupe check |
|
if (!i.validForInventory(source.getClientConnection(), source, this)) |
|
return false; |
|
|
|
if (!tradingWith.hasRoomTrade(i.getItemBase().getWeight())) { |
|
dispatch = Dispatch.borrow(source, msg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
return false; |
|
} |
|
|
|
UpdateTradeWindowMsg utwm = new UpdateTradeWindowMsg(source, other); |
|
|
|
this.setTradeCommitted((byte) 0); |
|
tradingWith.setTradeCommitted((byte) 0); |
|
|
|
this.addItemToTrade(i); |
|
|
|
dispatch = Dispatch.borrow(other, msg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
|
|
modifyCommitToTrade(); |
|
|
|
dispatch = Dispatch.borrow(other, utwm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY); |
|
return true; |
|
} |
|
|
|
public synchronized boolean addGoldToTradeWindow(AddGoldToTradeWindowMsg msg) { |
|
|
|
PlayerCharacter source = (PlayerCharacter) this.getOwner(); |
|
Dispatch dispatch; |
|
|
|
if (source == null || !source.isAlive()) |
|
return false; |
|
|
|
|
|
|
|
|
|
ClientConnection ccOther = this.getTradingWith(); |
|
|
|
if (ccOther == null) |
|
return false; |
|
|
|
PlayerCharacter other = ccOther.getPlayerCharacter(); |
|
|
|
if (other == null || !other.isAlive()) |
|
return false; |
|
|
|
CharacterItemManager tradingWith = other.getCharItemManager(); |
|
|
|
if (tradingWith == null) |
|
return false; |
|
|
|
UpdateTradeWindowMsg utwm = new UpdateTradeWindowMsg(other, source); |
|
UpdateTradeWindowMsg utwmOther = new UpdateTradeWindowMsg(source, other); |
|
|
|
if (!canTrade(source, other)) |
|
return false; |
|
|
|
this.setTradeCommitted((byte) 0); |
|
tradingWith.setTradeCommitted((byte) 0); |
|
|
|
int amt = msg.getAmount(); |
|
|
|
if (amt <= 0){ |
|
Logger.info( source.getFirstName() + " added negative gold to trade window. Dupe attempt FAILED!"); |
|
return false; |
|
} |
|
|
|
if (amt > MBServerStatics.PLAYER_GOLD_LIMIT) |
|
return false; |
|
|
|
if (this.getGoldInventory().getNumOfItems() - amt < 0) |
|
return false; |
|
|
|
this.addGoldToTrade(amt); |
|
|
|
// BONUS CODE BELOW: Thanks some unknown retard! |
|
// sourceItemMan.updateInventory(sourceItemMan.getInventory(), true); |
|
|
|
UpdateGoldMsg ugm = new UpdateGoldMsg(source); |
|
ugm.configure(); |
|
|
|
modifyCommitToTrade(); |
|
|
|
dispatch = Dispatch.borrow(source, utwm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
dispatch = Dispatch.borrow(source, ugm); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
dispatch = Dispatch.borrow(other, utwmOther); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
return true; |
|
|
|
} |
|
|
|
|
|
public synchronized boolean uncommitToTrade(UncommitToTradeMsg msg) { |
|
|
|
PlayerCharacter source = (PlayerCharacter) this.getOwner(); |
|
|
|
if (source == null || !source.isAlive()) |
|
return false; |
|
|
|
CharacterItemManager sourceItemMan = source.getCharItemManager(); |
|
|
|
if (sourceItemMan == null) |
|
return false; |
|
|
|
sourceItemMan.setTradeCommitted((byte) 0); |
|
|
|
ClientConnection ccOther = sourceItemMan.getTradingWith(); |
|
|
|
if (ccOther == null) |
|
return false; |
|
|
|
PlayerCharacter other = ccOther.getPlayerCharacter(); |
|
|
|
if (other == null) |
|
return false; |
|
|
|
if (!canTrade(source, other)) |
|
return false; |
|
|
|
return modifyCommitToTrade(); |
|
} |
|
|
|
public synchronized boolean commitToTrade(CommitToTradeMsg msg) { |
|
|
|
PlayerCharacter source = (PlayerCharacter)this.getOwner(); |
|
|
|
if (source == null || !source.isAlive()) |
|
return false; |
|
|
|
|
|
|
|
|
|
this.setTradeCommitted((byte) 1); |
|
|
|
ClientConnection ccOther = this.getTradingWith(); |
|
|
|
if (ccOther == null) |
|
return false; |
|
|
|
PlayerCharacter other = ccOther.getPlayerCharacter(); |
|
|
|
if (other == null || !other.isAlive()) |
|
return false; |
|
|
|
CharacterItemManager tradingWith = other.getCharItemManager(); |
|
|
|
if (tradingWith == null) |
|
return false; |
|
|
|
if (!canTrade(source, other)) |
|
return false; |
|
|
|
modifyCommitToTrade(); |
|
|
|
if (this.getTradeCommitted() == (byte) 1 && tradingWith.getTradeCommitted() == (byte) 1) { |
|
int tradeID = this.tradeID; |
|
CloseTradeWindowMsg ctwm1 = new CloseTradeWindowMsg(source, tradeID); |
|
CloseTradeWindowMsg ctwm2 = new CloseTradeWindowMsg(other, tradeID); |
|
this.commitTrade(); |
|
this.closeTradeWindow(ctwm1, false); |
|
other.getCharItemManager().closeTradeWindow(ctwm2, false); |
|
} |
|
return true; |
|
} |
|
|
|
private synchronized boolean modifyCommitToTrade() { |
|
CharacterItemManager man1 = this; |
|
|
|
if (this.getTradingWith() == null) |
|
return false; |
|
|
|
if (this.getTradingWith().getPlayerCharacter() == null) |
|
return false; |
|
CharacterItemManager man2 = this.getTradingWith().getPlayerCharacter().getCharItemManager(); |
|
Dispatch dispatch; |
|
|
|
if (man1 == null || man2 == null) |
|
return false; |
|
|
|
ModifyCommitToTradeMsg modify = new ModifyCommitToTradeMsg(this.getOwner(), man2.getOwner(), man1.getTradeCommitted(), |
|
man2.getTradeCommitted()); |
|
|
|
dispatch = Dispatch.borrow((PlayerCharacter) this.getOwner(), modify); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
dispatch = Dispatch.borrow((PlayerCharacter) man2.getOwner(), modify); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
return true; |
|
|
|
} |
|
|
|
public synchronized boolean closeTradeWindow(CloseTradeWindowMsg msg, boolean sourceTrade) { |
|
|
|
|
|
Dispatch dispatch; |
|
|
|
PlayerCharacter source = (PlayerCharacter) this.getOwner(); |
|
if (source == null) |
|
return false; |
|
|
|
CharacterItemManager sourceItemMan = source.getCharItemManager(); |
|
|
|
if (sourceItemMan == null) |
|
return false; |
|
|
|
int tradeID = this.tradeID; |
|
CloseTradeWindowMsg closeMsg = new CloseTradeWindowMsg(source,tradeID); |
|
|
|
dispatch = Dispatch.borrow(source, closeMsg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
if (!sourceTrade){ |
|
sourceItemMan.endTrade(); |
|
return true; |
|
} |
|
|
|
ClientConnection cc2 = sourceItemMan.getTradingWith(); |
|
|
|
if (cc2 == null || cc2.getPlayerCharacter() == null){ |
|
sourceItemMan.endTrade(); |
|
return true; |
|
} |
|
|
|
sourceItemMan.endTrade(); |
|
|
|
|
|
|
|
cc2.getPlayerCharacter().getCharItemManager().closeTradeWindow(msg, false); |
|
|
|
|
|
|
|
|
|
return true; |
|
} |
|
|
|
public Item getGoldInventory() { |
|
if (this.goldInventory == null) |
|
loadGoldItems(); |
|
return this.goldInventory; |
|
} |
|
|
|
public Item getGoldBank() { |
|
if (this.goldBank == null) |
|
loadGoldItems(); |
|
return this.goldBank; |
|
} |
|
|
|
public Item getGoldVault() { |
|
if (this.goldVault == null) |
|
loadGoldItems(); |
|
return this.goldVault; |
|
} |
|
|
|
public void addEquipOrder(int slot) { |
|
synchronized (this.equipOrder) { |
|
Integer iSlot = slot; |
|
if (this.equipOrder.contains(iSlot)) |
|
this.equipOrder.remove(iSlot); |
|
this.equipOrder.add(slot); |
|
} |
|
} |
|
|
|
public synchronized boolean doesCharOwnThisItem(int itemID) { |
|
return this.itemIDtoType.containsKey(itemID); |
|
} |
|
|
|
public synchronized boolean junk(Item i) { |
|
return junk(i, true); |
|
} |
|
|
|
public synchronized boolean recycle(Item i) { |
|
if (i.getObjectType() == GameObjectType.Item) |
|
return junk(i, false); |
|
else{ |
|
if(this.removeItemFromInventory(i) == false) |
|
return false; |
|
((MobLoot)i).recycle((NPC)this.absCharacter); |
|
calculateInventoryWeight(); |
|
return true; |
|
} |
|
} |
|
|
|
// The DeleteItemMsg takes care of updating inventory, so we don't want to do it separately |
|
public synchronized boolean delete(Item i) { |
|
return junk(i, false); |
|
} |
|
|
|
//cleanup an item from CharacterItemManager if it doesn't belong here |
|
public synchronized boolean cleanupDupe(Item i) { |
|
if (i == null) |
|
return false; |
|
|
|
if(i.getItemBase().getType().equals(ItemType.GOLD)){ |
|
if (this.getGoldInventory() != null){ |
|
if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID()) |
|
this.goldInventory = null; |
|
}else if (this.getGoldBank() != null){ |
|
if (i.getObjectUUID() == this.getGoldBank().getObjectUUID()) |
|
this.goldBank = null; |
|
} |
|
return true; |
|
} |
|
|
|
byte slot = i.getEquipSlot(); |
|
|
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
return false; |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
this.itemIDtoType.remove(i.getObjectUUID()); |
|
|
|
calculateWeights(); |
|
return true; |
|
} |
|
|
|
public synchronized boolean consume(Item i) { |
|
i.decrementChargesRemaining(); |
|
if (i.getChargesRemaining() > 0) |
|
return true; |
|
return junk(i, true); |
|
} |
|
|
|
private synchronized boolean junk(Item i, boolean updateInventory) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) { |
|
if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID()) |
|
if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) { |
|
this.getGoldInventory().setNumOfItems(0); |
|
if (updateInventory) |
|
updateInventory(); |
|
return true; |
|
}else{ |
|
return false; |
|
} |
|
if (!(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) |
|
return false; |
|
} |
|
|
|
byte slot = i.getEquipSlot(); |
|
|
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false && this.absCharacter.getObjectType() != GameObjectType.Mob && (i.containerType != Enum.ItemContainerType.FORGE)) |
|
return false; |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
this.itemIDtoType.remove(i.getObjectUUID()); |
|
|
|
i.junk(); |
|
|
|
//Why are we adding junked items?! |
|
|
|
// if (i.getObjectType() != GameObjectType.MobLoot) |
|
// CharacterItemManager.junkedItems.add(i); |
|
|
|
|
|
calculateWeights(); |
|
|
|
if (updateInventory) |
|
// Send the new inventory |
|
//updateInventory(i, false); this line was causing entire inventory to disappear |
|
updateInventory(this.getInventory(), true); |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean moveItemToInventory(Item i) { |
|
|
|
boolean fromEquip = false; |
|
synchronized (this) { |
|
byte slot = i.getEquipSlot(); |
|
|
|
//Skip if NOT in vault. |
|
if (i.containerType != Enum.ItemContainerType.VAULT) |
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
return false; |
|
|
|
// Only valid from bank, equip and vault |
|
if (!bankContains(i) && !equippedContains(i) && !vaultContains(i)) |
|
return false; |
|
|
|
if (equippedContains(i)) { |
|
fromEquip = true; |
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null && ib.getType().equals(ItemType.GOLD)) |
|
this.absCharacter.cancelOnUnEquip(); |
|
} |
|
|
|
// check to see what type of AbstractCharacter subclass we have stored |
|
if (this.absCharacter.getClass() == PlayerCharacter.class) { |
|
if (!i.moveItemToInventory((PlayerCharacter) this.absCharacter)) |
|
return false; |
|
} else if (!i.moveItemToInventory((NPC) this.absCharacter)) |
|
return false; |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
|
|
// add to Inventory |
|
this.inventory.add(i); |
|
i.addToCache(); |
|
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); |
|
|
|
calculateWeights(); |
|
} |
|
|
|
//Apply bonuses if from equip |
|
if (fromEquip && this.absCharacter != null) { |
|
this.absCharacter.applyBonuses(); |
|
if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
this.absCharacter.incVer(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean moveItemToBank(Item i) { |
|
byte slot = i.getEquipSlot(); |
|
|
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
return false; |
|
|
|
// Item must be in inventory to move to bank |
|
if (!this.inventory.contains(i)) |
|
return false; |
|
|
|
// check to see what type of AbstractCharacter subclass we have stored |
|
if (this.absCharacter.getClass() == PlayerCharacter.class) { |
|
if (!i.moveItemToBank((PlayerCharacter) this.absCharacter)) |
|
return false; |
|
} else if (!i.moveItemToBank((NPC) this.absCharacter)) |
|
return false; |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
|
|
// add to Bank |
|
this.bank.add(i); |
|
i.addToCache(); |
|
|
|
calculateWeights(); |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean moveGoldToBank(Item from, int amt) { |
|
if (from == null) |
|
return false; |
|
if (from.getNumOfItems() - amt < 0) |
|
return false; |
|
if (this.goldBank.getNumOfItems() + amt > MBServerStatics.BANK_GOLD_LIMIT){ |
|
if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter){ |
|
PlayerCharacter pc = (PlayerCharacter)this.absCharacter; |
|
if (pc.getClientConnection() != null) |
|
ErrorPopupMsg.sendErrorPopup(pc, 202); |
|
return false; |
|
} |
|
} |
|
|
|
if (!DbManager.ItemQueries.MOVE_GOLD(from, this.getGoldBank(), amt)) |
|
return false; |
|
from.setNumOfItems(from.getNumOfItems() - amt); |
|
this.goldBank.setNumOfItems(this.goldBank.getNumOfItems() + amt); |
|
return true; |
|
} |
|
|
|
public synchronized boolean moveGoldToVault(Item from, int amt) { |
|
if (from == null) |
|
return false; |
|
if (from.getNumOfItems() - amt < 0) |
|
return false; |
|
if (!DbManager.ItemQueries.MOVE_GOLD(from, this.account.vaultGold, amt)) |
|
return false; |
|
from.setNumOfItems(from.getNumOfItems() - amt); |
|
this.account.vaultGold.setNumOfItems(this.goldVault.getNumOfItems() + amt); |
|
return true; |
|
} |
|
|
|
public synchronized boolean moveGoldToInventory(Item from, int amt) { |
|
if (from == null) |
|
return false; |
|
if (from.getNumOfItems() - amt < 0 || amt < 1) |
|
return false; |
|
|
|
if (this.goldInventory.getNumOfItems() + amt > MBServerStatics.PLAYER_GOLD_LIMIT){ |
|
if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter){ |
|
PlayerCharacter pc = (PlayerCharacter)this.absCharacter; |
|
if (pc.getClientConnection() != null) |
|
ErrorPopupMsg.sendErrorPopup(pc, 202); |
|
return false; |
|
} |
|
} |
|
|
|
if (from instanceof MobLoot) { |
|
if (!DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), |
|
this.goldInventory.getNumOfItems() + amt)) |
|
return false; |
|
} else if (!DbManager.ItemQueries.MOVE_GOLD(from, this.goldInventory, amt)) |
|
return false; |
|
from.setNumOfItems(from.getNumOfItems() - amt); |
|
this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + amt); |
|
return true; |
|
} |
|
|
|
//This is called by the addGold devCmd. |
|
public synchronized boolean addGoldToInventory(int amt, boolean fromDevCmd) { |
|
|
|
if (this.absCharacter == null || (!(this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)))) |
|
return false; |
|
|
|
if (this.getGoldInventory().getNumOfItems() + amt > MBServerStatics.PLAYER_GOLD_LIMIT){ |
|
return false; |
|
} |
|
|
|
if (this.getGoldInventory().getNumOfItems() + amt < 0) |
|
return false; |
|
|
|
|
|
boolean worked = DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + amt); |
|
if (worked) { |
|
//log this since it's technically a dupe. Only use on test server! |
|
if (fromDevCmd) { |
|
String logString = this.absCharacter.getName() + " added " + amt + " gold to their inventory"; |
|
Logger.info(logString); |
|
} |
|
this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + amt); |
|
} |
|
return worked; |
|
} |
|
|
|
//Used to trainsfer gold from one inventory to another, for steal, etc. |
|
public boolean transferGoldToMyInventory(AbstractCharacter tar, int amount) { |
|
if (tar == null) |
|
return false; |
|
|
|
CharacterItemManager tarCim = tar.getCharItemManager(); |
|
if (tarCim == null) |
|
return false; |
|
|
|
if (this.getGoldInventory().getNumOfItems() + amount < 0) |
|
return false; |
|
|
|
if (this.getGoldInventory().getNumOfItems() + amount > MBServerStatics.PLAYER_GOLD_LIMIT) |
|
return false; |
|
|
|
if (tarCim.getGoldInventory().getNumOfItems() -amount < 0) |
|
return false; |
|
|
|
if (tarCim.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT) |
|
return false; |
|
|
|
synchronized (this) { |
|
synchronized (tarCim) { |
|
if (!tarCim.addGoldToInventory(0 - amount, false)) //remove gold from target |
|
return false; |
|
if (!addGoldToInventory(amount, false)) //add to this inventory |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
public synchronized boolean moveItemToVault(Item i) { |
|
byte slot = i.getEquipSlot(); |
|
|
|
// if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
// return false; |
|
|
|
// Item must be in inventory to move to vault |
|
if (!this.inventory.contains(i)) |
|
return false; |
|
|
|
// check to see what type of AbstractCharacter subclass we have stored |
|
if (this.absCharacter.getClass() == PlayerCharacter.class) { |
|
if (!i.moveItemToVault(this.account)) |
|
return false; |
|
} else |
|
return false; // NPC's dont have vaults! |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
|
|
// add to Vault |
|
i.addToCache(); |
|
|
|
calculateWeights(); |
|
|
|
return true; |
|
} |
|
|
|
// This removes ingame item from inventory for loot. |
|
private synchronized boolean removeItemFromInventory(Item i) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) { |
|
if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID()) |
|
return false; |
|
if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)){ |
|
return false; |
|
} |
|
|
|
} else { |
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
return false; |
|
if (this.inventory.contains(i)) { |
|
this.inventory.remove(i); |
|
this.itemIDtoType.remove(i.getObjectUUID()); |
|
return true; |
|
} |
|
} |
|
// tell client we're removing item |
|
updateInventory(i, false); |
|
return false; |
|
} |
|
|
|
// This adds item to inventory for loot. Validity checks already handled |
|
public synchronized boolean addItemToInventory(Item i) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
if (this.absCharacter.getObjectType() == GameObjectType.Mob) { |
|
if (this.goldInventory == null) |
|
loadGoldItems(); |
|
this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + i.getNumOfItems()); |
|
} else { |
|
int amt = i.getNumOfItems(); |
|
if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, this.goldInventory.getNumOfItems() + amt)) { |
|
updateInventory(); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
this.inventory.add(i); |
|
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); |
|
|
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null) |
|
this.inventoryWeight += ib.getWeight(); |
|
return true; |
|
} |
|
|
|
|
|
|
|
//called for adding gold of a specified amount |
|
public synchronized boolean addItemToInventory(Item i, int amount) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
return DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + amount); |
|
return false; |
|
} |
|
|
|
public boolean equipItem(Item i, byte slot) { |
|
|
|
synchronized (this) { |
|
byte curSlot = i.getEquipSlot(); // Should be 0 |
|
|
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false && this.absCharacter.getObjectType() != GameObjectType.Mob) { |
|
Logger.error("Doesnt own item"); |
|
return false; |
|
} |
|
|
|
// Item must be in inventory to equip |
|
if (!this.inventory.contains(i) && this.absCharacter.getObjectType() != GameObjectType.Mob) |
|
return false; |
|
|
|
// make sure player can equip item |
|
if (i.getItemBase() == null) |
|
return false; |
|
if (!i.getItemBase().canEquip(slot, this, absCharacter, i) && this.absCharacter.getObjectType() != GameObjectType.Mob) |
|
return false; |
|
|
|
// check to see if item is already there. |
|
Item old = this.equipped.get((int) slot); |
|
if (old != null) { |
|
Logger.error( "already equipped"); |
|
return false; |
|
} |
|
|
|
// check to see what type of AbstractCharacter subclass we have stored |
|
if (this.absCharacter.getClass() == PlayerCharacter.class) { |
|
if (!i.equipItem((PlayerCharacter) this.absCharacter, slot)) |
|
return false; |
|
} else if (this.absCharacter.getObjectType() == GameObjectType.Mob) { |
|
if (!i.equipItem((Mob) this.absCharacter, slot)) { |
|
Logger.error("Failed to set Equip"); |
|
return false; |
|
} |
|
|
|
} else if (!i.equipItem((NPC) this.absCharacter, slot)) |
|
return false; |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(i, slot); |
|
|
|
// add to Equipped |
|
this.equipped.put((int) slot, i); |
|
i.addToCache(); |
|
|
|
addEquipOrder(i.getEquipSlot()); |
|
|
|
//calculateWeights(); |
|
} |
|
|
|
//Apply Bonuses and update player |
|
if (this.absCharacter != null) { |
|
this.absCharacter.applyBonuses(); |
|
if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
this.absCharacter.incVer(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//Used for buying MobEquipment from NPC |
|
//Handles the gold transfer aspect |
|
|
|
public synchronized boolean buyFromNPC(Building vendorBuilding, int cost,int buildingDeposit) { |
|
|
|
Item gold = this.getGoldInventory(); |
|
|
|
if (cost <= 0 || (gold.getNumOfItems() - cost) < 0) |
|
return false; |
|
|
|
|
|
if (this.getOwner() != null && this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)){ |
|
if (this.goldTradingAmount > 0){ |
|
ErrorPopupMsg.sendErrorPopup((PlayerCharacter)this.getOwner(), 195); |
|
return false; |
|
} |
|
} |
|
|
|
// Create gold from screatch instead of building strongbox |
|
// if the NPC is not slotted. |
|
|
|
if (vendorBuilding == null) { |
|
|
|
return this.modifyInventoryGold(-cost); |
|
} |
|
|
|
|
|
if (vendorBuilding.getStrongboxValue() + cost > vendorBuilding.getMaxGold()){ |
|
|
|
if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter){ |
|
PlayerCharacter pc = (PlayerCharacter)this.absCharacter; |
|
if (pc.getClientConnection() != null) |
|
ErrorPopupMsg.sendErrorPopup(pc, 206); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
// Update strongbox and inventory gold |
|
if (!this.modifyInventoryGold(-cost)) |
|
return false; |
|
|
|
City buildingCity = vendorBuilding.getCity(); |
|
|
|
if (buildingCity != null){ |
|
buildingCity.transactionLock.writeLock().lock(); |
|
try{ |
|
if (!vendorBuilding.transferGold(buildingDeposit, true)) |
|
return false; |
|
}catch(Exception e){ |
|
Logger.error(e); |
|
return false; |
|
}finally{ |
|
buildingCity.transactionLock.writeLock().unlock(); |
|
} |
|
}else |
|
if (!vendorBuilding.transferGold(buildingDeposit, true)) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
//Used for selling items to NPC |
|
public synchronized boolean sellToNPC(Building building, int cost, Item item) { |
|
|
|
// Create gold from screatch instead of building strongbox |
|
// if the NPC is not slotted. |
|
|
|
if (this.getGoldInventory().getNumOfItems() + cost < 0) |
|
return false; |
|
|
|
if (this.getGoldInventory().getNumOfItems() + cost > MBServerStatics.PLAYER_GOLD_LIMIT) |
|
return false; |
|
|
|
|
|
if (this.getOwner().getCharItemManager().getGoldTrading() > 0){ |
|
if (this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
ErrorPopupMsg.sendErrorPopup((PlayerCharacter)this.getOwner(), 195); |
|
return false; |
|
} |
|
|
|
|
|
if (building == null) { |
|
return this.modifyInventoryGold(cost); |
|
} |
|
|
|
//make sure strongbox can afford gold. |
|
|
|
if (!building.hasFunds(cost)) |
|
return false; |
|
|
|
if ((building.getStrongboxValue() - cost) < 0) |
|
return false; |
|
|
|
// Update strongbox and inventory gold |
|
|
|
if (!building.transferGold(-cost,false)) |
|
return false; |
|
|
|
return this.modifyInventoryGold(cost); |
|
} |
|
|
|
/** |
|
* This sells an item to an npc |
|
* |
|
* @return True on success |
|
*/ |
|
public synchronized boolean sellToNPC(Item itemToSell, NPC npc) { |
|
|
|
CharacterItemManager itemMan; |
|
|
|
if (itemToSell == null || npc == null) |
|
return false; |
|
|
|
itemMan = npc.getCharItemManager(); |
|
|
|
if (itemMan == null) |
|
return false; |
|
|
|
//test npc inventory is not full |
|
|
|
synchronized (this) { |
|
synchronized (itemMan) { |
|
if (!this.doesCharOwnThisItem(itemToSell.getObjectUUID())) |
|
return false; |
|
// attempt to transfer item in db |
|
|
|
boolean sdrMerchant = false; |
|
|
|
if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906) |
|
sdrMerchant = true; |
|
|
|
if (sdrMerchant){ |
|
this.delete(itemToSell); |
|
this.updateInventory(); |
|
|
|
}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. |
|
if(!sdrMerchant) |
|
if (!itemMan.addItemToInventory(itemToSell)) |
|
return false; |
|
} |
|
} |
|
|
|
// calculate new weights |
|
calculateInventoryWeight(); |
|
itemMan.calculateInventoryWeight(); |
|
return true; |
|
} |
|
|
|
/** |
|
* This buys an item from an npc |
|
* Handles transfer of item. |
|
* |
|
* @return True on success |
|
*/ |
|
public synchronized boolean buyFromNPC(Item purchasedItem, NPC npc) { |
|
|
|
CharacterItemManager itemMan; |
|
ItemBase itemBase; |
|
|
|
if (purchasedItem == null || npc == null) |
|
return false; |
|
|
|
itemMan = npc.getCharItemManager(); |
|
|
|
if (itemMan == null) |
|
return false; |
|
|
|
|
|
|
|
synchronized (this) { |
|
synchronized (itemMan) { |
|
itemBase = purchasedItem.getItemBase(); |
|
|
|
if (itemBase == null) |
|
return false; |
|
|
|
//test inventory is not full |
|
|
|
if (!hasRoomInventory(itemBase.getWeight())) |
|
return false; |
|
|
|
if (!itemMan.inventory.contains(purchasedItem)) |
|
return false; |
|
// attempt to transfer item in db |
|
|
|
if (purchasedItem.getObjectType() == GameObjectType.MobLoot){ |
|
|
|
Item newItem = ((MobLoot) purchasedItem).promoteToItem((PlayerCharacter)this.absCharacter); |
|
if (newItem == null) |
|
return false; |
|
|
|
if (!itemMan.removeItemFromInventory(purchasedItem)) |
|
return false; |
|
|
|
if (!addItemToInventory(newItem)) |
|
return false; |
|
//Item was created and still a mobloot item, remove from npc production list in db. |
|
|
|
DbManager.NPCQueries.REMOVE_FROM_PRODUCTION_LIST(purchasedItem.getObjectUUID(),npc.getObjectUUID()); |
|
|
|
|
|
}else{ |
|
if (!purchasedItem.moveItemToInventory((PlayerCharacter) this.absCharacter)) |
|
return false; |
|
|
|
if (purchasedItem.getValue() != purchasedItem.getMagicValue()){ |
|
DbManager.ItemQueries.UPDATE_VALUE(purchasedItem,0); |
|
purchasedItem.setValue(0); |
|
} |
|
|
|
// db transfer successfull, remove from this character |
|
// skip this check if this is a mobLoot item (which is not in any inventory) |
|
if (!itemMan.removeItemFromInventory(purchasedItem)) |
|
return false; |
|
|
|
// add item to looter. |
|
|
|
if (!addItemToInventory(purchasedItem)) |
|
return false; |
|
} |
|
|
|
} |
|
} |
|
|
|
// calculate new weights |
|
calculateInventoryWeight(); |
|
itemMan.calculateInventoryWeight(); |
|
return true; |
|
} |
|
|
|
/** |
|
* Loot an item from an AbstractCharacter. Call this function on |
|
* the CharacterItemManager of the current item owner, not the looter. |
|
* This method will verify that the looter can receive the item |
|
* (e.g. inventory isn't full). |
|
* |
|
* @param i Item being looted |
|
* @param looter Player looting the item |
|
* @param origin ClientConnection |
|
* @return True on success |
|
*/ |
|
public synchronized Item lootItemFromMe(Item i, PlayerCharacter looter, ClientConnection origin) { |
|
return lootItemFromMe(i, looter, origin, false, -1); |
|
} |
|
|
|
//This function is used for both looting and stealing |
|
public synchronized Item lootItemFromMe(Item lootItem, PlayerCharacter lootingPlayer, ClientConnection origin, boolean fromSteal, int amount) { |
|
|
|
//TODO this function should have more logging |
|
// make sure lootingPlayer exists |
|
if (lootingPlayer == null) |
|
return null; |
|
|
|
// get looters item manager |
|
CharacterItemManager looterItems = lootingPlayer.getCharItemManager(); |
|
|
|
if (looterItems == null) |
|
return null; |
|
|
|
if (fromSteal) { |
|
if (!this.absCharacter.isAlive()) |
|
return null; |
|
} else if (!this.absCharacter.canBeLooted()) |
|
return null; |
|
|
|
MobLoot mobLoot = null; |
|
if (lootItem instanceof MobLoot) { |
|
mobLoot = (MobLoot) lootItem; |
|
if (mobLoot.isDeleted()) |
|
return null; |
|
} |
|
|
|
//Lock both ItemManagers; lower ID first |
|
CharacterItemManager lockFirst; |
|
CharacterItemManager lockSecond; |
|
if (this.absCharacter.getObjectUUID() |
|
< looterItems.absCharacter.getObjectUUID()) { |
|
lockFirst = this; |
|
lockSecond = looterItems; |
|
} else { |
|
lockFirst = looterItems; |
|
lockSecond = this; |
|
} |
|
|
|
synchronized (lockFirst) { |
|
synchronized (lockSecond) { |
|
// make sure current player has item in inventory |
|
if (lootItem.getItemBase().getType().equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) |
|
return null; |
|
else if (!this.inventory.contains(lootItem) && !this.getEquippedList().contains(lootItem) && !lootItem.getItemBase().getType().equals(ItemType.GOLD)) |
|
return null; |
|
|
|
// get weight of item |
|
ItemBase ib = lootItem.getItemBase(); |
|
if (ib == null) |
|
return null; |
|
short weight = ib.getWeight(); |
|
|
|
// make sure lootingPlayer has room for item |
|
if (!lootItem.getItemBase().getType().equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight)) |
|
return null; |
|
|
|
if (lootItem.getItemBase().getType().equals(ItemType.GOLD)) |
|
if (amount != -1) { //from steal |
|
int total = lootItem.getNumOfItems(); |
|
amount = (amount > total) ? total : amount; |
|
if (!looterItems.moveGoldToInventory(lootItem, amount)) |
|
return null; |
|
if (mobLoot != null && amount == total) |
|
this.delete(mobLoot); |
|
} else { //from loot |
|
if (!looterItems.moveGoldToInventory(lootItem, lootItem.getNumOfItems())) |
|
return null; |
|
if (mobLoot != null) // delete mobloot after it has been looted |
|
this.delete(mobLoot); |
|
} |
|
else { //not Gold item |
|
boolean created = false; |
|
if (mobLoot != null) { |
|
lootItem = mobLoot.promoteToItem(lootingPlayer); |
|
|
|
// delete mobloot after it has been looted |
|
this.delete(mobLoot); |
|
if (lootItem == null) |
|
return null; |
|
|
|
created = true; |
|
} |
|
|
|
// attempt to transfer item in db |
|
|
|
if (!lootItem.moveItemToInventory(lootingPlayer)) |
|
return null; |
|
|
|
// db transfer successfull, remove from this character |
|
// skip this check if this is a mobLoot item (which is not in any inventory) |
|
if (mobLoot == null) |
|
if (!removeItemFromInventory(lootItem)) |
|
return null; |
|
|
|
// add item to lootingPlayer. |
|
if (!looterItems.addItemToInventory(lootItem)) |
|
return null; |
|
} |
|
} |
|
} |
|
|
|
// calculate new weights |
|
calculateInventoryWeight(); |
|
looterItems.calculateInventoryWeight(); |
|
|
|
return lootItem; |
|
} |
|
|
|
private synchronized void remItemFromLists(Item i, byte slot) { |
|
|
|
this.equipped.remove((int) slot); |
|
this.vault.remove(i); |
|
this.bank.remove(i); |
|
this.inventory.remove(i); |
|
} |
|
|
|
/* |
|
* Delegates |
|
*/ |
|
public synchronized boolean bankContains(Item i) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == i.getObjectUUID()); |
|
return bank.contains(i); |
|
} |
|
|
|
|
|
public synchronized boolean inventoryContains(Item i) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == i.getObjectUUID()); |
|
return inventory.contains(i); |
|
} |
|
|
|
public synchronized boolean forgeContains(Item i,NPC vendor) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == i.getObjectUUID()); |
|
return vendor.getRolling().contains(i); |
|
} |
|
|
|
|
|
|
|
public synchronized boolean vaultContains(Item i) { |
|
if (i.getItemBase().getType().equals(ItemType.GOLD)) |
|
return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == i.getObjectUUID()); |
|
return this.account.getVault().contains(i); |
|
} |
|
|
|
public synchronized boolean vaultContainsType(ItemBase ib) { |
|
if (ib.getUUID() == 7) |
|
return (this.getGoldVault() != null); |
|
for (Item i : vault) { |
|
if (i.getItemBase().getUUID() == ib.getUUID()) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
//for calling from devCmd fill vault. Already synchronized |
|
public boolean vaultContainsTypeA(ItemBase ib) { |
|
if (ib.getUUID() == 7) |
|
return (this.getGoldVault() != null); |
|
for (Item i : vault) { |
|
if (i.getItemBase().getUUID() == ib.getUUID()) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
public synchronized boolean equippedContains(Item i) { |
|
return equipped.containsValue(i); |
|
} |
|
|
|
public synchronized Item getItemFromEquipped(int slot) { |
|
return equipped.get(slot); |
|
} |
|
|
|
public synchronized Item getItemByUUID(int objectUUID) { |
|
if (this.itemIDtoType.containsKey(objectUUID)){ |
|
|
|
Integer integer = this.itemIDtoType.get(objectUUID); |
|
if (integer == GameObjectType.Item.ordinal()) { |
|
return Item.getFromCache(objectUUID); |
|
} else if (integer == GameObjectType.MobLoot.ordinal()) { |
|
return MobLoot.getFromCache(objectUUID); |
|
} |
|
|
|
} |
|
|
|
if (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == objectUUID) |
|
return this.goldInventory; |
|
if (this.getGoldBank() != null && this.goldBank.getObjectUUID() == objectUUID) |
|
return this.goldBank; |
|
if (this.getGoldVault() != null && this.goldVault.getObjectUUID() == objectUUID) |
|
return this.goldVault; |
|
return null; |
|
} |
|
|
|
public boolean tradingContains(Item i) { |
|
if (this.trading == null || i == null) |
|
return false; |
|
return this.trading.contains(i.getObjectUUID()); |
|
} |
|
|
|
public boolean isBankOpen() { |
|
return this.bankOpened; |
|
} |
|
|
|
public synchronized void setBankOpen(boolean bankOpened) { |
|
this.bankOpened = bankOpened; |
|
} |
|
|
|
public boolean isVaultOpen() { |
|
return this.vaultOpened; |
|
} |
|
|
|
public synchronized void setVaultOpen(boolean vaultOpened) { |
|
this.vaultOpened = vaultOpened; |
|
} |
|
|
|
public ClientConnection getTradingWith() { |
|
return tradingWith; |
|
} |
|
|
|
public synchronized void setTradingWith(ClientConnection tradingWith) { |
|
this.tradingWith = tradingWith; |
|
} |
|
|
|
public synchronized void clearTradingWith() { |
|
this.tradingWith = null; |
|
} |
|
|
|
public int getGoldTrading() { |
|
return goldTradingAmount; |
|
} |
|
|
|
public synchronized void setTradeCommitted(byte tradeCommitted) { |
|
this.tradeCommitted = tradeCommitted; |
|
} |
|
|
|
public byte getTradeCommitted() { |
|
return tradeCommitted; |
|
} |
|
|
|
public HashSet<Integer> getTrading() { |
|
return trading; |
|
} |
|
|
|
|
|
public synchronized void addItemToTrade(Item i) { |
|
this.trading.add(i.getObjectUUID()); |
|
} |
|
|
|
|
|
public synchronized void setTradeSuccess(boolean tradeSuccess) { |
|
this.tradeSuccess = tradeSuccess; |
|
} |
|
|
|
public boolean getTradeSuccess() { |
|
return tradeSuccess; |
|
} |
|
|
|
|
|
public synchronized boolean RemoveEquipmentFromLackOfSkill(PlayerCharacter pc, boolean initialized) { |
|
|
|
|
|
if (pc == null) |
|
return false; |
|
|
|
if (this.equipped == null) |
|
return false; |
|
|
|
|
|
for (int slot : this.equipped.keySet()) { |
|
|
|
if (slot == MBServerStatics.SLOT_HAIRSTYLE || slot == MBServerStatics.SLOT_BEARDSTYLE) |
|
continue; |
|
|
|
Item item = this.equipped.get(slot); |
|
|
|
if (item == null){ |
|
this.equipped.remove(slot); |
|
pc.applyBonuses(); |
|
continue; |
|
} |
|
|
|
if (!item.getItemBase().validForSkills(pc.getSkills())){ |
|
this.forceToInventory(slot, item, pc, initialized); |
|
pc.applyBonuses(); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/* |
|
* List Copiers |
|
*/ |
|
/** |
|
* Note that this method returns a <b>copy</b> of the internally stored |
|
* list. |
|
* |
|
* @return the equipped |
|
*/ |
|
public ConcurrentHashMap<Integer, Item> getEquipped() { |
|
synchronized (this.equipped) { |
|
return new ConcurrentHashMap<>(this.equipped); |
|
} |
|
} |
|
|
|
public ArrayList<Item> getEquippedList() { |
|
ArrayList<Item> ret = new ArrayList<>(); |
|
synchronized (this.equipOrder) { |
|
synchronized (this.equipped) { |
|
for (int slot : this.equipOrder) { |
|
if (this.equipped.containsKey(slot)) |
|
ret.add(this.equipped.get(slot)); |
|
} |
|
if (ret.size() != this.equipped.size()) |
|
//missed adding some items, figure out what. |
|
for (int slot : this.equipped.keySet()) { |
|
if (!(this.equipOrder.contains(slot))) { |
|
this.equipOrder.add(slot); |
|
ret.add(this.equipped.get(slot)); |
|
} |
|
} |
|
} |
|
} |
|
return ret; |
|
} |
|
|
|
public Item getEquipped(int slot) { |
|
synchronized (this.equipped) { |
|
return this.equipped.get(slot); |
|
} |
|
} |
|
|
|
/** |
|
* Note that this method returns a <b>copy</b> of the internally stored |
|
* list. |
|
* |
|
* @return the inventory |
|
*/ |
|
public ArrayList<Item> getInventory() { |
|
return getInventory(false); |
|
} |
|
|
|
public ArrayList<Item> getInventory(boolean sendGold) { |
|
synchronized (this.inventory) { |
|
ArrayList<Item> ret = new ArrayList<>(this.inventory); |
|
if (sendGold && this.getGoldInventory() != null && this.goldInventory.getNumOfItems() > 0) |
|
ret.add(this.goldInventory); |
|
return ret; |
|
} |
|
} |
|
|
|
public int getInventoryCount() { |
|
synchronized (this.inventory) { |
|
return this.inventory.size(); |
|
} |
|
} |
|
|
|
/** |
|
* Clears ownership of items. Called when player dies, but before |
|
* respawning. |
|
* |
|
* @return the inventory |
|
*/ |
|
public synchronized void orphanInventory() { |
|
PlayerCharacter pc = null; |
|
if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
pc = (PlayerCharacter) this.absCharacter; |
|
synchronized (this.inventory) { |
|
//dupe check, validate player properly owns all items |
|
if (pc != null) { |
|
Iterator<Item> iter = this.inventory.iterator(); |
|
while (iter.hasNext()) { |
|
Item item = iter.next(); |
|
//this call may remove the item from this.inventory |
|
if (!item.validForInventory(pc.getClientConnection(), pc, this)) { |
|
} |
|
} |
|
} |
|
|
|
if (this.inventory.size() > 0) |
|
DbManager.ItemQueries.ORPHAN_INVENTORY(this.inventory); |
|
//make a copy of gold inventory for looting |
|
//so we don't remove the goldInventory |
|
if (this.getGoldInventory().getNumOfItems() > 0) { |
|
int amt = this.goldInventory.getNumOfItems(); |
|
if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { |
|
this.goldInventory.setNumOfItems(0); |
|
MobLoot gold = new MobLoot(this.absCharacter, amt); |
|
this.inventory.add(gold); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* This transfers the entire inventory to another list For populating |
|
* corpse' inventory when player dies |
|
* |
|
* @return the inventory |
|
*/ |
|
public synchronized void transferEntireInventory( |
|
ArrayList<Item> newInventory, Corpse corpse, boolean enterWorld) { |
|
|
|
PlayerCharacter pc = null; |
|
if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
pc = (PlayerCharacter) this.absCharacter; |
|
|
|
if (this.getGoldInventory().getNumOfItems() > 0) { |
|
int amt = this.goldInventory.getNumOfItems(); |
|
if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { |
|
this.goldInventory.setNumOfItems(0); |
|
MobLoot gold = new MobLoot(this.absCharacter, amt); |
|
newInventory.add(gold); |
|
} |
|
} |
|
|
|
for (Item item : this.inventory) { |
|
if (item != null) |
|
if (item instanceof MobLoot) { |
|
|
|
//MobLoot |
|
item.zeroItem(); |
|
item.containerType = Enum.ItemContainerType.INVENTORY; |
|
|
|
if (item.getItemBase().getType().equals(ItemType.GOLD)) |
|
//only add gold item once |
|
if (!corpse.hasGold()) |
|
corpse.setHasGold(true); |
|
newInventory.add(item); |
|
} else //item |
|
if (item.getItemBase().getType().equals(ItemType.GOLD)) { |
|
int amt = item.getNumOfItems(); |
|
item.setNumOfItems(0); |
|
MobLoot ml = new MobLoot(this.absCharacter, amt); |
|
ml.zeroItem(); |
|
ml.containerType = Enum.ItemContainerType.INVENTORY; |
|
if (!corpse.hasGold()) { |
|
corpse.setHasGold(true); |
|
newInventory.add(ml); |
|
} |
|
} else { |
|
boolean transferred = item.moveItemToInventory(corpse); |
|
if (!transferred) |
|
Logger.error( |
|
"CharItemManager.transferEntireInvetory", |
|
"DB Error, Failed to transfer item " |
|
+ item.getObjectUUID() + " to new owner " |
|
+ corpse.getObjectUUID()); |
|
newInventory.add(item); |
|
|
|
} |
|
} |
|
|
|
// tell client we're clearing inventory |
|
|
|
|
|
// clear the inventory. |
|
this.inventory.clear(); |
|
|
|
//re-calculate inventory weight |
|
calculateInventoryWeight(); |
|
if (!enterWorld) |
|
updateInventory(this.getInventory(), false); |
|
} |
|
|
|
public synchronized void purgeInventory() { |
|
|
|
if (!this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
return; |
|
|
|
if (this.goldInventory != null) |
|
if (this.getGoldInventory().getNumOfItems() > 0) { |
|
if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { |
|
this.goldInventory.setNumOfItems(0); |
|
} |
|
} |
|
|
|
if (this.inventory.size() > 0) |
|
DbManager.ItemQueries.ORPHAN_INVENTORY(this.inventory); |
|
|
|
// clear the inventory. |
|
this.inventory.clear(); |
|
//re-calculate inventory weight |
|
calculateInventoryWeight(); |
|
} |
|
|
|
/** |
|
* Note that this method returns a <b>copy</b> of the internally stored |
|
* list. |
|
* |
|
* @return the bank |
|
*/ |
|
public ArrayList<Item> getBank() { |
|
synchronized (this.bank) { |
|
ArrayList<Item> ret = new ArrayList<>(this.bank); |
|
if (this.getGoldBank() != null && this.goldBank.getNumOfItems() > 0) |
|
ret.add(this.goldBank); |
|
return ret; |
|
} |
|
} |
|
|
|
/** |
|
* Note that this method returns a <b>copy</b> of the internally stored |
|
* list. |
|
* |
|
* @return the vault |
|
*/ |
|
public ArrayList<Item> getVault() { |
|
synchronized (this.vault) { |
|
ArrayList<Item> ret = new ArrayList<>(this.vault); |
|
if (this.getGoldVault() != null && this.goldVault.getNumOfItems() > 0) |
|
ret.add(this.goldVault); |
|
return ret; |
|
} |
|
} |
|
|
|
public boolean hasRoomInventory(short weight) { |
|
if (this.absCharacter == null) |
|
return false; |
|
if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) { |
|
PlayerCharacter pc = (PlayerCharacter) this.absCharacter; |
|
int newWeight = this.getCarriedWeight() + weight; |
|
return newWeight <= (int) pc.statStrBase * 3; |
|
} else if (this.absCharacter.getObjectType() == GameObjectType.NPC){ |
|
int newWeight = this.getCarriedWeight() + weight; |
|
return newWeight <= 1900 + (this.absCharacter.getLevel() * 3); |
|
}else |
|
return true; // npc's need checked |
|
} |
|
|
|
public boolean hasRoomTrade(short itemWeight) { |
|
|
|
PlayerCharacter playerCharacter; |
|
PlayerCharacter tradeCharacter; |
|
|
|
int tradeWeight; |
|
|
|
if (this.absCharacter == null) |
|
return false; |
|
|
|
if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) |
|
return false; |
|
|
|
playerCharacter = (PlayerCharacter) this.absCharacter; |
|
|
|
if ((this.tradingWith == null) || |
|
(this.tradingWith.isConnected() == false)) |
|
return false; |
|
|
|
tradeCharacter = this.tradingWith.getPlayerCharacter(); |
|
|
|
tradeWeight = this.getCarriedWeight() + itemWeight; |
|
tradeWeight = tradeWeight + tradeCharacter.getCharItemManager().getTradingWeight(); |
|
tradeWeight = tradeWeight - this.getTradingWeight(); |
|
|
|
return tradeWeight <= (int) playerCharacter.statStrBase * 3; |
|
} |
|
|
|
public boolean hasRoomBank(short weight) { |
|
if (this.absCharacter == null) |
|
return false; |
|
return weight <= this.absCharacter.getBankCapacityRemaining(); |
|
} |
|
|
|
public boolean hasRoomVault(short weight) { |
|
if (this.absCharacter == null) |
|
return false; |
|
return weight <= this.absCharacter.getVaultCapacityRemaining(); |
|
} |
|
|
|
public int getCarriedWeight() { |
|
return getInventoryWeight() + getEquipWeight(); |
|
} |
|
|
|
public int getInventoryWeight() { |
|
return this.inventoryWeight; |
|
} |
|
|
|
public int getBankWeight() { |
|
return this.bankWeight; |
|
} |
|
|
|
public int getEquipWeight() { |
|
return this.equipWeight; |
|
} |
|
|
|
public int getVaultWeight() { |
|
return this.vaultWeight; |
|
} |
|
|
|
public int getTradingForWeight() { |
|
return calculateTradingForWeight(); |
|
} |
|
|
|
public int getTradingWeight() { |
|
|
|
int weight = 0; |
|
Item item; |
|
|
|
for (int i : this.trading) { |
|
item = Item.getFromCache(i); |
|
|
|
if (item == null) |
|
continue; |
|
|
|
ItemBase ib = item.getItemBase(); |
|
weight += ib.getWeight(); |
|
} |
|
return weight; |
|
} |
|
|
|
public AbstractCharacter getOwner() { |
|
return this.absCharacter; |
|
} |
|
|
|
public void calculateWeights() { |
|
calculateBankWeight(); |
|
calculateInventoryWeight(); |
|
calculateEquipWeight(); |
|
calculateVaultWeight(); |
|
} |
|
|
|
public void calculateBankWeight() { |
|
this.bankWeight = 0; |
|
for (Item i : this.bank) { |
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null) |
|
this.bankWeight += ib.getWeight(); |
|
} |
|
} |
|
|
|
public void calculateEquipWeight() { |
|
this.equipWeight = 0; |
|
Collection<Item> c = this.equipped.values(); |
|
Iterator<Item> it = c.iterator(); |
|
while (it.hasNext()) { |
|
Item i = it.next(); |
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null) |
|
this.equipWeight += ib.getWeight(); |
|
} |
|
} |
|
|
|
public void calculateInventoryWeight() { |
|
this.inventoryWeight = 0; |
|
for (Item i : this.inventory) { |
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null) |
|
this.inventoryWeight += ib.getWeight(); |
|
} |
|
} |
|
|
|
public void calculateVaultWeight() { |
|
this.vaultWeight = 0; |
|
for (Item i : this.vault) { |
|
ItemBase ib = i.getItemBase(); |
|
if (ib != null) |
|
this.vaultWeight += ib.getWeight(); |
|
} |
|
} |
|
|
|
private int calculateTradingForWeight() { |
|
int tradingForWeight = 0; |
|
|
|
return tradingForWeight; |
|
} |
|
|
|
|
|
public void updateInventory(Item item, boolean add) { |
|
ArrayList<Item> list = new ArrayList<>(); |
|
list.add(item); |
|
updateInventory(list, add); |
|
} |
|
|
|
private void updateInventory(ArrayList<Item> inventory, boolean add) { |
|
|
|
if (this.absCharacter == null) |
|
return; |
|
|
|
if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) |
|
return; |
|
|
|
PlayerCharacter pc = (PlayerCharacter) this.absCharacter; |
|
|
|
UpdateInventoryMsg updateInventoryMsg = new UpdateInventoryMsg(inventory, this.getBank(), this.getGoldInventory(), add); |
|
Dispatch dispatch = Dispatch.borrow(pc, updateInventoryMsg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
} |
|
|
|
public void forceToInventory(int slot, Item item, PlayerCharacter pc, boolean initialized) { |
|
if (item == null || pc == null) |
|
return; |
|
|
|
if (!item.moveItemToInventory(pc)) { |
|
//TODO well why did this fail? clean it up |
|
} |
|
|
|
// remove it from other lists: |
|
this.remItemFromLists(item, (byte) slot); |
|
|
|
// add to Inventory |
|
this.inventory.add(item); |
|
item.addToCache(); |
|
|
|
calculateWeights(); |
|
|
|
//Update players with unequipped item |
|
if (initialized) { |
|
TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(pc, slot); |
|
DispatchMessage.dispatchMsgToInterestArea(pc, back, engine.Enum.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); |
|
} |
|
|
|
} |
|
|
|
/** |
|
* Update the player's inventory window by resending the entire contents. |
|
*/ |
|
public void updateInventory() { |
|
this.updateInventory(this.getInventory(), true); |
|
} |
|
|
|
public synchronized void initializeTrade() { |
|
this.trading = new HashSet<>(); |
|
} |
|
|
|
public synchronized boolean commitTrade() { |
|
int goldFrom1 = 0; |
|
int goldFrom2 = 0; |
|
|
|
if (this.getTradingWith() == null || this.getTradingWith().isConnected() == false |
|
|| this.getTradingWith().getPlayerCharacter() == null){ |
|
this.endTrade(); |
|
return false; |
|
} |
|
|
|
|
|
CharacterItemManager tradingWith = this.getTradingWith().getPlayerCharacter().getCharItemManager(); |
|
|
|
if (tradingWith == null) |
|
return false; |
|
|
|
if (this.goldTradingAmount != 0) { |
|
|
|
if (tradingWith.goldInventory == null){ |
|
Logger.error("Null Gold for player " + this.getOwner().getObjectUUID()); |
|
return false; |
|
} |
|
goldFrom1 = this.goldTradingAmount; |
|
} |
|
if (tradingWith.goldTradingAmount != 0) { |
|
|
|
if (this.getGoldInventory() == null){ |
|
Logger.error("Null Gold for player " + this.getOwner().getObjectUUID()); |
|
return false; |
|
} |
|
goldFrom2 = tradingWith.goldTradingAmount; |
|
} |
|
|
|
|
|
if (this.getGoldInventory().getNumOfItems() + goldFrom2 > 10000000){ |
|
PlayerCharacter pc = (PlayerCharacter)this.absCharacter; |
|
if (pc.getClientConnection() != null) |
|
ErrorPopupMsg.sendErrorPopup(pc, 202); |
|
return false; |
|
} |
|
|
|
|
|
if (tradingWith.getGoldInventory().getNumOfItems() + goldFrom1 > 10000000){ |
|
PlayerCharacter pc = (PlayerCharacter)tradingWith.absCharacter; |
|
if (pc.getClientConnection() != null) |
|
ErrorPopupMsg.sendErrorPopup(pc, 202); |
|
return false; |
|
} |
|
|
|
if (this.trading.size() > 0 || tradingWith.trading.size() > 0 || goldFrom1 > 0 || goldFrom2 > 0) { |
|
if (!DbManager.ItemQueries.DO_TRADE(this.trading, tradingWith.trading, this, tradingWith, |
|
this.goldInventory, tradingWith.goldInventory, goldFrom1, goldFrom2)) |
|
return false; |
|
} else |
|
return true; |
|
|
|
for (int i : this.trading) { |
|
Item item = Item.getFromCache(i); |
|
if (item == null) |
|
continue; |
|
this.trade(item); |
|
tradingWith.tradeForItem(item); |
|
} |
|
for (int i : tradingWith.trading) { |
|
Item item = Item.getFromCache(i); |
|
if (item == null) |
|
continue; |
|
tradingWith.trade(item); |
|
this.tradeForItem(item); |
|
} |
|
|
|
//subtract gold your trading from your inventory. |
|
if (this.goldTradingAmount > 0) |
|
this.getGoldInventory().setNumOfItems(this.getGoldInventory().getNumOfItems() - this.goldTradingAmount); |
|
//subtract gold your trading from your inventory. |
|
if (tradingWith.goldTradingAmount > 0) |
|
tradingWith.getGoldInventory().setNumOfItems(tradingWith.getGoldInventory().getNumOfItems() - tradingWith.goldTradingAmount); |
|
|
|
if (tradingWith.goldTradingAmount > 0) |
|
this.getGoldInventory().setNumOfItems(this.goldInventory.getNumOfItems() |
|
+ tradingWith.goldTradingAmount); |
|
if (this.goldTradingAmount > 0) |
|
tradingWith.getGoldInventory().setNumOfItems(tradingWith.goldInventory.getNumOfItems() |
|
+ this.goldTradingAmount); |
|
|
|
this.tradeSuccess = true; |
|
tradingWith.tradeSuccess = true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
public synchronized void endTrade() { |
|
updateInventory(this.getInventory(), true); |
|
this.tradeCommitted = (byte) 0; |
|
this.tradeSuccess = false; |
|
this.tradingWith = null; |
|
this.trading = null; |
|
this.goldTradingAmount = 0; |
|
this.tradeID = 0; |
|
} |
|
|
|
public synchronized void endTrade(boolean fromDeath) { |
|
this.tradeCommitted = (byte) 0; |
|
this.tradeSuccess = false; |
|
this.tradingWith = null; |
|
this.trading = null; |
|
this.goldTradingAmount = 0; |
|
} |
|
|
|
// Remove item from your possession |
|
private synchronized boolean trade(Item i) { |
|
if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) |
|
return false; |
|
|
|
// Only valid from inventory |
|
if (!inventoryContains(i)) |
|
return false; |
|
|
|
// remove from Inventory |
|
this.inventory.remove(i); |
|
this.itemIDtoType.remove(i.getObjectUUID()); |
|
i.setOwnerID(0); |
|
|
|
calculateWeights(); |
|
|
|
return true; |
|
} |
|
|
|
//Damage an equipped item a specified amount |
|
public void damageItem(Item item, int amount) { |
|
if (item == null || amount < 1 || amount > 5) |
|
return; |
|
|
|
//verify the item is equipped by this player |
|
int slot = item.getEquipSlot(); |
|
if (!this.equipped.containsKey(slot)) |
|
return; |
|
Item verify = this.equipped.get(slot); |
|
if (verify == null || item.getObjectUUID() != verify.getObjectUUID()) |
|
return; |
|
|
|
//don't damage noob gear, hair or beards. |
|
if (item.getDurabilityMax() == 0) |
|
return; |
|
|
|
if (!item.isCanDestroy()) |
|
return; |
|
|
|
int dur = (int) item.getDurabilityCurrent(); |
|
if (dur - amount <= 0) { |
|
//destroy the item |
|
junk(item); |
|
|
|
//TODO remove item from the client |
|
//This may not be correct |
|
dur = 0; |
|
} else { |
|
dur -= amount; |
|
if (!DbManager.ItemQueries.SET_DURABILITY(item, dur)) |
|
return; |
|
item.setDurabilityCurrent((short) dur); |
|
|
|
} |
|
|
|
if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) |
|
return; |
|
|
|
//send damage item msg to client |
|
PlayerCharacter pc = (PlayerCharacter) this.absCharacter; |
|
|
|
ItemHealthUpdateMsg itemHealthUpdateMsg = new ItemHealthUpdateMsg(slot, (float) dur); |
|
Dispatch dispatch = Dispatch.borrow(pc, itemHealthUpdateMsg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
} |
|
|
|
//Damage a random piece of armor a specified amount |
|
public void damageRandomArmor(int amount) { |
|
ArrayList<Item> armor = new ArrayList<>(); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_OFFHAND)) { |
|
Item item = this.equipped.get(MBServerStatics.SLOT_OFFHAND); |
|
ItemBase ib = item.getItemBase(); |
|
if (ib.isShield()) |
|
armor.add(item); |
|
} |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_HELMET)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_HELMET)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_CHEST)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_CHEST)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_ARMS)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_ARMS)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_GLOVES)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_GLOVES)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_GLOVES)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_GLOVES)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_LEGGINGS)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_LEGGINGS)); |
|
if (this.equipped.containsKey(MBServerStatics.SLOT_FEET)) |
|
armor.add(this.equipped.get(MBServerStatics.SLOT_FEET)); |
|
|
|
if (armor.isEmpty()) |
|
return; //nothing to damage |
|
|
|
int roll = ThreadLocalRandom.current().nextInt(armor.size()); |
|
damageItem(armor.get(roll), amount); |
|
} |
|
|
|
//Damage all equipped gear a random amount between 1 and 5 |
|
public void damageAllGear() { |
|
for (Item gear : this.equipped.values()) { |
|
damageItem(gear, (ThreadLocalRandom.current().nextInt(5) + 1)); |
|
} |
|
} |
|
|
|
// Add item to your possession |
|
public synchronized boolean tradeForItem(Item i) { |
|
// add to Inventory |
|
this.inventory.add(i); |
|
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); |
|
i.setOwnerID(this.absCharacter.getObjectUUID()); |
|
|
|
calculateWeights(); |
|
|
|
return true; |
|
} |
|
|
|
public synchronized boolean addGoldToTrade(int amount) { |
|
|
|
if (this.goldTradingAmount + amount > MBServerStatics.PLAYER_GOLD_LIMIT) |
|
return false; |
|
|
|
this.goldTradingAmount += amount; |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Completely empties inventory, deleting any items. Use with caution! |
|
*/ |
|
public synchronized void clearInventory() { |
|
this.getGoldInventory().setNumOfItems(0); |
|
Iterator<Item> ii = this.inventory.iterator(); |
|
while (ii.hasNext()) { |
|
Item itm = ii.next(); |
|
ii.remove(); |
|
this.delete(itm); |
|
} |
|
} |
|
|
|
public synchronized void clearEquip() { |
|
|
|
ArrayList<Item> equipCopy = new ArrayList<>(this.getEquippedList()); |
|
Iterator<Item> ii = equipCopy.iterator(); |
|
while (ii.hasNext()) { |
|
Item itm = ii.next(); |
|
this.getEquippedList().remove(itm); |
|
this.delete(itm); |
|
} |
|
} |
|
|
|
public byte getEquipVer() { |
|
return this.equipVer; |
|
} |
|
|
|
public static byte getInventoryVer() { |
|
return inventoryVer; |
|
} |
|
|
|
public static byte getBankVer() { |
|
return bankVer; |
|
} |
|
|
|
public static byte getVaultVer() { |
|
return vaultVer; |
|
} |
|
|
|
public void incEquipVer() { |
|
this.equipVer++; |
|
} |
|
|
|
public void incInventoryVer() { |
|
this.equipVer++; |
|
} |
|
|
|
public void incBankVer() { |
|
this.equipVer++; |
|
} |
|
|
|
public void incVaultVer() { |
|
this.equipVer++; |
|
} |
|
|
|
public static void takeFromNPC(NPC npc, PlayerCharacter pc, Item take, ClientMessagePump clientMessagePump) { |
|
ItemBase ib = take.getItemBase(); |
|
if (ib == null) |
|
return; |
|
CharacterItemManager itemMan = pc.getCharItemManager(); |
|
if (itemMan == null) |
|
return; |
|
CharacterItemManager npcCim = npc.getCharItemManager(); |
|
if (npcCim == null) |
|
return; |
|
if (!npcCim.inventoryContains(take)) { |
|
return; |
|
} |
|
|
|
if (!itemMan.hasRoomInventory(ib.getWeight())) |
|
return; |
|
if (take != null) { |
|
itemMan.buyFromNPC(take, npc); |
|
itemMan.updateInventory(); |
|
} |
|
} |
|
|
|
public int getTradeID() { |
|
return tradeID; |
|
} |
|
|
|
public synchronized boolean closeTradeWindow(){ |
|
if (this.getTradingWith() != null || this.getTradeID() != 0) |
|
this.closeTradeWindow(new CloseTradeWindowMsg(this.getOwner(), this.getTradeID()), true); |
|
return true; |
|
|
|
} |
|
|
|
}
|
|
|