Przeglądaj źródła

-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 lat temu
rodzic
commit
342745de1a
5 zmienionych plików z 400 dodań i 137 usunięć
  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)
 // 0x20000000: 2013-06-05	Ragexe		(version 38)
 // 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
 
-// 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])
 packet_ver_flag2: 0x7FFFFFFF
 

+ 165 - 1
db/packet_db.txt

@@ -1816,6 +1816,7 @@ packet_ver: 34
 0x0447,2,booking_playcancel,0
 0x044A,6,clientversion,2
 0x0844,2,cashshopopen,0
+0x0849,16 //clif_cashshop_result
 0x0848,-1,cashshopbuy,2:6:4:10
 0x084a,2,cashshopclose,0
 0x084b,19 //fallitem4
@@ -1995,7 +1996,7 @@ packet_ver: 38
 0x0361,5,hommenu,2,4
 0x0883,36,storagepassword,2:4:20
 
-//2013-06-05 Ragexe (Shakto)
+//2013-06-12 Ragexe (Shakto)
 packet_ver: 39
 0x0369,7,actionrequest,2:6
 0x083C,10,useskilltoid,2:4:6
@@ -2026,3 +2027,166 @@ packet_ver: 39
 0x0940,26,friendslistadd,2
 0x093A,5,hommenu,2:4
 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;
 #else
 		WBUFW(buf,0)=0x995;
-		memset((char*)WBUFP(buf,6),0,24); //storename
+		memset((char*)WBUFP(buf,4),0,24); //storename
 #endif
 		WBUFW(buf,2)=n*s+sidx;
 		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;
 #else
 		WBUFW(bufe,0)=0x996;
-		memset((char*)WBUFP(bufe,6),0,24); //storename
+		memset((char*)WBUFP(bufe,4),0,24); //storename
 #endif
 		WBUFW(bufe,2)=ne*se+sidxe;
 		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,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[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
@@ -14458,6 +14458,73 @@ void clif_parse_Auction_buysell(int fd, struct map_session_data* sd)
 /// 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).
 /// 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)
@@ -14523,6 +14590,16 @@ void clif_cashshop_ack(struct map_session_data* sd, int error)
 	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).
 /// 0288 <name id>.W <amount>.W
 /// 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;
 	struct s_packet_db* info;
+	int cmd = RFIFOW(fd,0);
 
 	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 )
 		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]);
 
 		fail = npc_cashshop_buy(sd, nameid, amount, points);
+		clif_cashshop_ack(sd,fail);
 #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 points = RFIFOL(fd,info->pos[1]);
 		int count  = RFIFOW(fd,info->pos[2]);
 		unsigned short* item_list = (unsigned short*)RFIFOP(fd,info->pos[3]);
-	
+
 		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);
 			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
 	}
-
 	clif_cashshop_ack(sd,fail);
 }
 
@@ -16447,84 +16521,6 @@ void clif_monster_hp_bar( struct mob_data* md, int fd ) {
 #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)
 /// 0979 <world name>.24B <char name>.24B
 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
 void DumpUnknow(int fd,TBL_PC *sd,int cmd,int packet_len){
 	const char* packet_txt = "save/packet.txt";
@@ -16947,7 +17034,7 @@ void packetdb_readdb(void)
 #if PACKETVER < 20130000
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 #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
 	    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,
@@ -17190,6 +17277,7 @@ void packetdb_readdb(void)
 		{ clif_parse_reqworldinfo, "reqworldinfo"},
 		{ clif_parse_client_version, "clientversion"},
 		{ clif_parse_blocking_playcancel, "booking_playcancel"},
+		{ clif_parse_ranklist, "ranklist"},
 		{NULL,NULL}
 	};
 

+ 3 - 1
src/map/clif.h

@@ -35,7 +35,7 @@ struct party_booking_ad_info;
 enum
 {// packet DB
 	MAX_PACKET_DB  = 0xf00,
-	MAX_PACKET_VER = 39,
+	MAX_PACKET_VER = 44,
 	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;
 
+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_ */

+ 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
 void pc_addfame(struct map_session_data *sd,int count)
 {
+	int ranktype=-1;
 	nullpo_retv(sd);
 	sd->status.fame += count;
 	if(sd->status.fame > MAX_FAME)
 		sd->status.fame = MAX_FAME;
+
 	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);
 }
 
@@ -3981,7 +3979,7 @@ int pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reas
 {
 	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;
 
 	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();
 	int amount, nameid;
 	struct script_code *script;
+	struct item item;
+	struct item_data *id;
 
 	nullpo_ret(sd);
 
@@ -4305,15 +4305,17 @@ int pc_useitem(struct map_session_data *sd,int n)
 			return 0;
 #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;
 
 	if( !pc_isUseitem(sd,n) )
 		return 0;
 
 	// 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)
 		return 0;
@@ -4337,8 +4339,8 @@ int pc_useitem(struct map_session_data *sd,int n)
 		return 0;
 
 	/* 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;
 		else if( pc_issit(sd) )
 			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]
 	//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]
-	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;
 
-	if( sd->inventory_data[n]->delay > 0 ) {
+	if( id->delay > 0 ) {
 		int i;
 		ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid );
 			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];
 					if( e_tick > 99 )
 						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);
 					else
 						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);
 					clif_colormes(sd,color_table[COLOR_RED],e_msg);
 					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 */
 	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 ) {
-			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);
 		}
 		return 0;/* regardless, effect is not run */
 	}
 
-	sd->itemid = sd->status.inventory[n].nameid;
+	sd->itemid = item.nameid;
 	sd->itemindex = n;
 	if(sd->catch_target_class != -1) //Abort pet catching.
 		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]
-	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
 		 if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ROGUE)