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.
This commit is contained in:
aleos89 2013-11-18 15:19:52 -05:00
parent 24ca5b5c3c
commit 30648216ec
40 changed files with 944 additions and 241 deletions

View File

@ -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)
@ -142,3 +144,47 @@ 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

View File

@ -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

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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) ) if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) )
Sql_ShowDebug(sql_handle); Sql_ShowDebug(sql_handle);
if( Sql_NumRows(sql_handle) >= char_per_account ) if( Sql_NumRows(sql_handle) >= sd->char_slots )
return -2; // character account limit exceeded 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,4) = MAX_CHARS; // Max slots
WFIFOB(fd,5) = sd->char_slots; // Available slots. (PremiumStartSlot) WFIFOB(fd,5) = MAX_CHARS - sd->chars_billing - sd->chars_vip; // 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) 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 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,4) = MAX_CHARS - sd->chars_billing - sd->chars_vip; //NormalSlotNum
WFIFOB(fd,5) = MAX_CHARS - sd->char_slots; WFIFOB(fd,5) = sd->chars_vip; //PremiumSlotNum
WFIFOB(fd,6) = MAX_CHARS - sd->char_slots; WFIFOB(fd,6) = sd->chars_billing; //BillingSlotNum
WFIFOB(fd,7) = sd->char_slots; WFIFOB(fd,7) = sd->char_slots; //ProducibleSlotNum
WFIFOB(fd,8) = sd->char_slots; 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);
@ -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)
@ -2297,7 +2375,6 @@ int logif_parse_reqpincode(int fd, struct char_session_data *sd){
} else { } else {
if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){ 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 ); 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 if( node != NULL && node->pincode_success ){ // User has already passed the check
pincode_sendstate( fd, sd, PINCODE_PASSED ); pincode_sendstate( fd, sd, PINCODE_PASSED );
}else{ }else{
@ -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) {

View File

@ -71,6 +71,7 @@
#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.
//Max value tested was 265
#define MAX_CHARS 9 #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.
@ -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]

View File

@ -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;

View File

@ -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_ */

View File

@ -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
**/ **/

View File

@ -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)
}; };

View File

@ -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,
#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", "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);

View File

@ -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) * Converting a timestamp is a srintf according to format
//----------------------------------------------------- * safefr then strftime as it ensure \0 at end of string
const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) * @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 case 0x2716: chrif_parse_reqaccdata(fd,id,ip); break; // 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 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 = MIN_CHARS;
acc.char_slots = 0;
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 else if(!strcmpi(w1, "account.engine"))
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 else {// try the account engines
{// try the account engines
int i; int i;
for( i = 0; account_engines[i].constructor; ++i ) for( i = 0; account_engines[i].constructor; ++i )
{ {

View File

@ -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;

View File

@ -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;

View File

@ -7233,6 +7233,16 @@ 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, }, { "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_woe_change", &battle_config.emblem_woe_change, 0, 0, 1, },

View File

@ -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;

View File

@ -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 //2b2b: Incoming, chrif_parse_ack_vipActive -> vip info result
//2b2c: FREE //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);

View File

@ -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);

View File

@ -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;
@ -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;
@ -6342,6 +6344,7 @@ void clif_bank_withdraw(struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK
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;
@ -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";
@ -17578,6 +17647,9 @@ void packetdb_readdb(void)
{ "ZC_ACK_BANKING_DEPOSIT", ZC_ACK_BANKING_DEPOSIT}, { "ZC_ACK_BANKING_DEPOSIT", ZC_ACK_BANKING_DEPOSIT},
{ "ZC_ACK_BANKING_WITHDRAW", ZC_ACK_BANKING_WITHDRAW}, { "ZC_ACK_BANKING_WITHDRAW", ZC_ACK_BANKING_WITHDRAW},
{ "ZC_BANKING_CHECK", ZC_BANKING_CHECK}, { "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

View File

@ -44,6 +44,9 @@ enum e_packet_ack {
ZC_ACK_BANKING_DEPOSIT, ZC_ACK_BANKING_DEPOSIT,
ZC_ACK_BANKING_WITHDRAW, ZC_ACK_BANKING_WITHDRAW,
ZC_BANKING_CHECK, ZC_BANKING_CHECK,
ZC_PERSONAL_INFOMATION,
ZC_PERSONAL_INFOMATION_CHN,
//add otehr here
MAX_ACK_FUNC //auto upd len MAX_ACK_FUNC //auto upd len
}; };
@ -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
**/ **/

View File

@ -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 else {
base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].adjust.bexp/100., 1, UINT_MAX); 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 else {
job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].adjust.jexp/100., 1, UINT_MAX); 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;

View File

@ -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]) if (sd->sc.data[SC_EXPBOOST]) {
bonus += sd->sc.data[SC_EXPBOOST]->val1; 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; unsigned int base_penalty = battle_config.death_penalty_base, job_penalty = battle_config.death_penalty_job;
if (battle_config.death_penalty_base > 0) { #ifdef VIP_ENABLE
switch (battle_config.death_penalty_type) { if(pc_isvip(sd)){
case 1: base_penalty = base_penalty*battle_config.vip_exp_penalty_base;
base_penalty = (unsigned int) ((double)pc_nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000); job_penalty = job_penalty*battle_config.vip_exp_penalty_job;
break;
case 2:
base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000);
break;
} }
if(base_penalty) { 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) {
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 > 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) { if(job_penalty > 0) {
base_penalty = 0;
switch (battle_config.death_penalty_type) { switch (battle_config.death_penalty_type) {
case 1: case 1: job_penalty = (uint32) ((double)(pc_nextjobexp(sd) * job_penalty)/10000); break;
base_penalty = (unsigned int) ((double)pc_nextjobexp(sd) * (double)battle_config.death_penalty_job/10000); case 2: job_penalty = (uint32) ((double)(sd->status.job_exp * job_penalty)/10000); break;
break;
case 2:
base_penalty = (unsigned int) ((double)sd->status.job_exp * (double)battle_config.death_penalty_job/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; job_penalty*=2;
sd->status.job_exp -= min(sd->status.job_exp, base_penalty); 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) ) {

View File

@ -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

View File

@ -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"

View File

@ -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,8 +14481,11 @@ 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 ) // 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 ) if( sd->special_state.no_gemstone )
{ // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica
if( skill_id != SA_ABRACADABRA ) if( skill_id != SA_ABRACADABRA )
@ -14498,6 +14501,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
req.amount[i] = 1; // Hocus Pocus always use at least 1 gem 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){
int16 itIndex; int16 itIndex;
if( (itIndex = pc_search_inventory(sd,req.itemid[i])) < 0 || ( itIndex >= 0 && sd->status.inventory[itIndex].amount < req.amount[i] ) ){ if( (itIndex = pc_search_inventory(sd,req.itemid[i])) < 0 || ( itIndex >= 0 && sd->status.inventory[itIndex].amount < req.amount[i] ) ){

View File

@ -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 ); ARR_FIND( 0, sd->storage_size, i, stor->items[i].nameid == 0 );
if( i >= MAX_STORAGE ) 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,7 +281,7 @@ 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 ) if( sd->status.storage.storage_amount > sd->storage_size )
return 0; // storage full / storage closed return 0; // storage full / storage closed
if( index < 0 || index >= MAX_CART ) if( index < 0 || index >= MAX_CART )
@ -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 )

View File

@ -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" />

View File

@ -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">

View File

@ -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" />

View File

@ -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">

View File

@ -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" />

View File

@ -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>

View File

@ -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" />

View File

@ -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>