Compare commits
7 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70e97f2a3c | ||
|
|
38bec1afe1 | ||
|
|
63517a9b4f | ||
|
|
9557581d05 | ||
|
|
4cba7a0bf3 | ||
|
|
a3eb4e62af | ||
|
|
b80dd8007e |
12 changed files with 397 additions and 3 deletions
|
|
@ -1548,6 +1548,12 @@ struct MoveItem_Struct
|
|||
/*0012*/
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ int32 count;
|
||||
/*0004*/ MoveItem_Struct moves[0];
|
||||
};
|
||||
|
||||
// both MoveItem_Struct/DeleteItem_Struct server structures will be changing to a structure-based slot format..this will
|
||||
// be used for handling SoF/SoD/etc... time stamps sent using the MoveItem_Struct format. (nothing will be done with this
|
||||
// info at the moment..but, it is forwarded on to the server for handling/future use)
|
||||
|
|
|
|||
|
|
@ -1762,6 +1762,36 @@ namespace RoF
|
|||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_MoveMultipleItems)
|
||||
{
|
||||
// can't use our macros :(
|
||||
if ((*p)->size < sizeof(MultiMoveItem_Struct) + sizeof(MoveItem_Struct)) {
|
||||
Log(Logs::Detail, Logs::Netcode,
|
||||
"Wrong size on outbound %s (MultiMoveItem_Struct): Got %d, expected at least %d",
|
||||
opcodes->EmuToName((*p)->GetOpcode()), (*p)->size,
|
||||
sizeof(MultiMoveItem_Struct) + sizeof(MoveItem_Struct));
|
||||
delete *p;
|
||||
*p = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
SETUP_VAR_ENCODE(MultiMoveItem_Struct);
|
||||
|
||||
int32 count = std::abs(emu->count);
|
||||
ALLOC_VAR_ENCODE(structs::MultiMoveItem_Struct, sizeof(structs::MultiMoveItem_Struct) +
|
||||
sizeof(structs::MultiMoveItemSub_Struct) * count);
|
||||
|
||||
OUT(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
eq->moves[i].from_slot = ServerToRoFSlot(emu->moves[i].from_slot);
|
||||
eq->moves[i].to_slot = ServerToRoFSlot(emu->moves[i].to_slot);
|
||||
eq->moves[i].number_in_stack = emu->moves[i].number_in_stack;
|
||||
}
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
||||
|
||||
ENCODE(OP_NewZone)
|
||||
|
|
@ -4873,6 +4903,39 @@ namespace RoF
|
|||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_MoveMultipleItems)
|
||||
{
|
||||
// can't use our macros :(
|
||||
if (__packet->size !=
|
||||
sizeof(structs::MultiMoveItem_Struct) + sizeof(structs::MultiMoveItemSub_Struct)) {
|
||||
Log(Logs::Detail, Logs::Netcode,
|
||||
"Wrong size on incoming %s (structs::MultiMoveItem_Struct): Got %d, expected %d",
|
||||
opcodes->EmuToName(__packet->GetOpcode()), __packet->size,
|
||||
sizeof(structs::MultiMoveItem_Struct) + sizeof(structs::MultiMoveItemSub_Struct));
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */
|
||||
return;
|
||||
}
|
||||
|
||||
// can be negative
|
||||
int32 count = std::abs(*(int32 *)__packet->pBuffer);
|
||||
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
__packet->size = sizeof(MultiMoveItem_Struct) + count * sizeof(MoveItem_Struct);
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
MultiMoveItem_Struct *emu = (MultiMoveItem_Struct *) __packet->pBuffer;
|
||||
structs::MultiMoveItem_Struct *eq = (structs::MultiMoveItem_Struct *) __eq_buffer;
|
||||
|
||||
IN(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
emu->moves[i].from_slot = RoFToServerSlot(eq->moves[i].from_slot);
|
||||
emu->moves[i].to_slot = RoFToServerSlot(eq->moves[i].to_slot);
|
||||
emu->moves[i].number_in_stack = eq->moves[i].number_in_stack;
|
||||
}
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_PetCommands)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
|
|
|
|||
|
|
@ -1831,6 +1831,36 @@ namespace RoF2
|
|||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_MoveMultipleItems)
|
||||
{
|
||||
// can't use our macros :(
|
||||
if ((*p)->size < sizeof(MultiMoveItem_Struct) + sizeof(MoveItem_Struct)) {
|
||||
Log(Logs::Detail, Logs::Netcode,
|
||||
"Wrong size on outbound %s (MultiMoveItem_Struct): Got %d, expected at least %d",
|
||||
opcodes->EmuToName((*p)->GetOpcode()), (*p)->size,
|
||||
sizeof(MultiMoveItem_Struct) + sizeof(MoveItem_Struct));
|
||||
delete *p;
|
||||
*p = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
SETUP_VAR_ENCODE(MultiMoveItem_Struct);
|
||||
|
||||
int32 count = std::abs(emu->count);
|
||||
ALLOC_VAR_ENCODE(structs::MultiMoveItem_Struct, sizeof(structs::MultiMoveItem_Struct) +
|
||||
sizeof(structs::MultiMoveItemSub_Struct) * count);
|
||||
|
||||
OUT(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
eq->moves[i].from_slot = ServerToRoF2Slot(emu->moves[i].from_slot);
|
||||
eq->moves[i].to_slot = ServerToRoF2Slot(emu->moves[i].to_slot);
|
||||
eq->moves[i].number_in_stack = emu->moves[i].number_in_stack;
|
||||
}
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
||||
|
||||
ENCODE(OP_NewZone)
|
||||
|
|
@ -5112,6 +5142,39 @@ namespace RoF2
|
|||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_MoveMultipleItems)
|
||||
{
|
||||
// can't use our macros :(
|
||||
if (__packet->size !=
|
||||
sizeof(structs::MultiMoveItem_Struct) + sizeof(structs::MultiMoveItemSub_Struct)) {
|
||||
Log(Logs::Detail, Logs::Netcode,
|
||||
"Wrong size on incoming %s (structs::MultiMoveItem_Struct): Got %d, expected %d",
|
||||
opcodes->EmuToName(__packet->GetOpcode()), __packet->size,
|
||||
sizeof(structs::MultiMoveItem_Struct) + sizeof(structs::MultiMoveItemSub_Struct));
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */
|
||||
return;
|
||||
}
|
||||
|
||||
// can be negative
|
||||
int32 count = std::abs(*(int32 *)__packet->pBuffer);
|
||||
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
__packet->size = sizeof(MultiMoveItem_Struct) + count * sizeof(MoveItem_Struct);
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
MultiMoveItem_Struct *emu = (MultiMoveItem_Struct *) __packet->pBuffer;
|
||||
structs::MultiMoveItem_Struct *eq = (structs::MultiMoveItem_Struct *) __eq_buffer;
|
||||
|
||||
IN(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
emu->moves[i].from_slot = RoF2ToServerSlot(eq->moves[i].from_slot);
|
||||
emu->moves[i].to_slot = RoF2ToServerSlot(eq->moves[i].to_slot);
|
||||
emu->moves[i].number_in_stack = eq->moves[i].number_in_stack;
|
||||
}
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_PetCommands)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ E(OP_ManaChange)
|
|||
E(OP_MercenaryDataResponse)
|
||||
E(OP_MercenaryDataUpdate)
|
||||
E(OP_MoveItem)
|
||||
E(OP_MoveMultipleItems)
|
||||
E(OP_NewSpawn)
|
||||
E(OP_NewZone)
|
||||
E(OP_OnLevelMessage)
|
||||
|
|
@ -183,6 +184,7 @@ D(OP_ItemVerifyRequest)
|
|||
D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_MoveMultipleItems)
|
||||
D(OP_PetCommands)
|
||||
D(OP_RaidInvite)
|
||||
D(OP_ReadBook)
|
||||
|
|
|
|||
|
|
@ -1837,7 +1837,7 @@ struct MultiMoveItemSub_Struct
|
|||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ uint32 count;
|
||||
/*0000*/ int32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ E(OP_ManaChange)
|
|||
E(OP_MercenaryDataResponse)
|
||||
E(OP_MercenaryDataUpdate)
|
||||
E(OP_MoveItem)
|
||||
E(OP_MoveMultipleItems)
|
||||
E(OP_NewSpawn)
|
||||
E(OP_NewZone)
|
||||
E(OP_OnLevelMessage)
|
||||
|
|
@ -167,6 +168,7 @@ D(OP_ItemVerifyRequest)
|
|||
D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_MoveMultipleItems)
|
||||
D(OP_PetCommands)
|
||||
D(OP_RaidInvite)
|
||||
D(OP_ReadBook)
|
||||
|
|
|
|||
|
|
@ -1815,6 +1815,20 @@ struct MoveItem_Struct
|
|||
/*0028*/
|
||||
};
|
||||
|
||||
struct MultiMoveItemSub_Struct
|
||||
{
|
||||
/*0000*/ InventorySlot_Struct from_slot;
|
||||
/*0012*/ InventorySlot_Struct to_slot;
|
||||
/*0024*/ uint32 number_in_stack;
|
||||
/*0028*/ uint8 unknown[8];
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ int32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
//
|
||||
// from_slot/to_slot
|
||||
// -1 - destroy
|
||||
|
|
|
|||
|
|
@ -47,10 +47,12 @@ namespace Titanium
|
|||
// server to client inventory location converters
|
||||
static inline int16 ServerToTitaniumSlot(uint32 serverSlot);
|
||||
static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot);
|
||||
//static inline structs::InventorySlot_Struct ServerToNewStyleTitaniumSlot(uint32 serverSlot, ItemPacketType PacketType = ItemPacketInvalid);
|
||||
|
||||
// client to server inventory location converters
|
||||
static inline uint32 TitaniumToServerSlot(int16 titaniumSlot);
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot);
|
||||
//static inline uint32 NewStyleTitaniumToServerSlot(structs::InventorySlot_Struct titaniumSlot, ItemPacketType PacketType = ItemPacketInvalid);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink);
|
||||
|
|
@ -2474,6 +2476,20 @@ namespace Titanium
|
|||
return titaniumCorpseSlot;
|
||||
}
|
||||
|
||||
/*static inline uint32 NewStyleTitaniumToServerSlot(structs::InventorySlot_Struct titaniumSlot, ItemPacketType PacketType)
|
||||
{
|
||||
uint32 ServerSlot = INVALID_INDEX;
|
||||
uint32 TempSlot = 0;
|
||||
|
||||
if (titaniumSlot.Type == invtype::InvTypePossessions) { // Worn/Personal Inventory and Cursor
|
||||
TempSlot = titaniumSlot.Slot;
|
||||
if (titaniumSlot.SubIndex >= EQEmu::inventory::containerBegin) // Bag Slots
|
||||
TempSlot = (TempSlot + 3) * EQEmu::inventory::ContainerCount + titaniumSlot.SubIndex + 1;
|
||||
|
||||
ServerSlot = TempSlot;
|
||||
}
|
||||
}*/
|
||||
|
||||
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Titanium
|
|||
InvTypeSharedBank,
|
||||
InvTypeTrade,
|
||||
InvTypeWorld,
|
||||
InvTypeLimbo,
|
||||
InvTypeLimbo, // this is where titanium actually ends
|
||||
InvTypeTribute,
|
||||
InvTypeGuildTribute,
|
||||
InvTypeMerchant,
|
||||
|
|
|
|||
|
|
@ -229,6 +229,13 @@ struct ClientReward
|
|||
uint32 amount;
|
||||
};
|
||||
|
||||
// used for OP_MoveMultipleItems
|
||||
struct InternalMultiMoveItem {
|
||||
MoveItem_Struct move;
|
||||
EQEmu::ItemInstance *item;
|
||||
bool move_finished;
|
||||
};
|
||||
|
||||
class ClientFactory {
|
||||
public:
|
||||
Client *MakeClient(std::shared_ptr<EQStreamInterface> ieqs);
|
||||
|
|
@ -869,6 +876,13 @@ public:
|
|||
bool SwapItem(MoveItem_Struct* move_in);
|
||||
void SwapItemResync(MoveItem_Struct* move_slots);
|
||||
void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false);
|
||||
bool MoveMultipleItems(MultiMoveItem_Struct *move_in);
|
||||
bool MoveMultipleItems(std::deque<InternalMultiMoveItem> &moves, bool send_packet = false);
|
||||
bool MultiMovesGetItems(std::deque<InternalMultiMoveItem> &moves);
|
||||
bool MultiMovesFinish(std::deque<InternalMultiMoveItem> &moves);
|
||||
void MultiMovesFailReturnItems(std::deque<InternalMultiMoveItem> &moves);
|
||||
void MultiMovesFailRevertMoves(std::deque<InternalMultiMoveItem> &moves);
|
||||
void SendMoveMultipleItems(std::deque<InternalMultiMoveItem> &moves);
|
||||
void PutLootInInventory(int16 slot_id, const EQEmu::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
|
||||
bool AutoPutLootInInventory(EQEmu::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
|
||||
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQEmu::inventory::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
|
||||
|
|
|
|||
|
|
@ -9858,7 +9858,9 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
|||
|
||||
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
|
||||
{
|
||||
Kick(); // TODO: lets not desync though
|
||||
// verify size? Translators already fail if too small
|
||||
// any state checking?
|
||||
MoveMultipleItems((MultiMoveItem_Struct *)app->pBuffer);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)
|
||||
|
|
|
|||
|
|
@ -2088,6 +2088,218 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
|
|||
safe_delete(qspack);
|
||||
}
|
||||
|
||||
/* The idea behind this is that we will move all the items out of their source slots
|
||||
* into a temporary holding area. Then we will move them from the holding area to their
|
||||
* destination slots. These steps can fail, and we will have to revert.
|
||||
*
|
||||
* The reason for this is because the client will say move item from slot x to slot y
|
||||
* then move item from slot y to slot x. Which means we have to some sort of temporary
|
||||
* area because otherwise we would just undo the move.
|
||||
*/
|
||||
|
||||
bool Client::MoveMultipleItems(MultiMoveItem_Struct *move_in)
|
||||
{
|
||||
// We need somewhere to hold the moves and the items need some place to live temporarily
|
||||
std::deque<InternalMultiMoveItem> moves;
|
||||
|
||||
for (int i = 0; i < move_in->count; ++i) {
|
||||
InternalMultiMoveItem m;
|
||||
m.move.from_slot = move_in->moves[i].from_slot;
|
||||
m.move.to_slot = move_in->moves[i].to_slot;
|
||||
m.move.number_in_stack = move_in->moves[i].number_in_stack;
|
||||
m.item = nullptr;
|
||||
m.move_finished = false;
|
||||
|
||||
if (!IsValidSlot(m.move.from_slot)) {
|
||||
Log(Logs::Detail, Logs::Inventory, "Invalid slot move from slot %u to slot %u with %u charges!", m.move.from_slot, m.move.to_slot, m.move.number_in_stack);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsValidSlot(m.move.to_slot)) {
|
||||
Log(Logs::Detail, Logs::Inventory, "Invalid slot move from slot %u to slot %u with %u charges!", m.move.from_slot, m.move.to_slot, m.move.number_in_stack);
|
||||
return false;
|
||||
}
|
||||
|
||||
moves.push_back(m);
|
||||
}
|
||||
|
||||
return MoveMultipleItems(moves);
|
||||
}
|
||||
|
||||
bool Client::MoveMultipleItems(std::deque<InternalMultiMoveItem> &moves, bool send_packet)
|
||||
{
|
||||
if (!MultiMovesGetItems(moves)) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesGetItems failed!");
|
||||
MultiMovesFailReturnItems(moves);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The client also calls a function called UpdateToSlots here, I think this will make sure items can fit in destination
|
||||
// and find where to put items that need a home (ex. when bandolier needs to remove an item)
|
||||
|
||||
if (!MultiMovesFinish(moves)) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MutliMovesFinish failed!");
|
||||
MultiMovesFailRevertMoves(moves);
|
||||
MultiMovesFailReturnItems(moves);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (send_packet)
|
||||
SendMoveMultipleItems(moves);
|
||||
|
||||
// Now we need to save, we couldn't do it in processing because of failure
|
||||
// could be better ...
|
||||
// This may save slots multiple times, can rethink later ...
|
||||
for (auto &m : moves) {
|
||||
database.SaveInventory(character_id, m_inv.GetItem(m.move.from_slot), m.move.from_slot);
|
||||
database.SaveInventory(character_id, m_inv.GetItem(m.move.to_slot), m.move.to_slot);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::MultiMovesFinish(std::deque<InternalMultiMoveItem> &moves)
|
||||
{
|
||||
for (auto &m : moves) {
|
||||
if (!m.item) { // this shouldn't happen
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesFinish encountered a null item!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check lore, we could be moving from shared to non-shared bank
|
||||
if (CheckLoreConflict(m.item->GetItem())) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesFinish encountered a lore conflict!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check we are allowed to equip it
|
||||
|
||||
auto dst_inst = m_inv.GetItem(m.move.to_slot);
|
||||
// so we need to verify each of these moves are good
|
||||
auto parent_slot = m_inv.CalcSlotId(m.move.to_slot);
|
||||
if (parent_slot != INVALID_INDEX) { // okay, we're moving into a bag, lets verify that
|
||||
auto bag_inst = m_inv.GetItem(parent_slot);
|
||||
|
||||
if (!bag_inst) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesFinish tried moving into a null bag!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bag_inst->IsClassBag()) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesFinish tried moving into a non-bag!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_inv.CanItemFitInContainer(m.item->GetItem(), bag_inst->GetItem())) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesFinish tried moving into a bag it can't fit in!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// so at this point, we know we're moving into a valid bag or not moving into a bag at all, time to check others
|
||||
if (dst_inst) { // okay, there is still an item here, we must be stacking
|
||||
if (m.item->GetCharges() + dst_inst->GetCharges() > m.item->GetItem()->StackSize) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMoveFinish tried to over flow a stack!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m.item->GetItem()->ID != dst_inst->GetItem()->ID) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MutliMoveFinish tried to stack different items!");
|
||||
return false;
|
||||
}
|
||||
|
||||
dst_inst->SetCharges(m.item->GetCharges() + dst_inst->GetCharges());
|
||||
} else { // okay, now we're not stacking so we just need to move
|
||||
m_inv.PutItem(m.move.to_slot, *m.item);
|
||||
}
|
||||
m.move_finished = true;
|
||||
safe_delete(m.item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function will move item instances out of the inventory into a temporary holding area
|
||||
* If this returns false, we need to move them back into their source slots
|
||||
*/
|
||||
bool Client::MultiMovesGetItems(std::deque<InternalMultiMoveItem> &moves)
|
||||
{
|
||||
for (auto &m : moves) {
|
||||
auto inst = m_inv.GetItem(m.move.from_slot);
|
||||
if (!inst) { // trying to move an item that doesn't exist ...
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesGetItems tried to move from an empty slot!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the item is stackable and we are not moving all the items out, we're splitting
|
||||
if (m.move.number_in_stack > 0 && inst->IsStackable() && inst->GetCharges() != m.move.number_in_stack) {
|
||||
if (inst->GetCharges() > m.move.number_in_stack) {
|
||||
Log(Logs::Detail, Logs::Inventory, "MultiMovesGetItems tried to move more items in a stack than we have!");
|
||||
return false;
|
||||
}
|
||||
// new instance
|
||||
auto new_inst = database.CreateItem(inst->GetItem(), m.move.number_in_stack);
|
||||
// modify old
|
||||
inst->SetCharges(inst->GetCharges() - m.move.number_in_stack);
|
||||
m.item = new_inst;
|
||||
} else {
|
||||
m.item = m_inv.PopItem(m.move.from_slot); // we need to steal the item!
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function will move the items back from the temporary holding area after a fail
|
||||
*/
|
||||
void Client::MultiMovesFailReturnItems(std::deque<InternalMultiMoveItem> &moves)
|
||||
{
|
||||
for (auto &m : moves) {
|
||||
if (!m.item) // if the item is null, we haven't stolen it yet, so nothing to fix
|
||||
continue;
|
||||
|
||||
// if we moved a partial stack, we need to put them all back
|
||||
if (m.move.number_in_stack > 0 && m.item->IsStackable() && m.item->GetCharges() != m.move.number_in_stack) {
|
||||
auto inst = m_inv.GetItem(m.move.from_slot);
|
||||
if (!inst) { // well shit
|
||||
safe_delete(m.item);
|
||||
continue;
|
||||
}
|
||||
|
||||
inst->SetCharges(inst->GetCharges() + m.item->GetCharges());
|
||||
safe_delete(m.item);
|
||||
} else {
|
||||
m_inv.PutItem(m.move.from_slot, *m.item);
|
||||
safe_delete(m.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function will move items back into the temporary holding area after a fail
|
||||
*/
|
||||
void Client::MultiMovesFailRevertMoves(std::deque<InternalMultiMoveItem> &moves)
|
||||
{
|
||||
for (auto &m : moves) {
|
||||
if (!m.move_finished) // if we haven't set this to true, we have not put the item in it's destination
|
||||
continue;
|
||||
m.item = m_inv.PopItem(m.move.to_slot);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SendMoveMultipleItems(std::deque<InternalMultiMoveItem> &moves)
|
||||
{
|
||||
auto app = new EQApplicationPacket(OP_MoveMultipleItems, sizeof(MultiMoveItem_Struct) + sizeof(MoveItem_Struct) * moves.size());
|
||||
auto mmi = (MultiMoveItem_Struct *)app->pBuffer;
|
||||
mmi->count = moves.size();
|
||||
int i = 0;
|
||||
|
||||
for (auto &e : moves) {
|
||||
mmi->moves[i].from_slot = e.move.from_slot;
|
||||
mmi->moves[i].to_slot = e.move.to_slot;
|
||||
mmi->moves[i].number_in_stack = e.move.number_in_stack;
|
||||
++i;
|
||||
}
|
||||
FastQueuePacket(&app);
|
||||
}
|
||||
|
||||
void Client::DyeArmor(EQEmu::TintProfile* dye){
|
||||
int16 slot=0;
|
||||
for (int i = EQEmu::textures::textureBegin; i <= EQEmu::textures::LastTintableTexture; i++) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue