mirror of
https://github.com/EQEmu/Server.git
synced 2026-08-29 04:28:00 +00:00
Merge branch 'master' of github.com:EQEmu/Server
This commit is contained in:
+468
-191
@@ -22,7 +22,10 @@
|
||||
#include "../common/rulesys.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "worldserver.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
// The maximum amount of a single bazaar/barter transaction expressed in copper.
|
||||
// Equivalent to 2 Million plat
|
||||
@@ -71,8 +74,8 @@ void Trade::Start(uint32 mob_id, bool initiate_with)
|
||||
}
|
||||
|
||||
// Add item from a given slot to trade bucket (automatically does bag data too)
|
||||
void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size) {
|
||||
// TODO: review for inventory saves
|
||||
void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
||||
// TODO: review for inventory saves / consider changing return type to bool so failure can be passed to desync handler
|
||||
|
||||
if (!owner || !owner->IsClient()) {
|
||||
// This should never happen
|
||||
@@ -121,7 +124,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
|
||||
if (_stack_size > 0)
|
||||
inst->SetCharges(_stack_size);
|
||||
else
|
||||
client->DeleteItemInInventory(from_slot_id);
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
|
||||
SendItemData(inst2, trade_slot_id);
|
||||
}
|
||||
@@ -136,7 +139,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
|
||||
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
|
||||
|
||||
client->PutItemInInventory(trade_slot_id, *inst);
|
||||
client->DeleteItemInInventory(from_slot_id);
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,200 +319,464 @@ void Trade::DumpTrade()
|
||||
#endif
|
||||
|
||||
void Client::ResetTrade() {
|
||||
const Item_Struct* TempItem = 0;
|
||||
ItemInst* ins;
|
||||
int x;
|
||||
AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true);
|
||||
for(x = EmuConstants::TRADE_BEGIN; x <= EmuConstants::TRADE_END; x++)
|
||||
{
|
||||
TempItem = 0;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem)
|
||||
{
|
||||
bool is_arrow = (TempItem->ItemType == ItemTypeArrow) ? true : false;
|
||||
int freeslotid = GetInv().FindFreeSlot(ins->IsType(ItemClassContainer), true, TempItem->Size, is_arrow);
|
||||
if (freeslotid == INVALID_INDEX)
|
||||
{
|
||||
DropInst(ins);
|
||||
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else
|
||||
{
|
||||
PutItemInInventory(freeslotid, *ins);
|
||||
SendItemPacket(freeslotid, ins, ItemPacketTrade);
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
DeleteItemInInventory(x);
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
ItemInst* partial_inst = GetInv().GetItem(free_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
PutItemInInventory(free_slot, *partial_inst);
|
||||
SendItemPacket(free_slot, partial_inst, ItemPacketTrade);
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) {
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, std::list<void*>* event_details) {
|
||||
if(tradingWith && tradingWith->IsClient()) {
|
||||
Client* other = tradingWith->CastToClient();
|
||||
QSPlayerLogTrade_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
if(other) {
|
||||
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
|
||||
|
||||
int16 slot_id;
|
||||
const Item_Struct* item = nullptr;
|
||||
QSPlayerLogTrade_Struct* qsaudit = nullptr;
|
||||
bool QSPLT = false;
|
||||
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
|
||||
// step 0: pre-processing
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
qsaudit = (QSPlayerLogTrade_Struct*) qspack->pBuffer;
|
||||
QSPLT = true;
|
||||
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
if (finalizer) {
|
||||
qs_audit->char2_id = this->character_id;
|
||||
|
||||
if(finalizer) { qsaudit->char2_id = this->character_id; }
|
||||
else { qsaudit->char1_id = this->character_id; }
|
||||
qs_audit->char2_money.platinum = this->trade->pp;
|
||||
qs_audit->char2_money.gold = this->trade->gp;
|
||||
qs_audit->char2_money.silver = this->trade->sp;
|
||||
qs_audit->char2_money.copper = this->trade->cp;
|
||||
}
|
||||
else {
|
||||
qs_audit->char1_id = this->character_id;
|
||||
|
||||
qs_audit->char1_money.platinum = this->trade->pp;
|
||||
qs_audit->char1_money.gold = this->trade->gp;
|
||||
qs_audit->char1_money.silver = this->trade->sp;
|
||||
qs_audit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
}
|
||||
|
||||
// Move each trade slot into free inventory slot
|
||||
for(int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){
|
||||
const ItemInst* inst = m_inv[i];
|
||||
uint16 parent_offset = 0;
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if(inst == nullptr) { continue; }
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
mlog(TRADING__CLIENT, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
mlog(TRADING__CLIENT, "Giving %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, i, other->GetName());
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
/// Log Player Trades through QueryServ if Rule Enabled
|
||||
if(QSPLT) {
|
||||
uint16 item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
parent_offset = item_count;
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = i;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = inst->GetID();
|
||||
qsaudit->items[item_count].charges = inst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = inst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = inst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = inst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = inst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = inst->GetAugmentItemID(5);
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = 1;
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
// Pseudo-Slot ID's are generated based on how the db saves bag items...
|
||||
for(uint8 j = SUB_BEGIN; j < inst->GetItem()->BagSlots; j++) {
|
||||
const ItemInst* baginst = inst->GetItem(j);
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if(baginst == nullptr) { continue; }
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
int16 k=Inventory::CalcSlotId(i, j);
|
||||
item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = Inventory::CalcSlotId(free_slot, sub_slot);
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = k;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = baginst->GetID();
|
||||
qsaudit->items[item_count].charges = baginst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = baginst->GetAugmentItemID(5);
|
||||
event_details->push_back(detail);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false;
|
||||
slot_id = other->GetInv().FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow);
|
||||
|
||||
mlog(TRADING__CLIENT, "Trying to put %s (%d) into slot %d", inst->GetItem()->Name, inst->GetItem()->ID, slot_id);
|
||||
|
||||
if(other->PutItemInInventory(slot_id, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transfered, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_slot = slot_id;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(slot_id, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_slot = to_bagslot_id;
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
mlog(TRADING__ERROR, "Unable to give item %d (%d) to %s, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i);
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
else {
|
||||
PushItemOnCursor(*inst, true);
|
||||
DeleteItemInInventory(i);
|
||||
}
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
ItemInst* partial_inst = other->GetInv().GetItem(partial_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
break;
|
||||
}
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
int16 partial_charges = partial_inst->GetCharges();
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
mlog(TRADING__CLIENT, "Transferring partial stack %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
if (other->PutItemInInventory(partial_slot, *partial_inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges()));
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = partial_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, other->GetName(), (old_charges - inst->GetCharges()));
|
||||
|
||||
inst->SetCharges(old_charges);
|
||||
partial_inst->SetCharges(partial_charges);
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Money - look into how NPC's receive cash
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
// This is currently setup to show character offers, not receipts
|
||||
if(QSPLT) {
|
||||
if(finalizer) {
|
||||
qsaudit->char2_money.platinum = this->trade->pp;
|
||||
qsaudit->char2_money.gold = this->trade->gp;
|
||||
qsaudit->char2_money.silver = this->trade->sp;
|
||||
qsaudit->char2_money.copper = this->trade->cp;
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = this->character_id;
|
||||
detail->to_slot = bias_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qsaudit->char1_money.platinum = this->trade->pp;
|
||||
qsaudit->char1_money.gold = this->trade->gp;
|
||||
qsaudit->char1_money.silver = this->trade->sp;
|
||||
qsaudit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
mlog(TRADING__CLIENT, "Giving item %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (!inst->IsStackable() ? 1 : inst->GetCharges());
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
// 'step 3' should never really see containers..but, just in case...
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,62 +784,72 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
|
||||
}
|
||||
}
|
||||
else if(tradingWith && tradingWith->IsNPC()) {
|
||||
QSPlayerLogHandin_Struct* qsaudit = nullptr;
|
||||
bool QSPLH = false;
|
||||
QSPlayerLogHandin_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
// Currently provides only basic functionality. Calling method will also
|
||||
// need to be modified before item returns and rewards can be logged. -U
|
||||
qsaudit = (QSPlayerLogHandin_Struct*) qspack->pBuffer;
|
||||
QSPLH = true;
|
||||
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
qsaudit->quest_id = 0;
|
||||
qsaudit->char_id = character_id;
|
||||
qsaudit->char_money.platinum = trade->pp;
|
||||
qsaudit->char_money.gold = trade->gp;
|
||||
qsaudit->char_money.silver = trade->sp;
|
||||
qsaudit->char_money.copper = trade->cp;
|
||||
qsaudit->char_count = 0;
|
||||
qsaudit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qsaudit->npc_money.platinum = 0;
|
||||
qsaudit->npc_money.gold = 0;
|
||||
qsaudit->npc_money.silver = 0;
|
||||
qsaudit->npc_money.copper = 0;
|
||||
qsaudit->npc_count = 0;
|
||||
qs_audit->quest_id = 0;
|
||||
qs_audit->char_id = character_id;
|
||||
qs_audit->char_money.platinum = trade->pp;
|
||||
qs_audit->char_money.gold = trade->gp;
|
||||
qs_audit->char_money.silver = trade->sp;
|
||||
qs_audit->char_money.copper = trade->cp;
|
||||
qs_audit->char_count = 0;
|
||||
qs_audit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qs_audit->npc_money.platinum = 0;
|
||||
qs_audit->npc_money.gold = 0;
|
||||
qs_audit->npc_money.silver = 0;
|
||||
qs_audit->npc_money.copper = 0;
|
||||
qs_audit->npc_count = 0;
|
||||
}
|
||||
|
||||
if(QSPLH) { // This can be incoporated below when revisions are made -U
|
||||
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) {
|
||||
const ItemInst* trade_inst = m_inv[slot_id];
|
||||
if(qs_log) { // This can be incorporated below when revisions are made -U
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
||||
const ItemInst* trade_inst = m_inv[trade_slot];
|
||||
|
||||
if(trade_inst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
QSHandinItems_Struct* detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = slot_id;
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_inst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_inst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = trade_slot;
|
||||
detail->item_id = trade_inst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
|
||||
if(trade_inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bag_idx = SUB_BEGIN; bag_idx < trade_inst->GetItem()->BagSlots; bag_idx++) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(bag_idx);
|
||||
for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot);
|
||||
|
||||
if(trade_baginst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = Inventory::CalcSlotId(slot_id, bag_idx);
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_baginst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_baginst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->item_id = trade_baginst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user