Browse Source

-Some clif work.
-Add packet definition for (2013-06-18, 2013-06-26, 2013-07-03, 2013-07-10, 2013-07-17) thx Shaktoh
-Optimise a bit pc_useitem processing
--Fix bugreport:7760 (Added new ranklist packet for newer client)
--Fix bugreport:7739 (2013+ storelist had invalid offset)
--Fix bugreport:7806 (fix typo for 2013+ support and also fix breaking of old npc/merchants/cash_trader.txt)

lighta 11 years ago
parent
commit
342745de1a
5 changed files with 400 additions and 137 deletions
  1. 6 2
      conf/battle/client.conf
  2. 165 1
      db/packet_db.txt
  3. 184 96
      src/map/clif.c
  4. 3 1
      src/map/clif.h
  5. 42 37
      src/map/pc.c

+ 6 - 2
conf/battle/client.conf

@@ -43,10 +43,14 @@
 // 0x10000000: 2013-05-29	Ragexe		(version 37)
 // 0x10000000: 2013-05-29	Ragexe		(version 37)
 // 0x20000000: 2013-06-05	Ragexe		(version 38)
 // 0x20000000: 2013-06-05	Ragexe		(version 38)
 // 0x40000000: 2013-06-12	Ragexe		(version 39)
 // 0x40000000: 2013-06-12	Ragexe		(version 39)
-// default value: 0x7FFFFFFF			(all clients/versions [5;40])
+// default value: 0x7FFFFFFF			(all clients/versions [5;39])
 packet_ver_flag: 0x7FFFFFFF
 packet_ver_flag: 0x7FFFFFFF
 
 
-// 0x00000001: 2013-06-19	Ragexe		(version 40)
+// 0x00000001: 2013-06-18	Ragexe		(version 40)
+// 0x00000002: 2013-06-26	Ragexe		(version 41)
+// 0x00000004: 2013-07-03	Ragexe		(version 42)
+// 0x00000008: 2013-07-10	Ragexe		(version 43)
+// 0x00000010: 2013-07-17	Ragexe		(version 44)
 // default value: 0x7FFFFFFF			(all clients/versions [41;72])
 // default value: 0x7FFFFFFF			(all clients/versions [41;72])
 packet_ver_flag2: 0x7FFFFFFF
 packet_ver_flag2: 0x7FFFFFFF
 
 

+ 165 - 1
db/packet_db.txt

@@ -1816,6 +1816,7 @@ packet_ver: 34
 0x0447,2,booking_playcancel,0
 0x0447,2,booking_playcancel,0
 0x044A,6,clientversion,2
 0x044A,6,clientversion,2
 0x0844,2,cashshopopen,0
 0x0844,2,cashshopopen,0
+0x0849,16 //clif_cashshop_result
 0x0848,-1,cashshopbuy,2:6:4:10
 0x0848,-1,cashshopbuy,2:6:4:10
 0x084a,2,cashshopclose,0
 0x084a,2,cashshopclose,0
 0x084b,19 //fallitem4
 0x084b,19 //fallitem4
@@ -1995,7 +1996,7 @@ packet_ver: 38
 0x0361,5,hommenu,2,4
 0x0361,5,hommenu,2,4
 0x0883,36,storagepassword,2:4:20
 0x0883,36,storagepassword,2:4:20
 
 
-//2013-06-05 Ragexe (Shakto)
+//2013-06-12 Ragexe (Shakto)
 packet_ver: 39
 packet_ver: 39
 0x0369,7,actionrequest,2:6
 0x0369,7,actionrequest,2:6
 0x083C,10,useskilltoid,2:4:6
 0x083C,10,useskilltoid,2:4:6
@@ -2026,3 +2027,166 @@ packet_ver: 39
 0x0940,26,friendslistadd,2
 0x0940,26,friendslistadd,2
 0x093A,5,hommenu,2:4
 0x093A,5,hommenu,2:4
 0x0964,36,storagepassword,2:4:20
 0x0964,36,storagepassword,2:4:20
+
+//2013-06-18 Ragexe (Shaktoh)
+packet_ver: 40
+0x0889,7,actionrequest,2:6
+0x0951,10,useskilltoid,2:4:6
+0x088E,5,walktoxy,2
+0x0930,6,ticksend,2
+0x08A6,5,changedir,2:4
+0x0962,6,takeitem,2
+0x0917,6,dropitem,2:4
+0x0885,8,movetokafra,2:4
+0x0936,8,movefromkafra,2:4
+0x096A,10,useskilltopos,2:4:6:8
+0x094F,90,useskilltoposinfo,2:4:6:8:10
+0x0944,6,getcharnamerequest,2
+0x0945,6,solvecharname,2
+0x0890,12,searchstoreinfolistitemclick,2:6:10
+0x0363,2,searchstoreinfonextpage,0
+0x0281,-1,searchstoreinfo,2:4:5:9:13:14:15
+0x0891,-1,reqtradebuyingstore,2:4:8:12
+0x0862,6,reqclickbuyingstore,2
+0x085A,2,reqclosebuyingstore,0
+0x0932,-1,reqopenbuyingstore,2:4:8:9:89
+0x08A7,18,bookingregreq,2:4:6
+// 0x087A,8 CZ_JOIN_BATTLE_FIELD
+0x0942,-1,itemlistwindowselected,2:4:8:12
+0x095B,19,wanttoconnection,2:6:10:14:18
+0x0887,26,partyinvite2,2
+// 0x0878,4 CZ_GANGSI_RANK
+0x0953,26,friendslistadd,2
+0x02C4,5,hommenu,2:4
+0x0864,36,storagepassword,2:4:20
+
+//2013-06-26 Ragexe
+packet_ver: 41
+0x0369,7,actionrequest,2:6
+0x083C,10,useskilltoid,2:4:6
+0x0437,5,walktoxy,2
+0x035F,6,ticksend,2
+0x094D,5,changedir,2:4
+0x088B,6,takeitem,2
+0x0952,6,dropitem,2:4
+0x0921,8,movetokafra,2:4
+0x0817,8,movefromkafra,2:4
+0x0438,10,useskilltopos,2:4:6:8
+0x0366,90,useskilltoposinfo,2:4:6:8:10
+0x096A,6,getcharnamerequest,2
+0x0368,6,solvecharname,2
+0x0838,12,searchstoreinfolistitemclick,2:6:10
+0x0835,2,searchstoreinfonextpage,0
+0x0819,-1,searchstoreinfo,2:4:5:9:13:14:15
+0x0811,-1,reqtradebuyingstore,2:4:8:12
+0x0360,6,reqclickbuyingstore,2
+0x0365,2,reqclosebuyingstore,0
+0x0815,-1,reqopenbuyingstore,2:4:8:9:89
+0x0894,18,bookingregreq,2:4:6
+// 0x0860,8 CZ_JOIN_BATTLE_FIELD
+0x08A5,-1,itemlistwindowselected,2:4:8:12
+0x088C,19,wanttoconnection,2:6:10:14:18
+0x0895,26,partyinvite2,2
+// 0x088F,4 CZ_GANGSI_RANK
+0x08AB,26,friendslistadd,2
+0x0960,5,hommenu,2:4
+0x0930,36,storagepassword,2:4:20
+
+//2013-07-03 Ragexe
+packet_ver: 42
+0x0369,7,actionrequest,2:6
+0x083C,10,useskilltoid,2:4:6
+0x0437,5,walktoxy,2
+0x035F,6,ticksend,2
+0x0930,5,changedir,2:4
+0x07E4,6,takeitem,2
+0x0362,6,dropitem,2:4
+0x07EC,8,movetokafra,2:4
+0x0364,8,movefromkafra,2:4
+0x0438,10,useskilltopos,2:4:6:8
+0x0366,90,useskilltoposinfo,2:4:6:8:10
+0x096A,6,getcharnamerequest,2
+0x0368,6,solvecharname,2
+0x0838,12,searchstoreinfolistitemclick,2:6:10
+0x0835,2,searchstoreinfonextpage,0
+0x0819,-1,searchstoreinfo,2:4:5:9:13:14:15
+0x0811,-1,reqtradebuyingstore,2:4:8:12
+0x0202,6,reqclickbuyingstore,2
+0x0817,2,reqclosebuyingstore,0
+0x0815,-1,reqopenbuyingstore,2:4:8:9:89
+0x0365,18,bookingregreq,2:4:6
+// 0x0363,8 CZ_JOIN_BATTLE_FIELD
+0x0281,-1,itemlistwindowselected,2:4:8:12
+0x022D,19,wanttoconnection,2:6:10:14:18
+0x0802,26,partyinvite2,2
+// 0x0436,4 CZ_GANGSI_RANK
+0x0360,26,friendslistadd,2
+0x094A,5,hommenu,2:4
+0x0873,36,storagepassword,2:4:20
+0x097C,4,ranklist,2
+
+//2013-07-10 Ragexe
+packet_ver: 43
+0x0369,7,actionrequest,2:6
+0x083C,10,useskilltoid,2:4:6
+0x0437,5,walktoxy,2
+0x035F,6,ticksend,2
+0x0202,5,changedir,2:4
+0x07E4,6,takeitem,2
+0x0362,6,dropitem,2:4
+0x07EC,8,movetokafra,2:4
+0x0364,8,movefromkafra,2:4
+0x0438,10,useskilltopos,2:4:6:8
+0x0366,90,useskilltoposinfo,2:4:6:8:10
+0x096A,6,getcharnamerequest,2
+0x0368,6,solvecharname,2
+0x0838,12,searchstoreinfolistitemclick,2:6:10
+0x0835,2,searchstoreinfonextpage,0
+0x0819,-1,searchstoreinfo,2:4:5:9:13:14:15
+0x0811,-1,reqtradebuyingstore,2:4:8:12
+0x0360,6,reqclickbuyingstore,2
+0x0817,2,reqclosebuyingstore,0
+0x0815,-1,reqopenbuyingstore,2:4:8:9:89
+0x0365,18,bookingregreq,2:4:6
+// 0x0363,8 CZ_JOIN_BATTLE_FIELD
+0x0281,-1,itemlistwindowselected,2:4:8:12
+0x022D,19,wanttoconnection,2:6:10:14:18
+0x0802,26,partyinvite2,2
+// 0x0436,4 CZ_GANGSI_RANK
+0x023B,26,friendslistadd,2
+0x0361,5,hommenu,2:4
+0x0880,36,storagepassword,2:4:20
+0x0848,-1,cashshopbuy,2:6:4:10
+0x97D,288 //ZC_ACK_RANKING
+
+//2013-07-17 Ragexe
+packet_ver: 44
+0x0918,7,actionrequest,2:6
+0x091E,10,useskilltoid,2:4:6
+0x083C,5,walktoxy,2
+0x02C4,6,ticksend,2
+0x088C,5,changedir,2:4
+0x08A9,6,takeitem,2
+0x0917,6,dropitem,2:4
+0x089B,8,movetokafra,2:4
+0x0956,8,movefromkafra,2:4
+0x0882,10,useskilltopos,2:4:6:8
+0x0952,90,useskilltoposinfo,2:4:6:8:10
+0x0958,6,getcharnamerequest,2
+0x0967,6,solvecharname,2
+0x0960,12,searchstoreinfolistitemclick,2:6:10
+0x0819,2,searchstoreinfonextpage,0
+0x086B,-1,searchstoreinfo,2:4:5:9:13:14:15
+0x093B,-1,reqtradebuyingstore,2:4:8:12
+0x0898,6,reqclickbuyingstore,2
+0x096A,2,reqclosebuyingstore,0
+0x08AA,-1,reqopenbuyingstore,2:4:8:9:89
+0x0862,18,bookingregreq,2:4:6
+// 0x08A6,8 CZ_JOIN_BATTLE_FIELD
+0x0897,-1,itemlistwindowselected,2:4:8:12
+0x091D,19,wanttoconnection,2:6:10:14:18
+0x092F,26,partyinvite2,2
+// 0x086C,4 CZ_GANGSI_RANK
+0x0863,26,friendslistadd,2
+0x088A,5,hommenu,2:4
+0x095B,36,storagepassword,2:4:20

+ 184 - 96
src/map/clif.c

@@ -2520,7 +2520,7 @@ void clif_storagelist(struct map_session_data* sd, struct item* items, int items
 		WBUFW(buf,0)=0x2ea;
 		WBUFW(buf,0)=0x2ea;
 #else
 #else
 		WBUFW(buf,0)=0x995;
 		WBUFW(buf,0)=0x995;
-		memset((char*)WBUFP(buf,6),0,24); //storename
+		memset((char*)WBUFP(buf,4),0,24); //storename
 #endif
 #endif
 		WBUFW(buf,2)=n*s+sidx;
 		WBUFW(buf,2)=n*s+sidx;
 		clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
 		clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
@@ -2533,7 +2533,7 @@ void clif_storagelist(struct map_session_data* sd, struct item* items, int items
 		WBUFW(bufe,0)=0x2d1;
 		WBUFW(bufe,0)=0x2d1;
 #else
 #else
 		WBUFW(bufe,0)=0x996;
 		WBUFW(bufe,0)=0x996;
-		memset((char*)WBUFP(bufe,6),0,24); //storename
+		memset((char*)WBUFP(bufe,4),0,24); //storename
 #endif
 #endif
 		WBUFW(bufe,2)=ne*se+sidxe;
 		WBUFW(bufe,2)=ne*se+sidxe;
 		clif_send(bufe, WBUFW(bufe,2), &sd->bl, SELF);
 		clif_send(bufe, WBUFW(bufe,2), &sd->bl, SELF);
@@ -5647,8 +5647,8 @@ void clif_maptypeproperty2(struct block_list *bl,enum send_target t) {
 	WBUFW(buf,0)=0x99b; //2
 	WBUFW(buf,0)=0x99b; //2
 	WBUFW(buf,2)=0x28; //2
 	WBUFW(buf,2)=0x28; //2
 
 
-	WBUFB(buf,4) = ((map[bl->m].flag.partylock)?0:0x01); //party
-	WBUFB(buf,4) |= ((map[bl->m].flag.guildlock)?0:0x02); //guild
+	WBUFB(buf,4) = ((map_flag_vs(bl->m))?0x01:0); //tvt ?
+	WBUFB(buf,4) |= ((map_flag_gvg(bl->m))?0x02:0); //gvg
 	WBUFB(buf,4) |= ((map_flag_gvg2(bl->m))?0x04:0); //siege
 	WBUFB(buf,4) |= ((map_flag_gvg2(bl->m))?0x04:0); //siege
 	WBUFB(buf,4) |= ((map[bl->m].flag.nomineeffect)?0:0x08); //mineffect @FIXME what this do
 	WBUFB(buf,4) |= ((map[bl->m].flag.nomineeffect)?0:0x08); //mineffect @FIXME what this do
 	WBUFB(buf,4) |= ((map[bl->m].flag.nolockon)?0x10:0); //nolockon 0x10 @FIXME what this do
 	WBUFB(buf,4) |= ((map[bl->m].flag.nolockon)?0x10:0); //nolockon 0x10 @FIXME what this do
@@ -14458,6 +14458,73 @@ void clif_parse_Auction_buysell(int fd, struct map_session_data* sd)
 /// CASH/POINT SHOP
 /// CASH/POINT SHOP
 ///
 ///
 
 
+void clif_cashshop_open( struct map_session_data* sd ){
+	WFIFOHEAD( sd->fd, 10 );
+	WFIFOW( sd->fd, 0 ) = 0x845;
+	WFIFOL( sd->fd, 2 ) = sd->cashPoints;
+	WFIFOL( sd->fd, 6 ) = sd->kafraPoints;
+	WFIFOSET( sd->fd, 10 );
+}
+
+void clif_parse_cashshop_open_request( int fd, struct map_session_data* sd ){
+	sd->npc_shopid = -1; // Set npc_shopid when using cash shop from "cash shop" button [Aelys|Susu] bugreport:96
+	clif_cashshop_open( sd );
+}
+
+void clif_parse_cashshop_close( int fd, struct map_session_data* sd ){
+	sd->npc_shopid = 0; // Reset npc_shopid when using cash shop from "cash shop" button [Aelys|Susu] bugreport:96
+	// No need to do anything here
+}
+
+//0846 <tabid>.W (CZ_REQ_SE_CASH_TAB_CODE))
+//08c0 <len>.W <openIdentity>.L <itemcount>.W (ZC_ACK_SE_CASH_ITEM_LIST2)
+void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) {
+	short tab = RFIFOW(fd, packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+	int j;
+
+	if( tab < 0 || tab > CASHSHOP_TAB_SEARCH )
+		return;
+
+	WFIFOHEAD(fd, 10 + ( cash_shop_items[tab].count * 6 ) );
+	WFIFOW(fd, 0) = 0x8c0;
+	WFIFOW(fd, 2) = 10 + ( cash_shop_items[tab].count * 6 );
+	WFIFOL(fd, 4) = tab;
+	WFIFOW(fd, 8) = cash_shop_items[tab].count;
+
+	for( j = 0; j < cash_shop_items[tab].count; j++ ) {
+		WFIFOW(fd, 10 + ( 6 * j ) ) = cash_shop_items[tab].item[j]->nameid;
+		WFIFOL(fd, 12 + ( 6 * j ) ) = cash_shop_items[tab].item[j]->price;
+	}
+
+	WFIFOSET(fd, 10 + ( cash_shop_items[tab].count * 6 ));
+}
+
+//08ca <len>.W <itemcount> W <tabcode>.W (ZC_ACK_SCHEDULER_CASHITEM)
+void clif_cashshop_list( int fd ){
+	int tab;
+
+	for( tab = CASHSHOP_TAB_NEW; tab < CASHSHOP_TAB_SEARCH; tab++ ){
+		int length = 8 + cash_shop_items->count * 6;
+		int i, offset;
+
+		WFIFOHEAD( fd, length );
+		WFIFOW( fd, 0 ) = 0x8ca;
+		WFIFOW( fd, 2 ) = length;
+		WFIFOW( fd, 4 ) = cash_shop_items[tab].count;
+		WFIFOW( fd, 6 ) = tab;
+
+		for( i = 0, offset = 8; i < cash_shop_items[tab].count; i++, offset += 6 ){
+			WFIFOW( fd, offset ) = cash_shop_items[tab].item[i]->nameid;
+			WFIFOL( fd, offset + 2 ) = cash_shop_items[tab].item[i]->price;
+		}
+
+		WFIFOSET( fd, length );
+	}
+}
+
+void clif_parse_cashshop_list_request( int fd, struct map_session_data* sd ){
+	clif_cashshop_list( fd );
+}
 /// List of items offered in a cash shop (ZC_PC_CASH_POINT_ITEMLIST).
 /// List of items offered in a cash shop (ZC_PC_CASH_POINT_ITEMLIST).
 /// 0287 <packet len>.W <cash point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }*
 /// 0287 <packet len>.W <cash point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }*
 /// 0287 <packet len>.W <cash point>.L <kafra point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* (PACKETVER >= 20070711)
 /// 0287 <packet len>.W <cash point>.L <kafra point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* (PACKETVER >= 20070711)
@@ -14523,6 +14590,16 @@ void clif_cashshop_ack(struct map_session_data* sd, int error)
 	WFIFOSET(fd, packet_len(0x289));
 	WFIFOSET(fd, packet_len(0x289));
 }
 }
 
 
+void clif_cashshop_result( struct map_session_data *sd, uint16 item_id, uint16 result ){
+	WFIFOHEAD( sd->fd, 16 );
+	WFIFOW( sd->fd, 0 ) = 0x849;
+	WFIFOL( sd->fd, 2 ) = item_id;
+	WFIFOW( sd->fd, 6 ) = result;
+	WFIFOL( sd->fd, 8 ) = sd->cashPoints;
+	WFIFOL( sd->fd, 12 ) = sd->kafraPoints;
+	WFIFOSET( sd->fd, 16 );
+}
+
 /// Request to buy item(s) from cash shop (CZ_PC_BUY_CASH_POINT_ITEM).
 /// Request to buy item(s) from cash shop (CZ_PC_BUY_CASH_POINT_ITEM).
 /// 0288 <name id>.W <amount>.W
 /// 0288 <name id>.W <amount>.W
 /// 0288 <name id>.W <amount>.W <kafra points>.L (PACKETVER >= 20070711)
 /// 0288 <name id>.W <amount>.W <kafra points>.L (PACKETVER >= 20070711)
@@ -14532,10 +14609,11 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd){
 
 
 	int fail = 0;
 	int fail = 0;
 	struct s_packet_db* info;
 	struct s_packet_db* info;
+	int cmd = RFIFOW(fd,0);
 
 
 	nullpo_retv(sd);
 	nullpo_retv(sd);
 
 
-	info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
+	info = &packet_db[sd->packet_ver][cmd];
 
 
 	if( sd->state.trading || !sd->npc_shopid )
 	if( sd->state.trading || !sd->npc_shopid )
 		fail = 1;
 		fail = 1;
@@ -14546,29 +14624,25 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd){
 		int points   = RFIFOL(fd,info->pos[2]);
 		int points   = RFIFOL(fd,info->pos[2]);
 
 
 		fail = npc_cashshop_buy(sd, nameid, amount, points);
 		fail = npc_cashshop_buy(sd, nameid, amount, points);
+		clif_cashshop_ack(sd,fail);
 #else
 #else
-	#if PACKETVER < 20130000 //found accurate date
-		int s_itl = 6;
-	#else
-		int s_itl = 4;//item _list size
-	#endif
+		int s_itl = (cmd==0x848)?10:4; //item _list size (depend on cmd even for 2013+)
 		int len    = RFIFOW(fd,info->pos[0]);
 		int len    = RFIFOW(fd,info->pos[0]);
 		int points = RFIFOL(fd,info->pos[1]);
 		int points = RFIFOL(fd,info->pos[1]);
 		int count  = RFIFOW(fd,info->pos[2]);
 		int count  = RFIFOW(fd,info->pos[2]);
 		unsigned short* item_list = (unsigned short*)RFIFOP(fd,info->pos[3]);
 		unsigned short* item_list = (unsigned short*)RFIFOP(fd,info->pos[3]);
-	
+
 		if( len < 10 || len != 10 + count * s_itl){
 		if( len < 10 || len != 10 + count * s_itl){
 			ShowWarning("Player %u sent incorrect cash shop buy packet (len %u:%u)!\n", sd->status.char_id, len, 10 + count * s_itl);
 			ShowWarning("Player %u sent incorrect cash shop buy packet (len %u:%u)!\n", sd->status.char_id, len, 10 + count * s_itl);
 			return;
 			return;
 		}
 		}
-	#if PACKETVER < 20130000
-		fail = npc_cashshop_buylist(sd,points,count,item_list);
-	#elif PACKETVER >= 20130000
-		cashshop_buylist( sd, points, count, item_list);
-	#endif
+		if(cmd==0x848){
+			cashshop_buylist( sd, points, count, item_list);
+		} else {
+			fail = npc_cashshop_buylist(sd,points,count,item_list);
+		}
 #endif
 #endif
 	}
 	}
-
 	clif_cashshop_ack(sd,fail);
 	clif_cashshop_ack(sd,fail);
 }
 }
 
 
@@ -16447,84 +16521,6 @@ void clif_monster_hp_bar( struct mob_data* md, int fd ) {
 #endif
 #endif
 }
 }
 
 
-void clif_cashshop_open( struct map_session_data* sd ){
-	WFIFOHEAD( sd->fd, 10 );
-	WFIFOW( sd->fd, 0 ) = 0x845;
-	WFIFOL( sd->fd, 2 ) = sd->cashPoints;
-	WFIFOL( sd->fd, 6 ) = sd->kafraPoints;
-	WFIFOSET( sd->fd, 10 );
-}
-
-void clif_parse_cashshop_open_request( int fd, struct map_session_data* sd ){
-	clif_cashshop_open( sd );
-}
-
-void clif_parse_cashshop_close( int fd, struct map_session_data* sd ){
-	// No need to do anything here
-}
-
-//0846 <tabid>.W (CZ_REQ_SE_CASH_TAB_CODE))
-//08c0 <len>.W <openIdentity>.L <itemcount>.W (ZC_ACK_SE_CASH_ITEM_LIST2)
-void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) {
-	short tab = RFIFOW(fd, packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-	int j;
-
-	if( tab < 0 || tab > CASHSHOP_TAB_SEARCH )
-		return;
-
-	WFIFOHEAD(fd, 10 + ( cash_shop_items[tab].count * 6 ) );
-	WFIFOW(fd, 0) = 0x8c0;
-	WFIFOW(fd, 2) = 10 + ( cash_shop_items[tab].count * 6 );
-	WFIFOL(fd, 4) = tab;
-	WFIFOW(fd, 8) = cash_shop_items[tab].count;
-
-	for( j = 0; j < cash_shop_items[tab].count; j++ ) {
-		WFIFOW(fd, 10 + ( 6 * j ) ) = cash_shop_items[tab].item[j]->nameid;
-		WFIFOL(fd, 12 + ( 6 * j ) ) = cash_shop_items[tab].item[j]->price;
-	}
-
-	WFIFOSET(fd, 10 + ( cash_shop_items[tab].count * 6 ));
-}
-
-//08ca <len>.W <itemcount> W <tabcode>.W (ZC_ACK_SCHEDULER_CASHITEM)
-void clif_cashshop_list( int fd ){
-	int tab;
-
-	for( tab = CASHSHOP_TAB_NEW; tab < CASHSHOP_TAB_SEARCH; tab++ ){
-		int length = 8 + cash_shop_items->count * 6;
-		int i, offset;
-
-		WFIFOHEAD( fd, length );
-		WFIFOW( fd, 0 ) = 0x8ca;
-		WFIFOW( fd, 2 ) = length;
-		WFIFOW( fd, 4 ) = cash_shop_items[tab].count;
-		WFIFOW( fd, 6 ) = tab;
-
-		for( i = 0, offset = 8; i < cash_shop_items[tab].count; i++, offset += 6 ){
-			WFIFOW( fd, offset ) = cash_shop_items[tab].item[i]->nameid;
-			WFIFOL( fd, offset + 2 ) = cash_shop_items[tab].item[i]->price;
-		}
-
-		WFIFOSET( fd, length );
-	}
-}
-
-void clif_parse_cashshop_list_request( int fd, struct map_session_data* sd ){
-	clif_cashshop_list( fd );
-}
-
-
-
-void clif_cashshop_result( struct map_session_data *sd, uint16 item_id, uint16 result ){
-	WFIFOHEAD( sd->fd, 16 );
-	WFIFOW( sd->fd, 0 ) = 0x849;
-	WFIFOL( sd->fd, 2 ) = item_id;
-	WFIFOW( sd->fd, 6 ) = result;
-	WFIFOL( sd->fd, 8 ) = sd->cashPoints;
-	WFIFOL( sd->fd, 12 ) = sd->kafraPoints;
-	WFIFOSET( sd->fd, 16 );
-}
-
 /// Ack world info (ZC_ACK_BEFORE_WORLD_INFO)
 /// Ack world info (ZC_ACK_BEFORE_WORLD_INFO)
 /// 0979 <world name>.24B <char name>.24B
 /// 0979 <world name>.24B <char name>.24B
 void clif_ackworldinfo(struct map_session_data* sd) {
 void clif_ackworldinfo(struct map_session_data* sd) {
@@ -16562,6 +16558,97 @@ void clif_parse_client_version(int fd,struct map_session_data *sd){
 	;
 	;
 }
 }
 
 
+/// Ranking list
+
+/// ranking pointlist  { <name>.24B <point>.L }*10
+void clif_sub_ranklist(unsigned char *buf,int idx,struct map_session_data* sd, int16 rankingtype){
+	const char* name;
+	struct fame_list* list;
+	int i, skip=0;
+
+	switch(rankingtype+1) //to keep the same case as char.c
+	{
+	case 1: list = smith_fame_list; break;
+	case 2: list = chemist_fame_list; break;
+	case 3: list = taekwon_fame_list; break;
+	default: skip=1; break;
+	}
+
+	if(!skip){
+		//Packet size limits this list to 10 elements. [Skotlex]
+		for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) {
+			if (list[i].id > 0) {
+				if (strcmp(list[i].name, "-") == 0 &&
+					(name = map_charid2nick(list[i].id)) != NULL)
+				{
+					strncpy((char *)(WBUFP(buf,idx + 24 * i)), name, NAME_LENGTH);
+				} else {
+					strncpy((char *)(WBUFP(buf,idx + 24 * i)), list[i].name, NAME_LENGTH);
+				}
+			} else {
+				strncpy((char *)(WBUFP(buf, idx + 24 * i)), "None", 5);
+			}
+			WBUFL(buf, idx+24*10 + i * 4) = list[i].fame; //points
+		}
+		for(;i < 10; i++) { //In case the MAX is less than 10.
+			strncpy((char *)(WBUFP(buf, idx + 24 * i)), "Unavailable", 12);
+			WBUFL(buf, idx+24*10 + i * 4) = 0;
+		}
+	}
+}
+
+/// 097d <RankingType>.W {<CharName>.24B <point>L}*10 <mypoint>L (ZC_ACK_RANKING)
+void clif_ranklist(struct map_session_data *sd, int16 rankingType){
+	unsigned char buf[MAX_FAME_LIST * sizeof(struct fame_list)];
+	int mypoint=0;
+
+	WBUFW(buf,0) = 0x97d;
+	WBUFW(buf,2) = rankingType;
+	clif_sub_ranklist(buf,4,sd,rankingType);
+
+	switch(sd->class_&MAPID_UPPERMASK){ //mypoint (checking if valid type)
+		case MAPID_BLACKSMITH:
+		case MAPID_ALCHEMIST:
+		case MAPID_TAEKWON:
+			mypoint = sd->status.fame;
+	}
+	WBUFL(buf,284) = mypoint; //mypoint
+	clif_send(buf, 288, &sd->bl, SELF);
+}
+
+/*
+ *  097c <type> (CZ_REQ_RANKING)
+ * type
+ *  0: /blacksmith
+ *  1: /alchemist
+ *  2: /taekwon
+ *  3: /pk
+ * */
+void clif_parse_ranklist(int fd,struct map_session_data *sd){
+	struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
+	int16 rankingtype = RFIFOW(fd,info->pos[0]); //type
+	if(rankingtype != 3) clif_ranklist(sd,rankingtype); // pk_list unsuported atm
+}
+
+// 097e <RankingType>.W <point>.L <TotalPoint>.L (ZC_UPDATE_RANKING_POINT)
+void clif_update_rankingpoint(struct map_session_data *sd, int rankingtype, int point){
+#if PACKETVER < 20130710
+	switch(rankingtype){
+		case 0: clif_fame_blacksmith(sd,point); break;  // Blacksmith
+		case 1: clif_fame_alchemist(sd,point); break; //Alchemist
+		case 2: clif_fame_taekwon(sd,point); break; // Taekwon
+	}
+#else
+	int fd=sd->fd;
+	WFIFOHEAD(fd,14);
+	WFIFOW(fd,0) = 0x97e;
+	WFIFOW(fd,2) = rankingtype;
+	WFIFOL(fd,4) = point;
+	WFIFOL(fd,8) = sd->status.fame;
+	WFIFOSET(fd,12);
+#endif
+}
+
 #ifdef DUMP_UNKNOWN_PACKET
 #ifdef DUMP_UNKNOWN_PACKET
 void DumpUnknow(int fd,TBL_PC *sd,int cmd,int packet_len){
 void DumpUnknow(int fd,TBL_PC *sd,int cmd,int packet_len){
 	const char* packet_txt = "save/packet.txt";
 	const char* packet_txt = "save/packet.txt";
@@ -16947,7 +17034,7 @@ void packetdb_readdb(void)
 #if PACKETVER < 20130000
 #if PACKETVER < 20130000
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 #else
 #else
-	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  19,  0,  0,  0,  0,
+	    0,  0,  0,  0,  0,  0,  0,  0,  0,  16,  0,  19,  0,  0,  0,  0,
 #endif
 #endif
 	    0,  0,  0,  0,  0,  0, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -17190,6 +17277,7 @@ void packetdb_readdb(void)
 		{ clif_parse_reqworldinfo, "reqworldinfo"},
 		{ clif_parse_reqworldinfo, "reqworldinfo"},
 		{ clif_parse_client_version, "clientversion"},
 		{ clif_parse_client_version, "clientversion"},
 		{ clif_parse_blocking_playcancel, "booking_playcancel"},
 		{ clif_parse_blocking_playcancel, "booking_playcancel"},
+		{ clif_parse_ranklist, "ranklist"},
 		{NULL,NULL}
 		{NULL,NULL}
 	};
 	};
 
 

+ 3 - 1
src/map/clif.h

@@ -35,7 +35,7 @@ struct party_booking_ad_info;
 enum
 enum
 {// packet DB
 {// packet DB
 	MAX_PACKET_DB  = 0xf00,
 	MAX_PACKET_DB  = 0xf00,
-	MAX_PACKET_VER = 39,
+	MAX_PACKET_VER = 44,
 	MAX_PACKET_POS = 20,
 	MAX_PACKET_POS = 20,
 };
 };
 
 
@@ -784,5 +784,7 @@ void clif_channel_msg(struct Channel *channel, struct map_session_data *sd, char
 
 
 #define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0;
 #define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0;
 
 
+void clif_ranklist(struct map_session_data *sd, int16 rankingType);
+void clif_update_rankingpoint(struct map_session_data *sd, int rankingtype, int point);
 
 
 #endif /* _CLIF_H_ */
 #endif /* _CLIF_H_ */

+ 42 - 37
src/map/pc.c

@@ -353,21 +353,19 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) {
 // Increases a player's fame points and displays a notice to him
 // Increases a player's fame points and displays a notice to him
 void pc_addfame(struct map_session_data *sd,int count)
 void pc_addfame(struct map_session_data *sd,int count)
 {
 {
+	int ranktype=-1;
 	nullpo_retv(sd);
 	nullpo_retv(sd);
 	sd->status.fame += count;
 	sd->status.fame += count;
 	if(sd->status.fame > MAX_FAME)
 	if(sd->status.fame > MAX_FAME)
 		sd->status.fame = MAX_FAME;
 		sd->status.fame = MAX_FAME;
+
 	switch(sd->class_&MAPID_UPPERMASK){
 	switch(sd->class_&MAPID_UPPERMASK){
-		case MAPID_BLACKSMITH: // Blacksmith
-			clif_fame_blacksmith(sd,count);
-			break;
-		case MAPID_ALCHEMIST: // Alchemist
-			clif_fame_alchemist(sd,count);
-			break;
-		case MAPID_TAEKWON: // Taekwon
-			clif_fame_taekwon(sd,count);
-			break;
+		case MAPID_BLACKSMITH: ranktype=0; break;
+		case MAPID_ALCHEMIST:  ranktype=1; break;
+		case MAPID_TAEKWON: ranktype=2; break;
 	}
 	}
+
+	clif_update_rankingpoint(sd,ranktype,count);
 	chrif_updatefamelist(sd);
 	chrif_updatefamelist(sd);
 }
 }
 
 
@@ -3981,7 +3979,7 @@ int pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reas
 {
 {
 	nullpo_retr(1, sd);
 	nullpo_retr(1, sd);
 
 
-	if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
+	if(n < 0 || sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
 		return 1;
 		return 1;
 
 
 	log_pick_pc(sd, log_type, -amount, &sd->status.inventory[n]);
 	log_pick_pc(sd, log_type, -amount, &sd->status.inventory[n]);
@@ -4293,6 +4291,8 @@ int pc_useitem(struct map_session_data *sd,int n)
 	unsigned int tick = gettick();
 	unsigned int tick = gettick();
 	int amount, nameid;
 	int amount, nameid;
 	struct script_code *script;
 	struct script_code *script;
+	struct item item;
+	struct item_data *id;
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
@@ -4305,15 +4305,17 @@ int pc_useitem(struct map_session_data *sd,int n)
 			return 0;
 			return 0;
 #endif
 #endif
 	}
 	}
+	item = sd->status.inventory[n];
+	id = sd->inventory_data[n];
 
 
-	if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 )
+	if( item.nameid <= 0 || sd->status.inventory[n].amount <= 0 )
 		return 0;
 		return 0;
 
 
 	if( !pc_isUseitem(sd,n) )
 	if( !pc_isUseitem(sd,n) )
 		return 0;
 		return 0;
 
 
 	// Store information for later use before it is lost (via pc_delitem) [Paradox924X]
 	// Store information for later use before it is lost (via pc_delitem) [Paradox924X]
-	nameid = sd->inventory_data[n]->nameid;
+	nameid = id->nameid;
 
 
 	if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING)
 	if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING)
 		return 0;
 		return 0;
@@ -4337,8 +4339,8 @@ int pc_useitem(struct map_session_data *sd,int n)
 		return 0;
 		return 0;
 
 
 	/* Items with delayed consume are not meant to work while in mounts except reins of mount(12622) */
 	/* Items with delayed consume are not meant to work while in mounts except reins of mount(12622) */
-	if( sd->inventory_data[n]->flag.delay_consume && nameid != ITEMID_REINS_OF_MOUNT ) {
-		if( sd->sc.option&OPTION_MOUNTING )
+	if( id->flag.delay_consume ) {
+		if( nameid != ITEMID_REINS_OF_MOUNT && sd->sc.option&OPTION_MOUNTING )
 			return 0;
 			return 0;
 		else if( pc_issit(sd) )
 		else if( pc_issit(sd) )
 			return 0;
 			return 0;
@@ -4347,10 +4349,10 @@ int pc_useitem(struct map_session_data *sd,int n)
 	//perform a skill-use check before going through. [Skotlex]
 	//perform a skill-use check before going through. [Skotlex]
 	//resurrection was picked as testing skill, as a non-offensive, generic skill, it will do.
 	//resurrection was picked as testing skill, as a non-offensive, generic skill, it will do.
 	//FIXME: Is this really needed here? It'll be checked in unit.c after all and this prevents skill items using when silenced [Inkfish]
 	//FIXME: Is this really needed here? It'll be checked in unit.c after all and this prevents skill items using when silenced [Inkfish]
-	if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
+	if( id->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
 		return 0;
 		return 0;
 
 
-	if( sd->inventory_data[n]->delay > 0 ) {
+	if( id->delay > 0 ) {
 		int i;
 		int i;
 		ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid );
 		ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid );
 			if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */
 			if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */
@@ -4362,11 +4364,11 @@ int pc_useitem(struct map_session_data *sd,int n)
 					char e_msg[100];
 					char e_msg[100];
 					if( e_tick > 99 )
 					if( e_tick > 99 )
 						sprintf(e_msg,msg_txt(sd,379), //Item Failed. [%s] is cooling down. Wait %.1f minutes.
 						sprintf(e_msg,msg_txt(sd,379), //Item Failed. [%s] is cooling down. Wait %.1f minutes.
-										itemdb_jname(sd->status.inventory[n].nameid),
+										itemdb_jname(item.nameid),
 										(double)e_tick / 60);
 										(double)e_tick / 60);
 					else
 					else
 						sprintf(e_msg,msg_txt(sd,380), //Item Failed. [%s] is cooling down. Wait %d seconds.
 						sprintf(e_msg,msg_txt(sd,380), //Item Failed. [%s] is cooling down. Wait %d seconds.
-										itemdb_jname(sd->status.inventory[n].nameid),
+										itemdb_jname(item.nameid),
 										e_tick+1);
 										e_tick+1);
 					clif_colormes(sd,color_table[COLOR_RED],e_msg);
 					clif_colormes(sd,color_table[COLOR_RED],e_msg);
 					return 0; // Delay has not expired yet
 					return 0; // Delay has not expired yet
@@ -4390,38 +4392,41 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 
 	/* on restricted maps the item is consumed but the effect is not used */
 	/* on restricted maps the item is consumed but the effect is not used */
 	if (
 	if (
-		(!map_flag_vs(sd->bl.m) && sd->inventory_data[n]->flag.no_equip&1) || // Normal
-		(map[sd->bl.m].flag.pvp && sd->inventory_data[n]->flag.no_equip&2) || // PVP
-		(map_flag_gvg(sd->bl.m) && sd->inventory_data[n]->flag.no_equip&4) || // GVG
-		(map[sd->bl.m].flag.battleground && sd->inventory_data[n]->flag.no_equip&8) || // Battleground
-		(map[sd->bl.m].flag.restricted && sd->inventory_data[n]->flag.no_equip&(8*map[sd->bl.m].zone)) // Zone restriction
+		(!map_flag_vs(sd->bl.m) && id->flag.no_equip&1) || // Normal
+		(map[sd->bl.m].flag.pvp && id->flag.no_equip&2) || // PVP
+		(map_flag_gvg(sd->bl.m) && id->flag.no_equip&4) || // GVG
+		(map[sd->bl.m].flag.battleground && id->flag.no_equip&8) || // Battleground
+		(map[sd->bl.m].flag.restricted && id->flag.no_equip&(8*map[sd->bl.m].zone)) // Zone restriction
 		) {
 		) {
 		if( battle_config.item_restricted_consumption_type ) {
 		if( battle_config.item_restricted_consumption_type ) {
-			clif_useitemack(sd,n,sd->status.inventory[n].amount-1,true);
+			clif_useitemack(sd,n,item.amount-1,true);
 			pc_delitem(sd,n,1,1,0,LOG_TYPE_CONSUME);
 			pc_delitem(sd,n,1,1,0,LOG_TYPE_CONSUME);
 		}
 		}
 		return 0;/* regardless, effect is not run */
 		return 0;/* regardless, effect is not run */
 	}
 	}
 
 
-	sd->itemid = sd->status.inventory[n].nameid;
+	sd->itemid = item.nameid;
 	sd->itemindex = n;
 	sd->itemindex = n;
 	if(sd->catch_target_class != -1) //Abort pet catching.
 	if(sd->catch_target_class != -1) //Abort pet catching.
 		sd->catch_target_class = -1;
 		sd->catch_target_class = -1;
 
 
-	amount = sd->status.inventory[n].amount;
-	script = sd->inventory_data[n]->script;
+	amount = item.amount;
+	script = id->script;
 	//Check if the item is to be consumed immediately [Skotlex]
 	//Check if the item is to be consumed immediately [Skotlex]
-	if( sd->inventory_data[n]->flag.delay_consume )
-		clif_useitemack(sd,n,amount,true);
-	else {
-		if( sd->status.inventory[n].expire_time == 0 ) {
-			clif_useitemack(sd,n,amount-1,true);
-			pc_delitem(sd,n,1,1,0,LOG_TYPE_CONSUME); // Rental Usable Items are not deleted until expiration
-		} else
-			clif_useitemack(sd,n,0,false);
+	if (id->flag.delay_consume)
+		clif_useitemack(sd, n, amount, true);
+	else
+	{
+		if (item.expire_time == 0)
+		{
+			clif_useitemack(sd, n, amount - 1, true);
+			pc_delitem(sd, n, 1, 1, 0, LOG_TYPE_CONSUME); // Rental Usable Items are not deleted until expiration
+		}
+		else
+			clif_useitemack(sd, n, 0, false);
 	}
 	}
-	if(sd->status.inventory[n].card[0]==CARD0_CREATE &&
-		pc_famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST))
+	if(item.card[0]==CARD0_CREATE &&
+		pc_famerank(MakeDWord(item.card[2],item.card[3]), MAPID_ALCHEMIST))
 	{
 	{
 	    potion_flag = 2; // Famous player's potions have 50% more efficiency
 	    potion_flag = 2; // Famous player's potions have 50% more efficiency
 		 if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ROGUE)
 		 if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ROGUE)