diff --git a/src/map/clif.c b/src/map/clif.c index 9dc42bb07a1..eb67723e2f1 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -18193,33 +18193,30 @@ void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd) { sd->npc_shopid = 0; } -void clif_npc_market_purchase_ack(struct map_session_data *sd, const struct packet_npc_market_purchase *req, unsigned char response) +void clif_npc_market_purchase_ack(struct map_session_data *sd, const struct itemlist *item_list, unsigned char response) { #if PACKETVER >= 20131223 unsigned short c = 0; nullpo_retv(sd); - nullpo_retv(req); + nullpo_retv(item_list); npcmarket_result.PacketType = npcmarketresultackType; npcmarket_result.result = response == 0 ? 1 : 0;/* find other values */ - if( npcmarket_result.result ) { - unsigned short i, list_size = (req->PacketLength - 4) / sizeof(req->list[0]), j; - struct npc_data* nd; - struct npc_item_list *shop = NULL; - unsigned short shop_size = 0; - - nd = map->id2nd(sd->npc_shopid); - - shop = nd->u.scr.shop->item; - shop_size = nd->u.scr.shop->items; + if (npcmarket_result.result) { + struct npc_data *nd = map->id2nd(sd->npc_shopid); + struct npc_item_list *shop = nd->u.scr.shop->item; + unsigned short shop_size = nd->u.scr.shop->items; + int i; - for(i = 0; i < list_size; i++) { + for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { + const struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + int j; - npcmarket_result.list[i].ITID = req->list[i].ITID; - npcmarket_result.list[i].qty = req->list[i].qty; + npcmarket_result.list[i].ITID = entry->id; + npcmarket_result.list[i].qty = entry->amount; - ARR_FIND( 0, shop_size, j, req->list[i].ITID == shop[j].nameid ); + ARR_FIND( 0, shop_size, j, entry->id == shop[j].nameid); npcmarket_result.list[i].price = (j != shop_size) ? shop[j].value : 0; @@ -18238,16 +18235,28 @@ void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd) { #if PACKETVER >= 20131223 const struct packet_npc_market_purchase *p = RP2PTR(fd); - struct packet_npc_market_purchase pcopy; - int response = 0; + int response = 0, i; int count = (p->PacketLength - 4) / sizeof p->list[0]; + struct itemlist item_list; Assert_retv(count >= 0 && count <= MAX_INVENTORY); - memcpy(&pcopy, p, p->PacketLength); // FIXME: Temporary hack (until changed to a flexible array) + VECTOR_INIT(item_list); + VECTOR_ENSURE(item_list, count, 1); + + for (i = 0; i < count; i++) { + struct itemlist_entry entry = { 0 }; + + entry.id = p->list[i].ITID; + entry.amount = p->list[i].qty; - response = npc->market_buylist(sd, count, &pcopy); - clif->npc_market_purchase_ack(sd, &pcopy, response); + VECTOR_PUSH(item_list, entry); + } + + response = npc->market_buylist(sd, &item_list); + clif->npc_market_purchase_ack(sd, &item_list, response); + + VECTOR_CLEAR(item_list); #endif } diff --git a/src/map/clif.h b/src/map/clif.h index 3b7e2e99fcc..ac0191210a6 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -40,6 +40,7 @@ struct guild; struct homun_data; struct item; struct item_data; +struct itemlist; // map/itemdb.h struct map_session_data; struct mercenary_data; struct mob_data; @@ -1080,7 +1081,7 @@ struct clif_interface { int (*delay_damage_sub) (int tid, int64 tick, int id, intptr_t data); /* NPC Market */ void (*npc_market_open) (struct map_session_data *sd, struct npc_data *nd); - void (*npc_market_purchase_ack) (struct map_session_data *sd, const struct packet_npc_market_purchase *req, unsigned char response); + void (*npc_market_purchase_ack) (struct map_session_data *sd, const struct itemlist *item_list, unsigned char response); /* */ bool (*parse_roulette_db) (void); void (*roulette_generate_ack) (struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID); diff --git a/src/map/npc.c b/src/map/npc.c index 793ca9a0348..25a9722997a 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1930,10 +1930,9 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { } /** - * parses incoming npc market purchase list + * Processes incoming npc market purchase list **/ -// FIXME[Haru]: This needs to be decoupled from the client. A packet struct should never make it into npc functions. -int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, struct packet_npc_market_purchase *p) +int npc_market_buylist(struct map_session_data *sd, struct itemlist *item_list) { struct npc_data* nd; struct npc_item_list *shop = NULL; @@ -1942,11 +1941,11 @@ int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, st unsigned short shop_size = 0; nullpo_retr(1, sd); - nullpo_retr(1, p); + nullpo_retr(1, item_list); nd = npc->checknear(sd,map->id2bl(sd->npc_shopid)); - if( nd == NULL || nd->subtype != SCRIPT || !list_size || !nd->u.scr.shop || nd->u.scr.shop->type != NST_MARKET ) + if (nd == NULL || nd->subtype != SCRIPT || VECTOR_LENGTH(*item_list) == 0 || !nd->u.scr.shop || nd->u.scr.shop->type != NST_MARKET) return 1; shop = nd->u.scr.shop->item; @@ -1957,37 +1956,37 @@ int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, st new_ = 0; // process entries in buy list, one by one - for( i = 0; i < list_size; ++i ) { - int nameid, amount, value; + for (i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + int value; + struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); // find this entry in the shop's sell list ARR_FIND( 0, shop_size, j, - p->list[i].ITID == shop[j].nameid || //Normal items - p->list[i].ITID == itemdb_viewid(shop[j].nameid) //item_avail replacement + entry->id == shop[j].nameid || //Normal items + entry->id == itemdb_viewid(shop[j].nameid) //item_avail replacement ); - - if( j == shop_size ) /* TODO find official response for this */ + if (j == shop_size) /* TODO find official response for this */ return 1; // no such item in shop - if( p->list[i].qty > shop[j].qty ) + entry->id = shop[j].nameid; //item_avail replacement + + if (entry->amount > (int)shop[j].qty) return 1; - amount = p->list[i].qty; - nameid = p->list[i].ITID = shop[j].nameid; //item_avail replacement value = shop[j].value; npc_market_qty[i] = j; - if( !itemdb->exists(nameid) ) /* TODO find official response for this */ + if (!itemdb->exists(entry->id)) /* TODO find official response for this */ return 1; // item no longer in itemdb - if( !itemdb->isstackable(nameid) && amount > 1 ) { + if (!itemdb->isstackable(entry->id) && entry->amount > 1) { //Exploit? You can't buy more than 1 of equipment types o.O ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", - sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); - amount = p->list[i].qty = 1; + sd->status.name, sd->status.account_id, sd->status.char_id, entry->amount, entry->id); + entry->amount = 1; } - switch( pc->checkadditem(sd,nameid,amount) ) { + switch (pc->checkadditem(sd, entry->id, entry->amount)) { case ADDITEM_EXIST: break; case ADDITEM_NEW: @@ -1997,8 +1996,8 @@ int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, st return 1; } - z += (int64)value * amount; - w += itemdb_weight(nameid) * amount; + z += (int64)value * entry->amount; + w += itemdb_weight(entry->id) * entry->amount; } if (z > sd->status.zeny) /* TODO find official response for this */ @@ -2012,28 +2011,27 @@ int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, st pc->payzeny(sd,(int)z,LOG_TYPE_NPC, NULL); - for( i = 0; i < list_size; ++i ) { - int nameid = p->list[i].ITID; - int amount = p->list[i].qty; + for (i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); j = npc_market_qty[i]; - if( p->list[i].qty > shop[j].qty ) /* wohoo someone tampered with the packet. */ + if (entry->amount > (int)shop[j].qty) /* wohoo someone tampered with the packet. */ return 1; - shop[j].qty -= amount; + shop[j].qty -= entry->amount; npc->market_tosql(nd,j); - if (itemdb_type(nameid) == IT_PETEGG) { - pet->create_egg(sd, nameid); + if (itemdb_type(entry->id) == IT_PETEGG) { + pet->create_egg(sd, entry->id); } else { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = nameid; + item_tmp.nameid = entry->id; item_tmp.identify = 1; - pc->additem(sd,&item_tmp,amount,LOG_TYPE_NPC); + pc->additem(sd, &item_tmp, entry->amount, LOG_TYPE_NPC); } } diff --git a/src/map/npc.h b/src/map/npc.h index 2731d51db83..1c7ad839893 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -293,7 +293,7 @@ struct npc_interface { void (*trader_count_funds) (struct npc_data *nd, struct map_session_data *sd); bool (*trader_pay) (struct npc_data *nd, struct map_session_data *sd, int price, int points); void (*trader_update) (int master); - int (*market_buylist) (struct map_session_data* sd, unsigned short list_size, struct packet_npc_market_purchase *p); + int (*market_buylist) (struct map_session_data *sd, struct itemlist *item_list); bool (*trader_open) (struct map_session_data *sd, struct npc_data *nd); void (*market_fromsql) (void); void (*market_tosql) (struct npc_data *nd, unsigned short index); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 90ea85d4a0b..f23cefb2630 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -1105,8 +1105,7 @@ struct packet_npc_market_purchase { struct { unsigned short ITID; int qty; - } list[MAX_INVENTORY];/* assuming MAX_INVENTORY is max since you can't hold more than MAX_INVENTORY items thus cant buy that many at once. */ - // TODO[Haru]: Change to a flexible array + } list[]; // Note: We assume this should be <= MAX_INVENTORY (since you can't hold more than MAX_INVENTORY items thus cant buy that many at once). } __attribute__((packed)); struct packet_npc_market_result_ack {