diff options
-rw-r--r-- | src/map/clif.c | 23 | ||||
-rw-r--r-- | src/map/npc.c | 72 | ||||
-rw-r--r-- | src/map/npc.h | 4 |
3 files changed, 58 insertions, 41 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index eb67723e2..80eb7796a 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -10534,16 +10534,29 @@ void clif_parse_NpcBuyListSend(int fd, struct map_session_data* sd) __attribute_ /// 00c8 <packet len>.W { <amount>.W <name id>.W }* void clif_parse_NpcBuyListSend(int fd, struct map_session_data* sd) { - int n = (RFIFOW(fd,2)-4) /4; + int n = ((int)RFIFOW(fd,2)-4) / 4; int result; + Assert_retv(n >= 0); + if( sd->state.trading || !sd->npc_shopid || pc_has_permission(sd,PC_PERM_DISABLE_STORE) ) { result = 1; } else { - unsigned short *item_list = aMalloc(sizeof(*item_list) * 2 * n); - memcpy(item_list, RFIFOP(fd,4), sizeof(*item_list) * 2 * n); - result = npc->buylist(sd,n,item_list); - aFree(item_list); + struct itemlist item_list = { 0 }; + int i; + + VECTOR_INIT(item_list); + VECTOR_ENSURE(item_list, n, 1); + for (i = 0; i < n; i++) { + struct itemlist_entry entry = { 0 }; + + entry.amount = RFIFOW(fd, 4 + 4 * i); + entry.id = RFIFOW(fd, 4 + 4 * i + 2); + + VECTOR_PUSH(item_list, entry); + } + result = npc->buylist(sd, &item_list); + VECTOR_CLEAR(item_list); } sd->npc_shopid = 0; //Clear shop data. diff --git a/src/map/npc.c b/src/map/npc.c index 25a972299..042aa43b5 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1485,7 +1485,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, struct itemlis } //npc_buylist for script-controlled shops. -int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd) +int npc_buylist_sub(struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd) { char npc_ev[EVENT_NAME_LENGTH]; int i; @@ -1497,9 +1497,12 @@ int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_lis script->cleararray_pc(sd, "@bought_quantity", (void*)0); // save list of bought items - for( i = 0; i < n; i++ ) { - script->setarray_pc(sd, "@bought_nameid", i, (void*)(intptr_t)item_list[i*2+1], &key_nameid); - script->setarray_pc(sd, "@bought_quantity", i, (void*)(intptr_t)item_list[i*2], &key_amount); + for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { + struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + intptr_t nameid = entry->id; + intptr_t amount = entry->amount; + script->setarray_pc(sd, "@bought_nameid", i, (void *)nameid, &key_nameid); + script->setarray_pc(sd, "@bought_quantity", i, (void *)amount, &key_amount); } // invoke event @@ -1803,11 +1806,15 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po return ERROR_TYPE_NONE; } -/// Player item purchase from npc shop. -/// -/// @param item_list 'n' pairs <amount,itemid> -/// @return result code for clif->parse_NpcBuyListSend -int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { +/** + * Processes a player item purchase from npc shop. + * + * @param sd Buyer character. + * @param item_list List of items. + * @return result code for clif->parse_NpcBuyListSend. + */ +int npc_buylist(struct map_session_data *sd, struct itemlist *item_list) +{ struct npc_data* nd; struct npc_item_list *shop = NULL; int64 z; @@ -1836,30 +1843,29 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { w = 0; new_ = 0; // process entries in buy list, one by one - for( i = 0; i < n; ++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, - item_list[i*2+1] == shop[j].nameid || //Normal items - item_list[i*2+1] == 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 ) + if (j == shop_size) return 3; // no such item in shop - amount = item_list[i*2+0]; - nameid = item_list[i*2+1] = shop[j].nameid; //item_avail replacement + entry->id = shop[j].nameid; //item_avail replacement value = shop[j].value; - if( !itemdb->exists(nameid) ) + if (!itemdb->exists(entry->id)) return 3; // 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 = item_list[i*2+0] = 1; + sd->status.name, sd->status.account_id, sd->status.char_id, entry->amount, entry->id); + entry->amount = 1; } if( nd->master_nd ) { @@ -1867,7 +1873,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { continue; } - switch( pc->checkadditem(sd,nameid,amount) ) { + switch (pc->checkadditem(sd, entry->id, entry->amount)) { case ADDITEM_EXIST: break; @@ -1881,12 +1887,12 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { value = pc->modifybuyvalue(sd,value); - z += (int64)value * amount; - w += itemdb_weight(nameid) * amount; + z += (int64)value * entry->amount; + w += itemdb_weight(entry->id) * entry->amount; } - if( nd->master_nd != NULL ) //Script-based shops. - return npc->buylist_sub(sd,n,item_list,nd->master_nd); + if (nd->master_nd != NULL) //Script-based shops. + return npc->buylist_sub(sd, item_list, nd->master_nd); if (z > sd->status.zeny) return 1; // Not enough Zeny @@ -1897,19 +1903,17 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { pc->payzeny(sd, (int)z, LOG_TYPE_NPC, NULL); - for( i = 0; i < n; ++i ) { - int nameid = item_list[i*2+1]; - int amount = item_list[i*2+0]; - - if (itemdb_type(nameid) == IT_PETEGG) { - pet->create_egg(sd, nameid); + for (i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + 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 1c7ad8398..dbd740b46 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -233,9 +233,9 @@ struct npc_interface { int (*scriptcont) (struct map_session_data *sd, int id, bool closing); int (*buysellsel) (struct map_session_data *sd, int id, int type); int (*cashshop_buylist) (struct map_session_data *sd, int points, struct itemlist *item_list); - int (*buylist_sub) (struct map_session_data *sd, int n, unsigned short *item_list, struct npc_data *nd); + int (*buylist_sub) (struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd); int (*cashshop_buy) (struct map_session_data *sd, int nameid, int amount, int points); - int (*buylist) (struct map_session_data *sd, int n, unsigned short *item_list); + int (*buylist) (struct map_session_data *sd, struct itemlist *item_list); int (*selllist_sub) (struct map_session_data *sd, int n, unsigned short *item_list, struct npc_data *nd); int (*selllist) (struct map_session_data *sd, int n, unsigned short *item_list); int (*remove_map) (struct npc_data *nd); |