Refactored CZ_REQ_MERGE_ITEM (#8039)

Thanks to @secretdataz!
This commit is contained in:
Lemongrass3110 2023-12-20 13:39:11 +01:00 committed by GitHub
parent c33bb0b726
commit ac85d44197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 40 deletions

View File

@ -4,6 +4,8 @@
#include "clif.hpp" #include "clif.hpp"
#include <unordered_set>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -20943,69 +20945,95 @@ void clif_merge_item_open( map_session_data& sd ){
} }
/** /**
* Process item merger * Process item merge request.
* CZ 096E <size>.W { <index>.W }* (CZ_REQ_MERGE_ITEM) * 096E <size>.W { <index>.W }* (CZ_REQ_MERGE_ITEM)
* @param fd * @param fd
* @param sd * @param sd
**/ **/
void clif_parse_merge_item_req(int fd, map_session_data* sd) { void clif_parse_merge_item_req( int fd, map_session_data* sd ){
struct s_packet_db *info = NULL; struct PACKET_CZ_REQ_MERGE_ITEM* p = (struct PACKET_CZ_REQ_MERGE_ITEM*)RFIFOP( fd, 0 );
unsigned short n = 0, indexes[MAX_INVENTORY] = { 0 }, i, j;
unsigned int count = 0;
struct item_data *id = NULL;
nullpo_retv(sd); int count = ( p->packetLength - sizeof( *p ) ) / sizeof( p->indices[0] );
if (!clif_session_isValid(sd))
return;
if (!(info = &packet_db[RFIFOW(fd,0)]) || info->len == 0)
return;
n = (RFIFOW(fd, info->pos[0]) - 4) / 2; // No item need to be merged
if( count < 2 ){
if (n < 2) { // No item need to be merged clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE );
clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE);
return; return;
} }
for (i = 0, j = 0; i < n; i++) { uint16 idx_main = server_index( p->indices[0] );
uint16 idx = server_index( RFIFOW( fd, info->pos[1] + i * 2 ) );
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<uint16> indices;
for( int i = 1; i < count; i++ ){
uint16 idx = server_index( p->indices[i] );
if( idx >= MAX_INVENTORY ){ if( idx >= MAX_INVENTORY ){
return; return;
} }
if (!clif_merge_item_check((id = sd->inventory_data[idx]), &sd->inventory.u.items_inventory[idx])) if( sd->inventory_data[idx] == nullptr ){
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 );
return; 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]])) { if( indices.empty() ){
clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE); clif_msg( sd, MERGE_ITEM_NOT_AVAILABLE );
return; 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 ); clif_merge_item_ack( *sd, MERGE_ITEM_FAILED_MAX_COUNT );
return; return;
} }
// Merrrrge!!!! // Merrrrge!!!!
for (i = 1; i < n; i++) { for( uint16 idx : indices ){
unsigned short idx = indexes[i], amt = sd->inventory.u.items_inventory[idx].amount; uint16 amount = 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;
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 );
} }
/** /**

View File

@ -1916,7 +1916,7 @@
parseable_packet(0x0916,26,clif_parse_GuildInvite2,2); parseable_packet(0x0916,26,clif_parse_GuildInvite2,2);
parseable_packet(0x091d,41,clif_parse_PartyBookingRegisterReq,2,4,6); parseable_packet(0x091d,41,clif_parse_PartyBookingRegisterReq,2,4,6);
// Merge Item // 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(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM
parseable_packet(0x0844,2,clif_parse_cashshop_open_request,0); parseable_packet(0x0844,2,clif_parse_cashshop_open_request,0);
packet(0x0849,16); //clif_cashshop_result packet(0x0849,16); //clif_cashshop_result
@ -2061,7 +2061,6 @@
// 2013-08-07Ragexe // 2013-08-07Ragexe
#if PACKETVER >= 20130807 #if PACKETVER >= 20130807
// Merge Item // 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 parseable_packet(0x0974,2,clif_parse_merge_item_cancel,0); // CZ_CANCEL_MERGE_ITEM
packet(0x9CD,8); // ZC_MSG_COLOR packet(0x9CD,8); // ZC_MSG_COLOR
#endif #endif

View File

@ -475,6 +475,12 @@ struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2{
struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub items[]; struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub items[];
} __attribute__((packed)); } __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 // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 ) #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
#pragma pack( pop ) #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_SE_CASH_ITEM_LIST2, 0x8c0)
DEFINE_PACKET_HEADER(ZC_ACK_SCHEDULER_CASHITEM, 0x8ca) DEFINE_PACKET_HEADER(ZC_ACK_SCHEDULER_CASHITEM, 0x8ca)
DEFINE_PACKET_HEADER(ZC_CLEAR_DIALOG, 0x8d6) 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_BANKING_CHECK, 0x9a6)
DEFINE_PACKET_HEADER(ZC_ACK_BANKING_DEPOSIT, 0x9a8) DEFINE_PACKET_HEADER(ZC_ACK_BANKING_DEPOSIT, 0x9a8)
DEFINE_PACKET_HEADER(ZC_ACK_BANKING_WITHDRAW, 0x9aa) DEFINE_PACKET_HEADER(ZC_ACK_BANKING_WITHDRAW, 0x9aa)