Skip to content

Commit

Permalink
Edited npc->market_buylist() to use the new struct itemlist
Browse files Browse the repository at this point in the history
- The npc-side code no longer depends on the client data layout.

Signed-off-by: Haru <haru@dotalux.com>
  • Loading branch information
MishimaHaruna committed Feb 24, 2016
1 parent 23f1ef3 commit 3b9c0da
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 55 deletions.
51 changes: 30 additions & 21 deletions src/map/clif.c
Expand Up @@ -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;

Expand All @@ -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
}

Expand Down
3 changes: 2 additions & 1 deletion src/map/clif.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
58 changes: 28 additions & 30 deletions src/map/npc.c
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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:
Expand All @@ -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 */
Expand All @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/map/npc.h
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions src/map/packets_struct.h
Expand Up @@ -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 {
Expand Down

0 comments on commit 3b9c0da

Please sign in to comment.