From 811e8809ccd60fbdbd542e8635681064cbc95f5a Mon Sep 17 00:00:00 2001 From: Trevius Date: Sat, 14 Feb 2015 11:09:36 -0600 Subject: [PATCH] (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. --- changelog.txt | 3 ++ common/eq_packet_structs.h | 2 + common/opcode_dispatch.h | 6 +-- common/patches/rof2.cpp | 53 ++++++++++++++++++++----- common/patches/rof2_ops.h | 3 ++ common/patches/rof2_structs.h | 14 +++++-- common/patches/ss_define.h | 4 +- zone/client_packet.cpp | 75 ++++++++++++++++++++++++----------- zone/trading.cpp | 1 - 9 files changed, 119 insertions(+), 42 deletions(-) diff --git a/changelog.txt b/changelog.txt index f1ff71c90..99da395d8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 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. + == 02/12/2015 == Akkadius: Implement zone based gravity, required SQL DB change - To test `zone` table `gravity` values, change the value and use #zheader to test diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 62f6072b3..cd30cf3d1 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3146,6 +3146,7 @@ struct Trader_ShowItems_Struct{ /*000*/ uint32 Code; /*004*/ uint32 TraderID; /*008*/ uint32 Unknown08[3]; +/*020*/ }; struct TraderBuy_Struct{ @@ -3194,6 +3195,7 @@ struct TraderClick_Struct{ /*004*/ uint32 Unknown004; /*008*/ uint32 Unknown008; /*012*/ uint32 Approval; +/*016*/ }; struct FormattedMessage_Struct{ diff --git a/common/opcode_dispatch.h b/common/opcode_dispatch.h index 46e8b9099..657d9a525 100644 --- a/common/opcode_dispatch.h +++ b/common/opcode_dispatch.h @@ -180,7 +180,7 @@ IN(OP_GMLastName, GMLastName_Struct); IN(OP_GMToggle, GMToggle_Struct); IN(OP_LFGCommand, LFG_Struct); IN(OP_GMGoto, GMSummon_Struct); -IN(OP_TraderShop, TraderClick_Struct); +INv(OP_TraderShop, TraderClick_Struct); IN(OP_ShopRequest, Merchant_Click_Struct); IN(OP_Bazaar, BazaarSearch_Struct); //alt:IN(OP_Bazaar, BazaarWelcome_Struct); //alternate structure for OP_Bazaar @@ -399,7 +399,7 @@ OUT(OP_Weather, Weather_Struct); OUT(OP_ZoneChange, ZoneChange_Struct); OUT(OP_ZoneInUnknown, ZoneInUnknown_Struct); -//this is the set of opcodes which are allready listed +//this is the set of opcodes which are already listed //in the IN section above, but are also sent OUT #ifdef DISJOINT_DIRECTIONS OUTz(OP_ClientReady); //follows OP_SetServerFilter @@ -449,7 +449,7 @@ OUT(OP_Trader, TraderBuy_Struct); //3 possible lengths //alt:OUT(OP_Trader, Trader_ShowItems_Struct); //alt:OUT(OP_Trader, Trader_Struct); OUT(OP_TraderBuy, TraderBuy_Struct); -OUT(OP_TraderShop, TraderClick_Struct); +OUTv(OP_TraderShop, TraderClick_Struct); OUT(OP_WearChange, WearChange_Struct); OUT(OP_ZoneEntry, ServerZoneEntry_Struct); #endif diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 25c63c52b..f1c89ff2f 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3578,7 +3578,9 @@ 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)); + //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) { eq->ItemCost[i] = emu->ItemCost[i]; @@ -3596,10 +3598,11 @@ namespace RoF2 SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); eq->Code = emu->Code; - strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber)); + //strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber)); + //snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", 0); eq->TraderID = emu->TraderID; - eq->Stacksize = 0; - eq->Price = 0; + //eq->Stacksize = 0; + //eq->Price = 0; FINISH_ENCODE(); } @@ -3634,6 +3637,18 @@ namespace RoF2 FINISH_ENCODE(); } + ENCODE(OP_TraderShop) + { + ENCODE_LENGTH_EXACT(TraderClick_Struct); + SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct); + + //eq->Code = emu->Unknown004; + OUT(TraderID); + OUT(Approval); + + FINISH_ENCODE(); + } + ENCODE(OP_TributeInfo) { ENCODE_LENGTH_ATLEAST(TributeAbility_Struct); @@ -4215,7 +4230,6 @@ namespace RoF2 return; SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct); - MEMSET_IN(structs::NewBazaarInspect_Struct); IN(Beginning.Action); memcpy(emu->Name, eq->Name, sizeof(emu->Name)); @@ -4912,7 +4926,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::ClickTrader_Struct); SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct); - MEMSET_IN(ClickTrader_Struct); emu->Code = eq->Code; // Live actually has 200 items now, but 80 is the most our internal struct supports @@ -4928,7 +4941,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct); SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); - MEMSET_IN(Trader_ShowItems_Struct); emu->Code = eq->Code; emu->TraderID = eq->TraderID; @@ -4939,9 +4951,8 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::TraderStatus_Struct); SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct); - MEMSET_IN(TraderStatus_Struct); - emu->Code = eq->Code; + emu->Code = eq->Code; // 11 = Start Trader, 2 = End Trader, 22 = ? - Guessing FINISH_DIRECT_DECODE(); } @@ -4951,7 +4962,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::TraderBuy_Struct); SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct); - MEMSET_IN(TraderBuy_Struct); IN(Action); IN(Price); @@ -4963,6 +4973,29 @@ namespace RoF2 FINISH_DIRECT_DECODE(); } + DECODE(OP_TraderShop) + { + uint32 psize = __packet->size; + if (psize == sizeof(structs::TraderClick_Struct)) + { + 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 + { + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Mismatch (%d), expected (%d)", psize, sizeof(structs::TraderClick_Struct)); + } + } + DECODE(OP_TradeSkillCombine) { DECODE_LENGTH_EXACT(structs::NewCombine_Struct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index aa5656f2b..0a85855f1 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -2,10 +2,13 @@ // Begin RoF2 Encodes E(OP_SendMembershipDetails) +E(OP_TraderShop) // incoming packets that require a DECODE translation: // Begin RoF2 Decodes +D(OP_TraderShop) + // End RoF2 Encodes/Decodes // These require Encodes/Decodes for RoF, so they do for RoF2 as well diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 0935517c1..8bab425a4 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -3200,6 +3200,13 @@ struct BecomeTrader_Struct { }; struct Trader_ShowItems_Struct { + /*000*/ uint32 Code; + /*004*/ uint16 TraderID; + /*008*/ uint32 Unknown08; + /*012*/ +}; + +struct Trader_ShowItems_Struct_WIP { /*000*/ uint32 Code; /*004*/ char SerialNumber[17]; /*021*/ uint8 Unknown21; @@ -3262,9 +3269,10 @@ struct TraderDelItem_Struct{ }; struct TraderClick_Struct{ - uint32 traderid; - uint32 unknown4[2]; - uint32 approval; + /*000*/ uint32 Code; + /*004*/ uint32 TraderID; + /*008*/ uint32 Approval; + /*012*/ }; struct FormattedMessage_Struct{ diff --git a/common/patches/ss_define.h b/common/patches/ss_define.h index 3198820b6..cac116c1a 100644 --- a/common/patches/ss_define.h +++ b/common/patches/ss_define.h @@ -124,14 +124,14 @@ //check length of packet before decoding. Call before setup. #define DECODE_LENGTH_EXACT(struct_) \ if(__packet->size != sizeof(struct_)) { \ - __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \ + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ return; \ } #define DECODE_LENGTH_ATLEAST(struct_) \ if(__packet->size < sizeof(struct_)) { \ - __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \ + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ return; \ } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index db7f65781..f602bf75d 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13278,7 +13278,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) /* if (GetClientVersion() >= EQClientRoF) - max_items = 200; + max_items = 200; */ //Show Items @@ -13290,20 +13290,25 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) { case BazaarTrader_EndTraderMode: { Trader_EndTrader(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session"); break; } case BazaarTrader_EndTransaction: { Client* c = entity_list.GetClientByID(sis->TraderID); if (c) + { c->WithCustomer(0); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction"); + } else - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer"); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer"); break; } case BazaarTrader_ShowItems: { Trader_ShowItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items"); break; } default: { @@ -13326,6 +13331,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) { GetItems_Struct* gis = GetTraderItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Start Trader Mode"); // Verify there are no NODROP or items with a zero price bool TradeItemsValid = true; @@ -13372,7 +13378,8 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) safe_delete(gis); this->Trader_StartTrader(); - + + // This refreshes the Trader window to display the End Trader button if (GetClientVersion() >= ClientVersion::RoF) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct)); @@ -13382,15 +13389,6 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) safe_delete(outapp); } } - else if (app->size == sizeof(TraderStatus_Struct)) - { - TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer; - - if (tss->Code == BazaarTrader_ShowItems) - { - Trader_ShowItems(); - } - } else { Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unknown TraderStruct code of: %i\n", ints->Code); @@ -13398,9 +13396,35 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) Log.Out(Logs::General, Logs::Error, "Unknown TraderStruct code of: %i\n", ints->Code); } } + else if (app->size == sizeof(TraderStatus_Struct)) + { + TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer; + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Status Code: %d", tss->Code); + + switch (tss->Code) + { + case BazaarTrader_EndTraderMode: { + Trader_EndTrader(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session"); + break; + } + case BazaarTrader_ShowItems: { + Trader_ShowItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items"); + break; + } + default: { + Log.Out(Logs::Detail, Logs::Trading, "Unhandled action code in OP_Trader ShowItems_Struct"); + break; + } + } + + + } else if (app->size == sizeof(TraderPriceUpdate_Struct)) { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Price Update"); HandleTraderPriceUpdate(app); } else { @@ -13425,8 +13449,8 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app) 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"); @@ -13502,23 +13526,24 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) // browse their goods. // - TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; - if (app->size != sizeof(TraderClick_Struct)) { - - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Returning due to struct size mismatch"); - + 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* Customer = entity_list.GetClientByID(tcs->TraderID); + Client* Trader = entity_list.GetClientByID(tcs->TraderID); - if (Customer) - outtcs->Approval = Customer->WithCustomer(GetID()); + 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"); @@ -13533,11 +13558,15 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) if (outtcs->Approval) { - this->BulkSendTraderInventory(Customer->CharacterID()); - Customer->Trader_CustomerBrowsing(this); + this->BulkSendTraderInventory(Trader->CharacterID()); + Trader->Trader_CustomerBrowsing(this); + 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); diff --git a/zone/trading.cpp b/zone/trading.cpp index 4874716ae..292f31713 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1138,7 +1138,6 @@ void Client::Trader_EndTrader() { QueuePacket(outapp); - safe_delete(outapp); WithCustomer(0);