Updates Item Sell checks (#3491)

* Added config values for `allow_bound_sell`
  * 0x4 allows bound item to be sold at NPC Shops
  * 0x8 restrict only guild leader who can sell guild bound item at NPC Shops or Itemshops
* Added config to allow rental items can be sold at NPC `rental_transaction` (planned for more config values based on #3490). Default to `yes` allowed to be sold, still can be restricted by item_trade, item id based.
* Fixed itemshop which ignores another item stack in inventory even for same item currency
* Fixed exploit potential by using Itemshop & Pointshop
* Now equipped item cannot be sold at NPC
* Typo and grammar fixes. Thanks to @aleos89 and @secretdataz
This commit is contained in:
Cydh Ramdh
2018-09-27 13:54:28 +07:00
committed by GitHub
parent 79766cd99e
commit 3e1105b0cf
8 changed files with 77 additions and 25 deletions

View File

@@ -1407,7 +1407,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
/** Payment Process for NPCTYPE_CASHSHOP, NPCTYPE_ITEMSHOP, and NPCTYPE_POINTSHOP
* @param nd NPC Shop data
* @param price Price must be paid
* @param points Total points that player has
* @param points Amount of secondary points that player requested
* @param sd Player data
* @return e_CASHSHOP_ACK
**/
@@ -1425,12 +1425,13 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
case NPCTYPE_ITEMSHOP:
{
struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid);
int delete_amount = price, i;
if (!id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
ShowWarning("Failed to find sellitem %hu for itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y);
return ERROR_TYPE_PURCHASE_FAIL;
}
if (cost[0] < (price - points)) {
if (cost[1] < points || cost[0] < (price - points)) {
char output[CHAT_SIZE_MAX];
memset(output, '\0', sizeof(output));
@@ -1439,8 +1440,28 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
clif_messagecolor(&sd->bl, color_table[COLOR_RED], output, false, SELF);
return ERROR_TYPE_PURCHASE_FAIL;
}
if (pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), price - points, 0, 0, LOG_TYPE_NPC)) {
ShowWarning("Failed to delete item %hu from '%s' at itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, sd->status.name, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y);
for (i = 0; i < MAX_INVENTORY && delete_amount > 0; i++) {
struct item *it;
int amount = 0;
if (sd->inventory.u.items_inventory[i].nameid == 0 || sd->inventory_data[i] == NULL || !(it = &sd->inventory.u.items_inventory[i]) || it->nameid != nd->u.shop.itemshop_nameid)
continue;
if (!pc_can_sell_item(sd, it, nd->subtype))
continue;
amount = it->amount;
if (amount > delete_amount)
amount = delete_amount;
if (pc_delitem(sd, i, amount, 0, 0, LOG_TYPE_NPC)) {
ShowWarning("Failed to delete item %hu from '%s' at itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, sd->status.name, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y);
return ERROR_TYPE_PURCHASE_FAIL;
}
delete_amount -= amount;
}
if (delete_amount > 0) {
ShowError("Item %hu is not enough as payment at itemshop NPC '%s' (%s, %d, %d, AID=%d, CID=%d)!\n", nd->u.shop.itemshop_nameid, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y, sd->status.account_id, sd->status.char_id);
return ERROR_TYPE_PURCHASE_FAIL;
}
}
@@ -1451,7 +1472,7 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
memset(output, '\0', sizeof(output));
if (cost[0] < (price - points)) {
if (cost[1] < points || cost[0] < (price - points)) {
sprintf(output, msg_txt(sd, 713), nd->u.shop.pointshop_str); // You do not have enough '%s'.
clif_messagecolor(&sd->bl, color_table[COLOR_RED], output, false, SELF);
return ERROR_TYPE_PURCHASE_FAIL;
@@ -1594,7 +1615,7 @@ void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, in
}
for (i = 0; i < MAX_INVENTORY; i++) {
if (sd->inventory.u.items_inventory[i].amount > 0 && sd->inventory.u.items_inventory[i].nameid == id->nameid && pc_can_sell_item(sd, &sd->inventory.u.items_inventory[i]))
if (sd->inventory.u.items_inventory[i].amount > 0 && sd->inventory.u.items_inventory[i].nameid == id->nameid && pc_can_sell_item(sd, &sd->inventory.u.items_inventory[i], nd->subtype))
total += sd->inventory.u.items_inventory[i].amount;
}
}
@@ -2014,6 +2035,10 @@ uint8 npc_selllist(struct map_session_data* sd, int n, unsigned short *item_list
continue;
}
if (!pc_can_sell_item(sd, &sd->inventory.u.items_inventory[idx], nd->subtype)) {
return 1; // In official server, this illegal attempt the player will be disconnected
}
value = pc_modifysellvalue(sd, sd->inventory_data[idx]->value_sell);
z+= (double)value*amount;