소스 검색

Fixes #4311 (#4312)

* Added item with GUID flag as `CHKADDITEM_NEW` in pc_checkadditem
* Adjust inventory blank check for guid item to `+n`
* Moved slot check as item_data function
* Removed quantity force-set-to-1 check for buying equip from cashshop, it will gives the item to player just like item with GUID flag
Cydh Ramdh 5 년 전
부모
커밋
dda63f517c
5개의 변경된 파일42개의 추가작업 그리고 28개의 파일을 삭제
  1. 5 9
      src/map/cashshop.cpp
  2. 19 11
      src/map/itemdb.cpp
  3. 3 0
      src/map/itemdb.hpp
  4. 12 8
      src/map/npc.cpp
  5. 3 0
      src/map/pc.cpp

+ 5 - 9
src/map/cashshop.cpp

@@ -471,6 +471,7 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 	uint32 totalcash = 0;
 	uint32 totalweight = 0;
 	int i,new_;
+	item_data *id;
 #if PACKETVER_SUPPORTS_SALES
 	struct sale_item_data* sale = NULL;
 #endif
@@ -504,13 +505,11 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 		}
 
 		nameid = *( item_list + i * 5 ) = cash_shop_items[tab].item[j]->nameid; //item_avail replacement
+		id = itemdb_exists(nameid);
 
-		if( !itemdb_exists( nameid ) ){
+		if( !id ){
 			clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKONWN_ITEM );
 			return false;
-		}else if( !itemdb_isstackable( nameid ) && quantity > 1 ){
-			/* ShowWarning( "Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable cash item %hu!\n", sd->status.name, sd->status.account_id, sd->status.char_id, quantity, nameid ); */
-			quantity = *( item_list + i * 5 + 2 ) = 1;
 		}
 
 		if( quantity > 99 ){
@@ -544,7 +543,7 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 				break;
 
 			case CHKADDITEM_NEW:
-				new_++;
+				new_ += id->inventorySlotNeeded(quantity);
 				break;
 
 			case CHKADDITEM_OVERAMOUNT:
@@ -580,13 +579,10 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 		if (!id)
 			continue;
 
-		if (!itemdb_isstackable2(id) && quantity > 1)
-			quantity = 1;
-
 		if (!pet_create_egg(sd, nameid)) {
 			unsigned short get_amt = quantity, j;
 
-			if (id->flag.guid)
+			if (id->flag.guid || !itemdb_isstackable2(id))
 				get_amt = 1;
 
 			for (j = 0; j < quantity; j += get_amt) {

+ 19 - 11
src/map/itemdb.cpp

@@ -502,19 +502,9 @@ bool itemdb_isequip2(struct item_data *id) {
 bool itemdb_isstackable2(struct item_data *id)
 {
 	nullpo_ret(id);
-	switch(id->type) {
-		case IT_WEAPON:
-		case IT_ARMOR:
-		case IT_PETEGG:
-		case IT_PETARMOR:
-		case IT_SHADOWGEAR:
-			return false;
-		default:
-			return true;
-	}
+	return id->isStackable();
 }
 
-
 /*==========================================
  * Trade Restriction functions [Skotlex]
  *------------------------------------------*/
@@ -1981,6 +1971,24 @@ static int itemdb_randomopt_free(DBKey key, DBData *data, va_list ap) {
 	return 1;
 }
 
+bool item_data::isStackable()
+{
+	switch (this->type) {
+		case IT_WEAPON:
+		case IT_ARMOR:
+		case IT_PETEGG:
+		case IT_PETARMOR:
+		case IT_SHADOWGEAR:
+			return false;
+	}
+	return true;
+}
+
+int item_data::inventorySlotNeeded(int quantity)
+{
+	return (this->flag.guid || !this->isStackable()) ? quantity : 1;
+}
+
 /**
 * Reload Item DB
 */

+ 3 - 0
src/map/itemdb.hpp

@@ -861,6 +861,9 @@ struct item_data
 	struct item_combo **combos;
 	unsigned char combos_count;
 	short delay_sc; ///< Use delay group if any instead using player's item_delay data [Cydh]
+
+	bool isStackable();
+	int inventorySlotNeeded(int quantity);
 };
 
 // Struct for item random option [Secret]

+ 12 - 8
src/map/npc.cpp

@@ -1563,6 +1563,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
 	unsigned short nameid;
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 	enum e_CASHSHOP_ACK res;
+	item_data *id;
 
 	if( !nd || ( nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 		return ERROR_TYPE_NPC;
@@ -1578,8 +1579,9 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
 	{
 		nameid = item_list[i*2+1];
 		amount = item_list[i*2+0];
+		id = itemdb_exists(nameid);
 
-		if( !itemdb_exists(nameid) || amount <= 0 )
+		if( !id || amount <= 0 )
 			return ERROR_TYPE_ITEM_ID;
 
 		ARR_FIND(0,nd->u.shop.count,j,nd->u.shop.shop_item[j].nameid == nameid || itemdb_viewid(nd->u.shop.shop_item[j].nameid) == nameid);
@@ -1588,7 +1590,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
 
 		nameid = item_list[i*2+1] = nd->u.shop.shop_item[j].nameid; //item_avail replacement
 
-		if( !itemdb_isstackable(nameid) && amount > 1 )
+		if( !itemdb_isstackable2(id) && amount > 1 )
 		{
 			ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %hu!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			amount = item_list[i*2+0] = 1;
@@ -1597,7 +1599,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
 		switch( pc_checkadditem(sd,nameid,amount) )
 		{
 			case CHKADDITEM_NEW:
-				new_++;
+				new_ += id->inventorySlotNeeded(amount);
 				break;
 			case CHKADDITEM_OVERAMOUNT:
 				return ERROR_TYPE_INVENTORY_WEIGHT;
@@ -1739,7 +1741,7 @@ int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amo
 
 	nameid = nd->u.shop.shop_item[i].nameid; //item_avail replacement
 
-	if(!itemdb_isstackable(nameid) && amount > 1)
+	if(!itemdb_isstackable2(item) && amount > 1)
 	{
 		ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %hu!\n",
 			sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
@@ -1749,7 +1751,7 @@ int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amo
 	switch( pc_checkadditem(sd, nameid, amount) )
 	{
 		case CHKADDITEM_NEW:
-			if( pc_inventoryblank(sd) == 0 )
+			if( pc_inventoryblank(sd) < item->inventorySlotNeeded(amount) )
 				return ERROR_TYPE_INVENTORY_WEIGHT;
 			break;
 		case CHKADDITEM_OVERAMOUNT:
@@ -1857,6 +1859,7 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *
 	for( i = 0; i < n; ++i ) {
 		unsigned short nameid, amount;
 		int value;
+		item_data *id;
 
 		// find this entry in the shop's sell list
 		ARR_FIND( 0, nd->u.shop.count, j,
@@ -1878,11 +1881,12 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *
 		amount = item_list[i].qty;
 		nameid = item_list[i].nameid = shop[j].nameid; //item_avail replacement
 		value = shop[j].value;
+		id = itemdb_exists(nameid);
 
-		if( !itemdb_exists(nameid) )
+		if( !id )
 			return 3; // item no longer in itemdb
 
-		if( !itemdb_isstackable(nameid) && amount > 1 ) { //Exploit? You can't buy more than 1 of equipment types o.O
+		if( !itemdb_isstackable2(id) && 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 nonstackable item %hu!\n",
 				sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			amount = item_list[i].qty = 1;
@@ -1897,7 +1901,7 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *
 				break;
 
 			case CHKADDITEM_NEW:
-				new_++;
+				new_ += id->inventorySlotNeeded(amount);
 				break;
 
 			case CHKADDITEM_OVERAMOUNT:

+ 3 - 0
src/map/pc.cpp

@@ -4577,6 +4577,9 @@ char pc_checkadditem(struct map_session_data *sd, unsigned short nameid, int amo
 	if( data->stack.inventory && amount > data->stack.amount )
 		return CHKADDITEM_OVERAMOUNT;
 
+	if (data->flag.guid)
+		return CHKADDITEM_NEW;
+
 	for(i=0;i<MAX_INVENTORY;i++){
 		// FIXME: This does not consider the checked item's cards, thus could check a wrong slot for stackability.
 		if(sd->inventory.u.items_inventory[i].nameid == nameid){