From d3ac751dd1610ea5098f48886af323e4cb5b7939 Mon Sep 17 00:00:00 2001 From: KimLS Date: Thu, 5 Dec 2024 19:39:59 -0800 Subject: [PATCH] Merchant window startup --- common/classes.h | 3 + common/emu_oplist.h | 1 + common/patches/laurion.cpp | 104 ++++++++++++++++++++----------- common/patches/laurion_limits.h | 34 +++++----- common/patches/laurion_ops.h | 2 + common/patches/laurion_structs.h | 40 +++++------- common/patches/rof2.cpp | 30 +++++++++ common/patches/rof2_ops.h | 2 + utils/patches/patch_Laurion.conf | 6 +- zone/client_packet.cpp | 5 +- 10 files changed, 149 insertions(+), 78 deletions(-) diff --git a/common/classes.h b/common/classes.h index 96e5cad26..7371ccaa3 100644 --- a/common/classes.h +++ b/common/classes.h @@ -71,6 +71,9 @@ namespace Class { constexpr uint8 FellowshipMaster = 69; constexpr uint8 AlternateCurrencyMerchant = 70; constexpr uint8 MercenaryLiaison = 71; + constexpr uint8 RealEstateMerchant = 72; + constexpr uint8 LoyaltyMerchant = 73; + constexpr uint8 TributeMaster2 = 74; constexpr uint8 PLAYER_CLASS_COUNT = 16; constexpr uint16 ALL_CLASSES_BITMASK = 65535; diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 236def1f8..f71d0d916 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -354,6 +354,7 @@ N(OP_MercenaryTimer), N(OP_MercenaryTimerRequest), N(OP_MercenaryUnknown1), N(OP_MercenaryUnsuspendResponse), +N(OP_MerchantBulkItems), N(OP_MobEnduranceUpdate), N(OP_MobHealth), N(OP_MobManaUpdate), diff --git a/common/patches/laurion.cpp b/common/patches/laurion.cpp index 1905ee880..0eb217637 100644 --- a/common/patches/laurion.cpp +++ b/common/patches/laurion.cpp @@ -71,7 +71,7 @@ namespace Laurion static inline uint32 LaurionToServerCorpseMainSlot(uint32 laurion_corpse_slot); static inline uint32 LaurionToServerTypelessSlot(structs::TypelessInventorySlot_Struct laurion_slot, int16 laurion_type); - structs::ItemPacketType ServerToLaurionItemPacketType(ItemPacketType laurion_type); + item::ItemPacketType ServerToLaurionItemPacketType(ItemPacketType laurion_type); void Register(EQStreamIdentifier& into) { @@ -246,35 +246,35 @@ namespace Laurion eq->entries[0] = -1; // Max AA Restriction eq->entries[1] = -1; // Max Level Restriction eq->entries[2] = -1; // Max Char Slots per Account (not used by client?) - eq->entries[3] = -1; // 1 for Silver + eq->entries[3] = -1; // SpellTier eq->entries[4] = -1; // Main Inventory Size eq->entries[5] = -1; // Max Platinum per level eq->entries[6] = 1; // Send Mail - eq->entries[7] = 1; // Use Parcels? - eq->entries[8] = 1; // Voice Chat + eq->entries[7] = 1; // Use Parcels + eq->entries[8] = 1; // Loyalty eq->entries[9] = -1; // Merc Tiers - eq->entries[10] = 1; // Create Guilds + eq->entries[10] = 1; // Housing eq->entries[11] = -1; // Shared Bank Slots eq->entries[12] = -1; // Max Journal Quests - eq->entries[13] = 1; // Housing Enabled - eq->entries[14] = 1; // Prestiege - eq->entries[15] = 1; // Broker System + eq->entries[13] = 1; // CreateGuild + eq->entries[14] = 1; // Bazaar + eq->entries[15] = 1; // Barter eq->entries[16] = 1; // Chat - eq->entries[17] = 1; // Progression Server Access - eq->entries[18] = 1; // Customer Support - eq->entries[19] = -1; // Popup reminders? - eq->entries[20] = -1; // Exit Popup? - eq->entries[21] = 0; - eq->entries[22] = 0; - eq->entries[23] = 0; // This is the highest we actually see in detail entries - eq->entries[24] = 0; - eq->entries[25] = 0; - eq->entries[26] = 0; - eq->entries[27] = 0; - eq->entries[28] = 0; - eq->entries[29] = 0; - eq->entries[30] = 0; - eq->entries[31] = 0; + eq->entries[17] = 1; // Petition + eq->entries[18] = 1; // Advertising + eq->entries[19] = -1; // UseItem + eq->entries[20] = -1; // StartingCity + eq->entries[21] = 1; // Ornament + eq->entries[22] = 0; // HeroicCharacter + eq->entries[23] = 0; // AutoGrantAA + eq->entries[24] = 0; // MountKeyRingSlots + eq->entries[25] = 0; // IllusionKeyRingSlots + eq->entries[26] = 0; // FamiliarKeyRingSlots + eq->entries[27] = 0; // FamiliarAutoLeave + eq->entries[28] = 0; // HeroForgeKeyRingSlots + eq->entries[29] = 0; // DragonHoardSlots + eq->entries[30] = 0; // TeleportKeyRingSlots + eq->entries[31] = 0; // PersonalDepotSlots eq->entries[32] = 0; FINISH_ENCODE(); @@ -2860,14 +2860,14 @@ namespace Laurion ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; auto type = ServerToLaurionItemPacketType(old_item_pkt->PacketType); - if (type == structs::ItemPacketInvalid) { + if (type == item::ItemPacketType::ItemPacketInvalid) { delete in; return; } switch (type) { - case structs::ItemPacketType::ItemPacketParcel: { + case item::ItemPacketType::ItemPacketParcel: { ParcelMessaging_Struct pms{}; EQ::Util::MemoryStreamReader ss(reinterpret_cast(in->pBuffer), in->size); cereal::BinaryInputArchive ar(ss); @@ -2906,6 +2906,26 @@ namespace Laurion delete in; } + ENCODE(OP_ShopRequest) + { + ENCODE_LENGTH_EXACT(MerchantClick_Struct); + SETUP_DIRECT_ENCODE(MerchantClick_Struct, structs::MerchantClickResponse_Struct); + + if (emu->command == 0) { + OUT(player_id); + eq->npc_id = 0; + } + else { + OUT(npc_id); + OUT(player_id); + OUT(rate); + OUT(tab_display); + eq->unknown028 = 256; + } + + FINISH_ENCODE(); + } + // DECODE methods DECODE(OP_EnterWorld) @@ -3094,6 +3114,16 @@ namespace Laurion FINISH_DIRECT_DECODE(); } + DECODE(OP_ShopRequest) + { + DECODE_LENGTH_EXACT(structs::MerchantClickRequest_Struct); + SETUP_DIRECT_DECODE(MerchantClick_Struct, structs::MerchantClickRequest_Struct); + + IN(npc_id); + + FINISH_DIRECT_DECODE(); + } + //Naive version but should work well enough for now int ExtractIDFile(const std::string& input) { std::string number; @@ -4451,30 +4481,30 @@ namespace Laurion return ServerSlot; } - structs::ItemPacketType ServerToLaurionItemPacketType(ItemPacketType server_type) { + item::ItemPacketType ServerToLaurionItemPacketType(ItemPacketType server_type) { switch (server_type) { case ItemPacketType::ItemPacketMerchant: - return structs::ItemPacketType::ItemPacketMerchant; + return item::ItemPacketType::ItemPacketMerchant; case ItemPacketType::ItemPacketTradeView: - return structs::ItemPacketType::ItemPacketTradeView; + return item::ItemPacketType::ItemPacketTradeView; case ItemPacketType::ItemPacketLoot: - return structs::ItemPacketType::ItemPacketLoot; + return item::ItemPacketType::ItemPacketLoot; case ItemPacketType::ItemPacketTrade: - return structs::ItemPacketType::ItemPacketTrade; + return item::ItemPacketType::ItemPacketTrade; case ItemPacketType::ItemPacketCharInventory: - return structs::ItemPacketType::ItemPacketCharInventory; + return item::ItemPacketType::ItemPacketCharInventory; case ItemPacketType::ItemPacketLimbo: - return structs::ItemPacketType::ItemPacketLimbo; + return item::ItemPacketType::ItemPacketLimbo; case ItemPacketType::ItemPacketWorldContainer: - return structs::ItemPacketType::ItemPacketWorldContainer; + return item::ItemPacketType::ItemPacketWorldContainer; case ItemPacketType::ItemPacketTributeItem: - return structs::ItemPacketType::ItemPacketTributeItem; + return item::ItemPacketType::ItemPacketTributeItem; case ItemPacketType::ItemPacketGuildTribute: - return structs::ItemPacketType::ItemPacketGuildTribute; + return item::ItemPacketType::ItemPacketGuildTribute; case ItemPacketType::ItemPacketCharmUpdate: - return structs::ItemPacketType::ItemPacketCharmUpdate; + return item::ItemPacketType::ItemPacketCharmUpdate; default: - return structs::ItemPacketType::ItemPacketInvalid; + return item::ItemPacketType::ItemPacketInvalid; } } } /*Laurion*/ diff --git a/common/patches/laurion_limits.h b/common/patches/laurion_limits.h index ab4eba11e..587844ce2 100644 --- a/common/patches/laurion_limits.h +++ b/common/patches/laurion_limits.h @@ -249,20 +249,26 @@ namespace Laurion //}; enum ItemPacketType : int { - ItemPacketMerchant = 100, - ItemPacketTradeView = 101, - ItemPacketLoot = 102, - ItemPacketTrade = 103, - ItemPacketCharInventory = 105, - ItemPacketLimbo = 106, - ItemPacketWorldContainer = 107, - ItemPacketTributeItem = 108, - ItemPacketGuildTribute = 109, - ItemPacket10 = 110, - ItemPacket11 = 111, - ItemPacket12 = 112, - ItemPacketRecovery = 113, - ItemPacket14 = 115 // Parcel? adds to merchant window too + ItemPacketMerchant = 0x64, + ItemPacketTradeView = 0x65, + ItemPacketLoot = 0x66, + ItemPacketTrade = 0x67, + //looks like they added something at 0x68 that didn't exist before and shifted everything after it up by 1 + ItemPacketUnknown068 = 0x68, //Not sure but it seems to deal with the cursor somehow. + ItemPacketCharInventory = 0x6A, //Rof 0x69 -> Larion 0x6a (requires translation) + ItemPacketLimbo = 0x6B, //0x6A -> 0x6B + ItemPacketWorldContainer = 0x6C, + ItemPacketTributeItem = 0x6D, + ItemPacketGuildTribute = 0x6E, + ItemPacketCharmUpdate = 0x6f, + ItemPacketRecovery = 0x72, + ItemPacketParcel = 0x74, + ItemPacketUnknown075 = 0x75, //Not sure but uses a lot of the same logic as the trade and char inventory types + ItemPacketOverflow = 0x76, + ItemPacketDragonHoard = 0x77, + ItemPacketTradeskill = 0x78, + ItemPacketTradeskillDepot = 0x79, + ItemPacketInvalid = 0xFF }; } /*item*/ diff --git a/common/patches/laurion_ops.h b/common/patches/laurion_ops.h index 3f6f31cef..2db186c25 100644 --- a/common/patches/laurion_ops.h +++ b/common/patches/laurion_ops.h @@ -34,6 +34,7 @@ E(OP_MoveItem) E(OP_ExpUpdate) E(OP_SendAATable) E(OP_ItemPacket) +E(OP_ShopRequest) //list of packets we need to decode on the way in: D(OP_EnterWorld) D(OP_ZoneEntry) @@ -47,6 +48,7 @@ D(OP_ConsiderCorpse) D(OP_ClickDoor) D(OP_SpawnAppearance) D(OP_MoveItem) +D(OP_ShopRequest) #undef E #undef D diff --git a/common/patches/laurion_structs.h b/common/patches/laurion_structs.h index 5546c4a57..c3c3e9794 100644 --- a/common/patches/laurion_structs.h +++ b/common/patches/laurion_structs.h @@ -602,29 +602,23 @@ namespace Laurion { /*0028*/ }; - //These are significantly changed in Laurion from RoF2 - enum ItemPacketType { - //ItemPacketViewLink = 0x00, - ItemPacketMerchant = 0x64, - ItemPacketTradeView = 0x65, - ItemPacketLoot = 0x66, - ItemPacketTrade = 0x67, - //looks like they added something at 0x68 that didn't exist before and shifted everything after it up by 1 - ItemPacketUnknown068 = 0x68, //Not sure but it seems to deal with the cursor somehow. - ItemPacketCharInventory = 0x6A, //Rof 0x69 -> Larion 0x6a (requires translation) - ItemPacketLimbo = 0x6B, //0x6A -> 0x6B - ItemPacketWorldContainer = 0x6C, - ItemPacketTributeItem = 0x6D, - ItemPacketGuildTribute = 0x6E, - ItemPacketCharmUpdate = 0x6f, - ItemPacketRecovery = 0x72, - ItemPacketParcel = 0x74, - ItemPacketUnknown075 = 0x75, //Not sure but uses a lot of the same logic as the trade and char inventory types - ItemPacketOverflow = 0x76, - ItemPacketDragonHoard = 0x77, - ItemPacketTradeskill = 0x78, - ItemPacketTradeskillDepot = 0x79, - ItemPacketInvalid = 0xFF + struct MerchantClickRequest_Struct + { + /*000*/ uint32 npc_id; // Merchant NPC's entity id + /*004*/ + }; + + struct MerchantClickResponse_Struct + { + /*000*/ uint32 npc_id; // Merchant NPC's entity id + /*004*/ uint32 player_id; + /*008*/ float rate; + /*012*/ uint32 tab_display; // bitmask b000 none, b001 Purchase/Sell, b010 Recover, b100 Parcels + /*016*/ uint32 ldon_category; // ldon cat for ldon merchants + /*020*/ uint32 alt_currency1; //These two usually match but I imagine they could be different? + /*024*/ uint32 alt_currency2; + /*028*/ uint32 unknown028; // Observed 256 + /*032*/ }; #pragma pack() diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 29c52f9ef..32ef8d5dd 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3602,6 +3602,21 @@ namespace RoF2 FINISH_ENCODE(); } + + ENCODE(OP_ShopRequest) + { + ENCODE_LENGTH_EXACT(MerchantClick_Struct); + SETUP_DIRECT_ENCODE(MerchantClick_Struct, structs::MerchantClick_Struct); + + OUT(npc_id); + OUT(player_id); + OUT(command); + OUT(rate); + OUT(tab_display); + eq->unknown02 = emu->unknown020; + + FINISH_ENCODE(); + } ENCODE(OP_SkillUpdate) { @@ -5993,6 +6008,21 @@ namespace RoF2 FINISH_DIRECT_DECODE(); } + DECODE(OP_ShopRequest) + { + DECODE_LENGTH_EXACT(structs::MerchantClick_Struct); + SETUP_DIRECT_DECODE(MerchantClick_Struct, structs::MerchantClick_Struct); + + IN(npc_id); + IN(player_id); + IN(command); + IN(rate); + IN(tab_display); + emu->unknown020 = 0; + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_Save) { DECODE_LENGTH_EXACT(structs::Save_Struct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 08d8b9985..7c59851f6 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -118,6 +118,7 @@ E(OP_SendZonepoints) E(OP_SetGuildRank) E(OP_ShopPlayerBuy) E(OP_ShopPlayerSell) +E(OP_ShopRequest) E(OP_SkillUpdate) E(OP_SomeItemPacketMaybe) E(OP_SpawnAppearance) @@ -203,6 +204,7 @@ D(OP_Save) D(OP_SetServerFilter) D(OP_ShopPlayerBuy) D(OP_ShopPlayerSell) +D(OP_ShopRequest) D(OP_ShopSendParcel) D(OP_Trader) D(OP_TraderBuy) diff --git a/utils/patches/patch_Laurion.conf b/utils/patches/patch_Laurion.conf index 12ad33297..944338be1 100644 --- a/utils/patches/patch_Laurion.conf +++ b/utils/patches/patch_Laurion.conf @@ -464,9 +464,9 @@ OP_ItemAdvancedLoreText=0x0000 # merchant stuff OP_ShopPlayerSell=0x0000 -OP_ShopRequest=0x0000 -OP_ShopEnd=0x0000 -OP_ShopEndConfirm=0x0000 +OP_ShopRequest=0x840 +OP_ShopEnd=0x74bb +OP_ShopEndConfirm=0x2ed1 OP_ShopPlayerBuy=0x0000 OP_ShopDelItem=0x0000 OP_ShopSendParcel=0x0000 diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index fa6244829..fe4091572 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -14639,7 +14639,10 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app) mco->rate = 1 / buy_cost_mod; } - outapp->priority = 6; + if (m_ClientVersion >= EQ::versions::ClientVersion::Laurion) { + mco->player_id = GetID(); + } + QueuePacket(outapp); safe_delete(outapp);