Browse Source

Initial release of VIP System.
By default system is disabled (src/config/core.h).
This follows the iRO implementation VIP System. More information can be found on the iRO Wiki.
All settings also have individual configs.
Official VIP scripts will be implemented later.
Big thanks to lighta and Cydh for support and debugging.

aleos89 11 years ago
parent
commit
30648216ec

+ 47 - 1
conf/battle/player.conf

@@ -5,6 +5,8 @@
 //--------------------------------------------------------------
 //--------------------------------------------------------------
 // Note 1: Value is a config switch (on/off, yes/no or 1/0)
 // Note 1: Value is a config switch (on/off, yes/no or 1/0)
 // Note 2: Value is in percents (100 means 100%)
 // Note 2: Value is in percents (100 means 100%)
+// Note 3: Value is a bit field. If no description is given,
+//         assume unit types (1: Pc, 2: Mob, 4: Pet, 8: Homun)
 //--------------------------------------------------------------
 //--------------------------------------------------------------
 
 
 // Players' maximum HP rate? (Default is 100)
 // Players' maximum HP rate? (Default is 100)
@@ -141,4 +143,48 @@ idle_no_autoloot: 0
 
 
 // Minimum distance a vending/chat room must be from a NPC in order to be placed.
 // Minimum distance a vending/chat room must be from a NPC in order to be placed.
 // Default: 3 (0: disabled).
 // Default: 3 (0: disabled).
-min_npc_vendchat_distance: 3
+min_npc_vendchat_distance: 3
+
+// Storage slot increase. Setting to 0 will disable.
+// Give more storage slots above the MIN_STORAGE limit.
+// Note: MIN_STORAGE + storage_increase cannot exceed MAX_STORAGE.
+// Default: 300
+vip_storage_increase: 300
+
+// Base experience rate increase. Setting to 0 will disable. (Note 2)
+// Default: 50
+vip_base_exp_increase: 50
+
+// Experience penalty rate multiplier for Non-VIP accounts
+// Multiplies the 'death_penalty_base' and 'death_penalty_job' settings in 'conf/battle/exp.conf'.
+// Default: 3 (3*100 = 3% penalty)
+vip_exp_penalty_base_normal: 3
+vip_exp_penalty_job_normal: 3
+
+// Experience penalty rate multiplier for VIP accounts
+// Multiplies the 'death_penalty_base' and 'death_penalty_job' settings in 'conf/battle/exp.conf'.
+// Default: 1 (1*100 = 1% penalty)
+vip_exp_penalty_base: 1
+vip_exp_penalty_job: 1
+
+// Job experience rate increase. Setting to 0 will disable. (Note 2)
+// Default: 50
+vip_job_exp_increase: 50
+
+// Battle Manual experience increase. Setting to 0 will disable.
+// - Regular/Thick Battle Manual: 50+(50/X) = 75%
+// - HE Battle Manual: 100+(100/X) = 150%
+// - Battle Manual x3: 200+(200/X) = 300%
+// Note: X is what the config is set to.
+// Default: 2
+vip_bm_increase: 2
+
+// Item drop increase. Setting to 0 will disable.
+// Note: 50 = 0.5%
+// Default: 50
+vip_drop_increase: 50
+
+// GemStone requirement. Setting to false will disable.
+// Can the VIP Group ignore GemStone requirement for skills?
+// Default: true
+vip_gemstone: true

+ 0 - 5
conf/char_athena.conf

@@ -140,11 +140,6 @@ char_name_option: 1
 // Note: Don't add spaces unless you mean to add 'space' to the list.
 // Note: Don't add spaces unless you mean to add 'space' to the list.
 char_name_letters: abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
 char_name_letters: abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
 
 
-// How many Characters are allowed per Account ? (0 = disabled)
-// You can not exceed the limit of MAX_CHARS slots, defined in mmo.h
-// Doing that, chars_per_account will be default to MAX_CHARS.
-chars_per_account: 0
-
 // Restrict character deletion by BaseLevel
 // Restrict character deletion by BaseLevel
 // 0: no restriction (players can delete characters of any level)
 // 0: no restriction (players can delete characters of any level)
 // -X: you can't delete chars with BaseLevel <= X
 // -X: you can't delete chars with BaseLevel <= X

+ 13 - 0
conf/groups.conf

@@ -219,6 +219,19 @@ groups: (
 		any_warp: true
 		any_warp: true
 	}
 	}
 },
 },
+{
+	id: 5
+	name: "VIP"
+	inherit: ( "Player" ) /* can do everything Players can */
+	level: 0
+	commands: {
+		rates: true
+		who: true
+	}
+	permissions: {
+		/* no permissions by default */
+	}
+},
 {
 {
 	id: 10
 	id: 10
 	name: "Law Enforcement"
 	name: "Law Enforcement"

+ 17 - 0
conf/login_athena.conf

@@ -73,6 +73,23 @@ group_id_to_connect: -1
 // 0 or more: group id
 // 0 or more: group id
 min_group_id_to_connect: -1
 min_group_id_to_connect: -1
 
 
+// Which group (ID) will be denoted as the VIP Group?
+// Default: 5
+vip_group: 5
+
+// How many Characters are allowed per Account ? (0 = disabled)
+// You can not exceed the limit of MAX_CHARS slots, defined in mmo.h
+// Doing that, chars_per_account will be default to MAX_CHARS.
+// If setting to 0 MIN_CHARS value will be used.
+chars_per_account: 0
+
+// Max character limit increase. Setting to 0 will disable.
+// Increase MAX_CHAR if you want to increase char_increase.
+// Note: MAX_CHARS - chars_per_account = Amount of VIP Chars (char_increase value in login table).
+// Note2: this setting need to be set after chars_per_account
+// Default: 6
+vip_char_increase: 6
+
 // Starting additional sec from now for the limited time at creation of account
 // Starting additional sec from now for the limited time at creation of account
 // -1: new account are created with UNlimited time (default value)
 // -1: new account are created with UNlimited time (default value)
 // 0 or more: new accounts was created by addition of the value (in sec) to the actual time (to set first limited time)
 // 0 or more: new accounts was created by addition of the value (in sec) to the actual time (to set first limited time)

+ 10 - 0
conf/msg_conf/map_msg.conf

@@ -693,6 +693,16 @@
 694: Hanbok
 694: Hanbok
 695: Rebellion
 695: Rebellion
 
 
+// @vip
+700: Usage: @vip <time> <character name>
+701: Invalid time for VIP command.
+702: Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
+703: GM has removed your VIP time.
+704: Player is no longer VIP.
+705: %s is VIP for %d years, %d months, %d days, %d hours and %d minutes.
+706: This player is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
+707: You are VIP until
+//708-899 free
 
 
 //------------------------------------
 //------------------------------------
 // More atcommands message
 // More atcommands message

+ 3 - 0
db/packet_db.txt

@@ -1761,6 +1761,7 @@ packet_ver: 30
 0x0977,14 //Monster HP Bar
 0x0977,14 //Monster HP Bar
 0x0916,26,guildinvite2,2
 0x0916,26,guildinvite2,2
 0x091d,18,bookingregreq,2:4:6
 0x091d,18,bookingregreq,2:4:6
+//0x08cb,10,ZC_PERSONAL_INFOMATION,2:4:6:8:10:11:13:15 // Disabled until further information is found.
 
 
 //2012-04-18aRagexeRE [Special Thanks to Judas!]
 //2012-04-18aRagexeRE [Special Thanks to Judas!]
 packet_ver:31
 packet_ver:31
@@ -1855,6 +1856,8 @@ packet_ver: 34
 0x0977,14 //Monster HP Bar
 0x0977,14 //Monster HP Bar
 0x0978,6,reqworldinfo,2
 0x0978,6,reqworldinfo,2
 0x0979,50 //ackworldinfo
 0x0979,50 //ackworldinfo
+//0x097b,16,ZC_PERSONAL_INFOMATION,2:4:8:12:16:17:21:25 // Disabled until further information is found.
+//0x0981,12,ZC_PERSONAL_INFOMATION_CHN,2:4:6:8:12:13:15:17:10 // Disabled until further information is found.
 0x0990,31 //additem
 0x0990,31 //additem
 0x0991,-1 //inv itemlist normal
 0x0991,-1 //inv itemlist normal
 0x0992,-1 //inv itemlist equip
 0x0992,-1 //inv itemlist equip

+ 2 - 0
sql-files/main.sql

@@ -460,6 +460,8 @@ CREATE TABLE IF NOT EXISTS `login` (
   `pincode` varchar(4) NOT NULL DEFAULT '',
   `pincode` varchar(4) NOT NULL DEFAULT '',
   `pincode_change` int(11) unsigned NOT NULL DEFAULT '0',
   `pincode_change` int(11) unsigned NOT NULL DEFAULT '0',
   `bank_vault` int(11) NOT NULL DEFAULT '0',
   `bank_vault` int(11) NOT NULL DEFAULT '0',
+  `vip_time` int(11) unsigned NOT NULL default '0',
+  `old_group` tinyint(3) NOT NULL default '0',
   PRIMARY KEY  (`account_id`),
   PRIMARY KEY  (`account_id`),
   KEY `name` (`userid`)
   KEY `name` (`userid`)
 ) ENGINE=MyISAM AUTO_INCREMENT=2000000; 
 ) ENGINE=MyISAM AUTO_INCREMENT=2000000; 

+ 134 - 60
src/char/char.c

@@ -111,7 +111,6 @@ char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the request
 #define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
 #define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
 char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
 char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
 
 
-int char_per_account = 0; //Maximum chars per account (default unlimited) [Sirius]
 int char_del_level = 0; //From which level u can delete character [Lupus]
 int char_del_level = 0; //From which level u can delete character [Lupus]
 int char_del_delay = 86400;
 int char_del_delay = 86400;
 
 
@@ -133,7 +132,9 @@ struct char_session_data {
 	char email[40]; // e-mail (default: a@a.com) by [Yor]
 	char email[40]; // e-mail (default: a@a.com) by [Yor]
 	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
 	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
 	int group_id; // permission
 	int group_id; // permission
-	uint8 char_slots;
+	uint8 char_slots; // total number of characters that can be created
+	uint8 chars_vip;
+	uint8 chars_billing;
 	uint32 version;
 	uint32 version;
 	uint8 clienttype;
 	uint8 clienttype;
 	char new_name[NAME_LENGTH];
 	char new_name[NAME_LENGTH];
@@ -146,6 +147,7 @@ struct char_session_data {
 	// Addon system
 	// Addon system
 	int bank_vault;
 	int bank_vault;
 	unsigned int char_moves[MAX_CHARS]; // character moves left
 	unsigned int char_moves[MAX_CHARS]; // character moves left
+	uint8 isvip;
 };
 };
 
 
 struct startitem {
 struct startitem {
@@ -183,6 +185,11 @@ void pincode_notifyLoginPinError( int account_id );
 void pincode_decrypt( uint32 userSeed, char* pin );
 void pincode_decrypt( uint32 userSeed, char* pin );
 int pincode_compare( int fd, struct char_session_data* sd, char* pin );
 int pincode_compare( int fd, struct char_session_data* sd, char* pin );
 
 
+int mapif_parse_vipactive(int fd);
+int mapif_vipack(uint32 aid, uint32 vip_time, uint8 isvip, uint32 groupid);
+int logif_reqviddata(uint32 aid, uint8 type, uint32 add_vip_time);
+int logif_parse_vipack(int fd);
+
 // Addon system
 // Addon system
 bool char_move_enabled = true;
 bool char_move_enabled = true;
 bool char_movetoused = true;
 bool char_movetoused = true;
@@ -1441,8 +1448,6 @@ int mmo_char_sql_init(void)
 {
 {
 	char_db_= idb_alloc(DB_OPT_RELEASE_DATA);
 	char_db_= idb_alloc(DB_OPT_RELEASE_DATA);
 
 
-	ShowStatus("Characters per Account: '%d'.\n", char_per_account);
-
 	//the 'set offline' part is now in check_login_conn ...
 	//the 'set offline' part is now in check_login_conn ...
 	//if the server connects to loginserver
 	//if the server connects to loginserver
 	//it will dc all off players
 	//it will dc all off players
@@ -1581,9 +1586,9 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
 
 
 	//check other inputs
 	//check other inputs
 #if PACKETVER >= 20120307
 #if PACKETVER >= 20120307
-	if(slot >= sd->char_slots)
+	if(slot < 0 || slot >= sd->char_slots)
 #else
 #else
-	if((slot >= sd->char_slots) // slots
+	if((slot < 0 || slot >= sd->char_slots) // slots
 	|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
 	|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
 	|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
 	|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
 	|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
 	|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
@@ -1596,12 +1601,10 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
 
 
 
 
 	// check the number of already existing chars in this account
 	// check the number of already existing chars in this account
-	if( char_per_account != 0 ) {
-		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) )
-			Sql_ShowDebug(sql_handle);
-		if( Sql_NumRows(sql_handle) >= char_per_account )
-			return -2; // character account limit exceeded
-	}
+	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) )
+		Sql_ShowDebug(sql_handle);
+	if( Sql_NumRows(sql_handle) >= sd->char_slots )
+		return -2; // character account limit exceeded
 
 
 	// check char slot
 	// check char slot
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) )
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) )
@@ -1979,7 +1982,7 @@ void char_parse_req_charlist(int fd, struct char_session_data* sd){
 //----------------------------------------
 //----------------------------------------
 int mmo_char_send006b(int fd, struct char_session_data* sd){
 int mmo_char_send006b(int fd, struct char_session_data* sd){
 	int j, offset = 0;
 	int j, offset = 0;
-	bool newvers = (sd->version >= (uint32)date2version(20100413));
+	bool newvers = (sd->version >= date2version(20100413));
 	if(newvers) //20100413
 	if(newvers) //20100413
 		offset += 3;
 		offset += 3;
 	if (save_log)
 	if (save_log)
@@ -1989,11 +1992,16 @@ int mmo_char_send006b(int fd, struct char_session_data* sd){
 	WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF);
 	WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF);
 	WFIFOW(fd,0) = 0x6b;
 	WFIFOW(fd,0) = 0x6b;
 	if(newvers){ //20100413
 	if(newvers){ //20100413
-		WFIFOB(fd,4) = MAX_CHARS; // Max slots.
-		WFIFOB(fd,5) = sd->char_slots; // Available slots. (PremiumStartSlot)
-		WFIFOB(fd,6) = MAX_CHARS; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red)
-	}
-	memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes
+		WFIFOB(fd,4) = MAX_CHARS; // Max slots
+		WFIFOB(fd,5) = MAX_CHARS - sd->chars_billing - sd->chars_vip; // PremiumStartSlot
+		WFIFOB(fd,6) = MAX_CHARS - sd->chars_billing; // PremiumEndSlot
+		/* this+0x7  char dummy1_beginbilling */
+		/* this+0x8  unsigned long code */
+		/* this+0xc  unsigned long time1 */
+		/* this+0x10  unsigned long time2 */
+		/* this+0x14  char dummy2_endbilling[7] */
+	}
+	memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes 4-24 7-27
 	j+=mmo_chars_fromsql(sd, WFIFOP(fd,j));
 	j+=mmo_chars_fromsql(sd, WFIFOP(fd,j));
 	WFIFOW(fd,2) = j; // packet len
 	WFIFOW(fd,2) = j; // packet len
 	WFIFOSET(fd,j);
 	WFIFOSET(fd,j);
@@ -2010,18 +2018,18 @@ void mmo_char_send082d(int fd, struct char_session_data* sd) {
 	WFIFOHEAD(fd,29);
 	WFIFOHEAD(fd,29);
 	WFIFOW(fd,0) = 0x82d;
 	WFIFOW(fd,0) = 0x82d;
 	WFIFOW(fd,2) = 29;
 	WFIFOW(fd,2) = 29;
-	WFIFOB(fd,4) = sd->char_slots;
-	WFIFOB(fd,5) = MAX_CHARS - sd->char_slots;
-	WFIFOB(fd,6) = MAX_CHARS - sd->char_slots;
-	WFIFOB(fd,7) = sd->char_slots;
-	WFIFOB(fd,8) = sd->char_slots;
+	WFIFOB(fd,4) = MAX_CHARS - sd->chars_billing - sd->chars_vip; //NormalSlotNum
+	WFIFOB(fd,5) = sd->chars_vip; //PremiumSlotNum
+	WFIFOB(fd,6) = sd->chars_billing; //BillingSlotNum
+	WFIFOB(fd,7) = sd->char_slots; //ProducibleSlotNum
+	WFIFOB(fd,8) = sd->char_slots; //ValidSlotNum
 	memset(WFIFOP(fd,9), 0, 20); // unused bytes
 	memset(WFIFOP(fd,9), 0, 20); // unused bytes
 	WFIFOSET(fd,29);
 	WFIFOSET(fd,29);
 }
 }
 
 
 void mmo_char_send(int fd, struct char_session_data* sd){
 void mmo_char_send(int fd, struct char_session_data* sd){
 	//ShowInfo("sd->version = %d\n",sd->version);
 	//ShowInfo("sd->version = %d\n",sd->version);
-	if(sd->version > (uint32)date2version(20130000) ){
+	if(sd->version > date2version(20130000) ){
 		mmo_char_send082d(fd,sd);
 		mmo_char_send082d(fd,sd);
 		char_charlist_notify(fd,sd);
 		char_charlist_notify(fd,sd);
 		char_block_character(fd,sd);
 		char_block_character(fd,sd);
@@ -2170,7 +2178,7 @@ int loginif_BankingReq(int32 account_id, int8 type, int32 data){
 		WFIFOB(login_fd,6) = type;
 		WFIFOB(login_fd,6) = type;
 		WFIFOL(login_fd,7) = data;
 		WFIFOL(login_fd,7) = data;
 		WFIFOSET(login_fd,11);
 		WFIFOSET(login_fd,11);
-  		return 1;
+		return 1;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -2239,6 +2247,76 @@ int mapif_parse_ReqBankInfo(int fd){
 	return 1;
 	return 1;
 }
 }
 
 
+/*
+ * ZH 0x2b2c
+ * HA 0x2742
+ * We received a request vip_info from map-server.
+ * Transmit it to login-serv as it's the one knowing the info
+ */
+int mapif_parse_vipactive(int fd) {
+#ifdef VIP_ENABLE
+	uint32 aid = RFIFOL(fd,2); //aid
+	uint8 type = RFIFOB(fd,6); //type
+	uint32 adddur = RFIFOL(fd,7); //req_inc_duration
+	RFIFOSKIP(fd,11);
+	logif_reqviddata(aid, type, adddur);
+#endif
+	return 0;
+}
+
+/*
+ * HZ 0x2b2b
+ * Transmist vip data to mapserv
+ */
+int mapif_vipack(uint32 aid, uint32 vip_time, uint8 isvip, uint32 groupid) {
+#ifdef VIP_ENABLE
+	uint8 buf[16];
+	WBUFW(buf,0) = 0x2b2b;
+	WBUFL(buf,2) = aid;
+	WBUFL(buf,6) = vip_time;
+	WBUFB(buf,10) = isvip;
+	WBUFL(buf,11) = groupid;
+	mapif_sendall(buf,15);  // inform all map-servers attached.
+#endif
+	return 0;
+}
+
+/*
+ * HZ 0x2b2b
+ * Request vip data from loginserv
+ */
+int logif_reqviddata(uint32 aid, uint8 type, uint32 add_vip_time) {
+#ifdef VIP_ENABLE
+	WFIFOHEAD(login_fd,11);
+	WFIFOW(login_fd,0) = 0x2742;
+	WFIFOL(login_fd,2) =  aid; //aid
+	WFIFOB(login_fd,6) = type; //type
+	WFIFOL(login_fd,7) =  add_vip_time; //req_inc_duration
+	WFIFOSET(login_fd,11);
+#endif
+	return 0;
+}
+
+/*
+ * AH 0x2743
+ * We received the info from login-serv, transmit it to map
+ */
+int logif_parse_vipack(int fd) {
+#ifdef VIP_ENABLE
+	if (RFIFOREST(fd) < 15)
+		return 0;
+	else {
+		uint32 aid = RFIFOL(fd,2); //aid
+		uint32 vip_time = RFIFOL(fd,6); //vip_time
+		uint8 isvip = RFIFOB(fd,10); //isvip
+		uint32 groupid = RFIFOL(fd,11); //new group id
+		RFIFOSKIP(fd,15);
+		mapif_vipack(aid,vip_time,isvip,groupid);
+	}
+#endif
+	return 1;
+}
+
 
 
 /// Resets all the data.
 /// Resets all the data.
 void loginif_reset(void)
 void loginif_reset(void)
@@ -2288,31 +2366,30 @@ void loginif_on_ready(void)
 
 
 int logif_parse_reqpincode(int fd, struct char_session_data *sd){
 int logif_parse_reqpincode(int fd, struct char_session_data *sd){
 #if PACKETVER >=  20110309
 #if PACKETVER >=  20110309
-    if( pincode_enabled ){
-            // PIN code system enabled
-            if( strlen( sd->pincode ) <= 0 ){
-                // No PIN code has been set yet
-                if( pincode_force ) pincode_sendstate( fd, sd, PINCODE_NEW );
-                else pincode_sendstate( fd, sd, PINCODE_PASSED );
-            } else {
-                    if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
-                            struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
-
-                            if( node != NULL && node->pincode_success ){ // User has already passed the check                    
-                                    pincode_sendstate( fd, sd, PINCODE_PASSED );
-                            }else{
-                                    // Ask user for his PIN code
-                                    pincode_sendstate( fd, sd, PINCODE_ASK );
-                            }
-                    }else{ // User hasnt changed his PIN code too long
-                            pincode_sendstate( fd, sd, PINCODE_EXPIRED );
-                    }
-            }
-    } else { // PIN code system disabled 
-            pincode_sendstate( fd, sd, PINCODE_OK );
-    }
+	if( pincode_enabled ){
+		// PIN code system enabled
+		if( strlen( sd->pincode ) <= 0 ){
+			// No PIN code has been set yet
+			if( pincode_force ) pincode_sendstate( fd, sd, PINCODE_NEW );
+			else pincode_sendstate( fd, sd, PINCODE_PASSED );
+		} else {
+			if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
+				struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
+				if( node != NULL && node->pincode_success ){ // User has already passed the check
+					pincode_sendstate( fd, sd, PINCODE_PASSED );
+				}else{
+					// Ask user for his PIN code
+					pincode_sendstate( fd, sd, PINCODE_ASK );
+				}
+			}else{ // User hasnt changed his PIN code too long
+				pincode_sendstate( fd, sd, PINCODE_EXPIRED );
+			}
+		}
+	} else { // PIN code system disabled 
+		pincode_sendstate( fd, sd, PINCODE_OK );
+	}
 #endif
 #endif
-    return 0;
+	return 0;
 }
 }
 
 
 int parse_fromlogin(int fd) {
 int parse_fromlogin(int fd) {
@@ -2352,6 +2429,7 @@ int parse_fromlogin(int fd) {
 		switch( command )
 		switch( command )
 		{
 		{
 		case 0x2741: loginif_parse_BankingAck(fd); break;
 		case 0x2741: loginif_parse_BankingAck(fd); break;
+		case 0x2743: logif_parse_vipack(fd); break;
 
 
 		// acknowledgement of connect-to-loginserver request
 		// acknowledgement of connect-to-loginserver request
 		case 0x2711:
 		case 0x2711:
@@ -2415,7 +2493,7 @@ int parse_fromlogin(int fd) {
 		break;
 		break;
 
 
 		case 0x2717: // account data
 		case 0x2717: // account data
-			if (RFIFOREST(fd) < 76)
+			if (RFIFOREST(fd) < 79)
 				return 0;
 				return 0;
 
 
 			// find the authenticated session with this account id
 			// find the authenticated session with this account id
@@ -2431,11 +2509,14 @@ int parse_fromlogin(int fd) {
 					ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.h! capping to MAX_CHARS...\n",sd->account_id,sd->char_slots);
 					ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.h! capping to MAX_CHARS...\n",sd->account_id,sd->char_slots);
 					sd->char_slots = MAX_CHARS;/* cap to maximum */
 					sd->char_slots = MAX_CHARS;/* cap to maximum */
 				} else if ( !sd->char_slots )/* no value aka 0 in sql */
 				} else if ( !sd->char_slots )/* no value aka 0 in sql */
-					sd->char_slots = MAX_CHARS;/* cap to maximum */
+					sd->char_slots = MIN_CHARS;/* cap to minimum */
 				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
 				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
 				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
 				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
 				sd->pincode_change = (time_t)RFIFOL(fd,68);
 				sd->pincode_change = (time_t)RFIFOL(fd,68);
 				sd->bank_vault = RFIFOL(fd,72);
 				sd->bank_vault = RFIFOL(fd,72);
+				sd->isvip = RFIFOB(fd,76);
+				sd->chars_vip = RFIFOB(fd,77);
+				sd->chars_billing = RFIFOB(fd,78);
 				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
 				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
 				// continued from char_auth_ok...
 				// continued from char_auth_ok...
 				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
 				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
@@ -2452,7 +2533,7 @@ int parse_fromlogin(int fd) {
 					logif_parse_reqpincode(i, sd);
 					logif_parse_reqpincode(i, sd);
 				}
 				}
 			}
 			}
-			RFIFOSKIP(fd,76);
+			RFIFOSKIP(fd,79);
 		break;
 		break;
 
 
 		// login-server alive packet
 		// login-server alive packet
@@ -3680,7 +3761,7 @@ int parse_frommap(int fd)
 		
 		
 		case 0x2b28: mapif_parse_UpdBankInfo(fd); break;
 		case 0x2b28: mapif_parse_UpdBankInfo(fd); break;
 		case 0x2b2a: mapif_parse_ReqBankInfo(fd); break;
 		case 0x2b2a: mapif_parse_ReqBankInfo(fd); break;
-			
+		case 0x2b2c: mapif_parse_vipactive(fd); break;
 		case 0x2b2d: //Load data
 		case 0x2b2d: //Load data
 			if (RFIFOREST(fd) < 6)
 			if (RFIFOREST(fd) < 6)
 				return 0;
 				return 0;
@@ -5382,13 +5463,6 @@ int char_config_read(const char* cfgName)
 			char_name_option = atoi(w2);
 			char_name_option = atoi(w2);
 		} else if (strcmpi(w1, "char_name_letters") == 0) {
 		} else if (strcmpi(w1, "char_name_letters") == 0) {
 			safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
 			safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
-		} else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
-			char_per_account = atoi(w2);
-			if( char_per_account == 0 || char_per_account > MAX_CHARS ) {
-				if( char_per_account > MAX_CHARS )
-					ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS);
-				char_per_account = MAX_CHARS;
-			}
 		} else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
 		} else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
 			char_del_level = atoi(w2);
 			char_del_level = atoi(w2);
 		} else if (strcmpi(w1, "char_del_delay") == 0) {
 		} else if (strcmpi(w1, "char_del_delay") == 0) {

+ 3 - 2
src/common/mmo.h

@@ -71,7 +71,8 @@
 #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps
 #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps
 #define MAX_INVENTORY 100
 #define MAX_INVENTORY 100
 //Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
 //Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
-#define MAX_CHARS 9
+//Max value tested was 265
+#define MAX_CHARS 9 
 //Number of slots carded equipment can have. Never set to less than 4 as they are also used to keep the data of forged items/equipment. [Skotlex]
 //Number of slots carded equipment can have. Never set to less than 4 as they are also used to keep the data of forged items/equipment. [Skotlex]
 //Note: The client seems unable to receive data for more than 4 slots due to all related packets having a fixed size.
 //Note: The client seems unable to receive data for more than 4 slots due to all related packets having a fixed size.
 #define MAX_SLOTS 4
 #define MAX_SLOTS 4
@@ -90,7 +91,7 @@
 #define DEFAULT_WALK_SPEED 150
 #define DEFAULT_WALK_SPEED 150
 #define MIN_WALK_SPEED 0
 #define MIN_WALK_SPEED 0
 #define MAX_WALK_SPEED 1000
 #define MAX_WALK_SPEED 1000
-#define MAX_STORAGE 600
+#define MAX_STORAGE 600 /// Max number of storage slots the client can support. Used as a cap for the VIP System.
 #define MAX_GUILD_STORAGE 600
 #define MAX_GUILD_STORAGE 600
 #define MAX_PARTY 12
 #define MAX_PARTY 12
 #define MAX_GUILD 16+10*6	// increased max guild members +6 per 1 extension levels [Lupus]
 #define MAX_GUILD 16+10*6	// increased max guild members +6 per 1 extension levels [Lupus]

+ 1 - 1
src/common/utils.c

@@ -259,7 +259,7 @@ uint32 MakeDWord(uint16 word0, uint16 word1)
 		( (uint32)(word1 << 0x10) );
 		( (uint32)(word1 << 0x10) );
 }
 }
 
 
-int date2version(int date){
+uint32 date2version(int date){
 	if(date < 20040906) return 5;
 	if(date < 20040906) return 5;
 	else if(date < 20040920) return 10;
 	else if(date < 20040920) return 10;
 	else if(date < 20041005) return 11;
 	else if(date < 20041005) return 11;

+ 1 - 1
src/common/utils.h

@@ -29,6 +29,6 @@ extern uint16 GetWord(uint32 val, int idx);
 extern uint16 MakeWord(uint8 byte0, uint8 byte1);
 extern uint16 MakeWord(uint8 byte0, uint8 byte1);
 extern uint32 MakeDWord(uint16 word0, uint16 word1);
 extern uint32 MakeDWord(uint16 word0, uint16 word1);
 
 
-int date2version(int date);
+uint32 date2version(int date);
 
 
 #endif /* _UTILS_H_ */
 #endif /* _UTILS_H_ */

+ 18 - 0
src/config/core.h

@@ -72,6 +72,24 @@
 /// Comment to disable the job HP/SP tables and use formulas instead
 /// Comment to disable the job HP/SP tables and use formulas instead
 #define HP_SP_TABLES
 #define HP_SP_TABLES
 
 
+/// Uncomment to enable VIP system.
+//#define VIP_ENABLE
+#ifdef VIP_ENABLE
+	#define MIN_STORAGE 300 // Default number of storage slots.
+	#define MIN_CHARS 3 // Default number of characters per account.
+	#define MAX_CHAR_VIP 6 // This must be less than MAX_CHARS
+	#define MAX_CHAR_BILLING 0 // This must be less than MAX_CHARS
+#else
+	#define MIN_STORAGE 600 // If the VIP system is disabled the min = max.
+	#define MIN_CHARS 9 // Default number of characters per account.
+	#define MAX_CHAR_BILLING 0
+	#define MAX_CHAR_VIP 0
+#endif
+#if (MIN_CHARS + MAX_CHAR_VIP + MAX_CHAR_BILLING) > MAX_CHARS
+	#error "Config of MAX_CHARS is invalid"
+#endif
+#define VIP_SCRIPT 0 //enable or disable scripts (require vip_enable)
+
 /**
 /**
  * No settings past this point
  * No settings past this point
  **/
  **/

+ 5 - 2
src/login/account.h

@@ -34,8 +34,7 @@ AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void);
 #endif
 #endif
 
 
 
 
-struct mmo_account
-{
+struct mmo_account {
 	int account_id;
 	int account_id;
 	char userid[NAME_LENGTH];
 	char userid[NAME_LENGTH];
 	char pass[32+1];        // 23+1 for plaintext, 32+1 for md5-ed passwords
 	char pass[32+1];        // 23+1 for plaintext, 32+1 for md5-ed passwords
@@ -54,6 +53,10 @@ struct mmo_account
 	time_t pincode_change;	// (timestamp): last time of pincode change
 	time_t pincode_change;	// (timestamp): last time of pincode change
 	int account_reg2_num;
 	int account_reg2_num;
 	int bank_vault;
 	int bank_vault;
+#ifdef VIP_ENABLE
+	int old_group;
+	int vip_time;
+#endif
 	struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
 	struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
 };
 };
 
 

+ 29 - 4
src/login/account_sql.c

@@ -7,6 +7,7 @@
 #include "../common/sql.h"
 #include "../common/sql.h"
 #include "../common/strlib.h"
 #include "../common/strlib.h"
 #include "../common/timer.h"
 #include "../common/timer.h"
+#include "../config/core.h"
 #include "account.h"
 #include "account.h"
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -522,7 +523,11 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
 
 
 	// retrieve login entry for the specified account
 	// retrieve login entry for the specified account
 	if( SQL_ERROR == Sql_Query(sql_handle,
 	if( SQL_ERROR == Sql_Query(sql_handle,
-	    "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault` FROM `%s` WHERE `account_id` = %d",
+#ifdef VIP_ENABLE
+		"SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault`, `vip_time`, `old_group` FROM `%s` WHERE `account_id` = %d",
+#else
+		"SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault` FROM `%s` WHERE `account_id` = %d",
+#endif
 		db->account_db, account_id )
 		db->account_db, account_id )
 	) {
 	) {
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
@@ -552,10 +557,12 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc
 	Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
 	Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
 	Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
 	Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
 	Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data);
 	Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data);
-
+#ifdef VIP_ENABLE
+	Sql_GetData(sql_handle, 17, &data, NULL); acc->vip_time = atol(data);
+	Sql_GetData(sql_handle, 18, &data, NULL); acc->old_group = atoi(data);
+#endif
 	Sql_FreeResult(sql_handle);
 	Sql_FreeResult(sql_handle);
 
 
-
 	// retrieve account regs for the specified user
 	// retrieve account regs for the specified user
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
 	{
 	{
@@ -600,7 +607,11 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	if( is_new )
 	if( is_new )
 	{// insert into account table
 	{// insert into account table
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
+#ifdef VIP_ENABLE
+			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`, `vip_time`, `old_group` ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+#else
 			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+#endif
 			db->account_db)
 			db->account_db)
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_INT,       (void*)&acc->account_id,      sizeof(acc->account_id))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_INT,       (void*)&acc->account_id,      sizeof(acc->account_id))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
@@ -619,6 +630,10 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT,       (void*)&acc->bank_vault,      sizeof(acc->bank_vault))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT,       (void*)&acc->bank_vault,      sizeof(acc->bank_vault))
+#ifdef VIP_ENABLE
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_LONG,       (void*)&acc->vip_time,         sizeof(acc->vip_time))
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 18, SQLDT_INT,       (void*)&acc->old_group,        sizeof(acc->old_group))
+#endif
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		) {
 		) {
 			SqlStmt_ShowDebug(stmt);
 			SqlStmt_ShowDebug(stmt);
@@ -627,7 +642,13 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	}
 	}
 	else
 	else
 	{// update account table
 	{// update account table
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
+		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, 
+#ifdef VIP_ENABLE
+			"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=?, `vip_time`=?, `old_group`=? WHERE `account_id` = '%d'",
+#else
+			"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=? WHERE `account_id` = '%d'",
+#endif
+			db->account_db, acc->account_id)
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
@@ -644,6 +665,10 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_INT,       (void*)&acc->bank_vault,      sizeof(acc->bank_vault))
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_INT,       (void*)&acc->bank_vault,      sizeof(acc->bank_vault))
+#ifdef VIP_ENABLE
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_LONG,      (void*)&acc->vip_time,        sizeof(acc->vip_time))
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_INT,       (void*)&acc->old_group,       sizeof(acc->old_group))
+#endif
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		) {
 		) {
 			SqlStmt_ShowDebug(stmt);
 			SqlStmt_ShowDebug(stmt);

+ 174 - 59
src/login/login.c

@@ -13,6 +13,9 @@
 #include "../common/msg_conf.h"
 #include "../common/msg_conf.h"
 #include "../common/cli.h"
 #include "../common/cli.h"
 #include "../common/ers.h"
 #include "../common/ers.h"
+#include "../common/utils.h"
+#include "../common/mmo.h"
+#include "../config/core.h"
 #include "account.h"
 #include "account.h"
 #include "ipban.h"
 #include "ipban.h"
 #include "login.h"
 #include "login.h"
@@ -294,11 +297,16 @@ bool check_password(const char* md5key, int passwdenc, const char* passwd, const
 }
 }
 
 
 
 
-//-----------------------------------------------------
-// custom timestamp formatting (from eApp)
-//-----------------------------------------------------
-const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
-{
+/**
+ * Converting a timestamp is a srintf according to format
+ * safefr then strftime as it ensure \0 at end of string
+ * @param str, pointer to the destination string
+ * @param size, max length of the string
+ * @param timestamp, see unix epoch
+ * @param format, format to convert timestamp on, see strftime format
+ * @return the string of timestamp
+ */
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format){
 	size_t len = strftime(str, size, format, localtime(&timestamp));
 	size_t len = strftime(str, size, format, localtime(&timestamp));
 	memset(str + len, '\0', size - len);
 	memset(str + len, '\0', size - len);
 	return str;
 	return str;
@@ -428,6 +436,132 @@ int parse_console(const char* buf){
 	return 0;
 	return 0;
 }
 }
 
 
+int chrif_send_accdata(int fd, uint32 aid) {
+	struct mmo_account acc;
+	time_t expiration_time = 0;
+	char email[40] = "";
+	int group_id = 0;
+	char birthdate[10+1] = "";
+	char pincode[PINCODE_LENGTH+1];
+	int bank_vault = 0;
+	char isvip = false;
+	uint8 char_slots = MIN_CHARS, char_vip = 0;
+
+	memset(pincode,0,PINCODE_LENGTH+1);
+	if( !accounts->load_num(accounts, &acc, aid) )
+		return -1;
+	else {
+		safestrncpy(email, acc.email, sizeof(email));
+		expiration_time = acc.expiration_time;
+		group_id = acc.group_id;
+
+		safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
+		safestrncpy(pincode, acc.pincode, sizeof(pincode));
+		bank_vault = acc.bank_vault;
+#ifdef VIP_ENABLE
+		char_vip = login_config.vip_sys.char_increase;
+		if( acc.vip_time > time(NULL) ) {
+			isvip=true;
+			char_slots = login_config.char_per_account + char_vip;
+		} else
+			char_slots = login_config.char_per_account;
+#endif
+	}
+
+	WFIFOHEAD(fd,79);
+	WFIFOW(fd,0) = 0x2717;
+	WFIFOL(fd,2) = aid;
+	safestrncpy((char*)WFIFOP(fd,6), email, 40);
+	WFIFOL(fd,46) = (uint32)expiration_time;
+	WFIFOB(fd,50) = (unsigned char)group_id;
+	WFIFOB(fd,51) = char_slots;
+	safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
+	safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
+	WFIFOL(fd,68) = (uint32)acc.pincode_change;
+	WFIFOL(fd,72) = bank_vault;
+	WFIFOB(fd,76) = isvip;
+	WFIFOB(fd,77) = char_vip;
+	WFIFOB(fd,78) = MAX_CHAR_BILLING; //TODO create a config for this
+	WFIFOSET(fd,79);
+	return 0;
+}
+
+int chrif_parse_reqaccdata(int fd, int cid, char *ip) {
+	if( RFIFOREST(fd) < 6 )
+		return 0;
+	else {
+		uint32 aid = RFIFOL(fd,2);
+		RFIFOSKIP(fd,6);
+		if( chrif_send_accdata(fd,aid) < 0 )
+			ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[cid].name, aid, ip);
+	}
+	return 0;
+}
+
+
+int chrif_sendvipdata(int fd, struct mmo_account acc, char isvip) {
+#ifdef VIP_ENABLE
+	uint8 buf[16];
+
+	WBUFW(buf,0) = 0x2743;
+	WBUFL(buf,2) = acc.account_id;
+	WBUFL(buf,6) = acc.vip_time;
+	WBUFB(buf,10) = isvip;
+	WBUFL(buf,11) = acc.group_id; //new group id
+	charif_sendallwos(-1,buf,15); //inform all char-servs of result
+
+	chrif_send_accdata(fd,acc.account_id); //refresh char with new setting
+#endif
+	return 1;
+}
+
+/**
+ * Received a vip data reqest from char
+ * type is the query to perform
+ *  &1 : Select info and update old_groupid
+ *  &2 : Update vip time
+ * @param fd link to charserv
+ * @return 0 missing data, 1 succeed
+ */
+int chrif_parse_reqvipdata(int fd) {
+#ifdef VIP_ENABLE
+	if( RFIFOREST(fd) < 11 )
+		return 0;
+	else { //request vip info
+		struct mmo_account acc;
+		int aid = RFIFOL(fd,2);
+		int8 type = RFIFOB(fd,6);
+		uint32 req_duration = RFIFOL(fd,7);
+		RFIFOSKIP(fd,11);
+
+		if( accounts->load_num(accounts, &acc, aid ) ){
+			time_t now = time(NULL);
+			time_t vip_time = acc.vip_time;
+			bool isvip = false;
+
+			if( type&2 ) vip_time = now + req_duration; // set new duration
+			if( now < vip_time ) { //isvip
+				if(acc.group_id != login_config.vip_sys.group) //only upd this if we're not vip already
+					acc.old_group = acc.group_id;
+				acc.group_id = login_config.vip_sys.group;
+				acc.char_slots = login_config.char_per_account + login_config.vip_sys.char_increase;
+				isvip = true;
+			} else { //expired
+				vip_time = 0;
+				acc.group_id = acc.old_group;
+				acc.old_group = 0;
+				acc.char_slots = login_config.char_per_account;
+			}
+			acc.vip_time = (int)vip_time;
+			accounts->save(accounts,&acc);
+			
+			chrif_sendvipdata(fd,acc,isvip);
+		}
+	}
+#endif
+	return 1;
+}
+
 
 
 //--------------------------------
 //--------------------------------
 // Packet parsing for char-servers
 // Packet parsing for char-servers
@@ -555,54 +689,10 @@ int parse_fromchar(int fd){
 			}
 			}
 		break;
 		break;
 
 
-		case 0x2716: // request account data
-			if( RFIFOREST(fd) < 6 )
-				return 0;
-			else{
-				struct mmo_account acc;
-				time_t expiration_time = 0;
-				char email[40] = "";
-				uint8 char_slots = 0;
-				int group_id = 0;
-				char birthdate[10+1] = "";
-				char pincode[PINCODE_LENGTH+1];
-				int account_id = RFIFOL(fd,2);
-				int bank_vault = 0;
-
-				memset(pincode,0,PINCODE_LENGTH+1);
-
-				RFIFOSKIP(fd,6);
-
-				if( !accounts->load_num(accounts, &acc, account_id) )
-					ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
-				else{
-					safestrncpy(email, acc.email, sizeof(email));
-					expiration_time = acc.expiration_time;
-					group_id = acc.group_id;
-					char_slots = acc.char_slots;
-					safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
-					safestrncpy(pincode, acc.pincode, sizeof(pincode));
-					bank_vault = acc.bank_vault;
-				}
-
-				WFIFOHEAD(fd,76);
-				WFIFOW(fd,0) = 0x2717;
-				WFIFOL(fd,2) = account_id;
-				safestrncpy((char*)WFIFOP(fd,6), email, 40);
-				WFIFOL(fd,46) = (uint32)expiration_time;
-				WFIFOB(fd,50) = (unsigned char)group_id;
-				WFIFOB(fd,51) = char_slots;
-				safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
-				safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
-				WFIFOL(fd,68) = (uint32)acc.pincode_change;
-				WFIFOL(fd,72) = bank_vault;
-				WFIFOSET(fd,76);
-			}
-		break;
+		case 0x2716: chrif_parse_reqaccdata(fd,id,ip); break; // request account data
 
 
 		case 0x2719: // ping request from charserver
 		case 0x2719: // ping request from charserver
 			RFIFOSKIP(fd,2);
 			RFIFOSKIP(fd,2);
-
 			WFIFOHEAD(fd,2);
 			WFIFOHEAD(fd,2);
 			WFIFOW(fd,0) = 0x2718;
 			WFIFOW(fd,0) = 0x2718;
 			WFIFOSET(fd,2);
 			WFIFOSET(fd,2);
@@ -973,6 +1063,8 @@ int parse_fromchar(int fd){
 			}
 			}
 		break;
 		break;
 
 
+		case 0x2742: chrif_parse_reqvipdata(fd); break; //Vip sys
+
 		default:
 		default:
 			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
 			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
 			set_eof(fd);
 			set_eof(fd);
@@ -1026,10 +1118,12 @@ int mmo_auth_new(const char* userid, const char* pass, const char sex, const cha
 	safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate));
 	safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate));
 	safestrncpy(acc.pincode, "", sizeof(acc.pincode));
 	safestrncpy(acc.pincode, "", sizeof(acc.pincode));
 	acc.pincode_change = 0;
 	acc.pincode_change = 0;
-
-	acc.char_slots = 0;
+	acc.char_slots = MIN_CHARS;
 	acc.bank_vault = 0;
 	acc.bank_vault = 0;
-
+#ifdef VIP_ENABLE
+	acc.vip_time = 0;
+	acc.old_group = 0;
+#endif
 	if( !accounts->create(accounts, &acc) )
 	if( !accounts->create(accounts, &acc) )
 		return 0;
 		return 0;
 
 
@@ -1638,8 +1732,7 @@ int parse_login(int fd)
 }
 }
 
 
 
 
-void login_set_defaults()
-{
+void login_set_defaults() {
 	login_config.login_ip = INADDR_ANY;
 	login_config.login_ip = INADDR_ANY;
 	login_config.login_port = 6900;
 	login_config.login_port = 6900;
 	login_config.ipban_cleanup_interval = 60;
 	login_config.ipban_cleanup_interval = 60;
@@ -1666,6 +1759,11 @@ void login_set_defaults()
 
 
 	login_config.client_hash_check = 0;
 	login_config.client_hash_check = 0;
 	login_config.client_hash_nodes = NULL;
 	login_config.client_hash_nodes = NULL;
+	login_config.char_per_account = MAX_CHARS - MAX_CHAR_VIP - MAX_CHAR_BILLING;
+#ifdef VIP_ENABLE
+	login_config.vip_sys.char_increase = MAX_CHAR_VIP;
+	login_config.vip_sys.group = 5;
+#endif
 }
 }
 
 
 //-----------------------------------
 //-----------------------------------
@@ -1767,14 +1865,31 @@ int login_config_read(const char* cfgName)
 
 
 				login_config.client_hash_nodes = nnode;
 				login_config.client_hash_nodes = nnode;
 			}
 			}
+		} else if(strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
+			login_config.char_per_account = atoi(w2);
+			if( login_config.char_per_account <= 0 || login_config.char_per_account > MAX_CHARS ) {
+				if( login_config.char_per_account > MAX_CHARS ) {
+					ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", login_config.char_per_account, MAX_CHARS);
+					login_config.char_per_account = MAX_CHARS;
+				}
+				login_config.char_per_account = MIN_CHARS;
+			}
+		}
+#ifdef VIP_ENABLE
+		else if(strcmpi(w1,"vip_group")==0)
+			login_config.vip_sys.group = cap_value(atoi(w2),0,99);
+		else if(strcmpi(w1,"vip_char_increase")==0) {
+			if(login_config.vip_sys.char_increase > (unsigned int) MAX_CHARS-login_config.char_per_account)
+				ShowWarning("vip_char_increase too high, can only go up to %d, according to your char_per_account config %d\n",
+					MAX_CHARS-login_config.char_per_account,login_config.char_per_account);
+			login_config.vip_sys.char_increase =  cap_value(atoi(w2),0,MAX_CHARS-login_config.char_per_account);
 		}
 		}
+#endif
 		else if(!strcmpi(w1, "import"))
 		else if(!strcmpi(w1, "import"))
 			login_config_read(w2);
 			login_config_read(w2);
-		else
-		if(!strcmpi(w1, "account.engine"))
+		else if(!strcmpi(w1, "account.engine"))
 			safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine));
 			safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine));
-		else
-		{// try the account engines
+		else {// try the account engines
 			int i;
 			int i;
 			for( i = 0; account_engines[i].constructor; ++i )
 			for( i = 0; account_engines[i].constructor; ++i )
 			{
 			{

+ 9 - 2
src/login/login.h

@@ -6,6 +6,7 @@
 
 
 #include "../common/mmo.h" // NAME_LENGTH,SEX_*
 #include "../common/mmo.h" // NAME_LENGTH,SEX_*
 #include "../common/core.h" // CORE_ST_LAST
 #include "../common/core.h" // CORE_ST_LAST
+#include "../config/core.h"
 
 
 enum E_LOGINSERVER_ST
 enum E_LOGINSERVER_ST
 {
 {
@@ -58,7 +59,6 @@ struct client_hash_node {
 };
 };
 
 
 struct Login_Config {
 struct Login_Config {
-
 	uint32 login_ip;                                // the address to bind to
 	uint32 login_ip;                                // the address to bind to
 	uint16 login_port;                              // the port to bind to
 	uint16 login_port;                              // the port to bind to
 	unsigned int ipban_cleanup_interval;            // interval (in seconds) to clean up expired IP bans
 	unsigned int ipban_cleanup_interval;            // interval (in seconds) to clean up expired IP bans
@@ -86,6 +86,13 @@ struct Login_Config {
 
 
 	int client_hash_check;							// flags for checking client md5
 	int client_hash_check;							// flags for checking client md5
 	struct client_hash_node *client_hash_nodes;		// linked list containg md5 hash for each gm group
 	struct client_hash_node *client_hash_nodes;		// linked list containg md5 hash for each gm group
+	int char_per_account;                           // number of characters an account can have
+#ifdef VIP_ENABLE
+	struct {
+		unsigned int group;
+		unsigned int char_increase;
+	} vip_sys;
+#endif
 };
 };
 
 
 #define sex_num2str(num) ( (num ==  SEX_FEMALE  ) ? 'F' : (num ==  SEX_MALE  ) ? 'M' : 'S' )
 #define sex_num2str(num) ( (num ==  SEX_FEMALE  ) ? 'F' : (num ==  SEX_MALE  ) ? 'M' : 'S' )
@@ -100,7 +107,7 @@ const char* login_msg_txt(int msg_number);
 void login_do_final_msg(void);
 void login_do_final_msg(void);
 
 
 
 
-#define MAX_SERVERS 30
+#define MAX_SERVERS 30 //number of charserv loginserv can handle
 extern struct mmo_char_server server[MAX_SERVERS];
 extern struct mmo_char_server server[MAX_SERVERS];
 extern struct Login_Config login_config;
 extern struct Login_Config login_config;
 
 

+ 74 - 5
src/map/atcommand.c

@@ -7549,21 +7549,28 @@ ACMD_FUNC(mutearea)
 ACMD_FUNC(rates)
 ACMD_FUNC(rates)
 {
 {
 	char buf[CHAT_SIZE_MAX];
 	char buf[CHAT_SIZE_MAX];
+	int base_exp_rate = 0, job_exp_rate = 0, item_rate = 0;
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 	memset(buf, '\0', sizeof(buf));
 	memset(buf, '\0', sizeof(buf));
 
 
+	// Display EXP and item rate increase for VIP.
+	if (pc_isvip(sd) && (battle_config.vip_base_exp_increase || battle_config.vip_job_exp_increase || battle_config.vip_drop_increase)) {
+		base_exp_rate += battle_config.vip_base_exp_increase;
+		job_exp_rate += battle_config.vip_job_exp_increase;
+		item_rate += battle_config.vip_drop_increase;
+	}
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1298), // Experience rates: Base %.2fx / Job %.2fx
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1298), // Experience rates: Base %.2fx / Job %.2fx
-		battle_config.base_exp_rate/100., battle_config.job_exp_rate/100.);
+		(battle_config.base_exp_rate+base_exp_rate)/100., (battle_config.job_exp_rate+job_exp_rate)/100.);
 	clif_displaymessage(fd, buf);
 	clif_displaymessage(fd, buf);
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1299), // Normal Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1299), // Normal Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
-		battle_config.item_rate_common/100., battle_config.item_rate_heal/100., battle_config.item_rate_use/100., battle_config.item_rate_equip/100., battle_config.item_rate_card/100.);
+		(battle_config.item_rate_common+item_rate)/100., (battle_config.item_rate_heal+item_rate)/100., (battle_config.item_rate_use+item_rate)/100., (battle_config.item_rate_equip+item_rate)/100., (battle_config.item_rate_card+item_rate)/100.);
 	clif_displaymessage(fd, buf);
 	clif_displaymessage(fd, buf);
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1300), // Boss Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1300), // Boss Drop Rates: Common %.2fx / Healing %.2fx / Usable %.2fx / Equipment %.2fx / Card %.2fx
-		battle_config.item_rate_common_boss/100., battle_config.item_rate_heal_boss/100., battle_config.item_rate_use_boss/100., battle_config.item_rate_equip_boss/100., battle_config.item_rate_card_boss/100.);
+		(battle_config.item_rate_common_boss+item_rate)/100., (battle_config.item_rate_heal_boss+item_rate)/100., (battle_config.item_rate_use_boss+item_rate)/100., (battle_config.item_rate_equip_boss+item_rate)/100., (battle_config.item_rate_card_boss+item_rate)/100.);
 	clif_displaymessage(fd, buf);
 	clif_displaymessage(fd, buf);
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1301), // Other Drop Rates: MvP %.2fx / Card-Based %.2fx / Treasure %.2fx
 	snprintf(buf, CHAT_SIZE_MAX, msg_txt(sd,1301), // Other Drop Rates: MvP %.2fx / Card-Based %.2fx / Treasure %.2fx
-		battle_config.item_rate_mvp/100., battle_config.item_rate_adddrop/100., battle_config.item_rate_treasure/100.);
+		(battle_config.item_rate_mvp+item_rate)/100., (battle_config.item_rate_adddrop+item_rate)/100., (battle_config.item_rate_treasure+item_rate)/100.);
 	clif_displaymessage(fd, buf);
 	clif_displaymessage(fd, buf);
 
 
 	return 0;
 	return 0;
@@ -8295,7 +8302,7 @@ ACMD_FUNC(itemlist)
 	{
 	{
 		location = "storage";
 		location = "storage";
 		items = sd->status.storage.items;
 		items = sd->status.storage.items;
-		size = MAX_STORAGE;
+		size = sd->storage_size;
 	}
 	}
 	else
 	else
 	if( strcmp(command+1, "cartlist") == 0 )
 	if( strcmp(command+1, "cartlist") == 0 )
@@ -9181,6 +9188,65 @@ ACMD_FUNC(langtype)
 	return -1;
 	return -1;
 }
 }
 
 
+#ifdef VIP_ENABLE
+ACMD_FUNC(vip)
+{
+	struct map_session_data *pl_sd = NULL;
+	char * modif_p;
+	int viptime = 0;
+	nullpo_retr(-1, sd);
+
+	if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
+		clif_displaymessage(fd, msg_txt(sd,700));	//Usage: @vip <time> <character name>
+		return -1;
+	}
+
+	atcmd_output[sizeof(atcmd_output)-1] = '\0';
+
+	modif_p = atcmd_output;
+	viptime = (int)solve_time(modif_p)/60; // Change to minutes
+	if (viptime == 0) {
+		clif_displaymessage(fd, msg_txt(sd,701)); // Invalid time for vip command.
+		clif_displaymessage(fd, msg_txt(sd,702)); // Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
+		return -1;
+	}
+
+	if ((pl_sd = map_nick2sd(atcmd_player_name)) == NULL) {
+		clif_displaymessage(fd, msg_txt(sd,3)); // Character not found.
+		return -1;
+	}
+
+	if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
+		clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
+		return -1;
+	}
+
+	pl_sd->vip.time += viptime;
+
+	if (pl_sd->vip.time <= 0) {
+		pl_sd->vip.time = 0;
+		pl_sd->vip.enabled = 0;
+		clif_displaymessage(pl_sd->fd, msg_txt(sd,703)); // GM has removed your VIP time.
+		clif_displaymessage(fd, msg_txt(sd,704)); // Player is no longer VIP.
+	} else {
+		int year,month,day,hour,minute,second;
+		char timestr[128];
+		split_time(pl_sd->vip.time*60,&year,&month,&day,&hour,&minute,&second);
+		sprintf(atcmd_output,msg_txt(sd,705),pl_sd->status.name,year,month,day,hour,minute); //%s is VIP for %d years, %d months, %d days, %d hours and %d minutes.
+		clif_displaymessage(pl_sd->fd, atcmd_output);
+		sprintf(atcmd_output,msg_txt(sd,706),year,month,day,hour,minute); //This player is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
+		clif_displaymessage(fd, atcmd_output);
+		time2str(timestr,"%Y-%m-%d %H:%M",pl_sd->vip.time*60);
+		sprintf(atcmd_output,"%s : %s",msg_txt(sd,707),timestr); //You are VIP until :
+		clif_displaymessage(pl_sd->fd, atcmd_output);
+		clif_displaymessage(fd, atcmd_output);
+	}
+	chrif_req_vipActive(pl_sd, viptime, 3);
+
+	return 0;
+}
+#endif
+
 #include "../custom/atcommand.inc"
 #include "../custom/atcommand.inc"
 
 
 /**
 /**
@@ -9461,6 +9527,9 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(channel),
 		ACMD_DEF(channel),
 		ACMD_DEF(fontcolor),
 		ACMD_DEF(fontcolor),
 		ACMD_DEF(langtype),
 		ACMD_DEF(langtype),
+#ifdef VIP_ENABLE
+		ACMD_DEF(vip),
+#endif
 	};
 	};
 	AtCommandInfo* atcommand;
 	AtCommandInfo* atcommand;
 	int i;
 	int i;

+ 13 - 3
src/map/battle.c

@@ -7233,10 +7233,20 @@ static const struct _battle_data {
 	{ "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
 	{ "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
 	{ "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
 	{ "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
 	{ "feature.banking",                    &battle_config.feature_banking,                 1,      0,      1,              },
 	{ "feature.banking",                    &battle_config.feature_banking,                 1,      0,      1,              },
+	{ "vip_storage_increase",               &battle_config.vip_storage_increase,            0,      0,      MAX_STORAGE-MIN_STORAGE, },
+	{ "vip_base_exp_increase",              &battle_config.vip_base_exp_increase,           0,      0,      INT_MAX,        },
+	{ "vip_job_exp_increase",               &battle_config.vip_job_exp_increase,            0,      0,      INT_MAX,        },
+	{ "vip_exp_penalty_base_normal",        &battle_config.vip_exp_penalty_base_normal,     0,      0,      INT_MAX,        },
+	{ "vip_exp_penalty_job_normal",         &battle_config.vip_exp_penalty_job_normal,      0,      0,      INT_MAX,        },
+	{ "vip_exp_penalty_base",               &battle_config.vip_exp_penalty_base,            0,      0,      INT_MAX,        },
+	{ "vip_exp_penalty_job",                &battle_config.vip_exp_penalty_job,             0,      0,      INT_MAX,        },
+	{ "vip_bm_increase",                    &battle_config.vip_bm_increase,                 0,      0,      INT_MAX,        },
+	{ "vip_drop_increase",                  &battle_config.vip_drop_increase,               0,      0,      INT_MAX,        },
+	{ "vip_gemstone",                       &battle_config.vip_gemstone,                    0,      0,      1,              },
 	{ "mon_trans_disable_in_gvg",           &battle_config.mon_trans_disable_in_gvg,        0,      0,      1,              },
 	{ "mon_trans_disable_in_gvg",           &battle_config.mon_trans_disable_in_gvg,        0,      0,      1,              },
-	{ "homunculus_S_growth_level",          &battle_config.hom_S_growth_level,              99,     0,      MAX_LEVEL,      },
-	{ "emblem_woe_change",                  &battle_config.emblem_woe_change,                0,     0,      1,              },
-	{ "emblem_transparency_limit",          &battle_config.emblem_transparency_limit,       80,     0,    100,              },
+	{ "homunculus_S_growth_level",          &battle_config.hom_S_growth_level,             99,      0,      MAX_LEVEL,      },
+	{ "emblem_woe_change",                  &battle_config.emblem_woe_change,               0,      0,      1,              },
+	{ "emblem_transparency_limit",          &battle_config.emblem_transparency_limit,      80,      0,      100,            },
 };
 };
 #ifndef STATS_OPT_OUT
 #ifndef STATS_OPT_OUT
 /**
 /**

+ 13 - 0
src/map/battle.h

@@ -4,6 +4,9 @@
 #ifndef _BATTLE_H_
 #ifndef _BATTLE_H_
 #define _BATTLE_H_
 #define _BATTLE_H_
 
 
+#include "../common/mmo.h"
+#include "../config/core.h"
+
 // state of a single attack attempt; used in flee/def penalty calculations when mobbed
 // state of a single attack attempt; used in flee/def penalty calculations when mobbed
 typedef enum damage_lv {
 typedef enum damage_lv {
 	ATK_NONE,    // not an attack
 	ATK_NONE,    // not an attack
@@ -496,6 +499,16 @@ extern struct Battle_Config
 	int bowling_bash_area;
 	int bowling_bash_area;
 	int drop_rateincrease;
 	int drop_rateincrease;
 	int feature_banking;
 	int feature_banking;
+	int vip_storage_increase;
+	int vip_base_exp_increase;
+	int vip_job_exp_increase;
+	int vip_bm_increase;
+	int vip_drop_increase;
+	int vip_gemstone;
+	int vip_exp_penalty_base_normal;
+	int vip_exp_penalty_base;
+	int vip_exp_penalty_job_normal;
+	int vip_exp_penalty_job;
 	int mon_trans_disable_in_gvg;
 	int mon_trans_disable_in_gvg;
 	int emblem_woe_change;
 	int emblem_woe_change;
 	int emblem_transparency_limit;
 	int emblem_transparency_limit;

+ 47 - 3
src/map/chrif.c

@@ -46,7 +46,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 	11,10,10, 0,11, -1,266,10,	// 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17
 	11,10,10, 0,11, -1,266,10,	// 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17
 	 2,10, 2,-1,-1,-1, 2, 7,	// 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
 	 2,10, 2,-1,-1,-1, 2, 7,	// 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
 	-1,10, 8, 2, 2,14,19,19,	// 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27
 	-1,10, 8, 2, 2,14,19,19,	// 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27
-	10,10, 6, 0, 0, 6, -1, -1,	// 2b28-2b2f: U->2b28, U->2b29, U->2b2a, F->2b2b, F->2b2c, U->2b2d, U->2b2e, U->2b2f
+	10,10, 6,15,11, 6,-1,-1,	// 2b28-2b2f: U->2b28, U->2b29, U->2b2a, U->2b2b, U->2b2c, U->2b2d, U->2b2e, U->2b2f
  };
  };
 
 
 //Used Packets:
 //Used Packets:
@@ -101,8 +101,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 //2b28: Outgoing, chrif_save_bankdata -> 'send bank data to be saved'
 //2b28: Outgoing, chrif_save_bankdata -> 'send bank data to be saved'
 //2b29: Incoming, chrif_load_bankdata -> 'received bank data for playeer to be loaded'
 //2b29: Incoming, chrif_load_bankdata -> 'received bank data for playeer to be loaded'
 //2b2a: Outgoing, chrif_bankdata_request -> 'request bank data for charid'
 //2b2a: Outgoing, chrif_bankdata_request -> 'request bank data for charid'
-//2b2b: FREE
-//2b2c: FREE
+//2b2b: Incoming, chrif_parse_ack_vipActive -> vip info result
+//2b2c: Outgoing, chrif_req_vipActive -> request vip info
 //2b2d: Outgoing, chrif_bsdata_request -> request bonus_script for pc_authok'ed char.
 //2b2d: Outgoing, chrif_bsdata_request -> request bonus_script for pc_authok'ed char.
 //2b2e: Outgoing, chrif_save_bsdata -> Send bonus_script of player for saving.
 //2b2e: Outgoing, chrif_save_bsdata -> Send bonus_script of player for saving.
 //2b2f: Incoming, chrif_load_bsdata -> received bonus_script of player for loading.
 //2b2f: Incoming, chrif_load_bsdata -> received bonus_script of player for loading.
@@ -1513,6 +1513,49 @@ void chrif_keepalive(int fd) {
 void chrif_keepalive_ack(int fd) {
 void chrif_keepalive_ack(int fd) {
 	session[fd]->flag.ping = 0;/* reset ping state, we received a packet */
 	session[fd]->flag.ping = 0;/* reset ping state, we received a packet */
 }
 }
+
+void chrif_parse_ack_vipActive(int fd) {
+#ifdef VIP_ENABLE
+	int aid = RFIFOL(char_fd,2);
+	uint32 vip_time = RFIFOL(char_fd,6);
+	bool isvip = RFIFOB(char_fd,10);
+	uint32 groupid = RFIFOL(char_fd,11);
+	TBL_PC *sd = map_id2sd(aid);
+
+	if (sd && isvip) {
+		sd->vip.enabled = 1;
+		sd->vip.time = vip_time;
+		sd->group_id = groupid;
+		pc_group_pc_load(sd);
+
+		// Increase storage size for VIP.
+		sd->storage_size = battle_config.vip_storage_increase + MIN_STORAGE;
+		if (sd->storage_size > MAX_STORAGE) {
+			ShowError("intif_parse_ack_vipActive: Storage size for player %s (%d:%d) is larger than MAX_STORAGE. Storage size has been set to MAX_STORAGE.\n", sd->status.name, sd->status.account_id, sd->status.char_id);
+			sd->storage_size = MAX_STORAGE;
+		}
+		// Magic Stone requirement avoidance for VIP.
+		if (battle_config.vip_gemstone && pc_isvip(sd))
+			sd->special_state.no_gemstone = 2; // need to be done after status_calc_bl(bl,first);
+	}
+#endif
+}
+
+int chrif_req_vipActive(TBL_PC *sd, int8 req_duration, int8 type) {
+#ifdef VIP_ENABLE
+	if (CheckForCharServer() || sd == NULL)
+		return 0;
+
+	WFIFOHEAD(char_fd,11);
+	WFIFOW(char_fd,0) = 0x2b2c;
+	WFIFOL(char_fd,2) = sd->bl.id; // AID
+	WFIFOB(char_fd,6) = type; // type&1 - SQL SELECT, type&2 - SQL UPDATE
+	WFIFOL(char_fd,7) = req_duration;
+	WFIFOSET(char_fd,11);
+#endif
+	return 0;
+}
+
 /*==========================================
 /*==========================================
  *
  *
  *------------------------------------------*/
  *------------------------------------------*/
@@ -1590,6 +1633,7 @@ int chrif_parse(int fd) {
 			case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
 			case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
 			case 0x2b27: chrif_authfail(fd); break;
 			case 0x2b27: chrif_authfail(fd); break;
 			case 0x2b29: chrif_load_bankdata(fd); break;
 			case 0x2b29: chrif_load_bankdata(fd); break;
+			case 0x2b2b: chrif_parse_ack_vipActive(fd); break;
 			case 0x2b2f: chrif_load_bsdata(fd); break;
 			case 0x2b2f: chrif_load_bsdata(fd); break;
 			default:
 			default:
 				ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
 				ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);

+ 3 - 0
src/map/chrif.h

@@ -67,6 +67,9 @@ int chrif_divorce(int partner_id1, int partner_id2);
 int chrif_removefriend(int char_id, int friend_id);
 int chrif_removefriend(int char_id, int friend_id);
 int chrif_send_report(char* buf, int len);
 int chrif_send_report(char* buf, int len);
 
 
+void chrif_parse_ack_vipActive(int fd);
+int chrif_req_vipActive(struct map_session_data *sd, int8 req_duration, int8 type);
+
 int chrif_bsdata_request(int char_id);
 int chrif_bsdata_request(int char_id);
 int chrif_save_bsdata(struct map_session_data *sd);
 int chrif_save_bsdata(struct map_session_data *sd);
 int chrif_load_bsdata(int fd);
 int chrif_load_bsdata(int fd);

+ 84 - 12
src/map/clif.c

@@ -6252,6 +6252,7 @@ void clif_Bank_Check(struct map_session_data* sd) {
 	if(!cmd) cmd = 0x09A6; //default
 	if(!cmd) cmd = 0x09A6; //default
 	info = &packet_db[sd->packet_ver][cmd]; 
 	info = &packet_db[sd->packet_ver][cmd]; 
 	len = info->len;
 	len = info->len;
+	if(!len) return; //version as packet disable
 //        sd->state.banking = 1; //mark opening and closing
 //        sd->state.banking = 1; //mark opening and closing
 
 
 	WBUFW(buf,0) = cmd;
 	WBUFW(buf,0) = cmd;
@@ -6274,8 +6275,8 @@ void clif_parse_BankCheck(int fd, struct map_session_data* sd) {
 	else {
 	else {
 		struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
 		struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
 		int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ?
 		int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ?
-                if(sd->status.account_id == aid) //since we have it let check it for extra security
-                        clif_Bank_Check(sd);
+		if(sd->status.account_id == aid) //since we have it let check it for extra security
+			clif_Bank_Check(sd);
 	}
 	}
 }
 }
 
 
@@ -6295,6 +6296,7 @@ void clif_bank_deposit(struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK r
 	if(!cmd) cmd = 0x09A8;
 	if(!cmd) cmd = 0x09A8;
 	info = &packet_db[sd->packet_ver][cmd]; 
 	info = &packet_db[sd->packet_ver][cmd]; 
 	len = info->len;
 	len = info->len;
+	if(!len) return; //version as packet disable
 	
 	
 	WBUFW(buf,0) = cmd;
 	WBUFW(buf,0) = cmd;
 	WBUFW(buf,info->pos[0]) = (short)reason;	
 	WBUFW(buf,info->pos[0]) = (short)reason;	
@@ -6309,7 +6311,7 @@ void clif_bank_deposit(struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK r
  * 09A7 <AID>L <Money>L (PACKET_CZ_REQ_BANKING_DEPOSIT)
  * 09A7 <AID>L <Money>L (PACKET_CZ_REQ_BANKING_DEPOSIT)
  */
  */
 void clif_parse_BankDeposit(int fd, struct map_session_data* sd) {
 void clif_parse_BankDeposit(int fd, struct map_session_data* sd) {
-        nullpo_retv(sd);
+	nullpo_retv(sd);
 	if( !battle_config.feature_banking ) {
 	if( !battle_config.feature_banking ) {
 		clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1496)); //Banking is disabled
 		clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1496)); //Banking is disabled
 		return;
 		return;
@@ -6337,14 +6339,15 @@ void clif_bank_withdraw(struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK
 	int cmd;
 	int cmd;
 
 
 	nullpo_retv(sd);
 	nullpo_retv(sd);
-        
+
 	cmd = packet_db_ack[sd->packet_ver][ZC_ACK_BANKING_WITHDRAW];
 	cmd = packet_db_ack[sd->packet_ver][ZC_ACK_BANKING_WITHDRAW];
 	if(!cmd) cmd = 0x09AA;
 	if(!cmd) cmd = 0x09AA;
 	info = &packet_db[sd->packet_ver][cmd]; 
 	info = &packet_db[sd->packet_ver][cmd]; 
 	len = info->len;
 	len = info->len;
+	if(!len) return; //version as packet disable
 
 
 	WBUFW(buf,0) = cmd;
 	WBUFW(buf,0) = cmd;
-	WBUFW(buf,info->pos[0]) = (short)reason;	
+	WBUFW(buf,info->pos[0]) = (short)reason;
 	WBUFQ(buf,info->pos[1]) = sd->status.bank_vault;/* money in the bank */
 	WBUFQ(buf,info->pos[1]) = sd->status.bank_vault;/* money in the bank */
 	WBUFL(buf,info->pos[2]) = sd->status.zeny;/* how much zeny char has after operation */
 	WBUFL(buf,info->pos[2]) = sd->status.zeny;/* how much zeny char has after operation */
 
 
@@ -9606,6 +9609,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 #if PACKETVER >= 20070918
 #if PACKETVER >= 20070918
 		clif_partyinvitationstate(sd);
 		clif_partyinvitationstate(sd);
 		clif_equipcheckbox(sd);
 		clif_equipcheckbox(sd);
+#endif
+#ifdef VIP_ENABLE
+		clif_display_pinfo(sd,ZC_PERSONAL_INFOMATION);
+		//clif_vip_display_info(sd,ZC_PERSONAL_INFOMATION_CHN);
 #endif
 #endif
 		if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) &&
 		if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) &&
 			(map_flag_gvg(sd->state.pmap) || map_flag_gvg(sd->bl.m) || map[sd->state.pmap].flag.battleground || map[sd->bl.m].flag.battleground) )
 			(map_flag_gvg(sd->state.pmap) || map_flag_gvg(sd->bl.m) || map[sd->state.pmap].flag.battleground || map[sd->bl.m].flag.battleground) )
@@ -16933,6 +16940,68 @@ void clif_update_rankingpoint(struct map_session_data *sd, int rankingtype, int
 #endif
 #endif
 }
 }
 
 
+/**
+ * Transmit personal information to player. (rates)
+ *  08cb <packet len>.W <exp>.W <death>.W <drop>.W <DETAIL_EXP_INFO>7B (ZC_PERSONAL_INFOMATION)
+ * <InfoType>.B <Exp>.W <Death>.W <Drop>.W (DETAIL_EXP_INFO 0x8cb) 
+ * 097b <packet len>.W <exp>.L <death>.L <drop>.L <DETAIL_EXP_INFO>13B (ZC_PERSONAL_INFOMATION2)
+ * 0981 <packet len>.W <exp>.W <death>.W <drop>.W <activity rate>.W <DETAIL_EXP_INFO>13B (ZC_PERSONAL_INFOMATION_CHN)
+ * <InfoType>.B <Exp>.L <Death>.L <Drop>.L (DETAIL_EXP_INFO 0x97b|0981)
+ * InfoType: 0 PCRoom, 1 Premium, 2 Server, 3 TPlus
+*/
+void clif_display_pinfo(struct map_session_data *sd, int cmdtype) {
+	if (sd) {
+		struct s_packet_db* info;
+		int16 len, szdetails = 13, maxinfotype = PINFO_MAX;
+		int cmd = 0, fd, i = 0, details_prem_penalty = 0;
+		int tot_baseexp = 0, total_penalty = 0, tot_drop = 0, factor = 1000;
+		int details_bexp[PINFO_MAX]= {map[sd->bl.m].adjust.bexp,battle_config.vip_base_exp_increase,battle_config.base_exp_rate,0 }; //TODO move me ?
+		int details_penalty[PINFO_MAX]= {0,0,battle_config.death_penalty_base,0 };
+		int details_drop[PINFO_MAX]= {0,battle_config.vip_drop_increase,battle_config.item_rate_common,0 };
+
+		cmd = packet_db_ack[sd->packet_ver][cmdtype];
+		info = &packet_db[sd->packet_ver][cmd];
+		len = info->len; //this is the base len without details
+		if(!len) return; //version as packet disable
+
+		if (cmdtype == ZC_PERSONAL_INFOMATION && len == 10) { //8cb version
+			szdetails = 7;
+			maxinfotype = 3;
+			factor = 1;
+		}
+
+		// Need to alter penalty data for VIP whether the system is enabled or not.
+		details_prem_penalty = battle_config.death_penalty_base;
+#ifdef VIP_ENABLE
+		details_prem_penalty = battle_config.death_penalty_base * (battle_config.vip_exp_penalty_base_normal - 1);
+		if (pc_isvip(sd)) details_prem_penalty = battle_config.death_penalty_base * (battle_config.vip_exp_penalty_base - 1);
+		details_prem_penalty = max(0,details_prem_penalty);
+#endif
+		details_penalty[PINFO_PREMIUM] = details_prem_penalty;
+		fd = sd->fd;
+		WFIFOHEAD(fd,len+maxinfotype*szdetails);
+		WFIFOW(fd,0) = cmd;
+
+		for (i = 0; i < maxinfotype; i++) {
+			WFIFOB(fd,info->pos[4]+(i*szdetails)) = i; //infotype //0 PCRoom, 1 Premium, 2 Server, 3 TPlus
+			WFIFOW(fd,info->pos[5]+(i*szdetails)) = 0;
+			tot_baseexp += details_bexp[i]*factor;
+			WFIFOW(fd,info->pos[6]+(i*szdetails)) = details_penalty[i]*factor;
+			total_penalty += details_penalty[i]*factor;
+			WFIFOW(fd,info->pos[7]+(i*szdetails)) = details_drop[i]*factor;
+			tot_drop += details_drop[i]*factor;
+			len += szdetails;
+		}
+		WFIFOW(fd,info->pos[0])  = len; //packetlen
+		WFIFOW(fd,info->pos[1])  = tot_baseexp;
+		WFIFOW(fd,info->pos[2])  = total_penalty; //6 8
+		WFIFOW(fd,info->pos[3])  = tot_drop; //8 12
+		if (cmdtype == ZC_PERSONAL_INFOMATION_CHN) 
+			WFIFOW(fd,info->pos[8])  = 0; //activity rate case of event ??
+		WFIFOSET(fd,len);
+	}
+}
+
 #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";
@@ -17570,15 +17639,18 @@ void packetdb_readdb(void)
 		{ clif_parse_ranklist, "ranklist"},
 		{ clif_parse_ranklist, "ranklist"},
 		{NULL,NULL}
 		{NULL,NULL}
 	};
 	};
-        struct {
+	struct {
 		char *name; //function name
 		char *name; //function name
-                int funcidx; //
+		int funcidx; //
 	} clif_ack_func[]={ //hash
 	} clif_ack_func[]={ //hash
-            { "ZC_ACK_OPEN_BANKING", ZC_ACK_OPEN_BANKING},
-            { "ZC_ACK_BANKING_DEPOSIT", ZC_ACK_BANKING_DEPOSIT},
-            { "ZC_ACK_BANKING_WITHDRAW", ZC_ACK_BANKING_WITHDRAW},
-            { "ZC_BANKING_CHECK", ZC_BANKING_CHECK},
-        };
+		{ "ZC_ACK_OPEN_BANKING", ZC_ACK_OPEN_BANKING},
+		{ "ZC_ACK_BANKING_DEPOSIT", ZC_ACK_BANKING_DEPOSIT},
+		{ "ZC_ACK_BANKING_WITHDRAW", ZC_ACK_BANKING_WITHDRAW},
+		{ "ZC_BANKING_CHECK", ZC_BANKING_CHECK},
+		{ "ZC_BANKING_CHECK", ZC_BANKING_CHECK},
+		{ "ZC_PERSONAL_INFOMATION", ZC_PERSONAL_INFOMATION},
+		{ "ZC_PERSONAL_INFOMATION_CHN", ZC_PERSONAL_INFOMATION_CHN},
+	};
 
 
 	// initialize packet_db[SERVER] from hardcoded packet_len_table[] values
 	// initialize packet_db[SERVER] from hardcoded packet_len_table[] values
 	memset(packet_db,0,sizeof(packet_db));
 	memset(packet_db,0,sizeof(packet_db));

+ 18 - 5
src/map/clif.h

@@ -40,11 +40,14 @@ enum
 };
 };
 
 
 enum e_packet_ack {
 enum e_packet_ack {
-    ZC_ACK_OPEN_BANKING = 0,
-    ZC_ACK_BANKING_DEPOSIT,
-    ZC_ACK_BANKING_WITHDRAW,
-    ZC_BANKING_CHECK,
-    MAX_ACK_FUNC //auto upd len
+	ZC_ACK_OPEN_BANKING = 0,
+	ZC_ACK_BANKING_DEPOSIT,
+	ZC_ACK_BANKING_WITHDRAW,
+	ZC_BANKING_CHECK,
+	ZC_PERSONAL_INFOMATION,
+	ZC_PERSONAL_INFOMATION_CHN,
+	//add otehr here
+	MAX_ACK_FUNC //auto upd len
 };
 };
 
 
 struct s_packet_db {
 struct s_packet_db {
@@ -348,6 +351,14 @@ enum clif_messages {
 	ADDITEM_TO_CART_FAIL_COUNT = 0x1,
 	ADDITEM_TO_CART_FAIL_COUNT = 0x1,
 };
 };
 
 
+enum e_personalinfo {
+ PINFO_BASIC = 0,
+ PINFO_PREMIUM,
+ PINFO_SERVER,
+ PINFO_CAFE,
+ PINFO_MAX,
+};
+
 int clif_setip(const char* ip);
 int clif_setip(const char* ip);
 void clif_setbindip(const char* ip);
 void clif_setbindip(const char* ip);
 void clif_setport(uint16 port);
 void clif_setport(uint16 port);
@@ -773,6 +784,8 @@ void clif_search_store_info_click_ack(struct map_session_data* sd, short x, shor
 void clif_cashshop_result( struct map_session_data* sd, uint16 item_id, uint16 result );
 void clif_cashshop_result( struct map_session_data* sd, uint16 item_id, uint16 result );
 void clif_cashshop_open( struct map_session_data* sd );
 void clif_cashshop_open( struct map_session_data* sd );
 
 
+void clif_display_pinfo(struct map_session_data *sd, int type);
+
 /**
 /**
  * 3CeAM
  * 3CeAM
  **/
  **/

+ 19 - 4
src/map/mob.c

@@ -2249,13 +2249,23 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 
 			if (map[m].flag.nobaseexp || !md->db->base_exp)
 			if (map[m].flag.nobaseexp || !md->db->base_exp)
 				base_exp = 0;
 				base_exp = 0;
-			else
-				base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].adjust.bexp/100., 1, UINT_MAX);
+			else {
+				int vip_bonus = 0;
+				// Increase base EXP rate for VIP.
+				if (battle_config.vip_base_exp_increase && (sd && pc_isvip(sd)))
+					vip_bonus += battle_config.vip_base_exp_increase;
+				base_exp = (unsigned int)cap_value(md->db->base_exp * per * (bonus+vip_bonus)/100. * map[m].adjust.bexp/100., 1, UINT_MAX);
+			}
 
 
 			if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost.
 			if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost.
 				job_exp = 0;
 				job_exp = 0;
-			else
-				job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].adjust.jexp/100., 1, UINT_MAX);
+			else {
+				int vip_bonus = 0;
+				// Increase job EXP rate for VIP.
+				if (battle_config.vip_job_exp_increase && (sd && pc_isvip(sd)))
+					vip_bonus += battle_config.vip_job_exp_increase;
+				job_exp = (unsigned int)cap_value(md->db->job_exp * per * (bonus+vip_bonus)/100. * map[m].adjust.jexp/100., 1, UINT_MAX);
+			}
 
 
 			if ( ( temp = tmpsd[i]->status.party_id)>0 ) {
 			if ( ( temp = tmpsd[i]->status.party_id)>0 ) {
 				int j;
 				int j;
@@ -2371,6 +2381,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			// Increase drop rate if user has SC_ITEMBOOST
 			// Increase drop rate if user has SC_ITEMBOOST
 			if (sd && sd->sc.data[SC_ITEMBOOST]) // now rig the drop rate to never be over 90% unless it is originally >90%.
 			if (sd && sd->sc.data[SC_ITEMBOOST]) // now rig the drop rate to never be over 90% unless it is originally >90%.
 				drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_ITEMBOOST]->val1)/100.),0,9000));
 				drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_ITEMBOOST]->val1)/100.),0,9000));
+			// Increase item drop rate for VIP.
+			if (battle_config.vip_drop_increase && (sd && pc_isvip(sd))) {
+				drop_rate += (int)(0.5 + (drop_rate * battle_config.vip_drop_increase) / 10000.);
+				drop_rate = min(drop_rate,10000); //cap it to 100%
+			}
 #ifdef RENEWAL_DROP
 #ifdef RENEWAL_DROP
 			if( drop_modifier != 100 ) {
 			if( drop_modifier != 100 ) {
 				drop_rate = drop_rate * drop_modifier / 100;
 				drop_rate = drop_rate * drop_modifier / 100;

+ 30 - 24
src/map/pc.c

@@ -1276,6 +1276,8 @@ int pc_reg_received(struct map_session_data *sd)
 	chrif_skillcooldown_request(sd->status.account_id, sd->status.char_id);
 	chrif_skillcooldown_request(sd->status.account_id, sd->status.char_id);
 	chrif_bankdata_request(sd->status.account_id, sd->status.char_id);
 	chrif_bankdata_request(sd->status.account_id, sd->status.char_id);
 	chrif_bsdata_request(sd->status.char_id);
 	chrif_bsdata_request(sd->status.char_id);
+	sd->storage_size = MIN_STORAGE; //default to min
+	chrif_req_vipActive(sd, 0, 1); // request VIP informations
 	intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
 	intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
 	intif_request_questlog(sd);
 	intif_request_questlog(sd);
 
 
@@ -2489,7 +2491,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 			sd->special_state.no_misc_damage = cap_value(val,0,100);
 			sd->special_state.no_misc_damage = cap_value(val,0,100);
 			break;
 			break;
 		case SP_NO_GEMSTONE:
 		case SP_NO_GEMSTONE:
-			if(sd->state.lr_flag != 2)
+			if(sd->state.lr_flag != 2 && sd->special_state.no_gemstone != 2)
 				sd->special_state.no_gemstone = 1;
 				sd->special_state.no_gemstone = 1;
 			break;
 			break;
 		case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG]
 		case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG]
@@ -5877,8 +5879,11 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi
 		(int)(status_get_lv(src) - sd->status.base_level) >= 20)
 		(int)(status_get_lv(src) - sd->status.base_level) >= 20)
 		bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris]
 		bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris]
 
 
-	if (sd->sc.data[SC_EXPBOOST])
-		bonus += sd->sc.data[SC_EXPBOOST]->val1;
+	if (sd->sc.data[SC_EXPBOOST]) {	
+ 		bonus += sd->sc.data[SC_EXPBOOST]->val1;
+		if( battle_config.vip_bm_increase && pc_isvip(sd) ) // Increase Battle Manual EXP rate for VIP.
+			bonus += ( sd->sc.data[SC_EXPBOOST]->val1 / battle_config.vip_bm_increase );
+	}
 
 
 	*base_exp = (unsigned int) cap_value(*base_exp + (double)*base_exp * bonus/100., 1, UINT_MAX);
 	*base_exp = (unsigned int) cap_value(*base_exp + (double)*base_exp * bonus/100., 1, UINT_MAX);
 
 
@@ -6928,37 +6933,38 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		&& !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m)
 		&& !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m)
 		&& !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE])
 		&& !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE])
 	{
 	{
-		unsigned int base_penalty =0;
-		if (battle_config.death_penalty_base > 0) {
+		unsigned int base_penalty = battle_config.death_penalty_base, job_penalty = battle_config.death_penalty_job;
+#ifdef VIP_ENABLE
+		if(pc_isvip(sd)){
+			base_penalty = base_penalty*battle_config.vip_exp_penalty_base;
+			job_penalty = job_penalty*battle_config.vip_exp_penalty_job;
+		}
+		else {
+			base_penalty = base_penalty*battle_config.vip_exp_penalty_base_normal;
+			job_penalty = job_penalty*battle_config.vip_exp_penalty_job_normal;
+		}
+#endif
+		if (base_penalty > 0) {
 			switch (battle_config.death_penalty_type) {
 			switch (battle_config.death_penalty_type) {
-				case 1:
-					base_penalty = (unsigned int) ((double)pc_nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000);
-				break;
-				case 2:
-					base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000);
-				break;
+				case 1: base_penalty = (uint32) ((double)(pc_nextbaseexp(sd) * base_penalty)/10000); break;
+				case 2: base_penalty = (uint32) ((double)(sd->status.base_exp * base_penalty)/10000); break;
 			}
 			}
-			if(base_penalty) {
+			if (base_penalty > 0){ //recheck after altering to speedup
 				if (battle_config.pk_mode && src && src->type==BL_PC)
 				if (battle_config.pk_mode && src && src->type==BL_PC)
 					base_penalty*=2;
 					base_penalty*=2;
 				sd->status.base_exp -= min(sd->status.base_exp, base_penalty);
 				sd->status.base_exp -= min(sd->status.base_exp, base_penalty);
 				clif_updatestatus(sd,SP_BASEEXP);
 				clif_updatestatus(sd,SP_BASEEXP);
 			}
 			}
 		}
 		}
-		if(battle_config.death_penalty_job > 0) {
-			base_penalty = 0;
+		if(job_penalty > 0) {
 			switch (battle_config.death_penalty_type) {
 			switch (battle_config.death_penalty_type) {
-				case 1:
-					base_penalty = (unsigned int) ((double)pc_nextjobexp(sd) * (double)battle_config.death_penalty_job/10000);
-				break;
-				case 2:
-					base_penalty = (unsigned int) ((double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000);
-				break;
+				case 1: job_penalty = (uint32) ((double)(pc_nextjobexp(sd) * job_penalty)/10000); break;
+				case 2: job_penalty = (uint32) ((double)(sd->status.job_exp * job_penalty)/10000); break;
 			}
 			}
-			if(base_penalty) {
+			if(job_penalty) {
 				if (battle_config.pk_mode && src && src->type==BL_PC)
 				if (battle_config.pk_mode && src && src->type==BL_PC)
-					base_penalty*=2;
-				sd->status.job_exp -= min(sd->status.job_exp, base_penalty);
+					job_penalty*=2;
+				sd->status.job_exp -= min(sd->status.job_exp, job_penalty);
 				clif_updatestatus(sd,SP_JOBEXP);
 				clif_updatestatus(sd,SP_JOBEXP);
 			}
 			}
 		}
 		}
@@ -9087,7 +9093,7 @@ int pc_check_available_item(struct map_session_data *sd) {
 	}
 	}
 
 
 	if( battle_config.item_check&4 ) { // Check for invalid(ated) items in storage.
 	if( battle_config.item_check&4 ) { // Check for invalid(ated) items in storage.
-		for( i = 0; i < MAX_STORAGE; i++ ) {
+		for( i = 0; i < sd->storage_size; i++ ) {
 			it = sd->status.storage.items[i].nameid;
 			it = sd->status.storage.items[i].nameid;
 
 
 			if( it && !itemdb_available(it) ) {
 			if( it && !itemdb_available(it) ) {

+ 15 - 3
src/map/pc.h

@@ -201,7 +201,7 @@ struct map_session_data {
 		unsigned int no_castcancel : 1;
 		unsigned int no_castcancel : 1;
 		unsigned int no_castcancel2 : 1;
 		unsigned int no_castcancel2 : 1;
 		unsigned int no_sizefix : 1;
 		unsigned int no_sizefix : 1;
-		unsigned int no_gemstone : 1;
+		unsigned int no_gemstone : 2;
 		unsigned int intravision : 1; // Maya Purple Card effect [DracoRPG]
 		unsigned int intravision : 1; // Maya Purple Card effect [DracoRPG]
 		unsigned int perfect_hiding : 1; // [Valaris]
 		unsigned int perfect_hiding : 1; // [Valaris]
 		unsigned int no_knockback : 1;
 		unsigned int no_knockback : 1;
@@ -213,7 +213,7 @@ struct map_session_data {
 	unsigned int permissions;/* group permissions */
 	unsigned int permissions;/* group permissions */
 
 
 	int langtype;
 	int langtype;
-	int packet_ver;  // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18
+	uint32 packet_ver;  // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18
 	struct mmo_charstatus status;
 	struct mmo_charstatus status;
 	struct registry save_reg;
 	struct registry save_reg;
 
 
@@ -551,6 +551,14 @@ struct map_session_data {
 	} c_marker;
 	} c_marker;
 	bool flicker;
 	bool flicker;
 
 
+	int storage_size; // Holds player storage size (VIP system).
+#ifdef VIP_ENABLE
+	struct {
+		unsigned int enabled;
+		unsigned int time;
+	} vip;
+#endif
+
 	//Timed bonus 'bonus_script' struct [Cydh]
 	//Timed bonus 'bonus_script' struct [Cydh]
 	struct s_script {
 	struct s_script {
 		struct script_code *script;
 		struct script_code *script;
@@ -683,7 +691,11 @@ struct {
 #define pc_ishiding(sd)       ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
 #define pc_ishiding(sd)       ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
 #define pc_iscloaking(sd)     ( !((sd)->sc.option&OPTION_CHASEWALK) && ((sd)->sc.option&OPTION_CLOAK) )
 #define pc_iscloaking(sd)     ( !((sd)->sc.option&OPTION_CHASEWALK) && ((sd)->sc.option&OPTION_CLOAK) )
 #define pc_ischasewalk(sd)    ( (sd)->sc.option&OPTION_CHASEWALK )
 #define pc_ischasewalk(sd)    ( (sd)->sc.option&OPTION_CHASEWALK )
-
+#ifdef VIP_ENABLE
+	#define pc_isvip(sd)      ( sd->vip.enabled ? 1 : 0 )
+#else
+	#define pc_isvip(sd)      ( 0 )
+#endif
 #ifdef NEW_CARTS
 #ifdef NEW_CARTS
 	#define pc_iscarton(sd)       ( (sd)->sc.data[SC_PUSH_CART] )
 	#define pc_iscarton(sd)       ( (sd)->sc.data[SC_PUSH_CART] )
 #else
 #else

+ 73 - 0
src/map/script.c

@@ -18010,6 +18010,7 @@ BUILDIN_FUNC(getserverdef) {
 		case 7: script_pushint(st,MAX_GUILDLEVEL); break;
 		case 7: script_pushint(st,MAX_GUILDLEVEL); break;
 		case 8: script_pushint(st,MAX_GUILD_STORAGE); break;
 		case 8: script_pushint(st,MAX_GUILD_STORAGE); break;
 		case 9: script_pushint(st,MAX_BG_MEMBERS); break;
 		case 9: script_pushint(st,MAX_BG_MEMBERS); break;
+		case 10: script_pushint(st,VIP_SCRIPT); break;
 		default:
 		default:
 			ShowWarning("buildin_getserverdef: unknown type %d.\n", type);
 			ShowWarning("buildin_getserverdef: unknown type %d.\n", type);
 			script_pushint(st,0);
 			script_pushint(st,0);
@@ -18018,6 +18019,74 @@ BUILDIN_FUNC(getserverdef) {
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef VIP_ENABLE
+/* Returns various information about a player's VIP status.
+ * vip_status <type>,{"<character name>"};
+ * Note: VIP System needs to be enabled.
+ */
+BUILDIN_FUNC(vip_status) {
+	TBL_PC *sd;
+	char *vip_str = (char *)aMalloc(24*sizeof(char));
+	time_t now = time(NULL);
+	int type = script_getnum(st, 2);
+
+	if (script_hasdata(st, 3))
+		sd = map_nick2sd(script_getstr(st, 3));
+	else
+		sd = script_rid2sd(st);
+
+	if (sd == NULL)
+		return 0;
+
+	switch(type) {
+		case 0: // Get VIP status.
+			script_pushint(st, pc_isvip(sd));
+			break;
+		case 1: // Get VIP expire date.
+			if (pc_isvip(sd)) {
+				time_t viptime = (time_t)sd->vip.time;
+				strftime(vip_str, 24, "%Y-%m-%d %H:%M", localtime(&viptime));
+				vip_str[24] = '\0';
+				script_pushstr(st, vip_str);
+			} else
+				script_pushint(st, 0);
+			break;
+		case 2: // Get remaining time.
+			if (pc_isvip(sd)) {
+				time_t viptime = (time_t)sd->vip.time;
+				strftime(vip_str, 24, "%Y-%m-%d %H:%M", localtime(&viptime - now));
+				vip_str[24] = '\0';
+				script_pushstr(st, vip_str);
+			} else
+				script_pushint(st, 0);
+			break;
+	}
+	return 0;
+}
+
+/* Adds or removes VIP time in minutes.
+ * vip_time <time>,{"<character name>"};
+ * If time < 0 remove time, else add time.
+ * Note: VIP System needs to be enabled. 
+ */
+BUILDIN_FUNC(vip_time) {
+	TBL_PC *sd;
+	int time = script_getnum(st, 2) * 60; // Convert since it's given in minutes.
+
+	if (script_hasdata(st, 3))
+		sd = map_nick2sd(script_getstr(st, 3));
+	else
+		sd = script_rid2sd(st);
+
+	if (sd == NULL)
+		return 0;
+
+	chrif_req_vipActive(sd, time, 2);
+
+	return 0;
+}
+#endif
+
 /*==========================================
 /*==========================================
  * Turns a player into a monster and grants SC attribute effect. [malufett/Hercules]
  * Turns a player into a monster and grants SC attribute effect. [malufett/Hercules]
  * montransform <monster name/ID>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>;
  * montransform <monster name/ID>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>;
@@ -18636,6 +18705,10 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(is_clientver,"ii?"),
 	BUILDIN_DEF(is_clientver,"ii?"),
 	BUILDIN_DEF(getserverdef,"i"),
 	BUILDIN_DEF(getserverdef,"i"),
 	BUILDIN_DEF2(montransform, "transform", "vii????"), // Monster Transform [malufett/Hercules]
 	BUILDIN_DEF2(montransform, "transform", "vii????"), // Monster Transform [malufett/Hercules]
+#ifdef VIP_ENABLE
+	BUILDIN_DEF(vip_status,"i?"),
+	BUILDIN_DEF(vip_time,"i?"),
+#endif
 	BUILDIN_DEF(bonus_script,"si???"),
 	BUILDIN_DEF(bonus_script,"si???"),
 
 
 #include "../custom/script_def.inc"
 #include "../custom/script_def.inc"

+ 22 - 18
src/map/skill.c

@@ -13714,7 +13714,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
 		 * Warlock
 		 * Warlock
 		 **/
 		 **/
 		case WL_COMET:
 		case WL_COMET:
-			if( skill_check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0
+			if( skill_check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && require.itemid[0]
 				&& sd->special_state.no_gemstone == 0
 				&& sd->special_state.no_gemstone == 0
 				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) {
 				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) {
 				//clif_skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]);
 				//clif_skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]);
@@ -14454,11 +14454,11 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
 					continue;
 					continue;
 				break;
 				break;
 			case AB_ADORAMUS:
 			case AB_ADORAMUS:
-				if( itemid_isgemstone(skill_db[idx].require.itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 2) )
+				if( itemid_isgemstone(skill_db[idx].require.itemid[i]) && (sd->special_state.no_gemstone == 2 || skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 2)) )
 					continue;
 					continue;
 				break;
 				break;
 			case WL_COMET:
 			case WL_COMET:
-				if( itemid_isgemstone(skill_db[idx].require.itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 0) )
+				if( itemid_isgemstone(skill_db[idx].require.itemid[i]) && (sd->special_state.no_gemstone == 2 || skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 0)) )
 					continue;
 					continue;
 				break;
 				break;
 			case GN_FIRE_EXPANSION:
 			case GN_FIRE_EXPANSION:
@@ -14481,21 +14481,25 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
 		req.itemid[i] = skill_db[idx].require.itemid[i];
 		req.itemid[i] = skill_db[idx].require.itemid[i];
 		req.amount[i] = skill_db[idx].require.amount[i];
 		req.amount[i] = skill_db[idx].require.amount[i];
 
 
-		if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN )
-		{
-			if( sd->special_state.no_gemstone )
-			{	// All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica
-				if( skill_id != SA_ABRACADABRA )
-					req.itemid[i] = req.amount[i] = 0;
-				else if( --req.amount[i] < 1 )
-					req.amount[i] = 1; // Hocus Pocus always use at least 1 gem
-			}
-			if(sc && sc->data[SC_INTOABYSS])
-			{
-				if( skill_id != SA_ABRACADABRA )
-					req.itemid[i] = req.amount[i] = 0;
-				else if( --req.amount[i] < 1 )
-					req.amount[i] = 1; // Hocus Pocus always use at least 1 gem
+		// Check requirement for gemstone.
+		if (itemid_isgemstone(req.itemid[i])) {
+			if( sd->special_state.no_gemstone == 2 ) // Remove all Magic Stone required for all skills for VIP.
+				req.itemid[i] = req.amount[i] = 0;
+			else {
+				if( sd->special_state.no_gemstone )
+				{	// All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica
+					if( skill_id != SA_ABRACADABRA )
+		 				req.itemid[i] = req.amount[i] = 0;
+					else if( --req.amount[i] < 1 )
+						req.amount[i] = 1; // Hocus Pocus always use at least 1 gem
+				}
+				if(sc && sc->data[SC_INTOABYSS])
+				{
+					if( skill_id != SA_ABRACADABRA )
+						req.itemid[i] = req.amount[i] = 0;
+					else if( --req.amount[i] < 1 )
+						req.amount[i] = 1; // Hocus Pocus always use at least 1 gem
+				}
 			}
 			}
 		}
 		}
 		if( skill_id >= HT_SKIDTRAP && skill_id <= HT_TALKIEBOX && pc_checkskill(sd, RA_RESEARCHTRAP) > 0){
 		if( skill_id >= HT_SKIDTRAP && skill_id <= HT_TALKIEBOX && pc_checkskill(sd, RA_RESEARCHTRAP) > 0){

+ 5 - 5
src/map/status.c

@@ -2636,10 +2636,10 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
 				wa->atk2 = refine_info[wlv].bonus[r-1] / 100;
 				wa->atk2 = refine_info[wlv].bonus[r-1] / 100;
 
 
 #ifdef RENEWAL
 #ifdef RENEWAL
-            wa->matk += sd->inventory_data[index]->matk;
-            wa->wlv = wlv;
-            if( r ) // Renewal magic attack refine bonus
-                wa->matk += refine_info[wlv].bonus[r-1] / 100;
+			wa->matk += sd->inventory_data[index]->matk;
+			wa->wlv = wlv;
+			if( r ) // Renewal magic attack refine bonus
+				wa->matk += refine_info[wlv].bonus[r-1] / 100;
 #endif
 #endif
 
 
 			// Overrefine bonus.
 			// Overrefine bonus.
@@ -4988,7 +4988,7 @@ static unsigned short status_calc_ematk(struct block_list *bl, struct status_cha
 		matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; // 70 lvl1, 100lvl2
 		matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; // 70 lvl1, 100lvl2
 	if(sc->data[SC_IZAYOI])
 	if(sc->data[SC_IZAYOI])
 		matk += 50 * sc->data[SC_IZAYOI]->val1;
 		matk += 50 * sc->data[SC_IZAYOI]->val1;
-    return (unsigned short)cap_value(matk,0,USHRT_MAX);
+	return (unsigned short)cap_value(matk,0,USHRT_MAX);
 }
 }
 #endif
 #endif
 /**
 /**

+ 12 - 12
src/map/storage.c

@@ -107,7 +107,7 @@ int storage_storageopen(struct map_session_data *sd)
 	sd->state.storage_flag = 1;
 	sd->state.storage_flag = 1;
 	storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
 	storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
 	clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
 	clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
-	clif_updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
+	clif_updatestorageamount(sd, sd->status.storage.storage_amount, sd->storage_size);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -162,7 +162,7 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
 
 
 	if( itemdb_isstackable2(data) )
 	if( itemdb_isstackable2(data) )
 	{//Stackable
 	{//Stackable
-		for( i = 0; i < MAX_STORAGE; i++ )
+		for( i = 0; i < sd->storage_size; i++ )
 		{
 		{
 			if( compare_item(&stor->items[i], item_data) )
 			if( compare_item(&stor->items[i], item_data) )
 			{// existing items found, stack them
 			{// existing items found, stack them
@@ -176,8 +176,8 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
 	}
 	}
 
 
 	// find free slot
 	// find free slot
-	ARR_FIND( 0, MAX_STORAGE, i, stor->items[i].nameid == 0 );
-	if( i >= MAX_STORAGE )
+	ARR_FIND( 0, sd->storage_size, i, stor->items[i].nameid == 0 );
+	if( i >= sd->storage_size )
 		return 1;
 		return 1;
 
 
 	// add item to slot
 	// add item to slot
@@ -185,7 +185,7 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
 	stor->storage_amount++;
 	stor->storage_amount++;
 	stor->items[i].amount = amount;
 	stor->items[i].amount = amount;
 	clif_storageitemadded(sd,&stor->items[i],i,amount);
 	clif_storageitemadded(sd,&stor->items[i],i,amount);
-	clif_updatestorageamount(sd, stor->storage_amount, MAX_STORAGE);
+	clif_updatestorageamount(sd, stor->storage_amount, sd->storage_size);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -203,7 +203,7 @@ int storage_delitem(struct map_session_data* sd, int n, int amount)
 	{
 	{
 		memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
 		memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
 		sd->status.storage.storage_amount--;
 		sd->status.storage.storage_amount--;
-		if( sd->state.storage_flag == 1 ) clif_updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
+		if( sd->state.storage_flag == 1 ) clif_updatestorageamount(sd, sd->status.storage.storage_amount, sd->storage_size);
 	}
 	}
 	if( sd->state.storage_flag == 1 ) clif_storageitemremoved(sd,n,amount);
 	if( sd->state.storage_flag == 1 ) clif_storageitemremoved(sd,n,amount);
 	return 0;
 	return 0;
@@ -220,7 +220,7 @@ int storage_storageadd(struct map_session_data* sd, int index, int amount)
 {
 {
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	if( sd->status.storage.storage_amount > MAX_STORAGE )
+	if( sd->status.storage.storage_amount > sd->storage_size )
 		return 0; // storage full
 		return 0; // storage full
 
 
 	if( index < 0 || index >= MAX_INVENTORY )
 	if( index < 0 || index >= MAX_INVENTORY )
@@ -253,7 +253,7 @@ int storage_storageget(struct map_session_data* sd, int index, int amount)
 {
 {
 	int flag;
 	int flag;
 
 
-	if( index < 0 || index >= MAX_STORAGE )
+	if( index < 0 || index >= sd->storage_size )
 		return 0;
 		return 0;
 
 
 	if( sd->status.storage.items[index].nameid <= 0 )
 	if( sd->status.storage.items[index].nameid <= 0 )
@@ -281,11 +281,11 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun
 {
 {
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	if( sd->status.storage.storage_amount > MAX_STORAGE )
-  		return 0; // storage full / storage closed
+	if( sd->status.storage.storage_amount > sd->storage_size )
+		return 0; // storage full / storage closed
 
 
 	if( index < 0 || index >= MAX_CART )
 	if( index < 0 || index >= MAX_CART )
-  		return 0;
+		return 0;
 
 
 	if( sd->status.cart[index].nameid <= 0 )
 	if( sd->status.cart[index].nameid <= 0 )
 		return 0; //No item there.
 		return 0; //No item there.
@@ -311,7 +311,7 @@ int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
 	short flag;
 	short flag;
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	if( index < 0 || index >= MAX_STORAGE )
+	if( index < 0 || index >= sd->storage_size )
 		return 0;
 		return 0;
 
 
 	if( sd->status.storage.items[index].nameid <= 0 )
 	if( sd->status.storage.items[index].nameid <= 0 )

+ 1 - 1
src/map/unit.c

@@ -2191,7 +2191,7 @@ int unit_skillcastcancel(struct block_list *bl,int type)
 			return 0;
 			return 0;
 
 
 		if (sd && (sd->special_state.no_castcancel2 ||
 		if (sd && (sd->special_state.no_castcancel2 ||
-                ((sd->sc.data[SC_UNLIMITEDHUMMINGVOICE] || sd->special_state.no_castcancel) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) // fixed flags being read the wrong way around [blackhole89]
+			((sd->sc.data[SC_UNLIMITEDHUMMINGVOICE] || sd->special_state.no_castcancel) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) // fixed flags being read the wrong way around [blackhole89]
 			return 0;
 			return 0;
 	}
 	}
 
 

+ 3 - 1
vcproj-10/char-server_sql.vcxproj

@@ -138,6 +138,7 @@
     <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
+    <ClInclude Include="..\src\common\conf.h" />
     <ClInclude Include="..\src\common\core.h" />
     <ClInclude Include="..\src\common\core.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\ers.h" />
     <ClInclude Include="..\src\common\ers.h" />
@@ -179,6 +180,7 @@
     <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
     <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
+    <ClCompile Include="..\src\common\conf.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\ers.c" />
     <ClCompile Include="..\src\common\ers.c" />
@@ -214,4 +216,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 11 - 1
vcproj-10/char-server_sql.vcxproj.filters

@@ -106,6 +106,11 @@
     <ClCompile Include="..\src\common\raconf.c">
     <ClCompile Include="..\src\common\raconf.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\src\common\msg_conf.c" />
+    <ClCompile Include="..\src\common\cli.c" />
+    <ClCompile Include="..\src\common\conf.c">
+      <Filter>common</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\src\common\cbasetypes.h">
     <ClInclude Include="..\src\common\cbasetypes.h">
@@ -228,6 +233,11 @@
     <ClInclude Include="..\src\common\raconf.h">
     <ClInclude Include="..\src\common\raconf.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\src\common\msg_conf.h" />
+    <ClInclude Include="..\src\common\cli.h" />
+    <ClInclude Include="..\src\common\conf.h">
+      <Filter>common</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Filter Include="common">
     <Filter Include="common">
@@ -246,4 +256,4 @@
       <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
       <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
-</Project>
+</Project>

+ 3 - 1
vcproj-10/login-server_sql.vcxproj

@@ -138,6 +138,7 @@
     <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
     <ClInclude Include="..\3rdparty\libconfig\scanner.h" />
     <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
     <ClInclude Include="..\3rdparty\libconfig\strbuf.h" />
     <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
     <ClInclude Include="..\3rdparty\libconfig\wincompat.h" />
+    <ClInclude Include="..\src\common\conf.h" />
     <ClInclude Include="..\src\common\mempool.h" />
     <ClInclude Include="..\src\common\mempool.h" />
     <ClInclude Include="..\src\common\mutex.h" />
     <ClInclude Include="..\src\common\mutex.h" />
     <ClInclude Include="..\src\common\raconf.h" />
     <ClInclude Include="..\src\common\raconf.h" />
@@ -172,6 +173,7 @@
     <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
     <ClCompile Include="..\3rdparty\libconfig\scanctx.c" />
     <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
     <ClCompile Include="..\3rdparty\libconfig\scanner.c" />
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
+    <ClCompile Include="..\src\common\conf.c" />
     <ClCompile Include="..\src\common\mempool.c" />
     <ClCompile Include="..\src\common\mempool.c" />
     <ClCompile Include="..\src\common\mutex.c" />
     <ClCompile Include="..\src\common\mutex.c" />
     <ClCompile Include="..\src\common\raconf.c" />
     <ClCompile Include="..\src\common\raconf.c" />
@@ -200,4 +202,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 11 - 1
vcproj-10/login-server_sql.vcxproj.filters

@@ -82,6 +82,11 @@
     <ClCompile Include="..\src\common\raconf.c">
     <ClCompile Include="..\src\common\raconf.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\src\common\msg_conf.c" />
+    <ClCompile Include="..\src\common\cli.c" />
+    <ClCompile Include="..\src\common\conf.c">
+      <Filter>common</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\src\login\account.h">
     <ClInclude Include="..\src\login\account.h">
@@ -180,6 +185,11 @@
     <ClInclude Include="..\src\common\raconf.h">
     <ClInclude Include="..\src\common\raconf.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\src\common\msg_conf.h" />
+    <ClInclude Include="..\src\common\cli.h" />
+    <ClInclude Include="..\src\common\conf.h">
+      <Filter>common</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Filter Include="common">
     <Filter Include="common">
@@ -198,4 +208,4 @@
       <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
       <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
-</Project>
+</Project>

+ 3 - 1
vcproj-12/char-server_sql.vcxproj

@@ -142,6 +142,7 @@
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\3rdparty\mt19937ar\mt19937ar.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\core.h" />
     <ClInclude Include="..\src\common\core.h" />
+    <ClInclude Include="..\src\common\conf.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\ers.h" />
     <ClInclude Include="..\src\common\ers.h" />
     <ClInclude Include="..\src\common\malloc.h" />
     <ClInclude Include="..\src\common\malloc.h" />
@@ -183,6 +184,7 @@
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\libconfig\strbuf.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
     <ClCompile Include="..\3rdparty\mt19937ar\mt19937ar.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\core.c" />
+    <ClCompile Include="..\src\common\conf.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\ers.c" />
     <ClCompile Include="..\src\common\ers.c" />
     <ClCompile Include="..\src\common\malloc.c" />
     <ClCompile Include="..\src\common\malloc.c" />
@@ -217,4 +219,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 7 - 1
vcproj-12/char-server_sql.vcxproj.filters

@@ -4,6 +4,9 @@
     <ClCompile Include="..\src\common\core.c">
     <ClCompile Include="..\src\common\core.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\src\common\conf.c">
+      <Filter>common</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\common\db.c">
     <ClCompile Include="..\src\common\db.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
@@ -114,6 +117,9 @@
     <ClInclude Include="..\src\common\core.h">
     <ClInclude Include="..\src\common\core.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\src\common\conf.h">
+      <Filter>common</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\common\db.h">
     <ClInclude Include="..\src\common\db.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
@@ -246,4 +252,4 @@
       <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
       <UniqueIdentifier>{9e8badd7-548f-4eb4-9e87-613e87e772ff}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
-</Project>
+</Project>

+ 3 - 1
vcproj-12/login-server_sql.vcxproj

@@ -153,6 +153,7 @@
     <ClInclude Include="..\src\login\loginlog.h" />
     <ClInclude Include="..\src\login\loginlog.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\cbasetypes.h" />
     <ClInclude Include="..\src\common\core.h" />
     <ClInclude Include="..\src\common\core.h" />
+    <ClInclude Include="..\src\common\conf.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\db.h" />
     <ClInclude Include="..\src\common\ers.h" />
     <ClInclude Include="..\src\common\ers.h" />
     <ClInclude Include="..\src\common\malloc.h" />
     <ClInclude Include="..\src\common\malloc.h" />
@@ -185,6 +186,7 @@
     <ClCompile Include="..\src\login\login.c" />
     <ClCompile Include="..\src\login\login.c" />
     <ClCompile Include="..\src\login\loginlog_sql.c" />
     <ClCompile Include="..\src\login\loginlog_sql.c" />
     <ClCompile Include="..\src\common\core.c" />
     <ClCompile Include="..\src\common\core.c" />
+    <ClCompile Include="..\src\common\conf.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\db.c" />
     <ClCompile Include="..\src\common\ers.c" />
     <ClCompile Include="..\src\common\ers.c" />
     <ClCompile Include="..\src\common\malloc.c" />
     <ClCompile Include="..\src\common\malloc.c" />
@@ -204,4 +206,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 7 - 1
vcproj-12/login-server_sql.vcxproj.filters

@@ -16,6 +16,9 @@
     <ClCompile Include="..\src\common\core.c">
     <ClCompile Include="..\src\common\core.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\src\common\conf.c">
+      <Filter>common</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\common\db.c">
     <ClCompile Include="..\src\common\db.c">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClCompile>
     </ClCompile>
@@ -102,6 +105,9 @@
     <ClInclude Include="..\src\common\core.h">
     <ClInclude Include="..\src\common\core.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\src\common\conf.h">
+      <Filter>common</Filter>
+    </ClInclude>
     <ClInclude Include="..\src\common\db.h">
     <ClInclude Include="..\src\common\db.h">
       <Filter>common</Filter>
       <Filter>common</Filter>
     </ClInclude>
     </ClInclude>
@@ -198,4 +204,4 @@
       <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
       <UniqueIdentifier>{779e8145-9bb2-4a88-9149-60586ab0bdd4}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
-</Project>
+</Project>

+ 2 - 2
vcproj-9/login-server_sql.vcproj

@@ -405,7 +405,7 @@
 			<File
 			<File
 				RelativePath="..\src\common\cli.c"
 				RelativePath="..\src\common\cli.c"
 				>
 				>
-			</File>						
+			</File>	
 			<File
 			<File
 				RelativePath="..\src\common\msg_conf.h"
 				RelativePath="..\src\common\msg_conf.h"
 				>
 				>
@@ -413,7 +413,7 @@
 			<File
 			<File
 				RelativePath="..\src\common\msg_conf.c"
 				RelativePath="..\src\common\msg_conf.c"
 				>
 				>
-			</File>				
+			</File>
 			
 			
 		</Filter>
 		</Filter>
 		<Filter
 		<Filter