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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user