OP_MoveItem encode/decode for RoF2, disabled other patches for now (until i get rof2 packets and mechanics working well enough to go back and fix those)

This commit is contained in:
KimLS 2015-02-23 22:45:50 -08:00
parent 8bce7893ed
commit 69612b44d4
20 changed files with 1560 additions and 1352 deletions

View File

@ -1556,7 +1556,7 @@ struct DeleteItem_Struct {
/*0012*/
};
struct MoveItem_Struct
struct MoveItemOld_Struct
{
/*0000*/ uint32 from_slot;
/*0004*/ uint32 to_slot;
@ -1564,6 +1564,19 @@ struct MoveItem_Struct
/*0012*/
};
struct MoveItem_Struct
{
int16 from_type;
int16 from_slot;
int16 from_bag_slot;
int16 from_aug_slot;
int16 to_type;
int16 to_slot;
int16 to_bag_slot;
int16 to_aug_slot;
uint32 number_in_stack;
};
// 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)

View File

@ -61,6 +61,8 @@ bool EQEmu::Inventory::Put(const InventorySlot &slot, std::shared_ptr<ItemInstan
impl_->containers_.insert(std::pair<int, ItemContainer>(slot.type_, ItemContainer()));
}
//Verify item can be put into the slot requested
auto &container = impl_->containers_[slot.type_];
if(slot.bag_index_ > -1) {
auto item = container.Get(slot.slot_);
@ -92,10 +94,64 @@ bool EQEmu::Inventory::Put(const InventorySlot &slot, std::shared_ptr<ItemInstan
return false;
}
bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest) {
bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, int charges) {
return false;
}
int EQEmu::Inventory::CalcMaterialFromSlot(const InventorySlot &slot) {
if(slot.type_ != 0)
return _MaterialInvalid;
switch(slot.slot_) {
case PersonalSlotHead:
return MaterialHead;
case PersonalSlotChest:
return MaterialChest;
case PersonalSlotArms:
return MaterialArms;
case PersonalSlotWrist1:
return MaterialWrist;
case PersonalSlotHands:
return MaterialHands;
case PersonalSlotLegs:
return MaterialLegs;
case PersonalSlotFeet:
return MaterialFeet;
case PersonalSlotPrimary:
return MaterialPrimary;
case PersonalSlotSecondary:
return MaterialSecondary;
default:
return _MaterialInvalid;
}
}
EQEmu::InventorySlot EQEmu::Inventory::CalcSlotFromMaterial(int material) {
switch(material)
{
case MaterialHead:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotHead);
case MaterialChest:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotChest);
case MaterialArms:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotArms);
case MaterialWrist:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotWrist1);
case MaterialHands:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotHands);
case MaterialLegs:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotLegs);
case MaterialFeet:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotFeet);
case MaterialPrimary:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotPrimary);
case MaterialSecondary:
return EQEmu::InventorySlot(InvTypePersonal, PersonalSlotSecondary);
default:
return EQEmu::InventorySlot(-1, -1);
}
}
bool EQEmu::Inventory::Serialize(MemoryBuffer &buf) {
buf.SetWritePosition(0);
buf.SetReadPosition(0);

View File

@ -51,6 +51,44 @@ namespace EQEmu
InvTypeGuildTribute
};
enum PersonaInventorylSlot : int
{
PersonalSlotCharm = 0,
PersonalSlotEar1,
PersonalSlotHead,
PersonalSlotFace,
PersonalSlotEar2,
PersonalSlotNeck,
PersonalSlotShoulders,
PersonalSlotArms,
PersonalSlotBack,
PersonalSlotWrist1,
PersonalSlotWrist2,
PersonalSlotRange,
PersonalSlotHands,
PersonalSlotPrimary,
PersonalSlotSecondary,
PersonalSlotFinger1,
PersonalSlotFinger2,
PersonalSlotChest,
PersonalSlotLegs,
PersonalSlotFeet,
PersonalSlotWaist,
PersonalSlotPowerSource,
PersonalSlotAmmo,
PersonalSlotGeneral1,
PersonalSlotGeneral2,
PersonalSlotGeneral3,
PersonalSlotGeneral4,
PersonalSlotGeneral5,
PersonalSlotGeneral6,
PersonalSlotGeneral7,
PersonalSlotGeneral8,
PersonalSlotGeneral9,
PersonalSlotGeneral10,
PersonalSlotCursor
};
class Inventory
{
public:
@ -59,8 +97,11 @@ namespace EQEmu
std::shared_ptr<ItemInstance> Get(const InventorySlot &slot);
bool Put(const InventorySlot &slot, std::shared_ptr<ItemInstance> inst);
bool Swap(const InventorySlot &src, const InventorySlot &dest);
bool Swap(const InventorySlot &src, const InventorySlot &dest, int charges);
//utility
static int CalcMaterialFromSlot(const InventorySlot &slot);
static InventorySlot CalcSlotFromMaterial(int material);
bool Serialize(MemoryBuffer &buf);
private:
struct impl;

View File

@ -192,14 +192,56 @@ void EQEmu::ItemInstance::SetCustomData(const std::string &custom_data) {
impl_->custom_data_ = custom_data;
}
uint32 EQEmu::ItemInstance::GetOrnamentIDFile() {
return impl_->ornament_idfile_;
}
uint32 EQEmu::ItemInstance::GetOrnamentIDFile() const {
return impl_->ornament_idfile_;
}
void EQEmu::ItemInstance::SetOrnamentIDFile(const uint32 ornament_idfile) {
impl_->ornament_idfile_ = ornament_idfile;
}
uint32 EQEmu::ItemInstance::GetOrnamentIcon() {
return impl_->ornament_icon_;
}
uint32 EQEmu::ItemInstance::GetOrnamentIcon() const {
return impl_->ornament_icon_;
}
void EQEmu::ItemInstance::SetOrnamentIcon(const uint32 ornament_icon) {
impl_->ornament_icon_ = ornament_icon;
}
uint32 EQEmu::ItemInstance::GetOrnamentHeroModel(int material_slot) {
uint32 hero_model = 0;
if(impl_->ornament_hero_model_ > 0)
{
hero_model = impl_->ornament_hero_model_;
if(material_slot >= 0)
{
hero_model = (impl_->ornament_hero_model_ * 100) + material_slot;
}
}
return hero_model;
}
uint32 EQEmu::ItemInstance::GetOrnamentHeroModel(int material_slot) const {
uint32 hero_model = 0;
if(impl_->ornament_hero_model_ > 0)
{
hero_model = impl_->ornament_hero_model_;
if(material_slot >= 0)
{
hero_model = (impl_->ornament_hero_model_ * 100) + material_slot;
}
}
return hero_model;
}
void EQEmu::ItemInstance::SetOrnamentHeroModel(const uint32 ornament_hero_model) {
impl_->ornament_hero_model_ = ornament_hero_model;
}

View File

@ -53,8 +53,17 @@ namespace EQEmu
void SetAttuned(const bool attuned);
void SetCustomData(const std::string &custom_data);
uint32 GetOrnamentIDFile();
uint32 GetOrnamentIDFile() const;
void SetOrnamentIDFile(const uint32 ornament_idfile);
uint32 GetOrnamentIcon();
uint32 GetOrnamentIcon() const;
void SetOrnamentIcon(const uint32 ornament_icon);
uint32 GetOrnamentHeroModel(int material_slot);
uint32 GetOrnamentHeroModel(int material_slot) const;
void SetOrnamentHeroModel(const uint32 ornament_hero_model);
const char* GetTrackingID();

View File

@ -32,20 +32,30 @@ EQEmu::MemoryBuffer::MemoryBuffer(const MemoryBuffer &other) {
}
EQEmu::MemoryBuffer::MemoryBuffer(MemoryBuffer &&other) {
buffer_ = other.buffer_;
size_ = other.size_;
capacity_ = other.capacity_;
write_pos_ = other.write_pos_;
read_pos_ = other.read_pos_;
uchar *tbuf = other.buffer_;
size_t tsz = other.size_;
size_t tcapacity = other.capacity_;
size_t twrite_pos = other.write_pos_;
size_t tread_pos = other.read_pos_;
other.buffer_ = nullptr;
other.size_ = 0;
other.capacity_ = 0;
other.read_pos_ = 0;
other.write_pos_ = 0;
buffer_ = tbuf;
size_ = tsz;
capacity_ = tcapacity;
write_pos_ = twrite_pos;
read_pos_ = tread_pos;
}
EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator=(const MemoryBuffer &other) {
if(buffer_) {
delete[] buffer_;
}
if(other.capacity_) {
buffer_ = new uchar[other.capacity_];
memcpy(buffer_, other.buffer_, other.capacity_);
@ -62,17 +72,23 @@ EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator=(const MemoryBuffer &other) {
}
EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator=(MemoryBuffer &&other) {
buffer_ = other.buffer_;
size_ = other.size_;
capacity_ = other.capacity_;
write_pos_ = other.write_pos_;
read_pos_ = other.read_pos_;
uchar *tbuf = other.buffer_;
size_t tsz = other.size_;
size_t tcapacity = other.capacity_;
size_t twrite_pos = other.write_pos_;
size_t tread_pos = other.read_pos_;
other.buffer_ = nullptr;
other.size_ = 0;
other.capacity_ = 0;
other.read_pos_ = 0;
other.write_pos_ = 0;
buffer_ = tbuf;
size_ = tsz;
capacity_ = tcapacity;
write_pos_ = twrite_pos;
read_pos_ = tread_pos;
return *this;
}

View File

@ -10,19 +10,19 @@
#include "rof2.h"
void RegisterAllPatches(EQStreamIdentifier &into) {
Titanium::Register(into);
SoF::Register(into);
SoD::Register(into);
UF::Register(into);
RoF::Register(into);
//Titanium::Register(into);
//SoF::Register(into);
//SoD::Register(into);
//UF::Register(into);
//RoF::Register(into);
RoF2::Register(into);
}
void ReloadAllPatches() {
Titanium::Reload();
SoF::Reload();
SoD::Reload();
UF::Reload();
RoF::Reload();
//Titanium::Reload();
//SoF::Reload();
//SoD::Reload();
//UF::Reload();
//RoF::Reload();
RoF2::Reload();
}

View File

@ -1707,14 +1707,14 @@ namespace RoF
ENCODE(OP_MoveItem)
{
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
eq->from_slot = ServerToRoFSlot(emu->from_slot);
eq->to_slot = ServerToRoFSlot(emu->to_slot);
OUT(number_in_stack);
FINISH_ENCODE();
//ENCODE_LENGTH_EXACT(MoveItem_Struct);
//SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//eq->from_slot = ServerToRoFSlot(emu->from_slot);
//eq->to_slot = ServerToRoFSlot(emu->to_slot);
//OUT(number_in_stack);
//
//FINISH_ENCODE();
}
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
@ -4684,16 +4684,16 @@ namespace RoF
DECODE(OP_MoveItem)
{
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Moved item from %u to %u", eq->from_slot.MainSlot, eq->to_slot.MainSlot);
Log.Out(Logs::General, Logs::Netcode, "[RoF] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack);
emu->from_slot = RoFToServerSlot(eq->from_slot);
emu->to_slot = RoFToServerSlot(eq->to_slot);
IN(number_in_stack);
FINISH_DIRECT_DECODE();
//DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
//SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//
////Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Moved item from %u to %u", eq->from_slot.MainSlot, eq->to_slot.MainSlot);
//Log.Out(Logs::General, Logs::Netcode, "[RoF] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack);
//emu->from_slot = RoFToServerSlot(eq->from_slot);
//emu->to_slot = RoFToServerSlot(eq->to_slot);
//IN(number_in_stack);
//
//FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)

File diff suppressed because it is too large Load Diff

View File

@ -1265,14 +1265,14 @@ namespace SoD
ENCODE(OP_MoveItem)
{
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
eq->from_slot = ServerToSoDSlot(emu->from_slot);
eq->to_slot = ServerToSoDSlot(emu->to_slot);
OUT(number_in_stack);
FINISH_ENCODE();
//ENCODE_LENGTH_EXACT(MoveItem_Struct);
//SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//eq->from_slot = ServerToSoDSlot(emu->from_slot);
//eq->to_slot = ServerToSoDSlot(emu->to_slot);
//OUT(number_in_stack);
//
//FINISH_ENCODE();
}
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
@ -3260,16 +3260,16 @@ namespace SoD
DECODE(OP_MoveItem)
{
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log.Out(Logs::General, Logs::Netcode, "[SoD] Moved item from %u to %u", eq->from_slot, eq->to_slot);
emu->from_slot = SoDToServerSlot(eq->from_slot);
emu->to_slot = SoDToServerSlot(eq->to_slot);
IN(number_in_stack);
FINISH_DIRECT_DECODE();
//DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
//SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//Log.Out(Logs::General, Logs::Netcode, "[SoD] Moved item from %u to %u", eq->from_slot, eq->to_slot);
//
//emu->from_slot = SoDToServerSlot(eq->from_slot);
//emu->to_slot = SoDToServerSlot(eq->to_slot);
//IN(number_in_stack);
//
//FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)

View File

@ -930,14 +930,14 @@ namespace SoF
ENCODE(OP_MoveItem)
{
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
eq->from_slot = ServerToSoFSlot(emu->from_slot);
eq->to_slot = ServerToSoFSlot(emu->to_slot);
OUT(number_in_stack);
FINISH_ENCODE();
//ENCODE_LENGTH_EXACT(MoveItem_Struct);
//SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//eq->from_slot = ServerToSoFSlot(emu->from_slot);
//eq->to_slot = ServerToSoFSlot(emu->to_slot);
//OUT(number_in_stack);
//
//FINISH_ENCODE();
}
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
@ -2598,16 +2598,16 @@ namespace SoF
DECODE(OP_MoveItem)
{
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log.Out(Logs::General, Logs::Netcode, "[SoF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
emu->from_slot = SoFToServerSlot(eq->from_slot);
emu->to_slot = SoFToServerSlot(eq->to_slot);
IN(number_in_stack);
FINISH_DIRECT_DECODE();
//DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
//SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//Log.Out(Logs::General, Logs::Netcode, "[SoF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
//
//emu->from_slot = SoFToServerSlot(eq->from_slot);
//emu->to_slot = SoFToServerSlot(eq->to_slot);
//IN(number_in_stack);
//
//FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)

View File

@ -778,14 +778,14 @@ namespace Titanium
ENCODE(OP_MoveItem)
{
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
eq->from_slot = ServerToTitaniumSlot(emu->from_slot);
eq->to_slot = ServerToTitaniumSlot(emu->to_slot);
OUT(number_in_stack);
FINISH_ENCODE();
//ENCODE_LENGTH_EXACT(MoveItem_Struct);
//SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//eq->from_slot = ServerToTitaniumSlot(emu->from_slot);
//eq->to_slot = ServerToTitaniumSlot(emu->to_slot);
//OUT(number_in_stack);
//
//FINISH_ENCODE();
}
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
@ -1854,16 +1854,16 @@ namespace Titanium
DECODE(OP_MoveItem)
{
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log.Out(Logs::General, Logs::Netcode, "[Titanium] Moved item from %u to %u", eq->from_slot, eq->to_slot);
emu->from_slot = TitaniumToServerSlot(eq->from_slot);
emu->to_slot = TitaniumToServerSlot(eq->to_slot);
IN(number_in_stack);
FINISH_DIRECT_DECODE();
//DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
//SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//Log.Out(Logs::General, Logs::Netcode, "[Titanium] Moved item from %u to %u", eq->from_slot, eq->to_slot);
//
//emu->from_slot = TitaniumToServerSlot(eq->from_slot);
//emu->to_slot = TitaniumToServerSlot(eq->to_slot);
//IN(number_in_stack);
//
//FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)

View File

@ -1504,14 +1504,14 @@ namespace UF
ENCODE(OP_MoveItem)
{
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
eq->from_slot = ServerToUFSlot(emu->from_slot);
eq->to_slot = ServerToUFSlot(emu->to_slot);
OUT(number_in_stack);
FINISH_ENCODE();
//ENCODE_LENGTH_EXACT(MoveItem_Struct);
//SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//eq->from_slot = ServerToUFSlot(emu->from_slot);
//eq->to_slot = ServerToUFSlot(emu->to_slot);
//OUT(number_in_stack);
//
//FINISH_ENCODE();
}
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
@ -3582,16 +3582,16 @@ namespace UF
DECODE(OP_MoveItem)
{
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log.Out(Logs::General, Logs::Netcode, "[UF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
emu->from_slot = UFToServerSlot(eq->from_slot);
emu->to_slot = UFToServerSlot(eq->to_slot);
IN(number_in_stack);
FINISH_DIRECT_DECODE();
//DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
//SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
//
//Log.Out(Logs::General, Logs::Netcode, "[UF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
//
//emu->from_slot = UFToServerSlot(eq->from_slot);
//emu->to_slot = UFToServerSlot(eq->to_slot);
//IN(number_in_stack);
//
//FINISH_DIRECT_DECODE();
}
DECODE(OP_PetCommands)

View File

@ -175,7 +175,7 @@ private:
void InventorySwapItemsTest()
{
auto swap_result = inv.Swap(EQEmu::InventorySlot(0, 23), EQEmu::InventorySlot(0, 24));
auto swap_result = inv.Swap(EQEmu::InventorySlot(0, 23), EQEmu::InventorySlot(0, 24), 0);
TEST_ASSERT(swap_result == true);
auto m_bag = inv.Get(EQEmu::InventorySlot(0, 24));

View File

@ -33,6 +33,7 @@ public:
TEST_ADD(MemoryBufferTest::CopyTest);
TEST_ADD(MemoryBufferTest::AssignTest);
TEST_ADD(MemoryBufferTest::MoveTest);
TEST_ADD(MemoryBufferTest::SelfTest);
TEST_ADD(MemoryBufferTest::ZeroTest);
TEST_ADD(MemoryBufferTest::ClearTest);
TEST_ADD(MemoryBufferTest::AddTest)
@ -449,6 +450,22 @@ private:
TEST_ASSERT(data[26] == 0);
}
void SelfTest()
{
EQEmu::MemoryBuffer mb2(mb);
void *addr = (void*)mb2;
mb2 = mb2;
void *addr2 = (void*)mb2;
TEST_ASSERT(addr != addr2);
mb2 = std::move(mb2);
addr2 = (void*)mb2;
TEST_ASSERT(addr2 != nullptr);
}
void ZeroTest()
{
mb.Zero();

View File

@ -813,9 +813,9 @@ public:
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
bool SwapItem(MoveItem_Struct* move_in);
void SwapItemResync(MoveItem_Struct* move_slots);
void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false);
bool SwapItem(MoveItemOld_Struct* move_in);
void SwapItemResync(MoveItemOld_Struct* move_slots);
void QSSwapItemAuditor(MoveItemOld_Struct* move_in, bool postaction_call = false);
void PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0);
bool AutoPutLootInInventory(ItemInst& 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 = MainCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);

View File

@ -9586,68 +9586,77 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
{
return;
}
if (app->size != sizeof(MoveItem_Struct)) {
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_MoveItem, size=%i, expected %i", app->size, sizeof(MoveItem_Struct));
return;
}
MoveItem_Struct* mi = (MoveItem_Struct*)app->pBuffer;
if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
{
if (mi->from_slot != mi->to_slot && (mi->from_slot <= EmuConstants::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
{
char *detect = nullptr;
const ItemInst *itm_from = GetInv().GetItem(mi->from_slot);
const ItemInst *itm_to = GetInv().GetItem(mi->to_slot);
MakeAnyLenString(&detect, "Player issued a move item from %u(item id %u) to %u(item id %u) while casting %u.",
mi->from_slot,
itm_from ? itm_from->GetID() : 0,
mi->to_slot,
itm_to ? itm_to->GetID() : 0,
casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect);
Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
return;
}
}
auto res = m_inventory.Swap(EQEmu::InventorySlot(mi->from_type, mi->from_slot, mi->from_bag_slot, mi->from_aug_slot),
EQEmu::InventorySlot(mi->to_type, mi->to_slot, mi->to_bag_slot, mi->to_aug_slot),
mi->number_in_stack);
// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
bool mi_hack = false;
//printf("%i %i %i %i --> %i %i %i %i (%u)\n",
// mi->from_type, mi->from_slot, mi->from_bag_slot, mi->from_aug_slot,
// mi->to_type, mi->to_slot, mi->to_bag_slot, mi->to_aug_slot,
// mi->number_in_stack);
if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
if (mi->from_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 from_parent = m_inv.CalcSlotId(mi->from_slot);
if (!m_inv[from_parent]) { mi_hack = true; }
else if (!m_inv[from_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi->to_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->to_slot <= EmuConstants::CURSOR_BAG_END) {
if (mi->to_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 to_parent = m_inv.CalcSlotId(mi->to_slot);
if (!m_inv[to_parent]) { mi_hack = true; }
else if (!m_inv[to_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
SwapItemResync(mi);
bool error = false;
InterrogateInventory(this, false, true, false, error, false);
if (error)
InterrogateInventory(this, true, false, true, error);
}
return;
//if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
//{
// if (mi->from_slot != mi->to_slot && (mi->from_slot <= EmuConstants::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
// {
// char *detect = nullptr;
// const ItemInst *itm_from = GetInv().GetItem(mi->from_slot);
// const ItemInst *itm_to = GetInv().GetItem(mi->to_slot);
// MakeAnyLenString(&detect, "Player issued a move item from %u(item id %u) to %u(item id %u) while casting %u.",
// mi->from_slot,
// itm_from ? itm_from->GetID() : 0,
// mi->to_slot,
// itm_to ? itm_to->GetID() : 0,
// casting_spell_id);
// database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
// safe_delete_array(detect);
// Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
// return;
// }
//}
//
//// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
//bool mi_hack = false;
//
//if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
// if (mi->from_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
// else {
// int16 from_parent = m_inv.CalcSlotId(mi->from_slot);
// if (!m_inv[from_parent]) { mi_hack = true; }
// else if (!m_inv[from_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
// else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
// }
//}
//
//if (mi->to_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->to_slot <= EmuConstants::CURSOR_BAG_END) {
// if (mi->to_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
// else {
// int16 to_parent = m_inv.CalcSlotId(mi->to_slot);
// if (!m_inv[to_parent]) { mi_hack = true; }
// else if (!m_inv[to_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
// else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
// }
//}
//
//if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
//
//if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
// SwapItemResync(mi);
//
// bool error = false;
// InterrogateInventory(this, false, true, false, error, false);
// if (error)
// InterrogateInventory(this, true, false, true, error);
//}
//
//return;
}
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)

View File

@ -3119,77 +3119,77 @@ void command_listpetition(Client *c, const Seperator *sep)
void command_equipitem(Client *c, const Seperator *sep)
{
uint32 slot_id = atoi(sep->arg[1]);
if (sep->IsNumber(1) && ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource))) {
const ItemInst* from_inst = c->GetInv().GetItem(MainCursor);
const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
bool partialmove = false;
int16 movecount;
if (from_inst && from_inst->IsType(ItemClassCommon)) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct* mi = (MoveItem_Struct*)outapp->pBuffer;
mi->from_slot = MainCursor;
mi->to_slot = slot_id;
// mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking
// crude stackable check to only 'move' the difference count on client instead of entire stack when applicable
if (to_inst && to_inst->IsStackable() &&
(to_inst->GetItem()->ID == from_inst->GetItem()->ID) &&
(to_inst->GetCharges() < to_inst->GetItem()->StackSize) &&
(from_inst->GetCharges() > to_inst->GetItem()->StackSize - to_inst->GetCharges())) {
movecount = to_inst->GetItem()->StackSize - to_inst->GetCharges();
mi->number_in_stack = (uint32)movecount;
partialmove = true;
}
else
mi->number_in_stack = from_inst->GetCharges();
// Save move changes
// Added conditional check to packet send..would have sent change even on a swap failure..whoops!
if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below
// mi->number_in_stack is always from_inst->GetCharges() when partialmove is false
c->Message(13, "Error: Partial stack added to existing stack exceeds allowable stacksize");
return;
}
else if(c->SwapItem(mi)) {
c->FastQueuePacket(&outapp);
// if the below code is still needed..just send an an item trade packet to each slot..it should overwrite the client instance
// below code has proper logic, but client does not like to have cursor charges changed
// (we could delete the cursor item and resend, but issues would arise if there are queued items)
//if (partialmove) {
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// DeleteItem_Struct* di = (DeleteItem_Struct*)outapp2->pBuffer;
// di->from_slot = SLOT_CURSOR;
// di->to_slot = 0xFFFFFFFF;
// di->number_in_stack = 0xFFFFFFFF;
// c->Message(0, "Deleting %i charges from stack", movecount); // debug line..delete
// for (int16 deletecount=0; deletecount < movecount; deletecount++)
// have to use 'movecount' because mi->number_in_stack is 'ENCODED' at this point (i.e., 99 charges returns 22...)
// c->QueuePacket(outapp2);
// safe_delete(outapp2);
//}
}
else {
c->Message(13, "Error: Unable to equip current item");
}
safe_delete(outapp);
// also send out a wear change packet?
}
else if (from_inst == nullptr)
c->Message(13, "Error: There is no item on your cursor");
else
c->Message(13, "Error: Item on your cursor cannot be equipped");
}
else
c->Message(0, "Usage: #equipitem slotid[0-21] - equips the item on your cursor to the position");
// uint32 slot_id = atoi(sep->arg[1]);
// if (sep->IsNumber(1) && ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource))) {
// const ItemInst* from_inst = c->GetInv().GetItem(MainCursor);
// const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
// bool partialmove = false;
// int16 movecount;
//
// if (from_inst && from_inst->IsType(ItemClassCommon)) {
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
// MoveItem_Struct* mi = (MoveItem_Struct*)outapp->pBuffer;
// mi->from_slot = MainCursor;
// mi->to_slot = slot_id;
// // mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking
//
// // crude stackable check to only 'move' the difference count on client instead of entire stack when applicable
// if (to_inst && to_inst->IsStackable() &&
// (to_inst->GetItem()->ID == from_inst->GetItem()->ID) &&
// (to_inst->GetCharges() < to_inst->GetItem()->StackSize) &&
// (from_inst->GetCharges() > to_inst->GetItem()->StackSize - to_inst->GetCharges())) {
// movecount = to_inst->GetItem()->StackSize - to_inst->GetCharges();
// mi->number_in_stack = (uint32)movecount;
// partialmove = true;
// }
// else
// mi->number_in_stack = from_inst->GetCharges();
//
// // Save move changes
// // Added conditional check to packet send..would have sent change even on a swap failure..whoops!
//
// if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below
// // mi->number_in_stack is always from_inst->GetCharges() when partialmove is false
// c->Message(13, "Error: Partial stack added to existing stack exceeds allowable stacksize");
// return;
// }
// else if(c->SwapItem(mi)) {
// c->FastQueuePacket(&outapp);
//
// // if the below code is still needed..just send an an item trade packet to each slot..it should overwrite the client instance
//
// // below code has proper logic, but client does not like to have cursor charges changed
// // (we could delete the cursor item and resend, but issues would arise if there are queued items)
// //if (partialmove) {
// // EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// // DeleteItem_Struct* di = (DeleteItem_Struct*)outapp2->pBuffer;
// // di->from_slot = SLOT_CURSOR;
// // di->to_slot = 0xFFFFFFFF;
// // di->number_in_stack = 0xFFFFFFFF;
//
// // c->Message(0, "Deleting %i charges from stack", movecount); // debug line..delete
//
// // for (int16 deletecount=0; deletecount < movecount; deletecount++)
// // have to use 'movecount' because mi->number_in_stack is 'ENCODED' at this point (i.e., 99 charges returns 22...)
// // c->QueuePacket(outapp2);
//
// // safe_delete(outapp2);
// //}
// }
// else {
// c->Message(13, "Error: Unable to equip current item");
// }
// safe_delete(outapp);
//
// // also send out a wear change packet?
// }
// else if (from_inst == nullptr)
// c->Message(13, "Error: There is no item on your cursor");
// else
// c->Message(13, "Error: Item on your cursor cannot be equipped");
// }
// else
// c->Message(0, "Usage: #equipitem slotid[0-21] - equips the item on your cursor to the position");
}
void command_zonelock(Client *c, const Seperator *sep)

View File

@ -716,122 +716,122 @@ void Client::SendCursorBuffer()
// Remove item from inventory
void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) {
#if (EQDEBUG >= 5)
Log.Out(Logs::General, Logs::None, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
#endif
// Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
// - cursor queue slots were slipping through and crashing client
if(!m_inv[slot_id]) {
// Make sure the client deletes anything in this slot to match the server.
if(client_update && IsValidSlot(slot_id)) {
EQApplicationPacket* outapp;
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp);
safe_delete(outapp);
}
return;
}
// start QS code
if(RuleB(QueryServ, PlayerLogDeletes)) {
uint16 delete_count = 0;
if(m_inv[slot_id]) { delete_count += m_inv.GetItem(slot_id)->GetTotalItemCount(); }
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogDeletes, sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count));
QSPlayerLogDelete_Struct* qsaudit = (QSPlayerLogDelete_Struct*)qspack->pBuffer;
uint16 parent_offset = 0;
qsaudit->char_id = character_id;
qsaudit->stack_size = quantity;
qsaudit->char_count = delete_count;
qsaudit->items[parent_offset].char_slot = slot_id;
qsaudit->items[parent_offset].item_id = m_inv[slot_id]->GetID();
qsaudit->items[parent_offset].charges = m_inv[slot_id]->GetCharges();
qsaudit->items[parent_offset].aug_1 = m_inv[slot_id]->GetAugmentItemID(1);
qsaudit->items[parent_offset].aug_2 = m_inv[slot_id]->GetAugmentItemID(2);
qsaudit->items[parent_offset].aug_3 = m_inv[slot_id]->GetAugmentItemID(3);
qsaudit->items[parent_offset].aug_4 = m_inv[slot_id]->GetAugmentItemID(4);
qsaudit->items[parent_offset].aug_5 = m_inv[slot_id]->GetAugmentItemID(5);
if(m_inv[slot_id]->IsType(ItemClassContainer)) {
for(uint8 bag_idx = SUB_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) {
ItemInst* bagitem = m_inv[slot_id]->GetItem(bag_idx);
if(bagitem) {
int16 bagslot_id = InventoryOld::CalcSlotId(slot_id, bag_idx);
qsaudit->items[++parent_offset].char_slot = bagslot_id;
qsaudit->items[parent_offset].item_id = bagitem->GetID();
qsaudit->items[parent_offset].charges = bagitem->GetCharges();
qsaudit->items[parent_offset].aug_1 = bagitem->GetAugmentItemID(1);
qsaudit->items[parent_offset].aug_2 = bagitem->GetAugmentItemID(2);
qsaudit->items[parent_offset].aug_3 = bagitem->GetAugmentItemID(3);
qsaudit->items[parent_offset].aug_4 = bagitem->GetAugmentItemID(4);
qsaudit->items[parent_offset].aug_5 = bagitem->GetAugmentItemID(5);
}
}
}
qspack->Deflate();
if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
safe_delete(qspack);
}
// end QS code
bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
const ItemInst* inst = nullptr;
if (slot_id == MainCursor) {
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
if(update_db)
database.SaveCursor(character_id, s, e);
}
else {
// Save change to database
inst = m_inv[slot_id];
if(update_db)
database.SaveInventory(character_id, inst, slot_id);
}
if(client_update && IsValidSlot(slot_id)) {
EQApplicationPacket* outapp = nullptr;
if(inst) {
if (!inst->IsStackable() && !isDeleted) {
// Non stackable item with charges = Item with clicky spell effect ? Delete a charge.
outapp = new EQApplicationPacket(OP_DeleteCharge, sizeof(MoveItem_Struct));
}
else {
// Stackable, arrows, etc ? Delete one from the stack
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct));
}
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
for(int loop=0;loop<quantity;loop++)
QueuePacket(outapp);
safe_delete(outapp);
}
else {
outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp);
safe_delete(outapp);
}
}
// #if (EQDEBUG >= 5)
// Log.Out(Logs::General, Logs::None, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
// #endif
//
// // Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
// // - cursor queue slots were slipping through and crashing client
// if(!m_inv[slot_id]) {
// // Make sure the client deletes anything in this slot to match the server.
// if(client_update && IsValidSlot(slot_id)) {
// EQApplicationPacket* outapp;
// outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// return;
// }
//
// // start QS code
// if(RuleB(QueryServ, PlayerLogDeletes)) {
// uint16 delete_count = 0;
//
// if(m_inv[slot_id]) { delete_count += m_inv.GetItem(slot_id)->GetTotalItemCount(); }
//
// ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogDeletes, sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count));
// QSPlayerLogDelete_Struct* qsaudit = (QSPlayerLogDelete_Struct*)qspack->pBuffer;
// uint16 parent_offset = 0;
//
// qsaudit->char_id = character_id;
// qsaudit->stack_size = quantity;
// qsaudit->char_count = delete_count;
//
// qsaudit->items[parent_offset].char_slot = slot_id;
// qsaudit->items[parent_offset].item_id = m_inv[slot_id]->GetID();
// qsaudit->items[parent_offset].charges = m_inv[slot_id]->GetCharges();
// qsaudit->items[parent_offset].aug_1 = m_inv[slot_id]->GetAugmentItemID(1);
// qsaudit->items[parent_offset].aug_2 = m_inv[slot_id]->GetAugmentItemID(2);
// qsaudit->items[parent_offset].aug_3 = m_inv[slot_id]->GetAugmentItemID(3);
// qsaudit->items[parent_offset].aug_4 = m_inv[slot_id]->GetAugmentItemID(4);
// qsaudit->items[parent_offset].aug_5 = m_inv[slot_id]->GetAugmentItemID(5);
//
// if(m_inv[slot_id]->IsType(ItemClassContainer)) {
// for(uint8 bag_idx = SUB_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) {
// ItemInst* bagitem = m_inv[slot_id]->GetItem(bag_idx);
//
// if(bagitem) {
// int16 bagslot_id = InventoryOld::CalcSlotId(slot_id, bag_idx);
//
// qsaudit->items[++parent_offset].char_slot = bagslot_id;
// qsaudit->items[parent_offset].item_id = bagitem->GetID();
// qsaudit->items[parent_offset].charges = bagitem->GetCharges();
// qsaudit->items[parent_offset].aug_1 = bagitem->GetAugmentItemID(1);
// qsaudit->items[parent_offset].aug_2 = bagitem->GetAugmentItemID(2);
// qsaudit->items[parent_offset].aug_3 = bagitem->GetAugmentItemID(3);
// qsaudit->items[parent_offset].aug_4 = bagitem->GetAugmentItemID(4);
// qsaudit->items[parent_offset].aug_5 = bagitem->GetAugmentItemID(5);
// }
// }
// }
//
// qspack->Deflate();
// if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
// safe_delete(qspack);
// }
// // end QS code
//
// bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
//
// const ItemInst* inst = nullptr;
// if (slot_id == MainCursor) {
// auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
// if(update_db)
// database.SaveCursor(character_id, s, e);
// }
// else {
// // Save change to database
// inst = m_inv[slot_id];
// if(update_db)
// database.SaveInventory(character_id, inst, slot_id);
// }
//
// if(client_update && IsValidSlot(slot_id)) {
// EQApplicationPacket* outapp = nullptr;
// if(inst) {
// if (!inst->IsStackable() && !isDeleted) {
// // Non stackable item with charges = Item with clicky spell effect ? Delete a charge.
// outapp = new EQApplicationPacket(OP_DeleteCharge, sizeof(MoveItem_Struct));
// }
// else {
// // Stackable, arrows, etc ? Delete one from the stack
// outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct));
// }
//
// DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
//
// for(int loop=0;loop<quantity;loop++)
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// else {
// outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
// MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// }
}
bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
@ -1315,7 +1315,7 @@ bool Client::IsBankSlot(uint32 slot)
// Moves items around both internally and in the database
// In the future, this can be optimized by pushing all changes through one database REPLACE call
bool Client::SwapItem(MoveItem_Struct* move_in) {
bool Client::SwapItem(MoveItemOld_Struct* move_in) {
uint32 src_slot_check = move_in->from_slot;
uint32 dst_slot_check = move_in->to_slot;
@ -1788,7 +1788,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
return true;
}
void Client::SwapItemResync(MoveItem_Struct* move_slots) {
void Client::SwapItemResync(MoveItemOld_Struct* move_slots) {
// wow..this thing created a helluva memory leak...
// with any luck..this won't be needed in the future
@ -1883,7 +1883,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
}
}
void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
void Client::QSSwapItemAuditor(MoveItemOld_Struct* move_in, bool postaction_call) {
int16 from_slot_id = static_cast<int16>(move_in->from_slot);
int16 to_slot_id = static_cast<int16>(move_in->to_slot);
int16 move_amount = static_cast<int16>(move_in->number_in_stack);

View File

@ -1333,68 +1333,68 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
}
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) {
if(!Customer)
return;
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
if(Quantity < Charges)
{
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
m_inv.DeleteItem(Slot, Quantity);
}
else
{
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
tdis->Unknown000 = 0;
tdis->TraderID = Customer->GetID();
if (Customer->GetClientVersion() >= ClientVersion::RoF)
{
// RoF+ use Item IDs for now
tdis->ItemID = itemid;
}
else
{
tdis->ItemID = SerialNumber;
}
tdis->Unknown012 = 0;
Customer->QueuePacket(outapp);
safe_delete(outapp);
m_inv.DeleteItem(Slot);
}
// This updates the trader. Removes it from his trading bags.
//
const ItemInst* Inst = m_inv[Slot];
database.SaveInventory(CharacterID(), Inst, Slot);
EQApplicationPacket* outapp2;
if(Quantity < Charges)
outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
else
outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = Slot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
if(Quantity >= Charges)
Quantity = 1;
for(int i = 0; i < Quantity; i++) {
this->QueuePacket(outapp2);
}
safe_delete(outapp2);
//
// if(!Customer)
// return;
//
// Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
//
// if(Quantity < Charges)
// {
// Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
// m_inv.DeleteItem(Slot, Quantity);
// }
// else
// {
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
// TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
//
// tdis->Unknown000 = 0;
// tdis->TraderID = Customer->GetID();
// if (Customer->GetClientVersion() >= ClientVersion::RoF)
// {
// // RoF+ use Item IDs for now
// tdis->ItemID = itemid;
// }
// else
// {
// tdis->ItemID = SerialNumber;
// }
// tdis->Unknown012 = 0;
//
//
// Customer->QueuePacket(outapp);
// safe_delete(outapp);
//
// m_inv.DeleteItem(Slot);
// }
// // This updates the trader. Removes it from his trading bags.
// //
// const ItemInst* Inst = m_inv[Slot];
//
// database.SaveInventory(CharacterID(), Inst, Slot);
//
// EQApplicationPacket* outapp2;
//
// if(Quantity < Charges)
// outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
// else
// outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = Slot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// if(Quantity >= Charges)
// Quantity = 1;
//
// for(int i = 0; i < Quantity; i++) {
//
// this->QueuePacket(outapp2);
// }
// safe_delete(outapp2);
//
}
void Client::TraderUpdate(uint16 SlotID,uint32 TraderID){
// This method is no longer used.
@ -2507,347 +2507,347 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) {
}
void Client::SellToBuyer(const EQApplicationPacket *app) {
char* Buf = (char *)app->pBuffer;
char ItemName[64];
/*uint32 Action =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
uint32 Quantity = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 BuyerID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 BuySlot = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
uint32 ItemID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
/* ItemName */ VARSTRUCT_DECODE_STRING(ItemName, Buf);
/*uint32 Unknown2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
uint32 QtyBuyerWants = VARSTRUCT_DECODE_TYPE(uint32, Buf);
UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
uint32 Price = VARSTRUCT_DECODE_TYPE(uint32, Buf);
/*uint32 BuyerID2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
/*uint32 Unknown3 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
const ItemData *item = database.GetItem(ItemID);
if(!item || !Quantity || !Price || !QtyBuyerWants) return;
if (m_inv.HasItem(ItemID, Quantity, invWhereWorn | invWherePersonal | invWhereCursor) == INVALID_INDEX) {
Message(13, "You do not have %i %s on you.", Quantity, item->Name);
return;
}
Client *Buyer = entity_list.GetClientByID(BuyerID);
if(!Buyer || !Buyer->IsBuyer()) {
Message(13, "The Buyer has gone away.");
return;
}
// For Stackable items, HasSpaceForItem will try check if there is space to stack with existing stacks in
// the buyer inventory.
if(!(Buyer->GetInv().HasSpaceForItem(item, Quantity))) {
Message(13, "The Buyer does not have space for %i %s", Quantity, item->Name);
return;
}
if((static_cast<uint64>(Quantity) * static_cast<uint64>(Price)) > MAX_TRANSACTION_VALUE) {
Message(13, "That would exceed the single transaction limit of %u platinum.", MAX_TRANSACTION_VALUE / 1000);
return;
}
if(!Buyer->HasMoney(Quantity * Price)) {
Message(13, "The Buyer does not have sufficient money to purchase that quantity of %s.", item->Name);
Buyer->Message(13, "%s tried to sell you %i %s, but you have insufficient funds.", GetName(), Quantity, item->Name);
return;
}
if(Buyer->CheckLoreConflict(item)) {
Message(13, "That item is LORE and the Buyer already has one.");
Buyer->Message(13, "%s tried to sell you %s but this item is LORE and you already have one.",
GetName(), item->Name);
return;
}
if(item->NoDrop == 0) {
Message(13, "That item is NODROP.");
return;
}
if(!item->Stackable) {
for(uint32 i = 0; i < Quantity; i++) {
int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
// This shouldn't happen, as we already checked there was space in the Buyer's inventory
if (SellerSlot == INVALID_INDEX) {
if(i > 0) {
// Set the Quantity to the actual number we successfully transferred.
Quantity = i;
break;
}
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
if(!ItemToTransfer || !Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
if(ItemToTransfer)
safe_delete(ItemToTransfer);
return;
}
database.SaveInventory(CharacterID(), 0, SellerSlot);
safe_delete(ItemToTransfer);
// Remove the item from inventory, clientside
//
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp2);
safe_delete(outapp2);
}
}
else {
// Stackable
//
uint32 QuantityMoved = 0;
while(QuantityMoved < Quantity) {
// Find the slot on the seller that has a stack of at least 1 of the item
int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
if (SellerSlot == INVALID_INDEX) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
if(!ItemToTransfer) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
// If the stack we found has less than the quantity we are selling ...
if(ItemToTransfer->GetCharges() <= (Quantity - QuantityMoved)) {
// Transfer the entire stack
QuantityMoved += ItemToTransfer->GetCharges();
if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
safe_delete(ItemToTransfer);
return;
}
// Delete the entire stack from the seller's inventory
database.SaveInventory(CharacterID(), 0, SellerSlot);
safe_delete(ItemToTransfer);
// and tell the client to do the same.
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp2);
safe_delete(outapp2);
}
else {
//Move the amount we need, and put the rest of the stack back in the seller's inventory
//
int QuantityToRemoveFromStack = Quantity - QuantityMoved;
ItemToTransfer->SetCharges(ItemToTransfer->GetCharges() - QuantityToRemoveFromStack);
m_inv.PutItem(SellerSlot, *ItemToTransfer);
database.SaveInventory(CharacterID(), ItemToTransfer, SellerSlot);
ItemToTransfer->SetCharges(QuantityToRemoveFromStack);
if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
safe_delete(ItemToTransfer);
return;
}
safe_delete(ItemToTransfer);
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
for(int i = 0; i < QuantityToRemoveFromStack; i++)
QueuePacket(outapp2);
safe_delete(outapp2);
QuantityMoved = Quantity;
}
}
}
Buyer->TakeMoneyFromPP(Quantity * Price);
AddMoneyToPP(Quantity * Price, false);
if(RuleB(Bazaar, AuditTrail))
BazaarAuditTrail(GetName(), Buyer->GetName(), ItemName, Quantity, Quantity * Price, 1);
// We now send a packet to the Seller, which causes it to display 'You have sold <Qty> <Item> to <Player> for <money>'
//
// The PacketLength of 1016 is from the only instance of this packet I have seen, which is from Live, November 2008
// The Titanium/6.2 struct is slightly different in that it appears to use fixed length strings instead of variable
// length as used on Live. The extra space in the packet is also likely to be used for Item compensation, if we ever
// implement that.
//
uint32 PacketLength = 1016;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, PacketLength);
Buf = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_SellerTransactionComplete);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
if(GetClientVersion() >= ClientVersion::SoD)
{
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
}
sprintf(Buf, "%s", Buyer->GetName()); Buf += 64;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
sprintf(Buf, "%s", ItemName); Buf += 64;
QueuePacket(outapp);
// This next packet goes to the Buyer and produces the 'You've bought <Qty> <Item> from <Seller> for <money>'
//
Buf = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerTransactionComplete);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
if(Buyer->GetClientVersion() >= ClientVersion::SoD)
{
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
}
sprintf(Buf, "%s", GetName()); Buf += 64;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
sprintf(Buf, "%s", ItemName); Buf += 64;
Buyer->QueuePacket(outapp);
safe_delete(outapp);
// Next we update the buyer table in the database to reflect the reduced quantity the Buyer wants to buy.
//
database.UpdateBuyLine(Buyer->CharacterID(), BuySlot, QtyBuyerWants - Quantity);
// Next we update the Seller's Barter Window to reflect the reduced quantity the Buyer is now looking to buy.
//
EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_Barter, 936);
Buf = (char *)outapp3->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, Buf,ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
// If the amount we have just sold completely satisfies the quantity the Buyer was looking for,
// setting the next byte to 0 will remove the item from the Barter Window.
//
if(QtyBuyerWants - Quantity > 0) {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
}
else {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
}
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
QueuePacket(outapp3);
safe_delete(outapp3);
// The next packet updates the /buyer window with the reduced quantity, and toggles the buy line off if the
// quantity they wanted to buy has been met.
//
EQApplicationPacket* outapp4 = new EQApplicationPacket(OP_Barter, 936);
Buf = (char*)outapp4->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerItemUpdate);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
if((QtyBuyerWants - Quantity) > 0) {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
}
else {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
}
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x08f4); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
Buyer->QueuePacket(outapp4);
safe_delete(outapp4);
return;
//
// char* Buf = (char *)app->pBuffer;
//
// char ItemName[64];
//
// /*uint32 Action =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// uint32 Quantity = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 BuyerID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 BuySlot = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
// uint32 ItemID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// /* ItemName */ VARSTRUCT_DECODE_STRING(ItemName, Buf);
// /*uint32 Unknown2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// uint32 QtyBuyerWants = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
// uint32 Price = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// /*uint32 BuyerID2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// /*uint32 Unknown3 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
//
// const ItemData *item = database.GetItem(ItemID);
//
// if(!item || !Quantity || !Price || !QtyBuyerWants) return;
//
// if (m_inv.HasItem(ItemID, Quantity, invWhereWorn | invWherePersonal | invWhereCursor) == INVALID_INDEX) {
// Message(13, "You do not have %i %s on you.", Quantity, item->Name);
// return;
// }
//
//
// Client *Buyer = entity_list.GetClientByID(BuyerID);
//
// if(!Buyer || !Buyer->IsBuyer()) {
// Message(13, "The Buyer has gone away.");
// return;
// }
//
// // For Stackable items, HasSpaceForItem will try check if there is space to stack with existing stacks in
// // the buyer inventory.
// if(!(Buyer->GetInv().HasSpaceForItem(item, Quantity))) {
// Message(13, "The Buyer does not have space for %i %s", Quantity, item->Name);
// return;
// }
//
// if((static_cast<uint64>(Quantity) * static_cast<uint64>(Price)) > MAX_TRANSACTION_VALUE) {
// Message(13, "That would exceed the single transaction limit of %u platinum.", MAX_TRANSACTION_VALUE / 1000);
// return;
// }
//
// if(!Buyer->HasMoney(Quantity * Price)) {
// Message(13, "The Buyer does not have sufficient money to purchase that quantity of %s.", item->Name);
// Buyer->Message(13, "%s tried to sell you %i %s, but you have insufficient funds.", GetName(), Quantity, item->Name);
// return;
// }
//
// if(Buyer->CheckLoreConflict(item)) {
// Message(13, "That item is LORE and the Buyer already has one.");
// Buyer->Message(13, "%s tried to sell you %s but this item is LORE and you already have one.",
// GetName(), item->Name);
// return;
// }
//
// if(item->NoDrop == 0) {
// Message(13, "That item is NODROP.");
// return;
// }
//
// if(!item->Stackable) {
//
// for(uint32 i = 0; i < Quantity; i++) {
//
// int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
//
// // This shouldn't happen, as we already checked there was space in the Buyer's inventory
// if (SellerSlot == INVALID_INDEX) {
//
// if(i > 0) {
// // Set the Quantity to the actual number we successfully transferred.
// Quantity = i;
// break;
// }
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
//
// if(!ItemToTransfer || !Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
//
// if(ItemToTransfer)
// safe_delete(ItemToTransfer);
//
// return;
// }
//
// database.SaveInventory(CharacterID(), 0, SellerSlot);
//
// safe_delete(ItemToTransfer);
//
// // Remove the item from inventory, clientside
// //
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp2);
// safe_delete(outapp2);
//
// }
// }
// else {
// // Stackable
// //
// uint32 QuantityMoved = 0;
//
// while(QuantityMoved < Quantity) {
//
// // Find the slot on the seller that has a stack of at least 1 of the item
// int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
//
// if (SellerSlot == INVALID_INDEX) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
//
// if(!ItemToTransfer) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// // If the stack we found has less than the quantity we are selling ...
// if(ItemToTransfer->GetCharges() <= (Quantity - QuantityMoved)) {
// // Transfer the entire stack
//
// QuantityMoved += ItemToTransfer->GetCharges();
//
// if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// safe_delete(ItemToTransfer);
// return;
// }
// // Delete the entire stack from the seller's inventory
// database.SaveInventory(CharacterID(), 0, SellerSlot);
//
// safe_delete(ItemToTransfer);
//
// // and tell the client to do the same.
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp2);
// safe_delete(outapp2);
// }
// else {
// //Move the amount we need, and put the rest of the stack back in the seller's inventory
// //
// int QuantityToRemoveFromStack = Quantity - QuantityMoved;
//
// ItemToTransfer->SetCharges(ItemToTransfer->GetCharges() - QuantityToRemoveFromStack);
//
// m_inv.PutItem(SellerSlot, *ItemToTransfer);
//
// database.SaveInventory(CharacterID(), ItemToTransfer, SellerSlot);
//
// ItemToTransfer->SetCharges(QuantityToRemoveFromStack);
//
// if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// safe_delete(ItemToTransfer);
// return;
// }
//
// safe_delete(ItemToTransfer);
//
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// for(int i = 0; i < QuantityToRemoveFromStack; i++)
// QueuePacket(outapp2);
//
// safe_delete(outapp2);
//
// QuantityMoved = Quantity;
// }
// }
//
// }
//
// Buyer->TakeMoneyFromPP(Quantity * Price);
//
// AddMoneyToPP(Quantity * Price, false);
//
// if(RuleB(Bazaar, AuditTrail))
// BazaarAuditTrail(GetName(), Buyer->GetName(), ItemName, Quantity, Quantity * Price, 1);
//
// // We now send a packet to the Seller, which causes it to display 'You have sold <Qty> <Item> to <Player> for <money>'
// //
// // The PacketLength of 1016 is from the only instance of this packet I have seen, which is from Live, November 2008
// // The Titanium/6.2 struct is slightly different in that it appears to use fixed length strings instead of variable
// // length as used on Live. The extra space in the packet is also likely to be used for Item compensation, if we ever
// // implement that.
// //
// uint32 PacketLength = 1016;
//
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, PacketLength);
//
// Buf = (char *)outapp->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_SellerTransactionComplete);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
//
// if(GetClientVersion() >= ClientVersion::SoD)
// {
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
// }
//
// sprintf(Buf, "%s", Buyer->GetName()); Buf += 64;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
//
// sprintf(Buf, "%s", ItemName); Buf += 64;
//
// QueuePacket(outapp);
//
// // This next packet goes to the Buyer and produces the 'You've bought <Qty> <Item> from <Seller> for <money>'
// //
//
// Buf = (char *)outapp->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerTransactionComplete);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
//
// if(Buyer->GetClientVersion() >= ClientVersion::SoD)
// {
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
// }
//
// sprintf(Buf, "%s", GetName()); Buf += 64;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
//
// sprintf(Buf, "%s", ItemName); Buf += 64;
//
// Buyer->QueuePacket(outapp);
//
// safe_delete(outapp);
//
// // Next we update the buyer table in the database to reflect the reduced quantity the Buyer wants to buy.
// //
// database.UpdateBuyLine(Buyer->CharacterID(), BuySlot, QtyBuyerWants - Quantity);
//
// // Next we update the Seller's Barter Window to reflect the reduced quantity the Buyer is now looking to buy.
// //
// EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_Barter, 936);
//
// Buf = (char *)outapp3->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Unknown
// VARSTRUCT_ENCODE_TYPE(uint32, Buf,ItemID);
// VARSTRUCT_ENCODE_STRING(Buf, ItemName);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
//
// // If the amount we have just sold completely satisfies the quantity the Buyer was looking for,
// // setting the next byte to 0 will remove the item from the Barter Window.
// //
// if(QtyBuyerWants - Quantity > 0) {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
// }
// else {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
// }
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
//
// VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
//
// QueuePacket(outapp3);
// safe_delete(outapp3);
//
// // The next packet updates the /buyer window with the reduced quantity, and toggles the buy line off if the
// // quantity they wanted to buy has been met.
// //
// EQApplicationPacket* outapp4 = new EQApplicationPacket(OP_Barter, 936);
//
// Buf = (char*)outapp4->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerItemUpdate);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
// VARSTRUCT_ENCODE_STRING(Buf, ItemName);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
//
// if((QtyBuyerWants - Quantity) > 0) {
//
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
// }
// else {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
// }
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x08f4); // Unknown
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
// VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
//
// Buyer->QueuePacket(outapp4);
// safe_delete(outapp4);
//
// return;
}
void Client::SendBuyerPacket(Client* Buyer) {