Index: vcproj-10/login-server_sql.vcxproj =================================================================== --- vcproj-10/login-server_sql.vcxproj (revision 17327) +++ vcproj-10/login-server_sql.vcxproj (working copy) @@ -138,6 +138,7 @@ + @@ -172,6 +173,7 @@ + @@ -200,4 +202,4 @@ - \ No newline at end of file + Index: vcproj-10/char-server_sql.vcxproj =================================================================== --- vcproj-10/char-server_sql.vcxproj (revision 17327) +++ vcproj-10/char-server_sql.vcxproj (working copy) @@ -138,6 +138,7 @@ + @@ -179,6 +180,7 @@ + @@ -214,4 +216,4 @@ - \ No newline at end of file + Index: vcproj-10/login-server_sql.vcxproj.filters =================================================================== --- vcproj-10/login-server_sql.vcxproj.filters (revision 17327) +++ vcproj-10/login-server_sql.vcxproj.filters (working copy) @@ -82,6 +82,11 @@ common + + + + common + @@ -180,6 +185,11 @@ common + + + + common + @@ -198,4 +208,4 @@ {779e8145-9bb2-4a88-9149-60586ab0bdd4} - \ No newline at end of file + Index: vcproj-10/char-server_sql.vcxproj.filters =================================================================== --- vcproj-10/char-server_sql.vcxproj.filters (revision 17327) +++ vcproj-10/char-server_sql.vcxproj.filters (working copy) @@ -106,6 +106,11 @@ common + + + + common + @@ -228,6 +233,11 @@ common + + + + common + @@ -246,4 +256,4 @@ {9e8badd7-548f-4eb4-9e87-613e87e772ff} - \ No newline at end of file + Index: src/login/account_sql.c =================================================================== --- src/login/account_sql.c (revision 17327) +++ src/login/account_sql.c (working copy) @@ -7,6 +7,7 @@ #include "../common/sql.h" #include "../common/strlib.h" #include "../common/timer.h" +#include "../common/conf.h" //Inter_config #include "account.h" #include #include @@ -518,8 +519,62 @@ { Sql* sql_handle = db->accounts; char* data; - int i = 0; + int i = 0, acc_id = 0; + if( Inter_Config.vip_sys.enable ) { + ShowDebug("Reached login-server VIP system.\n"); + + ShowDebug("- Group ID: %d.\n", Inter_Config.vip_sys.group); + if( SQL_SUCCESS == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `group_id` < %d AND `account_id` = %d AND `vip_time` >= NOW()", db->account_db, Inter_Config.vip_sys.group, account_id) ){ + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ){ + Sql_GetData(sql_handle, 0, &data, NULL); acc_id = atoi(data); + ShowDebug("- Account ID: %d.\n", acc_id); + Sql_FreeResult(sql_handle); + } + } + else Sql_ShowDebug(sql_handle); + + if( acc_id ){ // Adjust to VIP group and add premium character slots. + if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `group_id` = %d, `character_slots` = %d WHERE `character_slots` < %d AND `account_id` = %d", db->account_db, Inter_Config.vip_sys.group, Inter_Config.vip_sys.char_increase, Inter_Config.vip_sys.char_increase, account_id)) + Sql_ShowDebug(sql_handle); + ShowDebug("- Increased character slots."); + acc_id = 0; + } + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` = %d AND `vip_time` != '0000-00-00 00:00:00' AND `vip_time` < NOW()", db->account_db, account_id) ){ + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ){ + Sql_GetData(sql_handle, 0, &data, NULL); acc_id = atoi(data); + Sql_FreeResult(sql_handle); + } + } + else Sql_ShowDebug(sql_handle); + + if( acc_id ){ // Adjust to VIP group and add premium character slots. + Sql_Query(sql_handle, "UPDATE `%s` SET `group_id` = 0, `character_slots` = 0 WHERE `account_id` = %d", db->account_db, account_id); + ShowDebug("- Decreased character slots."); + } + + // Check for VIP time and set if date has not been reached. +// if( SQL_SUCCESS == Sql_Query(sql_handle, +// "UPDATE `%s` SET `group_id` = %d WHERE `group_id` < %d AND `account_id` = %d AND `vip_time` >= NOW()", +// db->account_db, Inter_Config.vip_sys.group, Inter_Config.vip_sys.group, account_id) // Only update if group_id is lower. +// ) { + // Add premium character slots. +// Sql_Query(sql_handle, "UPDATE `%s` SET `character_slots` = %d WHERE `character_slots` < %d AND `account_id` = %d", db->account_db, Inter_Config.vip_sys.char_increase, Inter_Config.vip_sys.char_increase, account_id); +// } + + // Check for VIP time and remove if date has been passed. +// else if( SQL_SUCCESS == Sql_Query(sql_handle, +// "UPDATE `%s` SET `group_id` = 0 WHERE `account_id` = %d AND `vip_time` != '0000-00-00 00:00:00' AND `vip_time` < NOW()", +// db->account_db, account_id ) //@TODO return to previous group_id instead 0 ? +// ) { + // Remove premium character slots. + // Setting to 0 will cause the char_server to force it to server default (MIN_CHARS). + // Characters won't be deleted, they just won't be accessible. +// Sql_Query(sql_handle, "UPDATE `%s` SET `character_slots` = 0 WHERE `account_id` = %d", db->account_db, account_id); +// } + } + // retrieve login entry for the specified account if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change` FROM `%s` WHERE `account_id` = %d", Index: src/map/skill.c =================================================================== --- src/map/skill.c (revision 17327) +++ src/map/skill.c (working copy) @@ -13136,7 +13136,7 @@ * Warlock **/ 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 && ((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]); @@ -13857,11 +13857,11 @@ continue; break; case AB_ADORAMUS: - if( itemid_isgemstone(skill_db[idx].itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 2) ) + if( ( sd->special_state.no_gemstone != 2 ) && itemid_isgemstone(skill_db[idx].itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 2) ) continue; break; case WL_COMET: - if( itemid_isgemstone(skill_db[idx].itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 0) ) + if( ( sd->special_state.no_gemstone != 2 ) && itemid_isgemstone(skill_db[idx].itemid[i]) && skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 0) ) continue; break; case GN_FIRE_EXPANSION: @@ -13884,7 +13884,10 @@ req.itemid[i] = skill_db[idx].itemid[i]; req.amount[i] = skill_db[idx].amount[i]; - if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN ) + // Remove all Magic Stone required for all skills for VIP. + if( itemid_isgemstone(req.itemid[i]) && ( sd->special_state.no_gemstone == 2 ) ) + req.itemid[i] = req.amount[i] = 0; + else if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN ) { if( sd->special_state.no_gemstone ) { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica Index: src/map/clif.c =================================================================== --- src/map/clif.c (revision 17327) +++ src/map/clif.c (working copy) @@ -14098,7 +14098,7 @@ return; } - if( (item = itemdb_exists(sd->status.inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC) ) + if( (item = itemdb_exists(sd->status.inventory[idx].nameid)) != NULL && itemdb_available(sd->status.inventory[idx].nameid) && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC) ) { // Consumable or pets are not allowed clif_Auction_setitem(sd->fd, idx, true); return; Index: src/map/atcommand.c =================================================================== --- src/map/atcommand.c (revision 17327) +++ src/map/atcommand.c (working copy) @@ -7348,21 +7348,30 @@ ACMD_FUNC(rates) { char buf[CHAT_SIZE_MAX]; + int base_exp_rate = 0, job_exp_rate = 0, item_rate = 0; nullpo_ret(sd); memset(buf, '\0', sizeof(buf)); + // Display EXP and item rate increase for VIP. + if( ( Inter_Config.vip_sys.base_exp_increase || Inter_Config.vip_sys.job_exp_increase || Inter_Config.vip_sys.drop_increase ) && pc_get_vip(sd) ) { + base_exp_rate += Inter_Config.vip_sys.base_exp_increase; + job_exp_rate += Inter_Config.vip_sys.job_exp_increase; + + item_rate += Inter_Config.vip_sys.drop_increase; + } + 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); 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); 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); 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); return 0; @@ -8083,7 +8092,7 @@ { location = "storage"; items = sd->status.storage.items; - size = MAX_STORAGE; + size = sd->storage_size; } else if( strcmp(command+1, "cartlist") == 0 ) Index: src/map/mail.c =================================================================== --- src/map/mail.c (revision 17327) +++ src/map/mail.c (working copy) @@ -78,7 +78,7 @@ return 1; if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; - if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || + if( !pc_can_give_items(sd) || !itemdb_available(sd->status.inventory[idx].nameid) || sd->status.inventory[idx].expire_time || !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) ) return 1; Index: src/map/itemdb.c =================================================================== --- src/map/itemdb.c (revision 17327) +++ src/map/itemdb.c (working copy) @@ -1448,6 +1448,7 @@ for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ) { memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays pc_setinventorydata(sd); + pc_check_available_item(sd); // Check for invalid(ated) items in inventory/cart/storage. /* clear combo bonuses */ if( sd->combos.count ) { aFree(sd->combos.bonus); Index: src/map/pc.c =================================================================== --- src/map/pc.c (revision 17327) +++ src/map/pc.c (working copy) @@ -12,6 +12,7 @@ #include "../common/timer.h" #include "../common/utils.h" #include "../common/mmo.h" //NAME_LENGTH +#include "../common/conf.h" //Inter_config #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config @@ -38,6 +39,7 @@ #include "script.h" // script_config #include "skill.h" #include "status.h" // struct status_data +#include "storage.h" #include "pc.h" #include "pc_groups.h" #include "quest.h" @@ -1082,6 +1084,18 @@ clif_changemap(sd,sd->mapindex,sd->bl.x,sd->bl.y); } + // Increase storage size for VIP. + if( pc_get_vip(sd) ) { + int vip_size = Inter_Config.vip_sys.storage_increase; + + if( vip_size + MIN_STORAGE > MAX_STORAGE ) { + ShowError("pc_authok: 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; + } else + sd->storage_size = vip_size + MIN_STORAGE; + } else + sd->storage_size = MIN_STORAGE; + /** * Check if player have any cool downs on **/ @@ -1159,6 +1173,10 @@ sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT"); } + // Magic Stone requirement avoidance for VIP. + if( Inter_Config.vip_sys.magic_stone && pc_get_vip(sd) ) + sd->special_state.no_gemstone = 2; + //SG map and mob read [Komurka] for(i=0;istatus.account_id, sd->status.char_id); + pc_check_available_item(sd); // Check for invalid(ated) items in inventory/cart/storage. + pc_load_combo(sd); status_calc_pc(sd,1); @@ -2431,7 +2451,8 @@ break; case SP_NO_GEMSTONE: if(sd->state.lr_flag != 2) - sd->special_state.no_gemstone = 1; + if( sd->special_state.no_gemstone != 2 ) + sd->special_state.no_gemstone = 1; break; case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG] if(sd->state.lr_flag != 2) { @@ -5745,8 +5766,13 @@ (int)(status_get_lv(src) - sd->status.base_level) >= 20) bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris] - if (sd->sc.data[SC_EXPBOOST]) - bonus += sd->sc.data[SC_EXPBOOST]->val1; + if (sd->sc.data[SC_EXPBOOST]) { + // Increase Battle Manual EXP rate for VIP. + if( Inter_Config.vip_sys.bm_increase && pc_get_vip(sd) ) + bonus += sd->sc.data[SC_EXPBOOST]->val1 + ( sd->sc.data[SC_EXPBOOST]->val1 / Inter_Config.vip_sys.bm_increase ); + else + bonus += sd->sc.data[SC_EXPBOOST]->val1; + } *base_exp = (unsigned int) cap_value(*base_exp + (double)*base_exp * bonus/100., 1, UINT_MAX); @@ -6804,39 +6830,38 @@ && !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m) && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE]) { - unsigned int base_penalty =0; - if (battle_config.death_penalty_base > 0) { + unsigned int base_penalty = battle_config.death_penalty_base, job_penalty = battle_config.death_penalty_job; + if( ( Inter_Config.vip_sys.base_exp_penalty || Inter_Config.vip_sys.job_exp_penalty ) && pc_get_vip(sd) ) { // Decrease EXP penalty for VIP. + base_penalty -= Inter_Config.vip_sys.base_exp_penalty; + job_penalty -= Inter_Config.vip_sys.job_exp_penalty; + } + if (base_penalty > 0) { switch (battle_config.death_penalty_type) { case 1: - base_penalty = (unsigned int) ((double)pc_nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000); + base_penalty = (unsigned int) ((double)pc_nextbaseexp(sd) * (double)base_penalty/10000); break; case 2: - base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000); + base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)base_penalty/10000); break; } - if(base_penalty) { - if (battle_config.pk_mode && src && src->type==BL_PC) - base_penalty*=2; - sd->status.base_exp -= min(sd->status.base_exp, base_penalty); - clif_updatestatus(sd,SP_BASEEXP); - } + if (battle_config.pk_mode && src && src->type==BL_PC) + base_penalty*=2; + sd->status.base_exp -= min(sd->status.base_exp, base_penalty); + clif_updatestatus(sd,SP_BASEEXP); } - if(battle_config.death_penalty_job > 0) { - base_penalty = 0; + if(job_penalty > 0) { switch (battle_config.death_penalty_type) { case 1: - base_penalty = (unsigned int) ((double)pc_nextjobexp(sd) * (double)battle_config.death_penalty_job/10000); + job_penalty = (unsigned int) ((double)pc_nextjobexp(sd) * (double)job_penalty/10000); break; case 2: - base_penalty = (unsigned int) ((double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000); + job_penalty = (unsigned int) ((double)sd->status.job_exp * (double)job_penalty/10000); break; } - if(base_penalty) { - if (battle_config.pk_mode && src && src->type==BL_PC) - base_penalty*=2; - sd->status.job_exp -= min(sd->status.job_exp, base_penalty); - clif_updatestatus(sd,SP_JOBEXP); - } + if (battle_config.pk_mode && src && src->type==BL_PC) + job_penalty*=2; + sd->status.job_exp -= min(sd->status.job_exp, job_penalty); + clif_updatestatus(sd,SP_JOBEXP); } if(battle_config.zeny_penalty > 0 && !map[sd->bl.m].flag.nozenypenalty) { base_penalty = (unsigned int)((double)sd->status.zeny * (double)battle_config.zeny_penalty / 10000.); @@ -8878,54 +8903,86 @@ *------------------------------------------*/ int pc_checkitem(struct map_session_data *sd) { - int i,id,calc_flag = 0; + int i,calc_flag = 0; nullpo_ret(sd); if( sd->state.vending ) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam) return 0; - if( battle_config.item_check ) {// check for invalid(ated) items + for( i = 0; i < MAX_INVENTORY; i++) { + + if( sd->status.inventory[i].nameid == 0 ) + continue; + + if( !sd->status.inventory[i].equip ) + continue; + + if( sd->status.inventory[i].equip&~pc_equippoint(sd,i) ) { + pc_unequipitem(sd, i, 2); + calc_flag = 1; + continue; + } + + } + + if( calc_flag && sd->state.active ) { + pc_checkallowskill(sd); + status_calc_pc(sd,0); + } + + return 0; +} + +/*========================================== + * Checks for unavailable items and removes them. + *------------------------------------------*/ +int pc_check_available_item(struct map_session_data *sd) +{ + int i, id; + char output[256]; + + nullpo_ret(sd); + + if( battle_config.item_check&1 ) { // Check for invalid(ated) items in inventory. for( i = 0; i < MAX_INVENTORY; i++ ) { id = sd->status.inventory[i].nameid; if( id && !itemdb_available(id) ) { + sprintf(output, msg_txt(sd, 695), id); // Item %d has been removed from your inventory. + clif_displaymessage(sd->fd, output); ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id); pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); } } + } + if( battle_config.item_check&2 ) { // Check for invalid(ated) items in cart. for( i = 0; i < MAX_CART; i++ ) { id = sd->status.cart[i].nameid; if( id && !itemdb_available(id) ) { + sprintf(output, msg_txt(sd, 696), id); // Item %d has been removed from your cart. + clif_displaymessage(sd->fd, output); ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id); pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER); } } } - for( i = 0; i < MAX_INVENTORY; i++) { + if( battle_config.item_check&4 ) { // Check for invalid(ated) items in storage. + for( i = 0; i < sd->storage_size; i++ ) { + id = sd->status.storage.items[i].nameid; - if( sd->status.inventory[i].nameid == 0 ) - continue; - - if( !sd->status.inventory[i].equip ) - continue; - - if( sd->status.inventory[i].equip&~pc_equippoint(sd,i) ) { - pc_unequipitem(sd, i, 2); - calc_flag = 1; - continue; + if( id && !itemdb_available(id) ) { + sprintf(output, msg_txt(sd, 697), id); // Item %d has been removed from your storage. + clif_displaymessage(sd->fd, output); + ShowWarning("Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, sd->status.storage.items[i].amount, sd->status.char_id); + storage_delitem(sd, i, sd->status.storage.items[i].amount); + } } - } - if( calc_flag && sd->state.active ) { - pc_checkallowskill(sd); - status_calc_pc(sd,0); - } - return 0; } Index: src/map/pc.h =================================================================== --- src/map/pc.h (revision 17327) +++ src/map/pc.h (working copy) @@ -178,7 +178,7 @@ unsigned int no_castcancel : 1; unsigned int no_castcancel2 : 1; unsigned int no_sizefix : 1; - unsigned int no_gemstone : 1; + unsigned int no_gemstone : 2; // 1: Mistress Card effect, 2: VIP effect unsigned int intravision : 1; // Maya Purple Card effect [DracoRPG] unsigned int perfect_hiding : 1; // [Valaris] unsigned int no_knockback : 1; @@ -515,6 +515,9 @@ const char* delunit_prevfile; int delunit_prevline; + // Holds player storage size (VIP system). + int storage_size; + }; //Update this max as necessary. 55 is the value needed for Super Baby currently @@ -669,6 +672,8 @@ ) #define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)class_) +#define pc_get_vip(sd) ( Inter_Config.vip_sys.group && ( pc_get_group_id(sd) == Inter_Config.vip_sys.group ) ? 1 : 0 ) + // clientside display macros (values to the left/right of the "+") #ifdef RENEWAL #define pc_leftside_atk(sd) ((sd)->battle_status.batk) @@ -813,6 +818,7 @@ int pc_equipitem(struct map_session_data*,int,int); int pc_unequipitem(struct map_session_data*,int,int); int pc_checkitem(struct map_session_data*); +int pc_check_available_item(struct map_session_data *sd); int pc_useitem(struct map_session_data*,int); int pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id); Index: src/map/storage.c =================================================================== --- src/map/storage.c (revision 17327) +++ src/map/storage.c (working copy) @@ -107,7 +107,7 @@ sd->state.storage_flag = 1; storage_sortitem(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; } @@ -156,7 +156,7 @@ if( itemdb_isstackable2(data) ) {//Stackable - for( i = 0; i < MAX_STORAGE; i++ ) + for( i = 0; i < sd->storage_size; i++ ) { if( compare_item(&stor->items[i], item_data) ) {// existing items found, stack them @@ -170,8 +170,8 @@ } // find free slot - ARR_FIND( 0, MAX_STORAGE, i, stor->items[i].nameid == 0 ); - if( i >= MAX_STORAGE ) + ARR_FIND( 0, sd->storage_size, i, stor->items[i].nameid == 0 ); + if( i >= sd->storage_size ) return 1; // add item to slot @@ -179,7 +179,7 @@ stor->storage_amount++; stor->items[i].amount = 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; } @@ -197,7 +197,7 @@ { memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0])); 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); return 0; @@ -214,7 +214,7 @@ { nullpo_ret(sd); - if( sd->status.storage.storage_amount > MAX_STORAGE ) + if( sd->status.storage.storage_amount > sd->storage_size ) return 0; // storage full if( index < 0 || index >= MAX_INVENTORY ) @@ -243,7 +243,7 @@ { int flag; - if( index < 0 || index >= MAX_STORAGE ) + if( index < 0 || index >= sd->storage_size ) return 0; if( sd->status.storage.items[index].nameid <= 0 ) @@ -271,7 +271,7 @@ { 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 if( index < 0 || index >= MAX_CART ) @@ -300,7 +300,7 @@ { nullpo_ret(sd); - if( index < 0 || index >= MAX_STORAGE ) + if( index < 0 || index >= sd->storage_size ) return 0; if( sd->status.storage.items[index].nameid <= 0 ) Index: src/map/battle.c =================================================================== --- src/map/battle.c (revision 17327) +++ src/map/battle.c (working copy) @@ -5669,7 +5669,7 @@ { "max_heal_lv", &battle_config.max_heal_lv, 11, 1, INT_MAX, }, { "max_heal", &battle_config.max_heal, 9999, 0, INT_MAX, }, { "combo_delay_rate", &battle_config.combo_delay_rate, 100, 0, INT_MAX, }, - { "item_check", &battle_config.item_check, 0, 0, 1, }, + { "item_check", &battle_config.item_check, 0, 0, 7, }, { "item_use_interval", &battle_config.item_use_interval, 100, 0, INT_MAX, }, { "cashfood_use_interval", &battle_config.cashfood_use_interval, 60000, 0, INT_MAX, }, { "wedding_modifydisplay", &battle_config.wedding_modifydisplay, 0, 0, 1, }, Index: src/map/mob.c =================================================================== --- src/map/mob.c (revision 17327) +++ src/map/mob.c (working copy) @@ -12,6 +12,7 @@ #include "../common/strlib.h" #include "../common/utils.h" #include "../common/socket.h" +#include "../common/conf.h" //Inter_config #include "map.h" #include "path.h" @@ -2245,13 +2246,23 @@ if (map[m].flag.nobaseexp || !md->db->base_exp) base_exp = 0; - else + else { + // Increase base EXP rate for VIP. + if( Inter_Config.vip_sys.base_exp_increase && ( sd && pc_get_vip(sd) ) ) + bonus += Inter_Config.vip_sys.base_exp_increase; + base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].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. job_exp = 0; - else + else { + // Increase job EXP rate for VIP. + if( Inter_Config.vip_sys.job_exp_increase && ( sd && pc_get_vip(sd) ) ) + bonus += Inter_Config.vip_sys.job_exp_increase; + job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].jexp/100., 1, UINT_MAX); + } if ( ( temp = tmpsd[i]->status.party_id)>0 ) { int j; @@ -2371,6 +2382,11 @@ drop_rate = 1; } #endif + + // Increase item drop rate for VIP. + if( Inter_Config.vip_sys.drop_increase && ( sd && pc_get_vip(sd) ) ) + drop_rate += (int)(0.5+drop_rate*Inter_Config.vip_sys.drop_increase/100.); + // attempt to drop the item if (rnd() % 10000 >= drop_rate) continue; Index: src/char/char.c =================================================================== --- src/char/char.c (revision 17327) +++ src/char/char.c (working copy) @@ -108,7 +108,6 @@ #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] -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_delay = 86400; @@ -1408,8 +1407,6 @@ { 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 ... //if the server connects to loginserver //it will dc all off players @@ -1548,9 +1545,9 @@ //check other inputs #if PACKETVER >= 20120307 - if(slot >= sd->char_slots) + if(slot < 0 || slot >= sd->char_slots) #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 < 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 @@ -1561,14 +1558,11 @@ return -2; // invalid input #endif - // check the number of already existing chars in this account - if( char_per_account != 0 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) >= char_per_account ) - return -2; // character account limit exceeded - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) + Sql_ShowDebug(sql_handle); + if( Sql_NumRows(sql_handle) >= MAX_CHARS ) + return -2; // character account limit exceeded // 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) ) @@ -2242,7 +2236,7 @@ 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 */ } 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->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode)); sd->pincode_change = (time_t)RFIFOL(fd,68); @@ -5044,13 +5038,6 @@ char_name_option = atoi(w2); } else if (strcmpi(w1, "char_name_letters") == 0) { 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] char_del_level = atoi(w2); } else if (strcmpi(w1, "char_del_delay") == 0) { Index: src/common/core.c =================================================================== --- src/common/core.c (revision 17327) +++ src/common/core.c (working copy) @@ -5,6 +5,7 @@ #include "showmsg.h" #include "malloc.h" #include "core.h" +#include "conf.h" #ifndef MINICORE #include "db.h" #include "socket.h" @@ -334,6 +335,8 @@ timer_init(); socket_init(); + inter_conf_read(); + do_init(argc,argv); {// Main runtime cycle Index: src/common/mmo.h =================================================================== --- src/common/mmo.h (revision 17327) +++ src/common/mmo.h (working copy) @@ -71,8 +71,8 @@ #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps #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. -#define MAX_CHARS 9 +#define MIN_CHARS 9 // Default number of characters per account. +#define MAX_CHARS 15 // 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. //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. #define MAX_SLOTS 4 @@ -90,7 +90,8 @@ #define DEFAULT_WALK_SPEED 150 #define MIN_WALK_SPEED 0 #define MAX_WALK_SPEED 1000 -#define MAX_STORAGE 600 +#define MIN_STORAGE 300 // Default number of storage slots. +#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_PARTY 12 #define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] Index: src/common/conf.c =================================================================== --- src/common/conf.c (revision 17327) +++ src/common/conf.c (working copy) @@ -3,6 +3,8 @@ #include "conf.h" #include "libconfig.h" +#include "utils.h" +#include "mmo.h" #include "../common/showmsg.h" // ShowError @@ -64,7 +66,7 @@ config_setting_set_format(set, src->format); } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); + config_setting_set_format(set, src->format); } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { @@ -85,10 +87,10 @@ return; n = config_setting_length(src); - + for (i = 0; i < n; i++) { if (config_setting_is_group(src)) { - config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); + config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); } else { config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); } @@ -107,3 +109,60 @@ } return CONFIG_TRUE; } + +// +// Global configuration settings. +// +//void inter_conf_read(void); + +void inter_conf_read(void){ + config_t inter_conf; + config_setting_t *sys = NULL; + const char *config_filename = "conf/inter_battle.conf"; + + if (conf_read_file(&inter_conf, config_filename)) + return; + + sys = config_lookup(&inter_conf, "vip_sys"); + if (sys != NULL) { //reading vip_sys part + config_setting_t *settings = config_setting_get_elem(sys, 0); + int enable; //:1 + int group; + int magic_stone; //:1 + int storage_increase; + int char_increase; + int base_exp_increase; + int job_exp_increase; + int base_exp_penalty; + int job_exp_penalty; + int bm_increase; + int drop_increase; + + config_setting_lookup_bool(settings, "enable", &enable); + Inter_Config.vip_sys.enable = enable; + + if( enable ) { + config_setting_lookup_int(settings, "group", &group); + config_setting_lookup_int(settings, "storage_increase", &storage_increase); + config_setting_lookup_int(settings, "char_increase", &char_increase); + config_setting_lookup_int(settings, "base_exp_increase", &base_exp_increase); + config_setting_lookup_int(settings, "job_exp_increase", &job_exp_increase); + config_setting_lookup_int(settings, "base_exp_penalty", &base_exp_penalty); + config_setting_lookup_int(settings, "job_exp_penalty", &job_exp_penalty); + config_setting_lookup_int(settings, "bm_increase", &bm_increase); + config_setting_lookup_int(settings, "drop_increase", &drop_increase); + config_setting_lookup_bool(settings, "magic_stone", &magic_stone); + } + + Inter_Config.vip_sys.group = cap_value(group,0,99); + Inter_Config.vip_sys.storage_increase = cap_value(storage_increase,0,MAX_STORAGE-MIN_STORAGE); + Inter_Config.vip_sys.char_increase = cap_value(char_increase,0,MAX_CHARS-MIN_CHARS); + Inter_Config.vip_sys.base_exp_increase = cap_value(base_exp_increase,0,INT_MAX); + Inter_Config.vip_sys.job_exp_increase = cap_value(job_exp_increase,0,INT_MAX); + Inter_Config.vip_sys.base_exp_penalty = cap_value(base_exp_penalty,0,INT_MAX); + Inter_Config.vip_sys.job_exp_penalty = cap_value(job_exp_penalty,0,INT_MAX); + Inter_Config.vip_sys.bm_increase = cap_value(bm_increase,0,INT_MAX); + Inter_Config.vip_sys.drop_increase = cap_value(drop_increase,0,INT_MAX); + Inter_Config.vip_sys.magic_stone = magic_stone; + } +} Index: src/common/conf.h =================================================================== --- src/common/conf.h (revision 17327) +++ src/common/conf.h (working copy) @@ -7,6 +7,24 @@ #include "../common/cbasetypes.h" #include "libconfig.h" +struct { + struct { + unsigned int enable : 1; + unsigned int group; + unsigned int storage_increase; + unsigned int char_increase; + unsigned int base_exp_increase; + unsigned int job_exp_increase; + unsigned int base_exp_penalty; + unsigned int job_exp_penalty; + unsigned int bm_increase; + unsigned int drop_increase; + unsigned int magic_stone : 1; + } vip_sys; +} Inter_Config; + +void inter_conf_read(void); + int conf_read_file(config_t *config, const char *config_filename); int config_setting_copy(config_setting_t *parent, const config_setting_t *src); Index: conf/msg_conf/map_msg.conf =================================================================== --- conf/msg_conf/map_msg.conf (revision 17327) +++ conf/msg_conf/map_msg.conf (working copy) @@ -635,7 +635,6 @@ 678: You are no longer the Guild Master. 679: You have become the Guild Master! 680: You have been recovered! -//681-899 free 681: Rune Knight T 682: Warlock T @@ -652,6 +651,10 @@ 693: Shadow Chaser T 694: Hanbok +695: Item %d has been removed from your inventory. +696: Item %d has been removed from your cart. +697: Item %d has been removed from your storage. +//698-899 free //------------------------------------ // More atcommands message Index: conf/groups.conf =================================================================== --- conf/groups.conf (revision 17327) +++ conf/groups.conf (working copy) @@ -97,6 +97,18 @@ }, { id: 1 + name: "VIP" + inherit: ( "Player" ) /* can do everything Players can */ + level: 0 + commands: { + /* no commands by default */ + } + permissions: { + /* no permissions by default */ + } +}, +{ + id: 2 name: "Super Player" inherit: ( "Player" ) /* can do everything Players can and more */ level: 0 @@ -136,7 +148,7 @@ } }, { - id: 2 + id: 3 name: "Support" inherit: ( "Super Player" ) level: 1 @@ -161,7 +173,7 @@ } }, { - id: 3 + id: 4 name: "Script Manager" inherit: ( "Support" ) level: 1 @@ -180,7 +192,7 @@ } }, { - id: 4 + id: 5 name: "Event Manager" inherit: ( "Support" ) level: 1 Index: conf/battle/exp.conf =================================================================== --- conf/battle/exp.conf (revision 17327) +++ conf/battle/exp.conf (working copy) @@ -70,10 +70,10 @@ death_penalty_type: 1 // Base exp. penalty rate (Each 100 is 1% of their exp) -death_penalty_base: 100 +death_penalty_base: 300 // Job exp. penalty rate (Each 100 is 1% of their exp) -death_penalty_job: 100 +death_penalty_job: 300 // When a player dies (to another player), how much zeny should we penalize them with? // NOTE: It is a percentage of their zeny, so 100 = 1% Index: conf/battle/items.conf =================================================================== --- conf/battle/items.conf (revision 17327) +++ conf/battle/items.conf (working copy) @@ -51,12 +51,16 @@ // NOTE: Wedding Rings and Whips/Musical Instruments will check gender regardless of setting. ignore_items_gender: yes -// Item check? (Note 1) +// Item check? (Note 3) // On map change it will check for items not tagged as "available" and -// auto-delete them from inventory/cart. +// auto-delete them from inventory/cart. Items are auto-deleted from +// storage when the character data is saved. // NOTE: An item is not available if it was not loaded from the item_db or you // specify it as unavailable in db/item_avail.txt -item_check: no +// 1: Inventory +// 2: Cart +// 4: Storage +item_check: 0 // How much time must pass between item uses? // Only affects the delay between using items, prevents healing item abuse. Recommended ~500 ms Index: conf/char_athena.conf =================================================================== --- conf/char_athena.conf (revision 17327) +++ conf/char_athena.conf (working copy) @@ -140,11 +140,6 @@ // Note: Don't add spaces unless you mean to add 'space' to the list. 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 // 0: no restriction (players can delete characters of any level) // -X: you can't delete chars with BaseLevel <= X Index: sql-files/main.sql =================================================================== --- sql-files/main.sql (revision 17327) +++ sql-files/main.sql (working copy) @@ -442,6 +442,7 @@ `character_slots` tinyint(3) unsigned NOT NULL default '0', `pincode` varchar(4) NOT NULL DEFAULT '', `pincode_change` int(11) unsigned NOT NULL DEFAULT '0', + `vip_time` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`account_id`), KEY `name` (`userid`) ) ENGINE=MyISAM AUTO_INCREMENT=2000000;