Browse Source

* Fixed buyers, that are currently in a vending shop could be fooled into buying an item at different price than they see by reopening the vending shop (bugreport:4728).
- This implements the official vending shop unique id handling (previously mistaken for char id), made compatible with packets before it's introduction (follow up to r14234).

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@14682 54d463be-8e91-2dee-dedb-b68131a5f0ec

ai4rei 14 năm trước cách đây
mục cha
commit
0f1c66191c
5 tập tin đã thay đổi với 48 bổ sung19 xóa
  1. 3 0
      Changelog-Trunk.txt
  2. 18 10
      src/map/clif.c
  3. 1 0
      src/map/pc.h
  4. 25 8
      src/map/vending.c
  5. 1 1
      src/map/vending.h

+ 3 - 0
Changelog-Trunk.txt

@@ -1,5 +1,8 @@
 Date	Added
 
+2011/01/26
+	* Fixed buyers, that are currently in a vending shop could be fooled into buying an item at different price than they see by reopening the vending shop (bugreport:4728). [Ai4rei]
+	- This implements the official vending shop unique id handling (previously mistaken for char id), made compatible with packets before it's introduction (follow up to r14234).
 2011/01/24
 	* Added documentation for undocumented bonuses (bugreport:4727, follow up to r302, r354, r485, r699, r928, r1116, r6221, r7982, r10031, r13596 and r14018). [Ai4rei]
 2011/01/23

+ 18 - 10
src/map/clif.c

@@ -5599,9 +5599,9 @@ void clif_closevendingboard(struct block_list* bl, int fd)
 }
 
 /*==========================================
- * Sends a list of items in a shop
+ * Sends a list of items in a shop (ZC_PC_PURCHASE_ITEMLIST_FROMMC/ZC_PC_PURCHASE_ITEMLIST_FROMMC2)
  * R 0133 <len>.w <ID>.l {<value>.l <amount>.w <index>.w <type>.B <item ID>.w <identify flag>.B <attribute?>.B <refine>.B <card>.4w}.22B
- * R 0800 <len>.w <ID>.l <ID?>.l {<value>.l  <amount>.w <index>.w <type>.B <item ID>.w <identify flag>.B <attribute?>.B <refine>.B <card>.4w}.22B
+ * R 0800 <len>.w <ID>.l <UniqueID>.l {<value>.l  <amount>.w <index>.w <type>.B <item ID>.w <identify flag>.B <attribute?>.B <refine>.B <card>.4w}.22B
  *------------------------------------------*/
 void clif_vendinglist(struct map_session_data* sd, int id, struct s_vending* vending)
 {
@@ -5628,7 +5628,7 @@ void clif_vendinglist(struct map_session_data* sd, int id, struct s_vending* ven
 	WFIFOW(fd,2) = offset+count*22;
 	WFIFOL(fd,4) = id;
 #if PACKETVER >= 20100105
-	WFIFOL(fd,8) = vsd->status.char_id;
+	WFIFOL(fd,8) = vsd->vender_id;
 #endif
 
 	for( i = 0; i < count; i++ )
@@ -5649,12 +5649,14 @@ void clif_vendinglist(struct map_session_data* sd, int id, struct s_vending* ven
 }
 
 /*==========================================
- * Shop purchase failure
+ * Shop purchase failure (ZC_PC_PURCHASE_RESULT_FROMMC)
  * R 0135 <index>.w <amount>.w <fail>.B
  * fail=1 - not enough zeny
  * fail=2 - overweight
  * fail=4 - out of stock
  * fail=5 - "cannot use an npc shop while in a trade"
+ * fail=6 - Because the store information was incorrect the item was not purchased.
+ * fail=7 - No sales information.
  *------------------------------------------*/
 void clif_buyvending(struct map_session_data* sd, int index, int amount, int fail)
 {
@@ -10884,7 +10886,7 @@ void clif_parse_VendingListReq(int fd, struct map_session_data* sd)
 }
 
 /*==========================================
- * Shop item(s) purchase request
+ * Shop item(s) purchase request (CZ_PC_PURCHASE_ITEMLIST_FROMMC)
  * S 0134 <len>.w <ID>.l {<amount>.w <index>.w}.4B*
  *------------------------------------------*/
 void clif_parse_PurchaseReq(int fd, struct map_session_data* sd)
@@ -10893,21 +10895,27 @@ void clif_parse_PurchaseReq(int fd, struct map_session_data* sd)
 	int id = (int)RFIFOL(fd,4);
 	const uint8* data = (uint8*)RFIFOP(fd,8);
 
-	vending_purchasereq(sd, id, -1, data, len/4);
+	vending_purchasereq(sd, id, sd->vended_id, data, len/4);
+
+	// whether it fails or not, the buy window is closed
+	sd->vended_id = 0;
 }
 
 /*==========================================
- * Shop item(s) purchase request
- * S 0134/0801 <len>.w <AID>.l <CID>.l {<amount>.w <index>.w}.4B*
+ * Shop item(s) purchase request (CZ_PC_PURCHASE_ITEMLIST_FROMMC2)
+ * S 0801 <len>.w <AID>.l <UniqueID>.l {<amount>.w <index>.w}.4B*
  *------------------------------------------*/
 void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd)
 {
 	int len = (int)RFIFOW(fd,2) - 12;
 	int aid = (int)RFIFOL(fd,4);
-	int cid = (int)RFIFOL(fd,8);
+	int uid = (int)RFIFOL(fd,8);
 	const uint8* data = (uint8*)RFIFOP(fd,12);
 
-	vending_purchasereq(sd, aid, cid, data, len/4);
+	vending_purchasereq(sd, aid, uid, data, len/4);
+
+	// whether it fails or not, the buy window is closed
+	sd->vended_id = 0;
 }
 
 /*==========================================

+ 1 - 0
src/map/pc.h

@@ -350,6 +350,7 @@ struct map_session_data {
 	int guildspy; // [Syrus22]
 	int partyspy; // [Syrus22]
 
+	int vended_id;
 	int vender_id;
 	int vend_num;
 	char message[MESSAGE_SIZE];

+ 25 - 8
src/map/vending.c

@@ -19,6 +19,18 @@
 #include <stdio.h>
 #include <string.h>
 
+static int vending_nextid = 1;
+
+/// Returns an unique vending shop id.
+static int vending_getuid(void)
+{
+	if(!vending_nextid)
+	{// wrapped around, 0 is reserved for "not vending" state on eathena
+		vending_nextid = 1;
+	}
+
+	return vending_nextid++;
+}
 
 /*==========================================
  * Close shop
@@ -50,13 +62,15 @@ void vending_vendinglistreq(struct map_session_data* sd, int id)
 		return;
 	} 
 
+	sd->vended_id = vsd->vender_id;  // register vending uid
+
 	clif_vendinglist(sd, id, vsd->vending);
 }
 
 /*==========================================
  * Purchase item(s) from a shop
  *------------------------------------------*/
-void vending_purchasereq(struct map_session_data* sd, int aid, int cid, const uint8* data, int count)
+void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count)
 {
 	int i, j, cursor, w, new_ = 0, blank, vend_list[MAX_VENDING];
 	double z;
@@ -64,12 +78,15 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int cid, const ui
 	struct map_session_data* vsd = map_id2sd(aid);
 
 	nullpo_retv(sd);
-	if( vsd == NULL || vsd->vender_id == 0 || vsd->vender_id == sd->bl.id )
+	if( vsd == NULL || vsd->vender_id == 0 || vsd->bl.id == sd->bl.id )
 		return; // invalid shop
-#if PACKETVER >= 20100105
-	if( vsd->status.char_id != cid )
-		return; //Char-ID check
-#endif
+
+	if( vsd->vender_id != uid )
+	{// shop has changed
+		clif_buyvending(sd, 0, 0, 6);  // store information was incorrect
+		return;
+	}
+
 	if( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) )
 		return; // shop too far away
 	if( count < 1 || count > MAX_VENDING || count > vsd->vend_num )
@@ -289,11 +306,11 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
 		return;
 	}
 
-	sd->vender_id = sd->bl.id;
+	sd->vender_id = vending_getuid();
 	sd->vend_num = i;
 	safestrncpy(sd->message, message, MESSAGE_SIZE);
 
 	pc_stop_walking(sd,1);
-	clif_openvending(sd,sd->vender_id,sd->vending);
+	clif_openvending(sd,sd->bl.id,sd->vending);
 	clif_showvendingboard(&sd->bl,message,0);
 }

+ 1 - 1
src/map/vending.h

@@ -17,6 +17,6 @@ struct s_vending {
 void vending_closevending(struct map_session_data* sd);
 void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count);
 void vending_vendinglistreq(struct map_session_data* sd, int id);
-void vending_purchasereq(struct map_session_data* sd, int aid, int cid, const uint8* data, int count);
+void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count);
 
 #endif /* _VENDING_H_ */