mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 02:11:30 +00:00
(RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional.
This commit is contained in:
parent
db3feafe48
commit
28be3b87b7
@ -1,5 +1,8 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 02/16/2015 ==
|
||||
Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional.
|
||||
|
||||
== 02/14/2015 ==
|
||||
Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet.
|
||||
|
||||
|
||||
@ -3578,14 +3578,13 @@ namespace RoF2
|
||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||
for (uint32 i = 0; i < 200; i++)
|
||||
{
|
||||
//strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
|
||||
//snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]);
|
||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0);
|
||||
eq->items[i].Unknown18 = 0;
|
||||
if (i < 80) {
|
||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]);
|
||||
eq->ItemCost[i] = emu->ItemCost[i];
|
||||
}
|
||||
else {
|
||||
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0);
|
||||
eq->ItemCost[i] = 0;
|
||||
}
|
||||
}
|
||||
@ -3637,18 +3636,61 @@ namespace RoF2
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderShop)
|
||||
ENCODE(OP_TraderDelItem)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
||||
|
||||
//eq->Code = emu->Unknown004;
|
||||
OUT(TraderID);
|
||||
OUT(Approval);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderDelItem): TraderID %d, SerialNumber: %d", emu->TraderID, emu->ItemID);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_TraderShop)
|
||||
{
|
||||
uint32 psize = (*p)->size;
|
||||
if (psize == sizeof(TraderClick_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
|
||||
eq->Code = 28; // Seen on Live
|
||||
OUT(TraderID);
|
||||
OUT(Approval);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else if (psize == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
OUT(Action);
|
||||
OUT(TraderID);
|
||||
|
||||
//memcpy(eq->BuyerName, emu->BuyerName, sizeof(eq->BuyerName));
|
||||
//memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
||||
|
||||
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||
OUT(ItemID);
|
||||
OUT(AlreadySold);
|
||||
OUT(Price);
|
||||
OUT(Quantity);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Encode Size Unknown (%d)", psize);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_TributeInfo)
|
||||
{
|
||||
ENCODE_LENGTH_ATLEAST(TributeAbility_Struct);
|
||||
@ -4961,19 +5003,38 @@ namespace RoF2
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||
//MEMSET_IN(TraderClick_Struct);
|
||||
|
||||
//emu->Unknown004 = eq->Code;
|
||||
IN(TraderID);
|
||||
IN(Approval);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decoded packet size (%d) to size (%d)", sizeof(structs::TraderClick_Struct), sizeof(TraderClick_Struct));
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == sizeof(structs::TraderBuy_Struct))
|
||||
{
|
||||
|
||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||
|
||||
IN(Action);
|
||||
IN(Price);
|
||||
IN(TraderID);
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d",
|
||||
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == 4)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Mismatch (%d), expected (%d)", psize, sizeof(structs::TraderClick_Struct));
|
||||
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Unknown (%d)", psize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
E(OP_SendMembershipDetails)
|
||||
E(OP_TraderShop)
|
||||
E(OP_TraderDelItem)
|
||||
|
||||
// incoming packets that require a DECODE translation:
|
||||
// Begin RoF2 Decodes
|
||||
|
||||
@ -3224,6 +3224,26 @@ struct TraderStatus_Struct {
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Unknown008;
|
||||
/*012*/ uint32 Unknown012;
|
||||
/*016*/ uint32 TraderID;
|
||||
/*020*/ char BuyerName[64];
|
||||
/*084*/ char SellerName[64];
|
||||
/*148*/ char Unknown148[32];
|
||||
/*180*/ char ItemName[64];
|
||||
/*244*/ char SerialNumber[16];
|
||||
/*260*/ uint32 Unknown076;
|
||||
/*264*/ uint32 ItemID;
|
||||
/*268*/ uint32 Price;
|
||||
/*272*/ uint32 AlreadySold;
|
||||
/*276*/ uint32 Unknown276;
|
||||
/*280*/ uint32 Quantity;
|
||||
/*284*/
|
||||
};
|
||||
|
||||
struct TraderBuy_Struct_OLD {
|
||||
/*000*/ uint32 Action;
|
||||
/*004*/ uint32 Unknown004;
|
||||
/*008*/ uint32 Price;
|
||||
@ -3253,19 +3273,12 @@ struct MoneyUpdate_Struct{
|
||||
int32 copper;
|
||||
};
|
||||
|
||||
//struct MoneyUpdate_Struct
|
||||
//{
|
||||
//*0000*/ uint32 spawn_id; // ***Placeholder
|
||||
//*0004*/ uint32 cointype; // Coin Type
|
||||
//*0008*/ uint32 amount; // Amount
|
||||
//*0012*/
|
||||
//};
|
||||
|
||||
|
||||
struct TraderDelItem_Struct{
|
||||
uint32 slotid;
|
||||
uint32 quantity;
|
||||
uint32 unknown;
|
||||
/*000*/ uint32 Unknown000;
|
||||
/*004*/ uint32 TraderID;
|
||||
/*008*/ char SerialNumber[16];
|
||||
/*024*/ uint32 Unknown012;
|
||||
/*028*/
|
||||
};
|
||||
|
||||
struct TraderClick_Struct{
|
||||
|
||||
@ -402,12 +402,12 @@ OP_LootComplete=0x55c4
|
||||
|
||||
# bazaar trader stuff:
|
||||
OP_BazaarSearch=0x39d6
|
||||
OP_TraderDelItem=0x0000
|
||||
OP_TraderDelItem=0x5829
|
||||
OP_BecomeTrader=0x61b3
|
||||
OP_TraderShop=0x31df
|
||||
OP_Trader=0x4ef5
|
||||
OP_TraderBuy=0x0000
|
||||
OP_Barter=0x243a
|
||||
OP_TraderBuy=0x0000
|
||||
OP_ShopItem=0x0000
|
||||
OP_BazaarInspect=0x0000
|
||||
OP_Bazaar=0x0000
|
||||
|
||||
@ -165,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
Trader=false;
|
||||
Buyer = false;
|
||||
CustomerID = 0;
|
||||
TraderID = 0;
|
||||
TrackingID = 0;
|
||||
WID = 0;
|
||||
account_id = 0;
|
||||
|
||||
@ -266,10 +266,11 @@ public:
|
||||
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||
ItemInst* FindTraderItemBySerialNumber(int32 SerialNumber);
|
||||
void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot);
|
||||
void NukeTraderItem(uint16 slot,int16 charges,uint16 quantity,Client* customer,uint16 traderslot, int uniqueid);
|
||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges);
|
||||
void NukeTraderItem(uint16 slot, int16 charges, uint16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
|
||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
||||
@ -1388,6 +1389,7 @@ private:
|
||||
uint16 BoatID;
|
||||
uint16 TrackingID;
|
||||
uint16 CustomerID;
|
||||
uint16 TraderID;
|
||||
uint32 account_creation;
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
|
||||
@ -11952,12 +11952,6 @@ void Client::Handle_OP_ShopEnd(const EQApplicationPacket *app)
|
||||
{
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
//EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopEndConfirm, 2);
|
||||
//outapp->pBuffer[0] = 0x0a;
|
||||
//outapp->pBuffer[1] = 0x66;
|
||||
//QueuePacket(outapp);
|
||||
//safe_delete(outapp);
|
||||
//Save();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13443,23 +13437,22 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
//
|
||||
// Client has elected to buy an item from a Trader
|
||||
//
|
||||
if (app->size != sizeof(TraderBuy_Struct)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderBuy, size=%i, expected %i", app->size, sizeof(TraderBuy_Struct));
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size == sizeof(TraderBuy_Struct)){
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
}
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Struct size mismatch");
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13521,56 +13514,105 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
||||
{
|
||||
// Bazaar Trader:
|
||||
//
|
||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||
// browse their goods.
|
||||
//
|
||||
|
||||
if (app->size != sizeof(TraderClick_Struct)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderShop, size=%i, expected %i", app->size, sizeof(TraderClick_Struct));
|
||||
return;
|
||||
}
|
||||
|
||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
|
||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||
|
||||
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
||||
|
||||
if (Trader)
|
||||
if (app->size == sizeof(TraderClick_Struct))
|
||||
{
|
||||
outtcs->Approval = Trader->WithCustomer(GetID());
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||
" returned a nullptr pointer");
|
||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||
// browse their goods.
|
||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
|
||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||
|
||||
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
||||
|
||||
if (Trader)
|
||||
{
|
||||
outtcs->Approval = Trader->WithCustomer(GetID());
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||
" returned a nullptr pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
outtcs->TraderID = tcs->TraderID;
|
||||
|
||||
outtcs->Unknown008 = 0x3f800000;
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
if (outtcs->Approval) {
|
||||
this->BulkSendTraderInventory(Trader->CharacterID());
|
||||
Trader->Trader_CustomerBrowsing(this);
|
||||
TraderID = tcs->TraderID;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy");
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (app->size == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
// RoF+
|
||||
// Customer has purchased an item from the Trader
|
||||
|
||||
outtcs->TraderID = tcs->TraderID;
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
outtcs->Unknown008 = 0x3f800000;
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID))
|
||||
{
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "OP_TraderShop: Null Client Pointer");
|
||||
}
|
||||
}
|
||||
else if (app->size == 4)
|
||||
{
|
||||
// RoF+
|
||||
// Customer has closed the trade window
|
||||
uint32 Command = *((uint32 *)app->pBuffer);
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
if (outtcs->Approval) {
|
||||
this->BulkSendTraderInventory(Trader->CharacterID());
|
||||
Trader->Trader_CustomerBrowsing(this);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
||||
if (Command == 4)
|
||||
{
|
||||
Client* c = entity_list.GetClientByID(TraderID);
|
||||
TraderID = 0;
|
||||
if (c)
|
||||
{
|
||||
c->WithCustomer(0);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction - Code %d", Command);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer for Trader - Code %d", Command);
|
||||
}
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unhandled Code %d", Command);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy");
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
||||
|
||||
239
zone/trading.cpp
239
zone/trading.cpp
@ -1098,7 +1098,15 @@ void Client::Trader_EndTrader() {
|
||||
for(int i = 0; i < 80; i++) {
|
||||
if(gis->Items[i] != 0) {
|
||||
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = gis->Items[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
}
|
||||
|
||||
Customer->QueuePacket(outapp);
|
||||
}
|
||||
@ -1220,6 +1228,29 @@ void Client::BulkSendTraderInventory(uint32 char_id) {
|
||||
safe_delete(TraderItems);
|
||||
}
|
||||
|
||||
uint32 Client::FindTraderItemSerialNumber(int32 ItemID) {
|
||||
|
||||
ItemInst* item = nullptr;
|
||||
uint16 SlotID = 0;
|
||||
for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){
|
||||
item = this->GetInv().GetItem(i);
|
||||
if (item && item->GetItem()->ID == 17899){ //Traders Satchel
|
||||
for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) {
|
||||
// we already have the parent bag and a contents iterator..why not just iterate the bag!??
|
||||
SlotID = Inventory::CalcSlotId(i, x);
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
if (item) {
|
||||
if (item->GetID() == ItemID)
|
||||
return item->GetSerialNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::FindTraderItemSerialNumber Couldn't find item! Item ID %i", ItemID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){
|
||||
|
||||
ItemInst* item = nullptr;
|
||||
@ -1287,9 +1318,9 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
||||
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
|
||||
if(item && item->GetSerialNumber() == SerialNumber &&
|
||||
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1))){
|
||||
|
||||
if (item && item->GetSerialNumber() == SerialNumber &&
|
||||
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1)))
|
||||
{
|
||||
return SlotID;
|
||||
}
|
||||
}
|
||||
@ -1301,21 +1332,34 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int SerialNumber) {
|
||||
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) {
|
||||
|
||||
if(!Customer)
|
||||
return;
|
||||
|
||||
if(!Customer) return;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
|
||||
if(Quantity < Charges) {
|
||||
|
||||
if(Quantity < Charges)
|
||||
{
|
||||
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
|
||||
m_inv.DeleteItem(Slot, Quantity);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
|
||||
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
|
||||
|
||||
tdis->Unknown000 = 0;
|
||||
tdis->TraderID = Customer->GetID();
|
||||
tdis->ItemID = SerialNumber;
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = itemid;
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = SerialNumber;
|
||||
}
|
||||
tdis->Unknown012 = 0;
|
||||
|
||||
|
||||
@ -1323,7 +1367,6 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu
|
||||
safe_delete(outapp);
|
||||
|
||||
m_inv.DeleteItem(Slot);
|
||||
|
||||
}
|
||||
// This updates the trader. Removes it from his trading bags.
|
||||
//
|
||||
@ -1374,49 +1417,61 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
||||
int16 Charges=0;
|
||||
|
||||
uint16 SlotID = FindTraderItem(SerialNumber, Quantity);
|
||||
if(SlotID > 0){
|
||||
|
||||
if(SlotID > 0) {
|
||||
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
|
||||
if(item) {
|
||||
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
||||
|
||||
Stackable = item->IsStackable();
|
||||
|
||||
if(!Stackable)
|
||||
Quantity = (Charges > 0) ? Charges : 1;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
||||
if (!item)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Could not find Item: %i on Trader: %s", SerialNumber, Quantity, this->GetName());
|
||||
return;
|
||||
}
|
||||
if(item && (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)){
|
||||
|
||||
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
||||
|
||||
Stackable = item->IsStackable();
|
||||
|
||||
if (!Stackable)
|
||||
Quantity = (Charges > 0) ? Charges : 1;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
||||
|
||||
if (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)
|
||||
{
|
||||
this->DeleteItemInInventory(SlotID, Quantity);
|
||||
|
||||
TraderCharges_Struct* GetSlot = database.LoadTraderItemWithCharges(this->CharacterID());
|
||||
TraderCharges_Struct* TraderItems = database.LoadTraderItemWithCharges(this->CharacterID());
|
||||
|
||||
uint8 Count = 0;
|
||||
|
||||
bool TestSlot = true;
|
||||
|
||||
for(int y = 0;y < 80;y++){
|
||||
for(int i = 0;i < 80;i++){
|
||||
|
||||
if(TestSlot && GetSlot->SerialNumber[y] == SerialNumber){
|
||||
|
||||
database.DeleteTraderItem(this->CharacterID(),y);
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, GetSlot->SerialNumber[y]);
|
||||
if(TestSlot && TraderItems->SerialNumber[i] == SerialNumber)
|
||||
{
|
||||
database.DeleteTraderItem(this->CharacterID(),i);
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, TraderItems->SerialNumber[i], TraderItems->ItemID[i]);
|
||||
TestSlot=false;
|
||||
}
|
||||
else if(GetSlot->ItemID[y] > 0)
|
||||
else if (TraderItems->ItemID[i] > 0)
|
||||
{
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
if(Count == 0)
|
||||
if (Count == 0)
|
||||
{
|
||||
Trader_EndTrader();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if(item) {
|
||||
else
|
||||
{
|
||||
database.UpdateTraderItemCharges(this->CharacterID(), item->GetSerialNumber(), Charges-Quantity);
|
||||
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber());
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber(), item->GetID());
|
||||
|
||||
return;
|
||||
|
||||
@ -1426,22 +1481,38 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
||||
Quantity,this->GetName());
|
||||
}
|
||||
|
||||
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges){
|
||||
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges, uint32 itemid){
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
|
||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||
|
||||
memcpy(outtbs, tbs, app->size);
|
||||
|
||||
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Serial Number back to Item ID for RoF+
|
||||
outtbs->ItemID = itemid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// RoF+ requires individual price, but older clients require total price
|
||||
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
||||
}
|
||||
|
||||
outtbs->Quantity = TraderItemCharges;
|
||||
|
||||
// This should probably be trader ID, not customer ID as it is below.
|
||||
outtbs->TraderID = this->GetID();
|
||||
|
||||
outtbs->AlreadySold = 0;
|
||||
|
||||
QueuePacket(outapp);
|
||||
@ -1478,7 +1549,7 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char *
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){
|
||||
void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplicationPacket* app){
|
||||
|
||||
if(!Trader) return;
|
||||
|
||||
@ -1487,13 +1558,34 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
return;
|
||||
}
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader,sizeof(TraderBuy_Struct));
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
|
||||
if (Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
//outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
//outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
|
||||
outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct));
|
||||
|
||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||
|
||||
outtbs->ItemID = tbs->ItemID;
|
||||
|
||||
const ItemInst* BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
||||
const ItemInst* BuyItem = nullptr;
|
||||
uint32 ItemID = 0;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Item ID to Serial Number for RoF+
|
||||
ItemID = tbs->ItemID;
|
||||
tbs->ItemID = Trader->FindTraderItemSerialNumber(tbs->ItemID);
|
||||
}
|
||||
|
||||
BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
||||
|
||||
if(!BuyItem) {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Unable to find item on trader.");
|
||||
@ -1543,12 +1635,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
return;
|
||||
}
|
||||
|
||||
ReturnTraderReq(app, outtbs->Quantity);
|
||||
ReturnTraderReq(app, outtbs->Quantity, ItemID);
|
||||
|
||||
outtbs->TraderID = this->GetID();
|
||||
|
||||
outtbs->Action = BazaarBuyItem;
|
||||
|
||||
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
|
||||
|
||||
int TraderSlot = 0;
|
||||
@ -1558,54 +1648,50 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
else
|
||||
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
|
||||
|
||||
|
||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoneyUpdate,sizeof(MoneyUpdate_Struct));
|
||||
|
||||
MoneyUpdate_Struct* mus= (MoneyUpdate_Struct*)outapp2->pBuffer;
|
||||
|
||||
// This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000
|
||||
uint32 TotalCost = tbs->Price * outtbs->Quantity;
|
||||
|
||||
outtbs->Price = TotalCost;
|
||||
if (Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ uses individual item price where older clients use total price
|
||||
outtbs->Price = tbs->Price;
|
||||
}
|
||||
else
|
||||
{
|
||||
outtbs->Price = TotalCost;
|
||||
}
|
||||
|
||||
this->TakeMoneyFromPP(TotalCost);
|
||||
|
||||
mus->platinum = TotalCost / 1000;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Customer Paid: %d in Copper", TotalCost);
|
||||
|
||||
TotalCost -= (mus->platinum * 1000);
|
||||
uint32 platinum = TotalCost / 1000;
|
||||
TotalCost -= (platinum * 1000);
|
||||
uint32 gold = TotalCost / 100;
|
||||
TotalCost -= (gold * 100);
|
||||
uint32 silver = TotalCost / 10;
|
||||
TotalCost -= (silver * 10);
|
||||
uint32 copper = TotalCost;
|
||||
|
||||
mus->gold = TotalCost / 100;
|
||||
Trader->AddMoneyToPP(copper, silver, gold, platinum, true);
|
||||
|
||||
TotalCost -= (mus->gold * 100);
|
||||
|
||||
mus->silver = TotalCost / 10;
|
||||
|
||||
TotalCost -= (mus->silver * 10);
|
||||
|
||||
mus->copper = TotalCost;
|
||||
|
||||
Trader->AddMoneyToPP(mus->copper,mus->silver,mus->gold,mus->platinum,false);
|
||||
|
||||
mus->platinum = Trader->GetPlatinum();
|
||||
mus->gold = Trader->GetGold();
|
||||
mus->silver = Trader->GetSilver();
|
||||
mus->copper = Trader->GetCopper();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper);
|
||||
|
||||
TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity);
|
||||
|
||||
Trader->QueuePacket(outapp2);
|
||||
|
||||
|
||||
if(RuleB(Bazaar, AuditTrail))
|
||||
BazaarAuditTrail(Trader->GetName(), GetName(), BuyItem->GetItem()->Name, outtbs->Quantity, outtbs->Price, 0);
|
||||
|
||||
Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0);
|
||||
|
||||
if (ItemID > 0 && Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Serial Number back to ItemID for RoF+
|
||||
outtbs->ItemID = ItemID;
|
||||
}
|
||||
|
||||
Trader->QueuePacket(outapp);
|
||||
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete(outapp2);
|
||||
}
|
||||
|
||||
void Client::SendBazaarWelcome()
|
||||
@ -1996,6 +2082,15 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St
|
||||
for(int i = 0; i < 80; i++) {
|
||||
|
||||
if(gis->ItemID[i] == ItemID) {
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = gis->ItemID[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
}
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Telling customer to remove item %i with %i charges and S/N %i",
|
||||
ItemID, Charges, gis->SerialNumber[i]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user