diff options
author | Andrei Karas <akaras@inbox.ru> | 2018-12-28 20:05:19 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2019-01-14 20:18:11 +0300 |
commit | 0f3a9dfaf79b0227944f2f4052dd48be3b2588f4 (patch) | |
tree | 57c488a7786a51da3f3338af795afb3beb0ddb84 /src/map/npc.c | |
parent | e36edf03ce84351b27ef5d0f95b32c0f10725831 (diff) | |
download | hercules-0f3a9dfaf79b0227944f2f4052dd48be3b2588f4.tar.gz hercules-0f3a9dfaf79b0227944f2f4052dd48be3b2588f4.tar.bz2 hercules-0f3a9dfaf79b0227944f2f4052dd48be3b2588f4.tar.xz hercules-0f3a9dfaf79b0227944f2f4052dd48be3b2588f4.zip |
Add packet CZ_NPC_BARTER_PURCHASE
Diffstat (limited to 'src/map/npc.c')
-rw-r--r-- | src/map/npc.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/map/npc.c b/src/map/npc.c index 4c4cd0bb5..7f003c321 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2117,6 +2117,129 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item return 0; } +/** + * Processes incoming npc barter purchase list + **/ +static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist *item_list) +{ + struct npc_data* nd; + struct npc_item_list *shop = NULL; + int w, new_; + unsigned short shop_size = 0; + + nullpo_retr(1, sd); + nullpo_retr(1, item_list); + + nd = npc->checknear(sd, map->id2bl(sd->npc_shopid)); + + if (nd == NULL || nd->subtype != SCRIPT || VECTOR_LENGTH(*item_list) == 0 || !nd->u.scr.shop || nd->u.scr.shop->type != NST_BARTER) + return 11; + + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + w = 0; + new_ = 0; + + int items[MAX_INVENTORY] = { 0 }; + + // process entries in buy list, one by one + for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + + const int n = entry->removeIndex; + if (n < 0 || n >= sd->status.inventorySize) + return 11; // wrong inventory index + + if (!itemdb->exists(entry->addId)) + return 13; // item no longer in itemdb + + const int removeId = sd->status.inventory[n].nameid; + int j = shop_size; + // find this entry in the shop's sell list + ARR_FIND(0, shop_size, j, (entry->addId == shop[j].nameid || entry->addId == itemdb_viewid(shop[j].nameid)) && + (removeId == shop[j].value || removeId == itemdb_viewid(shop[j].value))); + if (j == shop_size) + return 13; // no such item in shop + + const int removeAmount = shop[j].value2; + + if (entry->addAmount > (int)shop[j].qty) + return 14; // not enough item amount in shop + + if (removeAmount * entry->addAmount > sd->status.inventory[n].amount) + return 14; // not enough item amount in inventory + + items[n] += removeAmount * entry->addAmount; + + if (items[n] > sd->status.inventory[n].amount) + return 14; // not enough item amount in inventory + + entry->addId = shop[j].nameid; //item_avail replacement + + npc_market_qty[i] = j; + + if (!itemdb->isstackable(entry->addId) && entry->addAmount > 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, entry->addAmount, entry->addId); + entry->addAmount = 1; + } + + switch (pc->checkadditem(sd, entry->addId, entry->addAmount)) { + case ADDITEM_EXIST: + break; + case ADDITEM_NEW: + new_++; + break; + case ADDITEM_OVERAMOUNT: /* TODO find official response for this */ + return 1; + } + + w += itemdb_weight(entry->addId) * entry->addAmount; + w -= itemdb_weight(removeId) * removeAmount; + } + + if (w + sd->weight > sd->max_weight) + return 2; // Too heavy + + if (pc->inventoryblank(sd) < new_) + return 3; // Not enough space to store items + + for (int i = 0; i < sd->status.inventorySize; ++i) { + const int removeAmountTotal = items[i]; + if (removeAmountTotal == 0) + continue; + if (pc->delitem(sd, i, removeAmountTotal, 0, DELITEM_SOLD, LOG_TYPE_NPC) != 0) { + return 11; // unknown exploit + } + } + + for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) { + struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + const int shopIdx = npc_market_qty[i]; + + if (entry->addAmount > (int)shop[shopIdx].qty) /* wohoo someone tampered with the packet. */ + return 14; + + shop[shopIdx].qty -= entry->addAmount; + + // TODO: save to sql + + if (itemdb_type(entry->addId) == IT_PETEGG) { + pet->create_egg(sd, entry->addId); + } else { + struct item item_tmp; + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = entry->addId; + item_tmp.identify = 1; + pc->additem(sd, &item_tmp, entry->addAmount, LOG_TYPE_NPC); + } + } + + return 12; +} + /// npc_selllist for script-controlled shops static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd) { @@ -5308,6 +5431,7 @@ void npc_defaults(void) npc->trader_pay = npc_trader_pay; npc->trader_update = npc_trader_update; npc->market_buylist = npc_market_buylist; + npc->barter_buylist = npc_barter_buylist; npc->trader_open = npc_trader_open; npc->market_fromsql = npc_market_fromsql; npc->market_tosql = npc_market_tosql; |