|
|
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
|
|
// Magicbane Emulator Project © 2013 - 2022
|
|
|
|
// www.magicbane.com
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package engine.net.client;
|
|
|
|
|
|
|
|
import engine.Enum.*;
|
|
|
|
import engine.InterestManagement.WorldGrid;
|
|
|
|
import engine.ai.MobileFSM.STATE;
|
|
|
|
import engine.exception.MsgSendException;
|
|
|
|
import engine.gameManager.*;
|
|
|
|
import engine.job.JobContainer;
|
|
|
|
import engine.job.JobScheduler;
|
|
|
|
import engine.jobs.RefreshGroupJob;
|
|
|
|
import engine.jobs.StuckJob;
|
|
|
|
import engine.math.Vector3fImmutable;
|
|
|
|
import engine.net.Dispatch;
|
|
|
|
import engine.net.DispatchMessage;
|
|
|
|
import engine.net.NetMsgHandler;
|
|
|
|
import engine.net.client.handlers.AbstractClientMsgHandler;
|
|
|
|
import engine.net.client.msg.*;
|
|
|
|
import engine.net.client.msg.chat.AbstractChatMsg;
|
|
|
|
import engine.net.client.msg.commands.ClientAdminCommandMsg;
|
|
|
|
import engine.objects.*;
|
|
|
|
import engine.powers.effectmodifiers.AbstractEffectModifier;
|
|
|
|
import engine.server.MBServerStatics;
|
|
|
|
import engine.server.world.WorldServer;
|
|
|
|
import engine.session.Session;
|
|
|
|
import engine.util.StringUtils;
|
|
|
|
import org.pmw.tinylog.Logger;
|
|
|
|
|
|
|
|
import java.sql.SQLException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
|
|
|
|
import static engine.math.FastMath.sqr;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author:
|
|
|
|
* @summary: This class is the mainline router for application protocol
|
|
|
|
* messages received by the client.
|
|
|
|
*/
|
|
|
|
|
|
|
|
public class ClientMessagePump implements NetMsgHandler {
|
|
|
|
|
|
|
|
// Instance variable declaration
|
|
|
|
|
|
|
|
private final WorldServer server;
|
|
|
|
|
|
|
|
public ClientMessagePump(WorldServer server) {
|
|
|
|
super();
|
|
|
|
this.server = server;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incoming client protocol message are processed here
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean handleClientMsg(ClientNetMsg msg) {
|
|
|
|
|
|
|
|
if (msg == null) {
|
|
|
|
Logger.error("handleClientMsg", "Recieved null msg. Returning.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientConnection origin;
|
|
|
|
Protocol protocolMsg = Protocol.NONE;
|
|
|
|
Session s;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
// Try registered opcodes first as we take a hatchet to this GodObject
|
|
|
|
|
|
|
|
AbstractClientMsgHandler msgHandler = msg.getProtocolMsg().handler;
|
|
|
|
|
|
|
|
if (msgHandler != null)
|
|
|
|
return msgHandler.handleNetMsg(msg);
|
|
|
|
|
|
|
|
// Any remaining opcodes fall through and are routed
|
|
|
|
// through this ungodly switch of doom.
|
|
|
|
|
|
|
|
origin = (ClientConnection) msg.getOrigin();
|
|
|
|
s = SessionManager.getSession(origin);
|
|
|
|
|
|
|
|
protocolMsg = msg.getProtocolMsg();
|
|
|
|
|
|
|
|
switch (protocolMsg) {
|
|
|
|
case SETSELECTEDOBECT:
|
|
|
|
ClientMessagePump.targetObject((TargetObjectMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Chat
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Simplify by fall through. Route in ChatManager
|
|
|
|
case CHATSAY:
|
|
|
|
case CHATSHOUT:
|
|
|
|
case CHATTELL:
|
|
|
|
case CHATGUILD:
|
|
|
|
case CHATGROUP:
|
|
|
|
case CHATPVP:
|
|
|
|
case CHATIC:
|
|
|
|
case CHATCITY:
|
|
|
|
case CHATINFO:
|
|
|
|
case SYSTEMBROADCASTCHANNEL:
|
|
|
|
case CHATCSR:
|
|
|
|
case SYSTEMCHANNEL:
|
|
|
|
case GLOBALCHANNELMESSAGE:
|
|
|
|
case LEADERCHANNELMESSAGE:
|
|
|
|
ChatManager.handleChatMsg(s, (AbstractChatMsg) msg);
|
|
|
|
break;
|
|
|
|
case UPDATESTATE:
|
|
|
|
UpdateStateMsg rwss = (UpdateStateMsg) msg;
|
|
|
|
runWalkSitStand(rwss, origin);
|
|
|
|
break;
|
|
|
|
case ACTIVATECHARTER:
|
|
|
|
UseCharterMsg ucm = (UseCharterMsg) msg;
|
|
|
|
ucm.setUnknown02(1);
|
|
|
|
ucm.configure();
|
|
|
|
Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), ucm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
break;
|
|
|
|
case CHECKUNIQUEGUILD:
|
|
|
|
break;
|
|
|
|
case CREATEPETITION:
|
|
|
|
break;
|
|
|
|
case CANCELGUILDCREATION:
|
|
|
|
break;
|
|
|
|
case LEAVEREQUEST:
|
|
|
|
origin.disconnect();
|
|
|
|
break;
|
|
|
|
case POWER:
|
|
|
|
PowersManager.usePower((PerformActionMsg) msg, origin, false);
|
|
|
|
break;
|
|
|
|
case REQUESTMELEEATTACK:
|
|
|
|
CombatManager.setAttackTarget((AttackCmdMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case READYTOENTER:
|
|
|
|
break;
|
|
|
|
case OPENVAULT:
|
|
|
|
break;
|
|
|
|
case WHOREQUEST:
|
|
|
|
WhoRequest((WhoRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case CLIENTADMINCOMMAND:
|
|
|
|
ChatManager.HandleClientAdminCmd((ClientAdminCommandMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case SOCIALCHANNEL:
|
|
|
|
social((SocialMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case COMBATMODE:
|
|
|
|
CombatManager.toggleCombat((ToggleCombatMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCCOMBATMODEATTACKING:
|
|
|
|
CombatManager.toggleCombat((SetCombatModeMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case MODIFYGUILDSTATE:
|
|
|
|
ToggleLfgRecruitingMsg tlrm = (ToggleLfgRecruitingMsg) msg;
|
|
|
|
toggleLfgRecruiting(tlrm, origin);
|
|
|
|
break;
|
|
|
|
case TOGGLESITSTAND:
|
|
|
|
ToggleSitStandMsg tssm = (ToggleSitStandMsg) msg;
|
|
|
|
toggleSitStand(tssm, origin);
|
|
|
|
break;
|
|
|
|
case GUILDTREESTATUS:
|
|
|
|
GuildTreeStatusMsg((GuildTreeStatusMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case CUSTOMERPETITION:
|
|
|
|
Logger.info("CCR Petition received: " + msg.toString());
|
|
|
|
// TODO need to send something back to client
|
|
|
|
// TODO what to do with petition?
|
|
|
|
break;
|
|
|
|
case IGNORE:
|
|
|
|
((IgnoreMsg) msg).handleRequest(origin);
|
|
|
|
break;
|
|
|
|
case UNEQUIP:
|
|
|
|
TransferItemFromEquipToInventory((TransferItemFromEquipToInventoryMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case EQUIP:
|
|
|
|
TransferItemFromInventoryToEquip((TransferItemFromInventoryToEquipMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case DELETEOBJECT:
|
|
|
|
DeleteItem((DeleteItemMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case VIEWRESOURCES:
|
|
|
|
ViewResourcesMessage((ViewResourcesMessage) msg, origin);
|
|
|
|
break;
|
|
|
|
case RAISEATTR:
|
|
|
|
modifyStat((ModifyStatMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case COSTTOOPENBANK:
|
|
|
|
ackBankWindowOpened((AckBankWindowOpenedMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case RESETAFTERDEATH:
|
|
|
|
respawn((RespawnMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case REQUESTCONTENTS:
|
|
|
|
lootWindowRequest((LootWindowRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case MOVEOBJECTTOCONTAINER:
|
|
|
|
loot((LootMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case SHOWCOMBATINFO:
|
|
|
|
show((ShowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRANSFERITEMTOBANK:
|
|
|
|
transferItemFromInventoryToBank((TransferItemFromInventoryToBankMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRANSFERITEMFROMBANK:
|
|
|
|
transferItemFromBankToInventory((TransferItemFromBankToInventoryMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRANSFERITEMFROMVAULTTOINVENTORY:
|
|
|
|
transferItemFromVaultToInventory((TransferItemFromVaultToInventoryMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ITEMTOVAULT:
|
|
|
|
transferItemFromInventoryToVault((TransferItemFromInventoryToVaultMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRANSFERGOLDFROMVAULTTOINVENTORY:
|
|
|
|
transferGoldFromVaultToInventory((TransferGoldFromVaultToInventoryMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case GOLDTOVAULT:
|
|
|
|
transferGoldFromInventoryToVault((TransferGoldFromInventoryToVaultMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case REQUESTTOTRADE:
|
|
|
|
TradeManager.tradeRequest((TradeRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case REQUESTTRADEOK:
|
|
|
|
TradeManager.acceptTradeRequest((AcceptTradeRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case REQUESTTRADECANCEL:
|
|
|
|
TradeManager.rejectTradeRequest((RejectTradeRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRADEADDOBJECT:
|
|
|
|
TradeManager.addItemToTradeWindow((AddItemToTradeWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRADEADDGOLD:
|
|
|
|
TradeManager.addGoldToTradeWindow((AddGoldToTradeWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRADECONFIRM:
|
|
|
|
TradeManager.commitToTrade((CommitToTradeMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRADEUNCONFIRM:
|
|
|
|
TradeManager.uncommitToTrade((UncommitToTradeMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRADECLOSE:
|
|
|
|
TradeManager.closeTradeWindow((CloseTradeWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCREQUESTTRADEBUSY:
|
|
|
|
TradeManager.invalidTradeRequest((InvalidTradeRequestMsg) msg);
|
|
|
|
break;
|
|
|
|
case VENDORDIALOG:
|
|
|
|
VendorDialogMsg.replyDialog((VendorDialogMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case SHOPLIST:
|
|
|
|
openBuyFromNPCWindow((BuyFromNPCWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case BUYFROMNPC:
|
|
|
|
buyFromNPC((BuyFromNPCMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case SHOPINFO:
|
|
|
|
openSellToNPCWindow((SellToNPCWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case SELLOBJECT:
|
|
|
|
sellToNPC((SellToNPCMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case REPAIROBJECT:
|
|
|
|
Repair((RepairMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRAINERLIST:
|
|
|
|
WorldServer.trainerInfo((TrainerInfoMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCUNTRAINLIST:
|
|
|
|
WorldServer.refinerScreen((RefinerScreenMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case TRAINSKILL:
|
|
|
|
TrainMsg.train((TrainMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCUNTRAINABILITY:
|
|
|
|
RefineMsg.refine((RefineMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case POWERTARGNAME:
|
|
|
|
PowersManager.summon((SendSummonsRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCSUMMON:
|
|
|
|
PowersManager.recvSummon((RecvSummonsRequestMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCTRACKINGLIST:
|
|
|
|
PowersManager.trackWindow((TrackWindowMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case STUCK:
|
|
|
|
stuck(origin);
|
|
|
|
break;
|
|
|
|
case RANDOM:
|
|
|
|
ClientMessagePump.randomRoll((RandomMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCPETATTACK:
|
|
|
|
petAttack((PetAttackMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCPETCMD:
|
|
|
|
petCmd((PetCmdMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case MANAGENPC:
|
|
|
|
ManageNPCCmd((ManageNPCMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case ARCPROMPTRECALL:
|
|
|
|
HandlePromptRecall((PromptRecallMsg) msg, origin);
|
|
|
|
break;
|
|
|
|
case CHANNELMUTE:
|
|
|
|
break;
|
|
|
|
case KEEPALIVESERVERCLIENT:
|
|
|
|
break;
|
|
|
|
case UNKNOWN:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONFIRMPROMOTE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
String ocHex = StringUtils.toHexString(protocolMsg.opcode);
|
|
|
|
Logger.error("Cannot handle Opcode: " + ocHex + " " + protocolMsg.name());
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (MsgSendException | SQLException e) {
|
|
|
|
Logger.error("handler for " + protocolMsg + " failed: " + e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// *** Refactor need to figure this out.
|
|
|
|
// Commented out for some reson or another.
|
|
|
|
|
|
|
|
//TODO what is this used for?
|
|
|
|
private void ManageNPCCmd(ManageNPCMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void WhoRequest(WhoRequestMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
// Handle /who request
|
|
|
|
PlayerCharacter pc = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pc.getTimeStamp("WHO") > System.currentTimeMillis()) {
|
|
|
|
ErrorPopupMsg.sendErrorMsg(pc, "Who too fast! Please wait 3 seconds.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WhoResponseMsg.HandleResponse(msg.getSet(), msg.getFilterType(), msg.getFilter(), origin);
|
|
|
|
pc.getTimestamps().put("WHO", System.currentTimeMillis() + 3000);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void runWalkSitStand(UpdateStateMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pc.update();
|
|
|
|
if (msg.getSpeed() == 2)
|
|
|
|
pc.setWalkMode(false);
|
|
|
|
else
|
|
|
|
pc.setWalkMode(true);
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void toggleLfgRecruiting(ToggleLfgRecruitingMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
int num = msg.toggleLfgRecruiting();
|
|
|
|
if (num == 1)
|
|
|
|
pc.toggleLFGroup();
|
|
|
|
else if (num == 2)
|
|
|
|
pc.toggleLFGuild();
|
|
|
|
else if (num == 3)
|
|
|
|
pc.toggleRecruiting();
|
|
|
|
UpdateStateMsg rwss = new UpdateStateMsg();
|
|
|
|
rwss.setPlayer(pc);
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void toggleSitStand(ToggleSitStandMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pc.update();
|
|
|
|
|
|
|
|
pc.setSit(msg.toggleSitStand());
|
|
|
|
|
|
|
|
// cancel effects that break on sit
|
|
|
|
if (pc.isSit()) {
|
|
|
|
pc.setCombat(false);
|
|
|
|
pc.cancelOnSit();
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateStateMsg rwss = new UpdateStateMsg();
|
|
|
|
if (pc.isSit()) {
|
|
|
|
pc.setCombat(false);
|
|
|
|
rwss.setAware(1);
|
|
|
|
}
|
|
|
|
rwss.setPlayer(pc);
|
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void targetObject(TargetObjectMsg msg, ClientConnection origin) {
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// TODO improve this later. hacky way to make sure player ingame is
|
|
|
|
// active.
|
|
|
|
|
|
|
|
if (!pc.isActive())
|
|
|
|
pc.setActive(true);
|
|
|
|
|
|
|
|
pc.setLastTarget(GameObjectType.values()[msg.getTargetType()], msg.getTargetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void social(SocialMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void TransferItemFromEquipToInventory(TransferItemFromEquipToInventoryMsg msg, ClientConnection origin) {
|
|
|
|
PlayerCharacter pc = origin.getPlayerCharacter();
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CharacterItemManager itemManager = pc.getCharItemManager();
|
|
|
|
if (itemManager == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int slot = msg.getSlotNumber();
|
|
|
|
|
|
|
|
Item i = itemManager.getItemFromEquipped(slot);
|
|
|
|
if (i == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!itemManager.doesCharOwnThisItem(i.getObjectUUID()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//dupe check
|
|
|
|
if (!i.validForEquip(origin, pc, itemManager))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (i.containerType == ItemContainerType.EQUIPPED)
|
|
|
|
itemManager.moveItemToInventory(i);
|
|
|
|
|
|
|
|
int ItemType = i.getObjectType().ordinal();
|
|
|
|
int ItemID = i.getObjectUUID();
|
|
|
|
for (String name : i.getEffects().keySet()) {
|
|
|
|
Effect eff = i.getEffects().get(name);
|
|
|
|
if (eff == null)
|
|
|
|
return;
|
|
|
|
ApplyEffectMsg pum = new ApplyEffectMsg();
|
|
|
|
pum.setEffectID(eff.getEffectToken());
|
|
|
|
pum.setSourceType(pc.getObjectType().ordinal());
|
|
|
|
pum.setSourceID(pc.getObjectUUID());
|
|
|
|
pum.setTargetType(pc.getObjectType().ordinal());
|
|
|
|
pum.setTargetID(pc.getObjectUUID());
|
|
|
|
pum.setNumTrains(eff.getTrains());
|
|
|
|
pum.setUnknown05(1);
|
|
|
|
pum.setUnknown02(2);
|
|
|
|
pum.setUnknown06((byte) 1);
|
|
|
|
pum.setEffectSourceType(ItemType);
|
|
|
|
pum.setEffectSourceID(ItemID);
|
|
|
|
pum.setDuration(-1);
|
|
|
|
|
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, pum, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);;
|
|
|
|
|
|
|
|
}
|
|
|
|
// Update player formulas
|
|
|
|
pc.applyBonuses();
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//call this if the transfer fails server side to kick the item back to inventory from equip
|
|
|
|
private void forceTransferFromInventoryToEquip(TransferItemFromEquipToInventoryMsg msg, ClientConnection origin, String reason) {
|
|
|
|
//TODO add this later
|
|
|
|
//PATCHED CODEZZ
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void TransferItemFromInventoryToEquip(TransferItemFromInventoryToEquipMsg msg, ClientConnection origin) {
|
|
|
|
PlayerCharacter pc = origin.getPlayerCharacter();
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CharacterItemManager itemManager = pc.getCharItemManager();
|
|
|
|
if (itemManager == null) {
|
|
|
|
forceTransferFromEquipToInventory(msg, origin, "Can't find your item manager");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int uuid = msg.getUUID();
|
|
|
|
int slot = msg.getSlotNumber();
|
|
|
|
//System.out.println("loading to slot: " + slot);
|
|
|
|
|
|
|
|
Item i = itemManager.getItemByUUID(uuid);
|
|
|
|
|
|
|
|
if (i == null) {
|
|
|
|
forceTransferFromEquipToInventory(msg, origin, "Item not found in your item manager");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemManager.doesCharOwnThisItem(i.getObjectUUID())) {
|
|
|
|
forceTransferFromEquipToInventory(msg, origin, "You do not own this item");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//dupe check
|
|
|
|
if (!i.validForInventory(origin, pc, itemManager))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (i.containerType == ItemContainerType.INVENTORY) {
|
|
|
|
if (!itemManager.equipItem(i, (byte) slot)) {
|
|
|
|
forceTransferFromEquipToInventory(msg, origin, "Failed to transfer item.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
forceTransferFromEquipToInventory(msg, origin, "This item is not in your inventory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update player formulas
|
|
|
|
pc.applyBonuses();
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
|
|
|
|
|
|
|
|
|
|
|
for (String name : i.getEffects().keySet()) {
|
|
|
|
Effect eff = i.getEffects().get(name);
|
|
|
|
if (eff == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ApplyEffectMsg pum = new ApplyEffectMsg();
|
|
|
|
pum.setEffectID(eff.getEffectToken());
|
|
|
|
pum.setSourceType(pc.getObjectType().ordinal());
|
|
|
|
pum.setSourceID(pc.getObjectUUID());
|
|
|
|
pum.setTargetType(pc.getObjectType().ordinal());
|
|
|
|
pum.setTargetID(pc.getObjectUUID());
|
|
|
|
pum.setNumTrains(eff.getTrains());
|
|
|
|
pum.setUnknown05(1);
|
|
|
|
pum.setUnknown06((byte) 1);
|
|
|
|
pum.setEffectSourceType(i.getObjectType().ordinal());
|
|
|
|
pum.setEffectSourceID(i.getObjectUUID());
|
|
|
|
pum.setDuration(-1);
|
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, pum, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//call this if the transfer fails server side to kick the item back to inventory from equip
|
|
|
|
private static void forceTransferFromEquipToInventory(TransferItemFromInventoryToEquipMsg msg, ClientConnection origin, String reason) {
|
|
|
|
|
|
|
|
PlayerCharacter pc = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(pc, msg.getSlotNumber());
|
|
|
|
Dispatch dispatch = Dispatch.borrow(pc, back);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
ChatManager.chatInfoError(pc, "Can't equip item: " + reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean NPCVaultBankRangeCheck(PlayerCharacter pc, ClientConnection origin, String bankorvault) {
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
NPC npc = pc.getLastNPCDialog();
|
|
|
|
|
|
|
|
if (npc == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// System.out.println(npc.getContract().getName());
|
|
|
|
// last npc must be either a banker or vault keeper
|
|
|
|
|
|
|
|
if (bankorvault.equals("vault")) {
|
|
|
|
if (npc.getContract().getContractID() != 861)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// assuming banker
|
|
|
|
|
|
|
|
if (!npc.getContract().getName().equals("Bursar"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (pc.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(pc, 14);
|
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferItemFromInventoryToBank(TransferItemFromInventoryToBankMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!NPCVaultBankRangeCheck(player, origin, "bank"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
CharacterItemManager itemManager = player.getCharItemManager();
|
|
|
|
|
|
|
|
if (itemManager == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (itemManager.getBankWeight() > 500) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(player, 21);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int uuid = msg.getUUID();
|
|
|
|
|
|
|
|
Item item = itemManager.getItemByUUID(uuid);
|
|
|
|
|
|
|
|
if (item == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//dupe check WTF CHECK BUT NO LOGGING?
|
|
|
|
|
|
|
|
if (!item.validForInventory(origin, player, itemManager))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (item.containerType == ItemContainerType.INVENTORY && itemManager.isBankOpen())
|
|
|
|
if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) {
|
|
|
|
if (!itemManager.moveGoldToBank(item, msg.getNumItems()))
|
|
|
|
return;
|
|
|
|
UpdateGoldMsg goldMes = new UpdateGoldMsg(player);
|
|
|
|
goldMes.configure();
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(player, goldMes);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
if (!itemManager.hasRoomBank(item.getItemBase().getWeight()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!itemManager.moveItemToBank(item))
|
|
|
|
return;
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(player, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferItemFromBankToInventory(TransferItemFromBankToInventoryMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!NPCVaultBankRangeCheck(player, origin, "bank"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
CharacterItemManager itemManager = player.getCharItemManager();
|
|
|
|
|
|
|
|
if (itemManager == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int uuid = msg.getUUID();
|
|
|
|
|
|
|
|
Item item = itemManager.getItemByUUID(uuid);
|
|
|
|
|
|
|
|
if (item == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//dupe check
|
|
|
|
// WTF Checking but not logging?
|
|
|
|
|
|
|
|
if (!item.validForBank(origin, player, itemManager))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (item.containerType == ItemContainerType.BANK && itemManager.isBankOpen() == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) {
|
|
|
|
|
|
|
|
if (!itemManager.moveGoldToInventory(item, msg.getNumItems()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
UpdateGoldMsg goldMes = new UpdateGoldMsg(player);
|
|
|
|
goldMes.configure();
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(player, goldMes);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not gold, process update here
|
|
|
|
|
|
|
|
if (!itemManager.hasRoomInventory(item.getItemBase().getWeight()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (itemManager.moveItemToInventory(item) == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(player, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferItemFromVaultToInventory(TransferItemFromVaultToInventoryMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (player.getAccount() == null)
|
|
|
|
return;
|
|
|
|
player.getAccount().transferItemFromVaultToInventory(msg, origin);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//call this if the transfer fails server side to kick the item back to inventory from vault
|
|
|
|
public static void forceTransferFromInventoryToVault(TransferItemFromVaultToInventoryMsg msg, ClientConnection origin, String reason) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TransferItemFromInventoryToVaultMsg back = new TransferItemFromInventoryToVaultMsg(msg);
|
|
|
|
dispatch = Dispatch.borrow(player, back);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
ChatManager.chatInfoError(player, "Can't transfer to inventory: " + reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferItemFromInventoryToVault(TransferItemFromInventoryToVaultMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (player.getAccount() == null)
|
|
|
|
return;
|
|
|
|
player.getAccount().transferItemFromInventoryToVault(msg, origin);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//call this if the transfer fails server side to kick the item back to vault from inventory
|
|
|
|
public static void forceTransferFromVaultToInventory(TransferItemFromInventoryToVaultMsg msg, ClientConnection origin, String reason) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TransferItemFromVaultToInventoryMsg back = new TransferItemFromVaultToInventoryMsg(msg);
|
|
|
|
dispatch = Dispatch.borrow(player, back);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
ChatManager.chatInfoError(player, "Can't transfer to vault: " + reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferGoldFromVaultToInventory(TransferGoldFromVaultToInventoryMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Account account = player.getAccount();
|
|
|
|
|
|
|
|
if (account == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
account.transferGoldFromVaultToInventory(msg, origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void transferGoldFromInventoryToVault(TransferGoldFromInventoryToVaultMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = origin.getPlayerCharacter();
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Account account = player.getAccount();
|
|
|
|
|
|
|
|
if (account == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
account.transferGoldFromInventoryToVault(msg, origin);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void DeleteItem(DeleteItemMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
CharacterItemManager itemManager = origin.getPlayerCharacter().getCharItemManager();
|
|
|
|
int uuid = msg.getUUID();
|
|
|
|
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!sourcePlayer.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item i = Item.getFromCache(msg.getUUID());
|
|
|
|
|
|
|
|
if (i == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!itemManager.doesCharOwnThisItem(i.getObjectUUID()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!itemManager.inventoryContains(i))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (i.isCanDestroy())
|
|
|
|
if (itemManager.delete(i) == true) {
|
|
|
|
Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) {
|
|
|
|
// According to the Wiki, the client should not send this message.
|
|
|
|
// Log the instance to investigate, and modify Wiki accordingly.
|
|
|
|
Logger.error( msg.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void modifyStat(ModifyStatMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int type = msg.getType();
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case MBServerStatics.STAT_STR_ID:
|
|
|
|
pc.addStr(msg.getAmount());
|
|
|
|
break;
|
|
|
|
case MBServerStatics.STAT_DEX_ID:
|
|
|
|
pc.addDex(msg.getAmount());
|
|
|
|
break;
|
|
|
|
case MBServerStatics.STAT_CON_ID:
|
|
|
|
pc.addCon(msg.getAmount());
|
|
|
|
break;
|
|
|
|
case MBServerStatics.STAT_INT_ID:
|
|
|
|
pc.addInt(msg.getAmount());
|
|
|
|
break;
|
|
|
|
case MBServerStatics.STAT_SPI_ID:
|
|
|
|
pc.addSpi(msg.getAmount());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// called when player clicks respawn button
|
|
|
|
private static void respawn(RespawnMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (msg.getObjectType() != sourcePlayer.getObjectType().ordinal() || msg.getObjectID() != sourcePlayer.getObjectUUID()) {
|
|
|
|
Logger.error( "Player " + sourcePlayer.getObjectUUID() + " respawning character of id " + msg.getObjectType() + ' '
|
|
|
|
+ msg.getObjectID());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sourcePlayer.isAlive()) {
|
|
|
|
Logger.error( "Player " + sourcePlayer.getObjectUUID() + " respawning while alive");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ResetAfterDeath player
|
|
|
|
sourcePlayer.respawnLock.writeLock().lock();
|
|
|
|
try{
|
|
|
|
sourcePlayer.respawn(true, false, true);
|
|
|
|
|
|
|
|
}catch(Exception e){
|
|
|
|
Logger.error(e);
|
|
|
|
}finally{
|
|
|
|
sourcePlayer.respawnLock.writeLock().unlock();
|
|
|
|
|
|
|
|
}
|
|
|
|
// Echo ResetAfterDeath message back
|
|
|
|
msg.setPlayerHealth(sourcePlayer.getHealth());
|
|
|
|
// TODO calculate any experience loss before this point
|
|
|
|
msg.setPlayerExp(sourcePlayer.getExp() + sourcePlayer.getOverFlowEXP());
|
|
|
|
Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
|
|
|
|
|
|
|
|
MoveToPointMsg moveMsg = new MoveToPointMsg();
|
|
|
|
moveMsg.setPlayer(sourcePlayer);
|
|
|
|
moveMsg.setStartCoord(sourcePlayer.getLoc());
|
|
|
|
moveMsg.setEndCoord(sourcePlayer.getLoc());
|
|
|
|
moveMsg.setInBuilding(-1);
|
|
|
|
moveMsg.setUnknown01(-1);
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(sourcePlayer, moveMsg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
|
|
|
|
|
|
|
|
MovementManager.sendRWSSMsg(sourcePlayer);
|
|
|
|
|
|
|
|
// refresh the whole group with what just happened
|
|
|
|
JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(sourcePlayer), MBServerStatics.LOAD_OBJECT_DELAY);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void lootWindowRequest(LootWindowRequestMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!pc.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (msg.getSourceType() != pc.getObjectType().ordinal() || msg.getSourceID() != pc.getObjectUUID()) {
|
|
|
|
Logger.error("Player " + pc.getObjectUUID() + " looting from character of id "
|
|
|
|
+ msg.getSourceType() + ' ' + msg.getSourceID());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pc.getAltitude() > 0)
|
|
|
|
return;
|
|
|
|
if (!pc.isAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LootWindowResponseMsg lwrm = null;
|
|
|
|
GameObjectType targetType = GameObjectType.values()[msg.getTargetType()];
|
|
|
|
AbstractCharacter characterTarget = null;
|
|
|
|
Corpse corpseTarget = null;
|
|
|
|
|
|
|
|
switch (targetType) {
|
|
|
|
case PlayerCharacter:
|
|
|
|
|
|
|
|
characterTarget = PlayerCharacter.getFromCache(msg.getTargetID());
|
|
|
|
if (characterTarget == null)
|
|
|
|
return;
|
|
|
|
if (characterTarget.isAlive())
|
|
|
|
return;
|
|
|
|
if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse.");
|
|
|
|
|
|
|
|
Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory(true));
|
|
|
|
break;
|
|
|
|
case NPC:
|
|
|
|
characterTarget = NPC.getFromCache(msg.getTargetID());
|
|
|
|
if (characterTarget == null)
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case Mob:
|
|
|
|
characterTarget = Mob.getFromCache(msg.getTargetID());
|
|
|
|
if ((characterTarget == null) || characterTarget.isAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse.");
|
|
|
|
|
|
|
|
Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." );
|
|
|
|
|
|
|
|
if (!((Mob)characterTarget).isLootSync()){
|
|
|
|
|
|
|
|
((Mob)characterTarget).setLootSync(true);
|
|
|
|
WorldGrid.updateObject(characterTarget, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory());
|
|
|
|
break;
|
|
|
|
case Corpse:
|
|
|
|
corpseTarget = Corpse.getCorpse(msg.getTargetID());
|
|
|
|
|
|
|
|
if ((corpseTarget == null)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pc.getLoc().distanceSquared(corpseTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse.");
|
|
|
|
|
|
|
|
Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lwrm = new LootWindowResponseMsg(corpseTarget.getObjectType().ordinal(), msg.getTargetID(), corpseTarget.getInventory());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lwrm == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
|
|
|
Dispatch dispatch = Dispatch.borrow(pc, lwrm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void loot(LootMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter player = SessionManager.getPlayerCharacter(origin);
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!player.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item item = msg.getItem();
|
|
|
|
|
|
|
|
if (item == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (item.lootLock.tryLock()) {
|
|
|
|
try {
|
|
|
|
Item itemRet = null;
|
|
|
|
// get current owner
|
|
|
|
int targetType = msg.getTargetType();
|
|
|
|
int targetID = msg.getTargetID();
|
|
|
|
|
|
|
|
if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal() || targetType == GameObjectType.Corpse.ordinal()) {
|
|
|
|
}
|
|
|
|
else { //needed for getting contracts for some reason
|
|
|
|
targetType = msg.getSourceID2();
|
|
|
|
targetID = msg.getUnknown01();
|
|
|
|
}
|
|
|
|
|
|
|
|
//can't loot while flying
|
|
|
|
if (player.getAltitude() > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
AbstractCharacter tar = null;
|
|
|
|
Corpse corpse = null;
|
|
|
|
|
|
|
|
if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal()) {
|
|
|
|
|
|
|
|
if (targetType == GameObjectType.PlayerCharacter.ordinal()) {
|
|
|
|
tar = PlayerCharacter.getFromCache(targetID);
|
|
|
|
|
|
|
|
if (tar == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (player.getObjectUUID() != tar.getObjectUUID() && ((PlayerCharacter) tar).isInSafeZone())
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (targetType == GameObjectType.NPC.ordinal())
|
|
|
|
tar = NPC.getFromCache(targetID);
|
|
|
|
else if (targetType == GameObjectType.Mob.ordinal())
|
|
|
|
tar = Mob.getFromCache(targetID);
|
|
|
|
if (tar == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (tar.equals(player)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(player, "Cannot loot this item.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (player.getLoc().distanceSquared2D(tar.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse.");
|
|
|
|
|
|
|
|
Logger.info( player.getFirstName() + " tried looting at " + player.getLoc().distance2D(tar.getLoc()) + " distance." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//can't loot from someone who is alive.
|
|
|
|
if (AbstractWorldObject.IsAbstractCharacter(tar)) {
|
|
|
|
if (tar.isAlive())
|
|
|
|
return;
|
|
|
|
// Logger.error("WorldServer.loot", "Looting from live player");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GroupManager.goldSplit(player, item, origin, tar)) {
|
|
|
|
|
|
|
|
if (tar.getCharItemManager() != null) {
|
|
|
|
|
|
|
|
itemRet = tar.getCharItemManager().lootItemFromMe(item, player, origin);
|
|
|
|
|
|
|
|
//Take equipment off mob
|
|
|
|
if (tar.getObjectType() == GameObjectType.Mob && itemRet != null){
|
|
|
|
Mob mobTarget = (Mob)tar;
|
|
|
|
|
|
|
|
if (item != null && item.getObjectType() == GameObjectType.MobLoot){
|
|
|
|
|
|
|
|
for (MobEquipment equip: mobTarget.getEquip().values()){
|
|
|
|
|
|
|
|
TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(mobTarget, equip.getSlot());
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(mobTarget, back, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
|
|
|
|
|
|
|
LootMsg lootMsg = new LootMsg(0,0,tar.getObjectType().ordinal(), tar.getObjectUUID(), equip);
|
|
|
|
Dispatch dispatch = Dispatch.borrow(player, lootMsg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (targetType == GameObjectType.Corpse.ordinal()) {
|
|
|
|
corpse = Corpse.getCorpse(targetID);
|
|
|
|
if (corpse == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (player.getLoc().distanceSquared2D(corpse.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){
|
|
|
|
ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse.");
|
|
|
|
|
|
|
|
Logger.info( player.getFirstName() + " tried looting at " + player.getLoc().distance2D(corpse.getLoc()) + " distance." );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//can't loot other players in safe zone.
|
|
|
|
if (corpse.getBelongsToType() == GameObjectType.PlayerCharacter.ordinal()){
|
|
|
|
|
|
|
|
if (player.getObjectUUID() == corpse.getBelongsToID())
|
|
|
|
itemRet = corpse.lootItem(item, player);
|
|
|
|
else if (!GroupManager.goldSplit(player, item, origin, corpse)) {
|
|
|
|
itemRet = corpse.lootItem(item, player);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itemRet == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) {
|
|
|
|
// this is done to prevent the temporary goldItem item
|
|
|
|
// (from the mob) from appearing in player's inventory.
|
|
|
|
// It also updates the goldItem quantity display
|
|
|
|
UpdateGoldMsg updateTargetGold = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (corpse != null)
|
|
|
|
updateTargetGold = new UpdateGoldMsg(corpse);
|
|
|
|
|
|
|
|
updateTargetGold.configure();
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(corpse, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
|
|
|
|
|
|
|
UpdateGoldMsg ugm = new UpdateGoldMsg(player);
|
|
|
|
ugm.configure();
|
|
|
|
Dispatch dispatch = Dispatch.borrow(player, ugm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
// respond back loot message. Try sending to everyone.
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(corpse, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true);
|
|
|
|
|
|
|
|
|
|
|
|
//player.getCharItemManager().updateInventory();
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO send group loot message if player is grouped and visible
|
|
|
|
Group group = GroupManager.getGroup(player);
|
|
|
|
|
|
|
|
if (group != null && group.getSplitGold() && (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD) == false)) {
|
|
|
|
String name = item.getName();
|
|
|
|
String text = player.getFirstName() + " has looted " + name + '.';
|
|
|
|
ChatManager.chatGroupInfoCanSee(player, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (itemRet == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) {
|
|
|
|
// this is done to prevent the temporary goldItem item
|
|
|
|
// (from the mob) from appearing in player's inventory.
|
|
|
|
// It also updates the goldItem quantity display
|
|
|
|
UpdateGoldMsg updateTargetGold = null;
|
|
|
|
|
|
|
|
if (tar != null)
|
|
|
|
updateTargetGold = new UpdateGoldMsg(tar);
|
|
|
|
else if (corpse != null)
|
|
|
|
updateTargetGold = new UpdateGoldMsg(corpse);
|
|
|
|
|
|
|
|
updateTargetGold.configure();
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(tar, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
|
|
|
|
|
|
|
UpdateGoldMsg ugm = new UpdateGoldMsg(player);
|
|
|
|
ugm.configure();
|
|
|
|
Dispatch dispatch = Dispatch.borrow(player, ugm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
// respond back loot message. Try sending to everyone.
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
msg.setSourceType1(0);
|
|
|
|
msg.setSourceType2(0);
|
|
|
|
msg.setSourceID1(0);
|
|
|
|
msg.setSourceID2(0);
|
|
|
|
Dispatch dispatch = Dispatch.borrow(player, msg);
|
|
|
|
//DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(tar, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true);
|
|
|
|
LootMsg newItemMsg = new LootMsg(GameObjectType.PlayerCharacter.ordinal(), player.getObjectUUID(),0,0, itemRet);
|
|
|
|
dispatch = Dispatch.borrow(player, newItemMsg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
|
|
|
|
|
|
|
|
//player.getCharItemManager().updateInventory();
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO send group loot message if player is grouped and visible
|
|
|
|
Group group = GroupManager.getGroup(player);
|
|
|
|
|
|
|
|
if (group != null && group.getSplitGold() && (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD) == false)) {
|
|
|
|
String name = item.getName();
|
|
|
|
String text = player.getFirstName() + " has looted " + name + '.';
|
|
|
|
ChatManager.chatGroupInfoCanSee(player, text);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Logger.info( e.getMessage());
|
|
|
|
} finally {
|
|
|
|
item.lootLock.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//returns true if looted item is goldItem and is split. Otherwise returns false
|
|
|
|
|
|
|
|
// called when player types /show
|
|
|
|
private static void show(ShowMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int targetType = msg.getTargetType();
|
|
|
|
AbstractCharacter tar = null;
|
|
|
|
|
|
|
|
if (targetType == GameObjectType.PlayerCharacter.ordinal())
|
|
|
|
tar = PlayerCharacter.getFromCache(msg.getTargetID());
|
|
|
|
else if (targetType == GameObjectType.NPC.ordinal())
|
|
|
|
tar = NPC.getFromCache(msg.getTargetID());
|
|
|
|
else if (targetType == GameObjectType.Mob.ordinal())
|
|
|
|
tar = Mob.getFromCache(msg.getTargetID());
|
|
|
|
|
|
|
|
if (tar == null || !tar.isAlive() || !tar.isActive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
msg.setUnknown01(pc.getLoc());
|
|
|
|
msg.setUnknown02(pc.getLoc());
|
|
|
|
msg.setRange01(pc.getRange());
|
|
|
|
msg.setUnknown03(tar.getLoc());
|
|
|
|
msg.setUnknown04(tar.getLoc());
|
|
|
|
msg.setRange01(tar.getRange());
|
|
|
|
|
|
|
|
Dispatch dispatch = Dispatch.borrow(pc, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void ViewResourcesMessage(ViewResourcesMessage msg, ClientConnection origin) throws SQLException {
|
|
|
|
|
|
|
|
PlayerCharacter player = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Guild guild = player.getGuild();
|
|
|
|
City city = guild.getOwnedCity();
|
|
|
|
|
|
|
|
if (city == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Building warehouse = BuildingManager.getBuilding(city.getWarehouseBuildingID());
|
|
|
|
|
|
|
|
if (warehouse == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ViewResourcesMessage vrm = new ViewResourcesMessage(player);
|
|
|
|
vrm.setWarehouseBuilding(warehouse);
|
|
|
|
vrm.setGuild(player.getGuild());
|
|
|
|
vrm.configure();
|
|
|
|
|
|
|
|
Dispatch dispatch = Dispatch.borrow(player, vrm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void randomRoll(RandomMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter source = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
if (source == null || !source.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
//2 second cooldown on random rolls
|
|
|
|
long lastRandom = source.getTimeStamp("RandomRoll");
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() - lastRandom < 2000)
|
|
|
|
return;
|
|
|
|
source.setTimeStamp("RandomRoll", System.currentTimeMillis());
|
|
|
|
|
|
|
|
//handle random roll
|
|
|
|
int max = msg.getMax();
|
|
|
|
|
|
|
|
if (max > 0)
|
|
|
|
msg.setRoll(ThreadLocalRandom.current().nextInt(max) + 1);
|
|
|
|
else if (max < 0) {
|
|
|
|
max = 1 - max;
|
|
|
|
msg.setRoll((ThreadLocalRandom.current().nextInt(max) - max) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
msg.setSourceType(source.getObjectType().ordinal());
|
|
|
|
msg.setSourceID(source.getObjectUUID());
|
|
|
|
|
|
|
|
//send to all in range
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(source, msg, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void stuck(ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = origin.getPlayerCharacter();
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sourcePlayer.getTimers().containsKey("Stuck"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
StuckJob sj = new StuckJob(sourcePlayer);
|
|
|
|
JobContainer jc = JobScheduler.getInstance().scheduleJob(sj, 10000); // Convert
|
|
|
|
ConcurrentHashMap<String, JobContainer> timers = sourcePlayer.getTimers();
|
|
|
|
|
|
|
|
if (timers != null) {
|
|
|
|
if (timers.containsKey("Stuck")) {
|
|
|
|
timers.get("Stuck").cancelJob();
|
|
|
|
timers.remove("Stuck");
|
|
|
|
}
|
|
|
|
timers.put("Stuck", jc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void GuildTreeStatusMsg(GuildTreeStatusMsg msg, ClientConnection origin) throws SQLException {
|
|
|
|
|
|
|
|
PlayerCharacter player = SessionManager.getPlayerCharacter(origin);
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (origin.guildtreespam > System.currentTimeMillis()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
origin.guildtreespam = System.currentTimeMillis() + 5000;
|
|
|
|
|
|
|
|
Building b = BuildingManager.getBuildingFromCache(msg.getTargetID());
|
|
|
|
if (b == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
GuildTreeStatusMsg gtsm = new GuildTreeStatusMsg(b, player);
|
|
|
|
gtsm.configure();
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(player, gtsm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void openSellToNPCWindow(SellToNPCWindowMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NPC npc = NPC.getFromCache(msg.getNPCID());
|
|
|
|
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// test within talking range
|
|
|
|
|
|
|
|
if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Contract con = npc.getContract();
|
|
|
|
|
|
|
|
if (con == null)
|
|
|
|
return;
|
|
|
|
float bargain = sourcePlayer.getBargain();
|
|
|
|
|
|
|
|
float profit = npc.getBuyPercent(sourcePlayer) + bargain;
|
|
|
|
|
|
|
|
if (profit > 1)
|
|
|
|
profit = 1;
|
|
|
|
|
|
|
|
msg.setupOutput();
|
|
|
|
|
|
|
|
msg.setUnknown05(profit);
|
|
|
|
msg.setUnknown06(500000); //TODO set goldItem on npc later
|
|
|
|
msg.setItemType(con.getBuyItemType());
|
|
|
|
msg.setSkillTokens(con.getBuySkillToken());
|
|
|
|
msg.setUnknownArray(con.getBuyUnknownToken());
|
|
|
|
|
|
|
|
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.getCharItemManager();
|
|
|
|
|
|
|
|
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.getCharItemManager().getInventoryCount() > 150) {
|
|
|
|
if (npc.getParentZone() != null && npc.getParentZone().getPlayerCityUUID() == 0) {
|
|
|
|
ArrayList<Item> inv = npc.getInventory();
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
|
|
try {
|
|
|
|
Item toRemove = inv.get(i);
|
|
|
|
if (toRemove != null)
|
|
|
|
npc.getCharItemManager().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
|
|
|
|
|
|
|
|
ItemBase ib = sell.getItemBase();
|
|
|
|
|
|
|
|
if (ib == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (npc.getParentZone() != null && npc.getParentZone().getPlayerCityUUID() != 0)
|
|
|
|
if (!npc.getCharItemManager().hasRoomInventory(ib.getWeight())){
|
|
|
|
|
|
|
|
ErrorPopupMsg.sendErrorPopup(player, 21);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sell.validForInventory(origin, player, itemMan))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//get goldItem cost to sell
|
|
|
|
|
|
|
|
|
|
|
|
cost = sell.getBaseValue();
|
|
|
|
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().getPlayerCityUUID() == 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) {
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NPC npc = NPC.getFromCache(msg.getNpcID());
|
|
|
|
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// test within talking range
|
|
|
|
|
|
|
|
if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch = Dispatch.borrow(sourcePlayer, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
|
|
|
|
|
|
|
|
if (sourcePlayer == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (origin.buyLock.tryLock()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
CharacterItemManager itemMan = sourcePlayer.getCharItemManager();
|
|
|
|
|
|
|
|
if (itemMan == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NPC npc = NPC.getFromCache(msg.getNPCID());
|
|
|
|
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item gold = itemMan.getGoldInventory();
|
|
|
|
|
|
|
|
if (gold == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item buy = null;
|
|
|
|
|
|
|
|
if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) {
|
|
|
|
ArrayList<MobEquipment> sellInventory = npc.getContract().getSellInventory();
|
|
|
|
if (sellInventory == null)
|
|
|
|
return;
|
|
|
|
for (MobEquipment me : sellInventory) {
|
|
|
|
if (me.getObjectUUID() == msg.getItemID()) {
|
|
|
|
ItemBase ib = me.getItemBase();
|
|
|
|
if (ib == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//test room available for item
|
|
|
|
if (!itemMan.hasRoomInventory(ib.getWeight()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int cost = me.getMagicValue();
|
|
|
|
|
|
|
|
float bargain = sourcePlayer.getBargain();
|
|
|
|
|
|
|
|
float profit = npc.getSellPercent(sourcePlayer) - bargain;
|
|
|
|
|
|
|
|
if (profit < 1)
|
|
|
|
profit = 1;
|
|
|
|
|
|
|
|
|
|
|
|
cost *= profit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (gold.getNumOfItems() - cost < 0) {
|
|
|
|
//dont' have enough goldItem exit!
|
|
|
|
// chatMan.chatSystemInfo(pc, "" + "You dont have enough gold.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
|
|
|
|
|
|
|
|
if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
|
|
|
|
b = null;
|
|
|
|
int buildingDeposit = cost - me.getMagicValue();
|
|
|
|
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
|
|
|
|
// chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buy = Item.createItemForPlayer(sourcePlayer, ib);
|
|
|
|
|
|
|
|
if (buy != null) {
|
|
|
|
me.transferEnchants(buy);
|
|
|
|
itemMan.addItemToInventory(buy);
|
|
|
|
//itemMan.updateInventory();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (msg.getItemType() == GameObjectType.Item.ordinal()) {
|
|
|
|
|
|
|
|
CharacterItemManager npcCim = npc.getCharItemManager();
|
|
|
|
|
|
|
|
if (npcCim == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buy = Item.getFromCache(msg.getItemID());
|
|
|
|
|
|
|
|
if (buy == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ItemBase ib = buy.getItemBase();
|
|
|
|
|
|
|
|
if (ib == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!npcCim.inventoryContains(buy))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//test room available for item
|
|
|
|
if (!itemMan.hasRoomInventory(ib.getWeight()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//TODO test cost and subtract goldItem
|
|
|
|
|
|
|
|
//TODO CHnage this if we ever put NPc city npcs in buildings.
|
|
|
|
int cost = buy.getBaseValue();
|
|
|
|
|
|
|
|
if (buy.isID() || buy.isCustomValue())
|
|
|
|
cost = buy.getMagicValue();
|
|
|
|
|
|
|
|
float bargain = sourcePlayer.getBargain();
|
|
|
|
|
|
|
|
float profit = npc.getSellPercent(sourcePlayer) - bargain;
|
|
|
|
|
|
|
|
if (profit < 1)
|
|
|
|
profit = 1;
|
|
|
|
|
|
|
|
if (!buy.isCustomValue())
|
|
|
|
cost *= profit;
|
|
|
|
else
|
|
|
|
cost = buy.getValue();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (gold.getNumOfItems() - cost < 0) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
|
|
|
|
|
|
|
|
if (b != null)
|
|
|
|
if (b.getProtectionState().equals(ProtectionState.NPC))
|
|
|
|
b = null;
|
|
|
|
|
|
|
|
int buildingDeposit = cost;
|
|
|
|
|
|
|
|
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buy != null)
|
|
|
|
itemMan.buyFromNPC(buy, npc);
|
|
|
|
|
|
|
|
}else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) {
|
|
|
|
|
|
|
|
CharacterItemManager npcCim = npc.getCharItemManager();
|
|
|
|
|
|
|
|
if (npcCim == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buy = MobLoot.getFromCache(msg.getItemID());
|
|
|
|
|
|
|
|
if (buy == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ItemBase ib = buy.getItemBase();
|
|
|
|
|
|
|
|
if (ib == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!npcCim.inventoryContains(buy))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//test room available for item
|
|
|
|
if (!itemMan.hasRoomInventory(ib.getWeight()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//TODO test cost and subtract goldItem
|
|
|
|
|
|
|
|
//TODO CHnage this if we ever put NPc city npcs in buildings.
|
|
|
|
|
|
|
|
int cost = buy.getMagicValue();
|
|
|
|
cost *= npc.getSellPercent(sourcePlayer);
|
|
|
|
|
|
|
|
|
|
|
|
if (gold.getNumOfItems() - cost < 0) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
|
|
|
|
|
|
|
|
if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
|
|
|
|
b = null;
|
|
|
|
int buildingDeposit = cost;
|
|
|
|
|
|
|
|
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemMan.buyFromNPC(b, cost, buildingDeposit))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buy != null)
|
|
|
|
itemMan.buyFromNPC(buy, npc);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buy != null) {
|
|
|
|
|
|
|
|
msg.setItem(buy);
|
|
|
|
//send the buy message back to update player
|
|
|
|
// msg.setItemType(buy.getObjectType().ordinal());
|
|
|
|
// msg.setItemID(buy.getObjectUUID());
|
|
|
|
Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
itemMan.updateInventory();
|
|
|
|
}
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
origin.buyLock.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//Handle RepairObject Window and RepairObject Requests
|
|
|
|
|
|
|
|
private static void Repair(RepairMsg msg, ClientConnection origin) {
|
|
|
|
|
|
|
|
PlayerCharacter player = SessionManager.getPlayerCharacter(origin);
|
|
|
|
Dispatch dispatch;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NPC npc = NPC.getFromCache(msg.getNPCID());
|
|
|
|
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (msg.getMsgType() == 1) { //Open RepairObject Window
|
|
|
|
|
|
|
|
if (player.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(player, 14);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//send open repair window response
|
|
|
|
msg.setRepairWindowAck(npc);
|
|
|
|
dispatch = Dispatch.borrow(player, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (msg.getMsgType() == 0) { //Request RepairObject
|
|
|
|
|
|
|
|
CharacterItemManager itemMan = player.getCharItemManager();
|
|
|
|
|
|
|
|
if (itemMan == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item gold = itemMan.getGoldInventory();
|
|
|
|
|
|
|
|
if (gold == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Item toRepair = Item.getFromCache(msg.getItemID());
|
|
|
|
|
|
|
|
if (toRepair == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (toRepair.getItemBase().isGlass())
|
|
|
|
return;
|
|
|
|
|
|
|
|
//make sure item is in player's inventory or equipment
|
|
|
|
if (!itemMan.inventoryContains(toRepair) && !itemMan.equippedContains(toRepair))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//make sure item is damaged and not destroyed
|
|
|
|
short dur = toRepair.getDurabilityCurrent();
|
|
|
|
short max = toRepair.getDurabilityMax();
|
|
|
|
//account for durability modifications
|
|
|
|
float durMod = toRepair.getBonusPercent(ModType.Durability,SourceType.None);
|
|
|
|
max *= (1 + (durMod * 0.01f));
|
|
|
|
if (dur >= max || dur < 1) {
|
|
|
|
//redundancy message to clear item from window in client
|
|
|
|
toRepair.setDurabilityCurrent(max);
|
|
|
|
msg.setupRepairAck(max - dur);
|
|
|
|
dispatch = Dispatch.borrow(player, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//TODO get cost to repair
|
|
|
|
int cost = (int) ((max - dur) * 80.1);
|
|
|
|
Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
|
|
|
|
|
|
|
|
if (b != null)
|
|
|
|
if (b.getProtectionState().equals(ProtectionState.NPC))
|
|
|
|
b = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (b != null && (b.getStrongboxValue() + cost) > b.getMaxGold()) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(player, 206);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (player.getCharItemManager().getGoldInventory().getNumOfItems() - cost < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (player.getCharItemManager().getGoldInventory().getNumOfItems() - cost > MBServerStatics.PLAYER_GOLD_LIMIT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!itemMan.buyFromNPC(b, cost, cost)) {
|
|
|
|
ErrorPopupMsg.sendErrorPopup(player, 128);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//update player's goldItem count
|
|
|
|
UpdateGoldMsg ugm = new UpdateGoldMsg(player);
|
|
|
|
ugm.configure();
|
|
|
|
dispatch = Dispatch.borrow(player, ugm);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
//update durability to database
|
|
|
|
if (!DbManager.ItemQueries.SET_DURABILITY(toRepair, max))
|
|
|
|
return;
|
|
|
|
//repair the item
|
|
|
|
toRepair.setDurabilityCurrent(max);
|
|
|
|
//send repair msg
|
|
|
|
msg.setupRepairAck(max - dur);
|
|
|
|
dispatch = Dispatch.borrow(player, msg);
|
|
|
|
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static void petAttack(PetAttackMsg msg, ClientConnection conn) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(conn);
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Mob pet = pc.getPet();
|
|
|
|
|
|
|
|
if (pet == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!pet.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((pc.inSafeZone())
|
|
|
|
&& (msg.getTargetType() == GameObjectType.PlayerCharacter.ordinal()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
CombatManager.setAttackTarget(msg, conn);
|
|
|
|
|
|
|
|
if (pet.getCombatTarget() == null)
|
|
|
|
return;
|
|
|
|
pet.setState(STATE.Attack);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static void petCmd(PetCmdMsg msg, ClientConnection conn) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter pc = SessionManager.getPlayerCharacter(conn);
|
|
|
|
|
|
|
|
if (pc == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Mob pet = pc.getPet();
|
|
|
|
|
|
|
|
if (pet == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!pet.isAlive())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pet.getState() == STATE.Disabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int type = msg.getType();
|
|
|
|
|
|
|
|
if (type == 1) { //stop attack
|
|
|
|
pet.setCombatTarget(null);
|
|
|
|
pc.setCombat(false);
|
|
|
|
pet.setState(STATE.Awake);
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (type == 2) { //dismiss
|
|
|
|
pet.dismiss();
|
|
|
|
pc.dismissPet();
|
|
|
|
|
|
|
|
if (pet.isAlive())
|
|
|
|
WorldGrid.updateObject(pet);
|
|
|
|
}
|
|
|
|
else if (type == 3) //toggle assist
|
|
|
|
pet.toggleAssist();
|
|
|
|
else if (type == 5) { //rest
|
|
|
|
boolean sit = (!(pet.isSit()));
|
|
|
|
pet.setSit(sit);
|
|
|
|
|
|
|
|
// cancel effects that break on sit
|
|
|
|
if (pet.isSit())
|
|
|
|
pet.cancelOnSit();
|
|
|
|
|
|
|
|
UpdateStateMsg rwss = new UpdateStateMsg();
|
|
|
|
rwss.setPlayer(pet);
|
|
|
|
DispatchMessage.sendToAllInRange(pet, rwss);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static void HandlePromptRecall(PromptRecallMsg msg, ClientConnection origin) throws MsgSendException {
|
|
|
|
|
|
|
|
PlayerCharacter player = SessionManager.getPlayerCharacter(origin);
|
|
|
|
boolean recallAccepted;
|
|
|
|
|
|
|
|
if (player == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
boolean confirmed = msg.getConfirmed();
|
|
|
|
|
|
|
|
if (confirmed == true) {
|
|
|
|
long timeElapsed = System.currentTimeMillis() - player.getTimeStamp("PromptRecall");
|
|
|
|
//send fail message
|
|
|
|
recallAccepted = timeElapsed < 15000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
recallAccepted = false;
|
|
|
|
|
|
|
|
if (recallAccepted == true) {
|
|
|
|
//handle recall
|
|
|
|
long type = player.getTimeStamp("LastRecallType");
|
|
|
|
|
|
|
|
if (type == 1) { //recall to bind
|
|
|
|
player.teleport(player.getBindLoc());
|
|
|
|
player.setSafeMode();
|
|
|
|
}
|
|
|
|
else { //recall to rg
|
|
|
|
float dist = 9999999999f;
|
|
|
|
Building rg = null;
|
|
|
|
Vector3fImmutable rgLoc;
|
|
|
|
|
|
|
|
for (Runegate runegate : Runegate._runegates.values()) {
|
|
|
|
|
|
|
|
rgLoc = runegate.gateBuilding.getLoc();
|
|
|
|
|
|
|
|
float distanceSquaredToRunegate = player.getLoc().distanceSquared2D(rgLoc);
|
|
|
|
|
|
|
|
if (distanceSquaredToRunegate < sqr(dist))
|
|
|
|
rg = runegate.gateBuilding;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//nearest runegate found. teleport characterTarget
|
|
|
|
|
|
|
|
if (rg != null) {
|
|
|
|
player.teleport(rg.getLoc());
|
|
|
|
player.setSafeMode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|