Index: src/common/mmo.h =================================================================== --- src/common/mmo.h (revision 17374) +++ src/common/mmo.h (working copy) @@ -47,8 +47,8 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120410 - //#define PACKETVER 20130320 + //#define PACKETVER 20120410 + #define PACKETVER 20130320 //#define PACKETVER 20111116 #endif Index: src/config/core.h =================================================================== --- src/config/core.h (revision 17374) +++ src/config/core.h (working copy) @@ -29,7 +29,7 @@ /// Uncomment to disable rAthena's anonymous stat report /// We kindly ask you to consider keeping it enabled, it helps us improve rAthena. -//#define STATS_OPT_OUT +#define STATS_OPT_OUT /// uncomment to enable query_sql script command and mysql logs to function on it's own thread /// be aware this feature is under tests and you should use at your own risk, we however Index: src/map/pc.c =================================================================== --- src/map/pc.c (revision 17374) +++ src/map/pc.c (working copy) @@ -9661,11 +9661,147 @@ } #endif + +//Reading job_db1.txt line, (class,weight,HPFactor,HPMultiplicator,SPFactor,aspdlvl...) +static bool pc_readdb_job1(char* fields[], int columns, int current){ + int idx, class_; + unsigned int i; + + class_ = atoi(fields[0]); + + if(!pcdb_checkid(class_)) + { + ShowWarning("status_readdb_job1: Invalid job class %d specified.\n", class_); + return false; + } + idx = pc_class2idx(class_); + + job_info[idx].max_weight_base = atoi(fields[1]); + job_info[idx].hp_factor = atoi(fields[2]); + job_info[idx].hp_multiplicator = atoi(fields[3]); + job_info[idx].sp_factor = atoi(fields[4]); +#ifdef RENEWAL_ASPD + for(i = 0; i <= MAX_WEAPON_TYPE; i++) +#else + for(i = 0; i < MAX_WEAPON_TYPE; i++) +#endif + { + job_info[idx].aspd_base[i] = atoi(fields[i+5]); + } + return true; +} + +//Reading job_db2.txt line (class,JobLv1,JobLv2,JobLv3,...) +static bool pc_readdb_job2(char* fields[], int columns, int current) +{ + int idx, class_, i; + + class_ = atoi(fields[0]); + + if(!pcdb_checkid(class_)) + { + ShowWarning("status_readdb_job2: Invalid job class %d specified.\n", class_); + return false; + } + idx = pc_class2idx(class_); + + for(i = 1; i < columns; i++) + { + job_info[idx].job_bonus[i-1] = atoi(fields[i]); + } + return true; +} + +//Reading job_maxhpsp.txt line +//startlvl,maxlvl,class,type,values... +static bool pc_readdb_job_maxhpsp(char* fields[], int columns, int current) +{ + int idx, i,j, maxlvl, startlvl; + int job_id,job_count,jobs[CLASS_COUNT]; + int type; + + startlvl = atoi(fields[0]); + if(startlvl > MAX_LEVEL || startlvl<1){ + ShowError("pc_readdb_job_maxhpsp: Invalid startlvl %d specified.\n", startlvl); + return false; + } + maxlvl = atoi(fields[1]); + if(maxlvl > MAX_LEVEL || maxlvl<1){ + ShowError("pc_readdb_job_maxhpsp: Invalid maxlevel %d specified.\n", maxlvl); + return false; + } + if((maxlvl-startlvl+1+4) != columns){ //nb values = (maxlvl-startlvl)+1-index1stvalue + ShowError("pc_readdb_job_maxhpsp: Number of colums=%d defined is too low for startlevel=%d,maxlevel=%d\n",columns,startlvl,maxlvl); + return false; + } + type = atoi(fields[3]); + if(type < 0 || type > 1){ + ShowError("pc_readdb_job_maxhpsp: Invalid type %d specified, only [0;1] is valid.\n", type); + return false; + } + job_count = pc_split_atoi(fields[2],jobs,':',CLASS_COUNT); + if (job_count < 1) + return false; + for (j = 0; j < job_count; j++) { + job_id = jobs[j]; + if(!pcdb_checkid(job_id)){ + ShowError("pc_readdb_job_maxhpsp: Invalid job class %d specified.\n", job_id); + return false; + } + idx = pc_class2idx(job_id); + if(job_info[idx].max_level && job_info[idx].max_level != maxlvl){ + ShowWarning("pc_readdb_job_maxhpsp: maxlevel %d was already specified with different value %d, (skipping assignment).\n",maxlvl,job_info[idx].max_level); + } + else job_info[idx].max_level = maxlvl; + if(type == 0){ //hp type + unsigned int k = 0; + unsigned int val, oldval=0; + for(i = 1; i <= MAX_LEVEL; i++) { + val = 0; + k += (job_info[idx].hp_factor*i + 50) / 100; + if(i>=startlvl && i <=maxlvl) val = atoi(fields[i+4]); + if(val==0) val = (35 + ((i+1)*job_info[idx].hp_factor))/100 + k; + if(oldval >= val) + ShowWarning("Warn, HP value is lower or equal then previous one for (job=%d,oldval=%d,val=%d,lvl=%d hp_factor=%d,hp_multiplicator=%d,k=%d)\n", + job_id,oldval,val,i,job_info[idx].hp_factor,job_info[idx].hp_multiplicator,k); + val = min(INT_MAX,val); + job_info[idx].hp_table[i-1] = val; + oldval = val; + } +// ShowInfo("Have readen hp table for job=%d\n{",job_id); +// for(i=0; i=startlvl && i <=maxlvl) val = atoi(fields[i+4]); + if(val==0) val = (10 + ((i+1)*job_info[idx].sp_factor))/100; + if(oldval >= val) ShowWarning("Warn, SP value is lower or equal then previous one for (job=%d,oldval=%d,val=%d,lvl=%d,sp_factor=%d)\n", + job_id,oldval,val,i,job_info[idx].sp_factor); + val = min(INT_MAX,val); + job_info[idx].sp_table[i-1] = val; + oldval = val; + } +// ShowInfo("Have readen sp table for job=%d\n{",job_id); +// for(i=0; iequip_index[EQI_AMMO] returns the index //where the arrows are equipped) enum equip_index { @@ -517,11 +523,6 @@ }; -//Update this max as necessary. 55 is the value needed for Super Baby currently -//Raised to 84 since Expanded Super Novice needs it. -#define MAX_SKILL_TREE 84 -//Total number of classes (for data storage) -#define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC) enum weapon_type { W_FIST, //Bare hands @@ -596,6 +597,21 @@ //EQP_SHADOW_ACC_L = 0x200000, }; +struct { + int hp_table[MAX_LEVEL]; + int sp_table[MAX_LEVEL]; + int max_level; + int hp_factor, hp_multiplicator; + int sp_factor; + int max_weight_base; + char job_bonus[MAX_LEVEL]; +#ifdef RENEWAL_ASPD + int aspd_base[MAX_WEAPON_TYPE+1]; +#else + int aspd_base[MAX_WEAPON_TYPE]; //[blackhole89] +#endif +} job_info[CLASS_COUNT]; + #define EQP_WEAPON EQP_HAND_R #define EQP_SHIELD EQP_HAND_L #define EQP_ARMS (EQP_HAND_R|EQP_HAND_L) @@ -700,6 +716,7 @@ ) #endif +int pc_split_atoi(char* str, int* val, char sep, int max); int pc_class2idx(int class_); int pc_get_group_level(struct map_session_data *sd); int pc_get_group_id(struct map_session_data *sd); Index: src/map/status.c =================================================================== --- src/map/status.c (revision 17374) +++ src/map/status.c (working copy) @@ -48,17 +48,6 @@ RGN_SSP = 0x08, }; -static int max_weight_base[CLASS_COUNT]; -static int hp_coefficient[CLASS_COUNT]; -static int hp_coefficient2[CLASS_COUNT]; -static int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1]; -static int sp_coefficient[CLASS_COUNT]; -#ifdef RENEWAL_ASPD -static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE+1]; -#else -static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE]; //[blackhole89] -#endif - // bonus values and upgrade chances for refining equipment static struct { int chance[MAX_REFINE]; // success chance @@ -67,7 +56,6 @@ } refine_info[REFINE_TYPE_MAX]; static int atkmods[3][MAX_WEAPON_TYPE]; //ATK weapon modification for size (size_fix.txt) -static char job_bonus[CLASS_COUNT][MAX_LEVEL]; static struct eri *sc_data_ers; //For sc_data entries static struct status_data dummy_status; @@ -1820,6 +1808,7 @@ int amotion; #ifdef RENEWAL_ASPD short mod = -1; + int classidx = pc_class2idx(sd->status.class_); switch( sd->weapontype2 ){ // adjustment for dual weilding case W_DAGGER: mod = 0; break; // 0, 1, 1 @@ -1830,21 +1819,21 @@ } amotion = ( sd->status.weapon < MAX_WEAPON_TYPE && mod < 0 ) - ? (aspd_base[pc_class2idx(sd->status.class_)][sd->status.weapon]) // single weapon - : ((aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2] // dual-wield - + aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2]) * 6 / 10 + 10 * mod - - aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2] - + aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype1]); + ? (job_info[classidx].aspd_base[sd->status.weapon]) // single weapon + : ((job_info[classidx].aspd_base[sd->weapontype2] // dual-wield + + job_info[classidx].aspd_base[sd->weapontype2]) * 6 / 10 + 10 * mod + - job_info[classidx].aspd_base[sd->weapontype2] + + job_info[classidx].aspd_base[sd->weapontype1]); if ( sd->status.shield ) - amotion += ( 2000 - aspd_base[pc_class2idx(sd->status.class_)][W_FIST] ) + - ( aspd_base[pc_class2idx(sd->status.class_)][MAX_WEAPON_TYPE] - 2000 ); + amotion += ( 2000 - job_info[classidx].aspd_base[W_FIST] ) + + ( job_info[classidx].aspd_base[MAX_WEAPON_TYPE] - 2000 ); #else // base weapon delay amotion = (sd->status.weapon < MAX_WEAPON_TYPE) - ? (aspd_base[pc_class2idx(sd->status.class_)][sd->status.weapon]) // single weapon - : (aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype1] + aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2])*7/10; // dual-wield + ? (job_info[classidx].aspd_base[sd->status.weapon]) // single weapon + : (job_info[classidx].aspd_base[sd->weapontype1] + job_info[classidx].aspd_base[sd->weapontype2])*7/10; // dual-wield // percentual delay reduction from stats amotion -= amotion * (4*status->agi + status->dex)/1000; @@ -2240,39 +2229,11 @@ return 1; } -/// Helper function for status_base_pc_maxhp(), used to pre-calculate the hp_sigma_val[] array -static void status_calc_sigma(void) -{ - int i,j; - - for(i = 0; i < CLASS_COUNT; i++) - { - unsigned int k = 0; - hp_sigma_val[i][0] = hp_sigma_val[i][1] = 0; - for(j = 2; j <= MAX_LEVEL; j++) - { - k += (hp_coefficient[i]*j + 50) / 100; - hp_sigma_val[i][j] = k; - if (k >= INT_MAX) - break; //Overflow protection. [Skotlex] - } - for(; j <= MAX_LEVEL; j++) - hp_sigma_val[i][j] = INT_MAX; - } -} - -/// Calculates base MaxHP value according to class and base level -/// The recursive equation used to calculate level bonus is (using integer operations) -/// f(0) = 35 | f(x+1) = f(x) + A + (x + B)*C/D -/// which reduces to something close to -/// f(x) = 35 + x*(A + B*C/D) + sum(i=2..x){ i*C/D } +//Calculate maxHP from tables static unsigned int status_base_pc_maxhp(struct map_session_data* sd, struct status_data* status) { - uint64 val = pc_class2idx(sd->status.class_); - val = 35 + sd->status.base_level*(int64)hp_coefficient2[val]/100 + hp_sigma_val[val][sd->status.base_level]; + uint32 val = job_info[pc_class2idx(sd->status.class_)].hp_table[sd->status.base_level-1]; - if((sd->class_&MAPID_UPPERMASK) == MAPID_NINJA || (sd->class_&MAPID_UPPERMASK) == MAPID_GUNSLINGER) - val += 100; //Since their HP can't be approximated well enough without this. if((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc_famerank(sd->status.char_id, MAPID_TAEKWON)) val *= 3; //Triple max HP for top ranking Taekwons over level 90. if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99) @@ -2287,11 +2248,11 @@ return (unsigned int)val; } +//Calculate maxSP from tables static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct status_data *status) { - uint64 val; + uint32 val = job_info[pc_class2idx(sd->status.class_)].sp_table[sd->status.base_level-1]; - val = 10 + sd->status.base_level*(int64)sp_coefficient[pc_class2idx(sd->status.class_)]/100; val += val * status->int_/100; if (sd->class_&JOBL_UPPER) @@ -2327,7 +2288,7 @@ pc_calc_skilltree(sd); // SkillTree calculation - sd->max_weight = max_weight_base[pc_class2idx(sd->status.class_)]+sd->status.str*300; + sd->max_weight = job_info[pc_class2idx(sd->status.class_)].max_weight_base+sd->status.str*300; if(first) { //Load Hp/SP from char-received data. @@ -2704,9 +2665,9 @@ // Job bonuses index = pc_class2idx(sd->status.class_); for(i=0;i<(int)sd->status.job_level && istr++; break; case 2: status->agi++; break; case 3: status->vit++; break; @@ -11343,63 +11304,6 @@ return refine_info[wlv].chance[refine]; } - -/*------------------------------------------ - * DB reading. - * job_db1.txt - weight, hp, sp, aspd - * job_db2.txt - job level stat bonuses - * size_fix.txt - size adjustment table for weapons - * refine_db.txt - refining data table - *------------------------------------------*/ -static bool status_readdb_job1(char* fields[], int columns, int current) -{// Job-specific values (weight, HP, SP, ASPD) - int idx, class_; - unsigned int i; - - class_ = atoi(fields[0]); - - if(!pcdb_checkid(class_)) - { - ShowWarning("status_readdb_job1: Invalid job class %d specified.\n", class_); - return false; - } - idx = pc_class2idx(class_); - - max_weight_base[idx] = atoi(fields[1]); - hp_coefficient[idx] = atoi(fields[2]); - hp_coefficient2[idx] = atoi(fields[3]); - sp_coefficient[idx] = atoi(fields[4]); -#ifdef RENEWAL_ASPD - for(i = 0; i <= MAX_WEAPON_TYPE; i++) -#else - for(i = 0; i < MAX_WEAPON_TYPE; i++) -#endif - { - aspd_base[idx][i] = atoi(fields[i+5]); - } - return true; -} - -static bool status_readdb_job2(char* fields[], int columns, int current) -{ - int idx, class_, i; - - class_ = atoi(fields[0]); - - if(!pcdb_checkid(class_)) - { - ShowWarning("status_readdb_job2: Invalid job class %d specified.\n", class_); - return false; - } - idx = pc_class2idx(class_); - - for(i = 1; i < columns; i++) - { - job_bonus[idx][i-1] = atoi(fields[i]); - } - return true; -} - static bool status_readdb_sizefix(char* fields[], int columns, int current) { unsigned int i; @@ -11445,34 +11349,20 @@ return true; } -/* -* Read status db -* job1.txt -* job2.txt -* size_fixe.txt -* refine_db.txt -*/ + +/*------------------------------------------ + * DB reading. + * size_fix.txt - size adjustment table for weapons + * refine_db.txt - refining data table + *------------------------------------------*/ int status_readdb(void) { int i, j; - // initialize databases to default - // - - // reset job_db1.txt data - memset(max_weight_base, 0, sizeof(max_weight_base)); - memset(hp_coefficient, 0, sizeof(hp_coefficient)); - memset(hp_coefficient2, 0, sizeof(hp_coefficient2)); - memset(sp_coefficient, 0, sizeof(sp_coefficient)); - memset(aspd_base, 0, sizeof(aspd_base)); - // reset job_db2.txt data - memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus - // size_fix.txt for(i=0;i