From ac85d441978bffc35d77345155272c6118eade7f Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Wed, 20 Dec 2023 13:39:11 +0100 Subject: [PATCH] Refactored CZ_REQ_MERGE_ITEM (#8039) Thanks to @secretdataz! --- src/map/clif.cpp | 102 ++++++++++++++++++++++++-------------- src/map/clif_packetdb.hpp | 3 +- src/map/packets.hpp | 9 +++- 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 998212a9cd..4d281dcceb 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -4,6 +4,8 @@ #include "clif.hpp" +#include + #include #include #include @@ -20943,69 +20945,95 @@ void clif_merge_item_open( map_session_data& sd ){ } /** - * Process item merger - * CZ 096E .W { .W }* (CZ_REQ_MERGE_ITEM) + * Process item merge request. + * 096E .W { .W }* (CZ_REQ_MERGE_ITEM) * @param fd * @param sd **/ -void clif_parse_merge_item_req(int fd, map_session_data* sd) { - struct s_packet_db *info = NULL; - unsigned short n = 0, indexes[MAX_INVENTORY] = { 0 }, i, j; - unsigned int count = 0; - struct item_data *id = NULL; +void clif_parse_merge_item_req( int fd, map_session_data* sd ){ + struct PACKET_CZ_REQ_MERGE_ITEM* p = (struct PACKET_CZ_REQ_MERGE_ITEM*)RFIFOP( fd, 0 ); - nullpo_retv(sd); - if (!clif_session_isValid(sd)) - return; - if (!(info = &packet_db[RFIFOW(fd,0)]) || info->len == 0) - return; + int count = ( p->packetLength - sizeof( *p ) ) / sizeof( p->indices[0] ); - n = (RFIFOW(fd, info->pos[0]) - 4) / 2; - - if (n < 2) { // No item need to be merged - clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE); + // No item need to be merged + if( count < 2 ){ + clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE ); return; } - for (i = 0, j = 0; i < n; i++) { - uint16 idx = server_index( RFIFOW( fd, info->pos[1] + i * 2 ) ); + uint16 idx_main = server_index( p->indices[0] ); + + if( idx_main >= MAX_INVENTORY ){ + return; + } + + if( !clif_merge_item_check( sd->inventory_data[idx_main], &sd->inventory.u.items_inventory[idx_main] ) ){ + clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE ); + return; + } + + // Ensure each index only comes once + std::unordered_set indices; + + for( int i = 1; i < count; i++ ){ + uint16 idx = server_index( p->indices[i] ); if( idx >= MAX_INVENTORY ){ return; } - if (!clif_merge_item_check((id = sd->inventory_data[idx]), &sd->inventory.u.items_inventory[idx])) - continue; - indexes[j] = idx; - if (j && id->nameid != sd->inventory_data[indexes[0]]->nameid) { // Only can merge 1 kind at once - clif_merge_item_ack( *sd, MERGE_ITEM_FAILED_NOT_MERGE ); + if( sd->inventory_data[idx] == nullptr ){ return; } - count += sd->inventory.u.items_inventory[idx].amount; - j++; + + // Check if it is the same item + if( sd->inventory_data[idx]->nameid != sd->inventory_data[idx_main]->nameid ){ + return; + } + + if( !clif_merge_item_check( sd->inventory_data[idx], &sd->inventory.u.items_inventory[idx] ) ){ + clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE ); + return; + } + + indices.insert( idx ); } - if (n != j || !(id = sd->inventory_data[indexes[0]])) { - clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE); + if( indices.empty() ){ + clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE ); return; } - if (count >= (id->stack.amount ? id->stack.amount : MAX_AMOUNT)) { + uint32 total_amount = sd->inventory.u.items_inventory[idx_main].amount; + + for( uint16 idx : indices ){ + total_amount += sd->inventory.u.items_inventory[idx].amount; + } + + uint16 stack = sd->inventory_data[idx_main]->stack.amount; + + if( stack == 0 ){ + stack = MAX_AMOUNT; + } + + if( total_amount >= stack ){ clif_merge_item_ack( *sd, MERGE_ITEM_FAILED_MAX_COUNT ); return; } // Merrrrge!!!! - for (i = 1; i < n; i++) { - unsigned short idx = indexes[i], amt = sd->inventory.u.items_inventory[idx].amount; - log_pick_pc(sd, LOG_TYPE_MERGE_ITEM, -amt, &sd->inventory.u.items_inventory[idx]); - memset(&sd->inventory.u.items_inventory[idx], 0, sizeof(sd->inventory.u.items_inventory[0])); - sd->inventory_data[idx] = NULL; - clif_delitem(sd, idx, amt, 0); - } - sd->inventory.u.items_inventory[indexes[0]].amount = count; + for( uint16 idx : indices ){ + uint16 amount = sd->inventory.u.items_inventory[idx].amount; - clif_merge_item_ack( *sd, MERGE_ITEM_SUCCESS, indexes[0], count ); + log_pick_pc( sd, LOG_TYPE_MERGE_ITEM, -amount, &sd->inventory.u.items_inventory[idx] ); + memset( &sd->inventory.u.items_inventory[idx], 0, sizeof( sd->inventory.u.items_inventory[0] ) ); + sd->inventory_data[idx] = nullptr; + clif_delitem( sd, idx, amount, 0 ); + } + + sd->inventory.u.items_inventory[idx_main].amount = total_amount; + + clif_merge_item_ack( *sd, MERGE_ITEM_SUCCESS, idx_main, total_amount ); } /** diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index aa3cb5fdfe..ad625b0127 100644 --- a/src/map/clif_packetdb.hpp +++ b/src/map/clif_packetdb.hpp @@ -1916,7 +1916,7 @@ parseable_packet(0x0916,26,clif_parse_GuildInvite2,2); parseable_packet(0x091d,41,clif_parse_PartyBookingRegisterReq,2,4,6); // Merge Item - parseable_packet(0x096E,-1,clif_parse_merge_item_req,2,4); // CZ_REQ_MERGE_ITEM + parseable_packet( HEADER_CZ_REQ_MERGE_ITEM, -1, clif_parse_merge_item_req, 0 ); parseable_packet(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM parseable_packet(0x0844,2,clif_parse_cashshop_open_request,0); packet(0x0849,16); //clif_cashshop_result @@ -2061,7 +2061,6 @@ // 2013-08-07Ragexe #if PACKETVER >= 20130807 // Merge Item - parseable_packet(0x096E,-1,clif_parse_merge_item_req,2,4); // CZ_REQ_MERGE_ITEM parseable_packet(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM packet(0x9CD,8); // ZC_MSG_COLOR #endif diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 8a71ac664f..2043ae9d57 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -475,6 +475,12 @@ struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2{ struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub items[]; } __attribute__((packed)); +struct PACKET_CZ_REQ_MERGE_ITEM{ + int16 packetType; + int16 packetLength; + uint16 indices[]; +} __attribute__((packed)); + // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 ) #pragma pack( pop ) @@ -516,7 +522,8 @@ DEFINE_PACKET_HEADER(CZ_REQ_SE_CASH_TAB_CODE, 0x846) DEFINE_PACKET_HEADER(ZC_ACK_SE_CASH_ITEM_LIST2, 0x8c0) DEFINE_PACKET_HEADER(ZC_ACK_SCHEDULER_CASHITEM, 0x8ca) DEFINE_PACKET_HEADER(ZC_CLEAR_DIALOG, 0x8d6) -DEFINE_PACKET_HEADER(ZC_ENTRY_QUEUE_INIT, 0x90e); +DEFINE_PACKET_HEADER(ZC_ENTRY_QUEUE_INIT, 0x90e) +DEFINE_PACKET_HEADER(CZ_REQ_MERGE_ITEM, 0x96e) DEFINE_PACKET_HEADER(ZC_BANKING_CHECK, 0x9a6) DEFINE_PACKET_HEADER(ZC_ACK_BANKING_DEPOSIT, 0x9a8) DEFINE_PACKET_HEADER(ZC_ACK_BANKING_WITHDRAW, 0x9aa)