diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index f2953da9cb1..99e66e0636f 100644 --- a/conf/battle/skill.conf +++ b/conf/battle/skill.conf @@ -330,3 +330,9 @@ arrow_shower_knockback: yes // punch a hole into SG it will for example create a "suck in" effect. // If you disable this setting, the knockback direction will be completely random (eAthena style). stormgust_knockback: yes + +// For RENEWAL_CAST (Note 2) +// By default skill that has '0' value for Fixed Casting Time will use 20% of cast time +// as Fixed Casting Time, and the rest (80%) as Variable Casting Time. +// Put it 0 to disable default Fixed Casting Time (just like -1 is the skill_cast_db.txt). +default_fixed_castrate: 20 diff --git a/db/re/item_db.txt b/db/re/item_db.txt index a3c43bb3a3b..e99a10bf370 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -1078,7 +1078,7 @@ 1824,BF_Knuckle2,Brave Battle Fist,5,20,,0,30,,1,0,0x00008100,63,2,2,3,80,1,12,{ bonus bStr,2; bonus bInt,1; bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-25; autobonus "{ bonus2 bVariableCastrate,\"MO_EXTREMITYFIST\",-100; }",50,6000,BF_WEAPON,"{ specialeffect2 EF_SUFFRAGIUM; }"; bonus bUnbreakableWeapon,0; },{},{} 1825,Horn_Of_Hilthrion,Horn of Hillslion,5,20,,600,95,,1,3,0x00008000,18,2,2,3,60,1,12,{ bonus3 bAutoSpell,"NPC_CRITICALWOUND",1,100; bonus4 bAutoSpellOnSkill,"CH_PALMSTRIKE","MO_INVESTIGATE",1,100; bonus3 bAutoSpell,"MO_CALLSPIRITS",5,100; },{},{} 1826,Krieger_Knuckle1,Glorious Claw,5,20,,0,30,,1,0,0x00008100,63,2,2,4,80,1,12,{ bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus3 bAutoSpell,"MO_INVESTIGATE",5,(getrefine()*10-50); bonus3 bAutoSpell,"AL_DECAGI",1,(getrefine()*10-50); } },{},{} -1827,Krieger_Knuckle2,Glorious Fist,5,20,,0,30,,1,0,0x00008100,63,2,2,4,80,1,12,{ bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-100; bonus4 bautospellonskill,"MO_EXPLOSIONSPIRITS","CH_SOULCOLLECT",1,1000; bonus bFixedCastrate,-100; } },{},{} +1827,Krieger_Knuckle2,Glorious Fist,5,20,,0,30,,1,0,0x00008100,63,2,2,4,80,1,12,{ bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-100; bonus2 bFixedCastrate,"MO_EXTREMITYFIST",-100; bonus4 bautospellonskill,"MO_EXPLOSIONSPIRITS","CH_SOULCOLLECT",1,1000; } },{},{} 1828,Monk_Knuckle,Monk Knuckle,5,20,,0,150,,1,0,0x00008100,63,2,2,4,0,0,12,{ bonus bInt,2; bonus2 bSkillAtk,"MO_FINGEROFFENSIVE",25; },{},{} 1829,Fist_C,Fist,5,0,,0,150,,1,0,0x00008100,63,2,2,3,1,0,12,{ bonus2 bAddSize,Size_All,40; },{},{} 1830,Sura_Rampage,Sura Rampage,5,20,,500,142,,1,1,0x00008100,63,2,2,3,102,1,12,{ bonus2 bSkillAtk,"SR_EARTHSHAKER",20; bonus2 bSkillAtk,"SR_SKYNETBLOW",20; bonus bUseSPrate,5; if(getrefine()>6) { bonus bUseSPrate,-1*(getrefine()-6); } },{},{} diff --git a/doc/item_bonus.txt b/doc/item_bonus.txt index 58f98db2f1c..de8138d8426 100644 --- a/doc/item_bonus.txt +++ b/doc/item_bonus.txt @@ -174,16 +174,18 @@ bonus2 bAddItemGroupHealRate,ig,n; Increases HP recovered by n% for items of ite Cast time/delay --------------- -bonus bCastrate,n; Skill cast time rate + n% -bonus2 bCastrate,sk,n; Adjust casting time of skill sk by n% -bonus bFixedCastrate,n; Increases fixed cast time of all skills by n% -bonus2 bFixedCastrate,sk,n; Increases fixed cast time of skill sk by n% -bonus bVariableCastrate,n; Increases variable cast time of all skills by n% -bonus2 bVariableCastrate,sk,n; Increases variable cast time of skill sk by n% -bonus bFixedCast,t; Increases fixed cast time of all skills by t milliseconds -bonus2 bSkillFixedCast,sk,t; Increases fixed cast time of skill sk by t milliseconds -bonus bVariableCast,t; Increases variable cast time of all skills by t milliseconds -bonus2 bSkillVariableCast,sk,t; Increases variable cast time of skill sk by t milliseconds +bonus bCastrate,n; Skill cast time rate + n%. (If RENEWAL_CAST is defined, this bonus is equal to bVariableCastrate) +bonus2 bCastrate,sk,n; Adjust casting time of skill sk by n%.(If RENEWAL_CAST is defined, this bonus is equal to bVariableCastrate) + +bonus bFixedCastrate,n; Increases fixed cast time of all skills by n% (has effect in RENEWAL_CAST only) +bonus2 bFixedCastrate,sk,n; Increases fixed cast time of skill sk by n% (has effect in RENEWAL_CAST only) +bonus bVariableCastrate,n; Increases variable cast time of all skills by n%. (If RENEWAL_CAST is NOT defined, this bonus is equal to bCastrate) +bonus2 bVariableCastrate,sk,n; Increases variable cast time of skill sk by n% (If RENEWAL_CAST is NOT defined, this bonus is equal to bCastrate) + +bonus bFixedCast,t; Increases fixed cast time of all skills by t milliseconds (has effect in RENEWAL_CAST only) +bonus2 bSkillFixedCast,sk,t; Increases fixed cast time of skill sk by t milliseconds (has effect in RENEWAL_CAST only) +bonus bVariableCast,t; Increases variable cast time of all skills by t milliseconds (has effect in RENEWAL_CAST only) +bonus2 bSkillVariableCast,sk,t; Increases variable cast time of skill sk by t milliseconds (has effect in RENEWAL_CAST only) bonus bNoCastCancel,n; Prevents casting from being interrupted when hit (does not work in GvG | n is meaningless) bonus bNoCastCancel2,n; Prevents casting from being interrupted when hit (works even in GvG | n is meaningless) diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 21012fd9011..0fa31145c25 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -1109,7 +1109,7 @@ REPLACE INTO `item_db_re` VALUES (1823,'BF_Knuckle1','Valorous Battle Fist',5,20 REPLACE INTO `item_db_re` VALUES (1824,'BF_Knuckle2','Brave Battle Fist',5,20,NULL,0,'30',NULL,1,0,0x00008100,63,2,2,3,'80',1,12,'bonus bStr,2; bonus bInt,1; bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-25; autobonus "{ bonus2 bVariableCastrate,\\\"MO_EXTREMITYFIST\\\",-100; }",50,6000,BF_WEAPON,"{ specialeffect2 EF_SUFFRAGIUM; }"; bonus bUnbreakableWeapon,0;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1825,'Horn_Of_Hilthrion','Horn of Hillslion',5,20,NULL,600,'95',NULL,1,3,0x00008000,18,2,2,3,'60',1,12,'bonus3 bAutoSpell,"NPC_CRITICALWOUND",1,100; bonus4 bAutoSpellOnSkill,"CH_PALMSTRIKE","MO_INVESTIGATE",1,100; bonus3 bAutoSpell,"MO_CALLSPIRITS",5,100;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1826,'Krieger_Knuckle1','Glorious Claw',5,20,NULL,0,'30',NULL,1,0,0x00008100,63,2,2,4,'80',1,12,'bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus3 bAutoSpell,"MO_INVESTIGATE",5,(getrefine()*10-50); bonus3 bAutoSpell,"AL_DECAGI",1,(getrefine()*10-50); }',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (1827,'Krieger_Knuckle2','Glorious Fist',5,20,NULL,0,'30',NULL,1,0,0x00008100,63,2,2,4,'80',1,12,'bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-100; bonus4 bautospellonskill,"MO_EXPLOSIONSPIRITS","CH_SOULCOLLECT",1,1000; bonus bFixedCastrate,-100; }',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (1827,'Krieger_Knuckle2','Glorious Fist',5,20,NULL,0,'30',NULL,1,0,0x00008100,63,2,2,4,'80',1,12,'bonus2 bAddRace,RC_DemiHuman,95; bonus2 bAddRace,RC_Player,95; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,20; bonus2 bIgnoreDefRaceRate,RC_Player,20; bonus bUnbreakableWeapon,0; if(getrefine()>5) { bonus2 bAddRace,RC_DemiHuman,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bAddRace,RC_Player,pow(((getrefine()>14)?14:getrefine())-4,2); bonus2 bIgnoreDefRaceRate,RC_DemiHuman,5; bonus2 bIgnoreDefRaceRate,RC_Player,5; } if(getrefine()>8) { bonus2 bVariableCastrate,"MO_EXTREMITYFIST",-100; bonus2 bFixedCastrate,"MO_EXTREMITYFIST",-100; bonus4 bautospellonskill,"MO_EXPLOSIONSPIRITS","CH_SOULCOLLECT",1,1000; }',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1828,'Monk_Knuckle','Monk Knuckle',5,20,NULL,0,'150',NULL,1,0,0x00008100,63,2,2,4,'0',0,12,'bonus bInt,2; bonus2 bSkillAtk,"MO_FINGEROFFENSIVE",25;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1829,'Fist_C','Fist',5,0,NULL,0,'150',NULL,1,0,0x00008100,63,2,2,3,'1',0,12,'bonus2 bAddSize,Size_All,40;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1830,'Sura_Rampage','Sura Rampage',5,20,NULL,500,'142',NULL,1,1,0x00008100,63,2,2,3,'102',1,12,'bonus2 bSkillAtk,"SR_EARTHSHAKER",20; bonus2 bSkillAtk,"SR_SKYNETBLOW",20; bonus bUseSPrate,5; if(getrefine()>6) { bonus bUseSPrate,-1*(getrefine()-6); }',NULL,NULL); diff --git a/src/config/const.h b/src/config/const.h index be52bd79061..4ffad249244 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -99,10 +99,12 @@ // Renewal variable cast time reduction #ifdef RENEWAL_CAST - #define VARCAST_REDUCTION(val){ \ - if( (varcast_r += (val)) != 0 && varcast_r >= 0 ) \ - time = time * (1 - (float)min((val), 100) / 100); \ - } + // Multiply the Variable CastTime + #define VARCAST_REDUCTION(val) ( time = time * (1 + (val) * 0.01) ) + + // Get the highest rate TO REDUCE Fixed CastTime + // -100 is "the highest" rate than 100. + #define FIXEDCASTRATE(fcast,val) ( ((fcast) == 0) ? ((fcast) = (val)) : ((fcast) = min((fcast),(val))) ) #endif /** * End of File diff --git a/src/config/renewal.h b/src/config/renewal.h index 332d31254ff..dae47098a8f 100644 --- a/src/config/renewal.h +++ b/src/config/renewal.h @@ -16,57 +16,60 @@ * @INFO: This file holds general-purpose renewal settings, for class-specific ones check /src/config/classes folder **/ -/// game renewal server mode +/// Game renewal server mode /// (disable by commenting the line) /// -/// leave this line to enable renewal specific support such as renewal formulas +/// Leave this line to enable renewal specific support such as renewal formulas #define RENEWAL -/// renewal cast time +/// Renewal cast time /// (disable by commenting the line) /// -/// leave this line to enable renewal casting time algorithms -/// cast time is decreased by DEX * 2 + INT while 20% of the cast time is not reduced by stats. -/// example: -/// on a skill whos cast time is 10s, only 8s may be reduced. the other 2s are part of a -/// "fixed cast time" which can only be reduced by specialist items and skills +/// Leave this line to enable renewal casting time algorithms and enable fixed cast bonuses. +/// See also default_fixed_castrate in conf/battle/skill.conf for default fixed cast time (default is 20%). +/// Cast time is altered be 2 portion, Variable Cast Time (VCT) and Fixed Cast Time (FCT). +/// By default FCT is 20% of VCT (some skills aren't) +/// - VCT is decreased by DEX * 2 + INT. +/// - FCT is NOT reduced by stats, reduced by equips or buffs. +/// Example: +/// On a skill whos cast time is 10s, only 8s may be reduced. the other 2s are part of a FCT #define RENEWAL_CAST -/// renewal drop rate algorithms +/// Renewal drop rate algorithms /// (disable by commenting the line) /// -/// leave this line to enable renewal item drop rate algorithms -/// while enabled a special modified based on the difference between the player and monster level is applied -/// based on the http://irowiki.org/wiki/Drop_System#Level_Factor table +/// Leave this line to enable renewal item drop rate algorithms +/// While enabled a special modified based on the difference between the player and monster level is applied +/// Based on the http://irowiki.org/wiki/Drop_System#Level_Factor table #define RENEWAL_DROP -/// renewal exp rate algorithms +/// Renewal exp rate algorithms /// (disable by commenting the line) /// -/// leave this line to enable renewal item exp rate algorithms -/// while enabled a special modified based on the difference between the player and monster level is applied +/// Leave this line to enable renewal item exp rate algorithms +/// While enabled a special modified based on the difference between the player and monster level is applied #define RENEWAL_EXP -/// renewal level modifier on damage +/// Renewal level modifier on damage /// (disable by commenting the line) /// -// leave this line to enable renewal base level modifier on skill damage (selected skills only) +// Leave this line to enable renewal base level modifier on skill damage (selected skills only) #define RENEWAL_LVDMG -/// renewal ASPD [malufett] +/// Renewal ASPD [malufett] /// (disable by commenting the line) /// -/// leave this line to enable renewal ASPD +/// Leave this line to enable renewal ASPD /// - shield penalty is applied /// - AGI has a greater factor in ASPD increase /// - there is a change in how skills/items give ASPD /// - some skill/item ASPD bonuses won't stack #define RENEWAL_ASPD -/// renewal stat calculations +/// Renewal stat calculations /// (disable by commenting the line) /// -/// leave this line to enable renewal calculation for increasing status/parameter points +/// Leave this line to enable renewal calculation for increasing status/parameter points #define RENEWAL_STAT #endif diff --git a/src/map/battle.c b/src/map/battle.c index c8bc9c226b2..27e26333dd6 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7945,6 +7945,7 @@ static const struct _battle_data { { "boss_icewall_walk_block", &battle_config.boss_icewall_walk_block, 0, 0, 255, }, { "snap_dodge", &battle_config.snap_dodge, 0, 0, 1, }, { "stormgust_knockback", &battle_config.stormgust_knockback, 1, 0, 1, }, + { "default_fixed_castrate", &battle_config.default_fixed_castrate, 20, 0, 100, }, }; #ifndef STATS_OPT_OUT diff --git a/src/map/battle.h b/src/map/battle.h index 005d8af987b..eae76a892b3 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -579,6 +579,7 @@ extern struct Battle_Config int boss_icewall_walk_block; //How a boss monster should be trapped in icewall [Playtester] int snap_dodge; // Enable or disable dodging damage snapping away [csnv] int stormgust_knockback; + int default_fixed_castrate; } battle_config; void do_init_battle(void); diff --git a/src/map/pc.c b/src/map/pc.c index 56fa315e978..471d4039b2e 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2497,13 +2497,6 @@ void pc_bonus(struct map_session_data *sd,int type,int val) break; sd->bonus.sp += val; break; -#ifndef RENEWAL_CAST - case SP_VARCASTRATE: -#endif - case SP_CASTRATE: - if(sd->state.lr_flag != 2) - sd->castrate+=val; - break; case SP_MAXHPRATE: if(sd->state.lr_flag != 2) sd->hprate+=val; @@ -2911,26 +2904,38 @@ void pc_bonus(struct map_session_data *sd,int type,int val) sd->bonus.itemhealrate2 += val; break; case SP_EMATK: - if(sd->state.lr_flag != 2) - sd->bonus.ematk += val; - break; + if(sd->state.lr_flag != 2) + sd->bonus.ematk += val; + break; +#ifdef RENEWAL_CAST case SP_FIXCASTRATE: if(sd->state.lr_flag != 2) - sd->bonus.fixcastrate -= val; + FIXEDCASTRATE(sd->bonus.fixcastrate,val); break; case SP_ADD_FIXEDCAST: if(sd->state.lr_flag != 2) sd->bonus.add_fixcast += val; break; -#ifdef RENEWAL_CAST + case SP_CASTRATE: case SP_VARCASTRATE: if(sd->state.lr_flag != 2) - sd->bonus.varcastrate -= val; + sd->bonus.varcastrate += val; break; case SP_ADD_VARIABLECAST: if(sd->state.lr_flag != 2) sd->bonus.add_varcast += val; break; +#else + case SP_ADD_FIXEDCAST: + case SP_FIXCASTRATE: + case SP_ADD_VARIABLECAST: + //ShowWarning("pc_bonus: non-RENEWAL_CAST doesn't support this bonus %d.\n", type); + break; + case SP_VARCASTRATE: + case SP_CASTRATE: + if(sd->state.lr_flag != 2) + sd->castrate += val; + break; #endif case SP_ADDMAXWEIGHT: if (sd->state.lr_flag != 2) @@ -3305,7 +3310,7 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2); if (i == ARRAYLENGTH(sd->skillblown)) { //Better mention this so the array length can be updated. [Skotlex] - ShowError("pc_bonus2: SP_ADD_SKILL_BLOW: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillblown), type2, val); + ShowError("pc_bonus2: SP_ADD_SKILL_BLOW: Reached max (%d) number of skills per character, bonus skill %d (%d) lost.\n", ARRAYLENGTH(sd->skillblown), type2, val); break; } if(sd->skillblown[i].id == type2) @@ -3315,49 +3320,6 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) sd->skillblown[i].val = val; } break; -#ifndef RENEWAL_CAST - case SP_VARCASTRATE: // bonus2 bVariableCastrate,sk,n; -#endif - case SP_CASTRATE: // bonus2 bCastrate,sk,n; - if(sd->state.lr_flag == 2) - break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowError("run_script: %s: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", - -#ifndef RENEWAL_CAST - "SP_VARCASTRATE", -#else - "SP_CASTRATE", -#endif - - ARRAYLENGTH(sd->skillcast), type2, val); - break; - } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val += val; - else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val = val; - } - break; - case SP_FIXCASTRATE: // bonus2 bFixedCastrate,sk,n; - if(sd->state.lr_flag == 2) - break; - ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); - if (i == ARRAYLENGTH(sd->skillfixcastrate)) - { - ShowError("run_script: SP_FIXCASTRATE: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcastrate), type2, val); - break; - } - if(sd->skillfixcastrate[i].id == type2) - sd->skillfixcastrate[i].val -= val; - else { - sd->skillfixcastrate[i].id = type2; - sd->skillfixcastrate[i].val -= val; - } - break; case SP_HP_LOSS_RATE: // bonus2 bHPLossRate,n,t; if(sd->state.lr_flag != 2) { sd->hp_loss.value = type2; @@ -3528,7 +3490,7 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2); if (i == ARRAYLENGTH(sd->skillcooldown)) { - ShowError("pc_bonus2: SP_SKILL_COOLDOWN: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillcooldown), type2, val); + ShowError("pc_bonus2: SP_SKILL_COOLDOWN: Reached max (%d) number of skills per character, bonus skill %d (%d) lost.\n", ARRAYLENGTH(sd->skillcooldown), type2, val); break; } if (sd->skillcooldown[i].id == type2) @@ -3538,13 +3500,14 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) sd->skillcooldown[i].val = val; } break; +#ifdef RENEWAL_CAST case SP_SKILL_FIXEDCAST: // bonus2 bSkillFixedCast,sk,t; if(sd->state.lr_flag == 2) break; ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2); if (i == ARRAYLENGTH(sd->skillfixcast)) { - ShowError("pc_bonus2: SP_SKILL_FIXEDCAST: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcast), type2, val); + ShowError("pc_bonus2: SP_SKILL_FIXEDCAST: Reached max (%d) number of skills per character, bonus skill %d (%d) lost.\n", ARRAYLENGTH(sd->skillfixcast), type2, val); break; } if (sd->skillfixcast[i].id == type2) @@ -3560,7 +3523,7 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2); if (i == ARRAYLENGTH(sd->skillvarcast)) { - ShowError("pc_bonus2: SP_SKILL_VARIABLECAST: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillvarcast), type2, val); + ShowError("pc_bonus2: SP_SKILL_VARIABLECAST: Reached max (%d) number of skills per character, bonus skill %d (%d) lost.\n", ARRAYLENGTH(sd->skillvarcast), type2, val); break; } if (sd->skillvarcast[i].id == type2) @@ -3570,21 +3533,61 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) sd->skillvarcast[i].val = val; } break; -#ifdef RENEWAL_CAST + case SP_CASTRATE: // bonus2 bCastrate,sk,n; case SP_VARCASTRATE: // bonus2 bVariableCastrate,sk,n; if(sd->state.lr_flag == 2) break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) + ARR_FIND(0, ARRAYLENGTH(sd->skillcastrate), i, sd->skillcastrate[i].id == 0 || sd->skillcastrate[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcastrate)) { - ShowError("pc_bonus2: SP_VARCASTRATE: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n",ARRAYLENGTH(sd->skillcast), type2, val); + ShowError("pc_bonus2: SP_VARCASTRATE: Reached max (%d) number of skills per character, bonus skill %d (%d%%) lost.\n",ARRAYLENGTH(sd->skillcastrate), type2, val); + break; + } + if(sd->skillcastrate[i].id == type2) + sd->skillcastrate[i].val += val; + else { + sd->skillcastrate[i].id = type2; + sd->skillcastrate[i].val += val; + } + break; + case SP_FIXCASTRATE: // bonus2 bFixedCastrate,sk,n; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); + if (i == ARRAYLENGTH(sd->skillfixcastrate)) + { + ShowError("pc_bonus2: SP_FIXCASTRATE: Reached max (%d) number of skills per character, bonus skill %d (%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcastrate), type2, val); + break; + } + if(sd->skillfixcastrate[i].id == type2) + FIXEDCASTRATE(sd->skillfixcastrate[i].val,val); + else { + sd->skillfixcastrate[i].id = type2; + sd->skillfixcastrate[i].val = val; + } + break; +#else + case SP_SKILL_FIXEDCAST: // bonus2 bSkillFixedCast,sk,t; + case SP_SKILL_VARIABLECAST: // bonus2 bSkillVariableCast,sk,t; + case SP_FIXCASTRATE: // bonus2 bFixedCastrate,sk,n; + //ShowWarning("pc_bonus2: Non-RENEWAL_CAST doesn't support this bonus %d.\n", type); + break; + case SP_VARCASTRATE: // bonus2 bVariableCastrate,sk,n; + case SP_CASTRATE: // bonus2 bCastrate,sk,n; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcastrate), i, sd->skillcastrate[i].id == 0 || sd->skillcastrate[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcastrate)) + { //Better mention this so the array length can be updated. [Skotlex] + ShowError("pc_bonus2: %s: Reached max (%d) number of skills per character, bonus skill %d (%d%%) lost.\n", + (type == SP_CASTRATE) ? "SP_CASTRATE" : "SP_VARCASTRATE", ARRAYLENGTH(sd->skillcastrate), type2, val); break; } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val -= val; + if(sd->skillcastrate[i].id == type2) + sd->skillcastrate[i].val += val; else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val -= val; + sd->skillcastrate[i].id = type2; + sd->skillcastrate[i].val = val; } break; #endif @@ -3593,7 +3596,7 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) break; ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2); if (i == ARRAYLENGTH(sd->skillusesp)) { - ShowError("pc_bonus2: SP_SKILL_USE_SP: Reached max (%d) number of skills per character, bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillusesp), type2, val); + ShowError("pc_bonus2: SP_SKILL_USE_SP: Reached max (%d) number of skills per character, bonus skill %d (%d) lost.\n", ARRAYLENGTH(sd->skillusesp), type2, val); break; } if (sd->skillusesp[i].id == type2) @@ -7572,12 +7575,6 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_FLEE1: val = sd->battle_status.flee; break; case SP_FLEE2: val = sd->battle_status.flee2; break; case SP_DEFELE: val = sd->battle_status.def_ele; break; -#ifndef RENEWAL_CAST - case SP_VARCASTRATE: -#endif - case SP_CASTRATE: - val = sd->castrate+=val; - break; case SP_MAXHPRATE: val = sd->hprate; break; case SP_MAXSPRATE: val = sd->sprate; break; case SP_SPRATE: val = sd->dsprate; break; @@ -7658,9 +7655,13 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_EMATK: val = sd->bonus.ematk; break; case SP_FIXCASTRATE: val = sd->bonus.fixcastrate; break; case SP_ADD_FIXEDCAST: val = sd->bonus.add_fixcast; break; + case SP_ADD_VARIABLECAST: val = sd->bonus.add_varcast; break; + case SP_CASTRATE: + case SP_VARCASTRATE: #ifdef RENEWAL_CAST - case SP_VARCASTRATE: val = sd->bonus.varcastrate; break; - case SP_ADD_VARIABLECAST:val = sd->bonus.add_varcast; break; + val = sd->bonus.varcastrate; break; +#else + val = sd->castrate; break; #endif } diff --git a/src/map/pc.h b/src/map/pc.h index 67cd5990c23..ed7c8d0f3ab 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -355,7 +355,7 @@ struct map_session_data { struct s_skill_bonus { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills. unsigned short id; short val; - } skillatk[MAX_PC_BONUS], skillusesprate[MAX_PC_BONUS], skillusesp[MAX_PC_BONUS], skillheal[MAX_PC_BONUS], skillheal2[MAX_PC_BONUS], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS], skillcooldown[MAX_PC_BONUS], skillfixcast[MAX_PC_BONUS], skillvarcast[MAX_PC_BONUS], skillfixcastrate[MAX_PC_BONUS]; + } skillatk[MAX_PC_BONUS], skillusesprate[MAX_PC_BONUS], skillusesp[MAX_PC_BONUS], skillheal[MAX_PC_BONUS], skillheal2[MAX_PC_BONUS], skillblown[MAX_PC_BONUS], skillcastrate[MAX_PC_BONUS], skillcooldown[MAX_PC_BONUS], skillfixcast[MAX_PC_BONUS], skillvarcast[MAX_PC_BONUS], skillfixcastrate[MAX_PC_BONUS]; struct s_regen { short value; int rate; @@ -419,8 +419,8 @@ struct map_session_data { unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest] unsigned short unbreakable_equip; //100% break resistance on certain equipment unsigned short unstripable_equip; - int fixcastrate,varcastrate; - int add_fixcast,add_varcast; + int fixcastrate, varcastrate; // n/100 + int add_fixcast, add_varcast; // in milliseconds int ematk; // matk bonus from equipment int eatk; // atk bonus from equipment } bonus; diff --git a/src/map/skill.c b/src/map/skill.c index 9b50acee3f6..0648bc62505 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -15449,11 +15449,11 @@ int skill_castfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv) { int i; if( sd->castrate != 100 ) time = time * sd->castrate / 100; - for( i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++ ) + for( i = 0; i < ARRAYLENGTH(sd->skillcastrate) && sd->skillcastrate[i].id; i++ ) { - if( sd->skillcast[i].id == skill_id ) + if( sd->skillcastrate[i].id == skill_id ) { - time+= time * sd->skillcast[i].val / 100; + time += time * sd->skillcastrate[i].val / 100; break; } } @@ -15488,8 +15488,8 @@ int skill_castfix_sc(struct block_list *bl, int time) if (sc && sc->count) { if (sc->data[SC_SLOWCAST]) time += time * sc->data[SC_SLOWCAST]->val2 / 100; - if (sc->data[SC_PARALYSIS]) - time += sc->data[SC_PARALYSIS]->val3; + if (sc->data[SC_PARALYSIS]) + time += sc->data[SC_PARALYSIS]->val3; if (sc->data[SC_SUFFRAGIUM]) { time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100; status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER); @@ -15511,7 +15511,14 @@ int skill_castfix_sc(struct block_list *bl, int time) } #else /** - * Get the skill cast time for RENEWAL_CAST + * Get the skill cast time for RENEWAL_CAST. + * FixedRate reduction never be stacked, always get the HIGHEST VALUE TO REDUCE (-20% vs 10%, -20% wins!) + * Additive value: + * Variable CastTime : time += value + * Fixed CastTime : fixed += value + * Multipicative value + * Variable CastTime : VARCAST_REDUCTION(value) + * Fixed CastTime : FIXEDCASTRATE2(value) * @param bl: The caster * @param time: Cast time without reduction * @param skill_id: Skill ID of the casted skill @@ -15522,7 +15529,13 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 { struct status_change *sc = status_get_sc(bl); struct map_session_data *sd = BL_CAST(BL_PC,bl); - int fixed = skill_get_fixed_cast(skill_id, skill_lv), fixcast_r = 0, varcast_r = 0, i = 0; + int fixed = skill_get_fixed_cast(skill_id, skill_lv); + short fixcast_r = 0; + uint8 i = 0, flag = skill_get_castnodex(skill_id, skill_lv); + +#define FIXEDCASTRATE2(val) ( FIXEDCASTRATE(fixcast_r,(val)) ) + + nullpo_ret(bl); if( time < 0 ) return 0; @@ -15530,97 +15543,116 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 if( bl->type == BL_MOB ) return (int)time; - if( fixed == 0 ){ - fixed = (int)time * 20 / 100; // fixed time - time = time * 80 / 100; // variable time - }else if( fixed < 0 ) // no fixed cast time + if( fixed < 0 || battle_config.default_fixed_castrate == 0 ) // no fixed cast time fixed = 0; + else if( fixed == 0 ) { + fixed = (int)time * battle_config.default_fixed_castrate / 100; // fixed time + time = time * (100 - battle_config.default_fixed_castrate) / 100; // variable time + } + + // Additive Variable Cast bonus first + if (sd && !(flag&4)) { // item bonus + time += sd->bonus.add_varcast; // bonus bVariableCast + + for (i = 0; i < ARRAYLENGTH(sd->skillvarcast) && sd->skillvarcast[i].id; i++) + if( sd->skillvarcast[i].id == skill_id ){ // bonus2 bSkillVariableCast + time += sd->skillvarcast[i].val; + break; + } + } + /*if (sc && sc->count && !(flag&2)) { // status change + // -NONE YET- + // if (sc->data[????]) + // bonus += sc->data[????]->val?; + }*/ + + // Adjusted by item bonuses + if (sd && !(flag&4)) { + // Additive values + fixed += sd->bonus.add_fixcast; // bonus bFixedCast - if(sd && !(skill_get_castnodex(skill_id, skill_lv)&4) ){ // Increases/Decreases fixed/variable cast time of a skill by item/card bonuses. - if( sd->bonus.varcastrate < 0 ) - VARCAST_REDUCTION(sd->bonus.varcastrate); - if( sd->bonus.add_varcast != 0 ) // bonus bVariableCast - time += sd->bonus.add_varcast; - if( sd->bonus.add_fixcast != 0 ) // bonus bFixedCast - fixed += sd->bonus.add_fixcast; for (i = 0; i < ARRAYLENGTH(sd->skillfixcast) && sd->skillfixcast[i].id; i++) if (sd->skillfixcast[i].id == skill_id){ // bonus2 bSkillFixedCast fixed += sd->skillfixcast[i].val; break; } - for( i = 0; i < ARRAYLENGTH(sd->skillvarcast) && sd->skillvarcast[i].id; i++ ) - if( sd->skillvarcast[i].id == skill_id ){ // bonus2 bSkillVariableCast - time += sd->skillvarcast[i].val; - break; - } - for( i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++ ) - if( sd->skillcast[i].id == skill_id ){ // bonus2 bVariableCastrate - VARCAST_REDUCTION(sd->skillcast[i].val); + + // Multipicative values + if (sd->bonus.varcastrate != 0) + VARCAST_REDUCTION(sd->bonus.varcastrate); // bonus bVariableCastrate + + if (sd->bonus.fixcastrate != 0) + FIXEDCASTRATE2(sd->bonus.fixcastrate); // bonus bFixedCastrate + + for( i = 0; i < ARRAYLENGTH(sd->skillcastrate) && sd->skillcastrate[i].id; i++ ) + if( sd->skillcastrate[i].id == skill_id ){ // bonus2 bVariableCastrate + VARCAST_REDUCTION(sd->skillcastrate[i].val); break; } for( i = 0; i < ARRAYLENGTH(sd->skillfixcastrate) && sd->skillfixcastrate[i].id; i++ ) if( sd->skillfixcastrate[i].id == skill_id ){ // bonus2 bFixedCastrate - fixcast_r = sd->skillfixcastrate[i].val; + FIXEDCASTRATE2(sd->skillfixcastrate[i].val); break; } } - if (sc && sc->count && !(skill_get_castnodex(skill_id, skill_lv)&2) ) { - // All variable cast additive bonuses must come first + // Adjusted by active statuses + if (sc && sc->count && !(flag&2) ) { + // Multiplicative Variable CastTime values if (sc->data[SC_SLOWCAST]) - VARCAST_REDUCTION(-sc->data[SC_SLOWCAST]->val2); - if( sc->data[SC__LAZINESS] ) - VARCAST_REDUCTION(-sc->data[SC__LAZINESS]->val2); + VARCAST_REDUCTION(sc->data[SC_SLOWCAST]->val2); + if (sc->data[SC__LAZINESS]) + VARCAST_REDUCTION(sc->data[SC__LAZINESS]->val2); - // Variable cast reduction bonuses if (sc->data[SC_SUFFRAGIUM]) { - VARCAST_REDUCTION(sc->data[SC_SUFFRAGIUM]->val2); + VARCAST_REDUCTION(-sc->data[SC_SUFFRAGIUM]->val2); status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER); } if (sc->data[SC_MEMORIZE]) { - VARCAST_REDUCTION(50); + VARCAST_REDUCTION(-50); if ((--sc->data[SC_MEMORIZE]->val2) <= 0) status_change_end(bl, SC_MEMORIZE, INVALID_TIMER); } if (sc->data[SC_POEMBRAGI]) - VARCAST_REDUCTION(sc->data[SC_POEMBRAGI]->val2); + VARCAST_REDUCTION(-sc->data[SC_POEMBRAGI]->val2); if (sc->data[SC_IZAYOI]) - VARCAST_REDUCTION(50); + VARCAST_REDUCTION(-50); if (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 3 && (skill_get_ele(skill_id, skill_lv) == ELE_WATER)) - VARCAST_REDUCTION(30); //Reduces 30% Variable Cast Time of Water spells. - if( sc->data[SC_TELEKINESIS_INTENSE] ) - VARCAST_REDUCTION(sc->data[SC_TELEKINESIS_INTENSE]->val2); - // Fixed cast reduction bonuses - if( sc->data[SC_SECRAMENT] ) - fixcast_r = max(fixcast_r, sc->data[SC_SECRAMENT]->val2); - if( sd && ( skill_lv = pc_checkskill(sd, WL_RADIUS) ) && skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP ) - fixcast_r = max(fixcast_r, 5 + skill_lv * 5); - // Fixed cast non percentage bonuses - if( sc->data[SC_MANDRAGORA] ) + VARCAST_REDUCTION(-30); //Reduces 30% Variable Cast Time of Water spells. + if (sc->data[SC_TELEKINESIS_INTENSE]) + VARCAST_REDUCTION(-sc->data[SC_TELEKINESIS_INTENSE]->val2); + + // Multiplicative Fixed CastTime values + if (sc->data[SC_SECRAMENT]) + FIXEDCASTRATE2(-sc->data[SC_SECRAMENT]->val2); + if (sd && (skill_lv = pc_checkskill(sd, WL_RADIUS) ) && skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP) + FIXEDCASTRATE2(-(5 + skill_lv * 5)); + if (sc->data[SC_DANCEWITHWUG]) + FIXEDCASTRATE2(-sc->data[SC_DANCEWITHWUG]->val4); + if (sc->data[SC_HEAT_BARREL]) + FIXEDCASTRATE2(-sc->data[SC_HEAT_BARREL]->val2); + + // Additive Fixed CastTime values + if (sc->data[SC_MANDRAGORA]) fixed += sc->data[SC_MANDRAGORA]->val1 * 1000 / 2; - if( sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_WILD_STORM_OPTION] ) + + if (sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_WILD_STORM_OPTION]) fixed -= 1000; - if (sc->data[SC_DANCEWITHWUG]) - fixed -= fixed * sc->data[SC_DANCEWITHWUG]->val4 / 100; - if( sc->data[SC_HEAT_BARREL] ) - fixcast_r = max(fixcast_r, sc->data[SC_HEAT_BARREL]->val2); if (sc->data[SC_IZAYOI]) fixed = 0; } - if( sd && !(skill_get_castnodex(skill_id, skill_lv)&4) ){ - VARCAST_REDUCTION( max(sd->bonus.varcastrate, 0) + max(i, 0) ); - fixcast_r = max(fixcast_r, sd->bonus.fixcastrate) + min(sd->bonus.fixcastrate,0); - } + // Apply Variable CastTime calculation by INT & DEX + if (!(flag&1)) + time = time * (1 - sqrt(((float)(status_get_dex(bl)*2 + status_get_int(bl)) / battle_config.vcast_stat_scale))); + + // Apply Fixed CastTime rate + if (fixed != 0 && fixcast_r != 0) + fixed = (int)(fixed * (1 + fixcast_r * 0.01)); - if( varcast_r < 0 ) // now compute overall factors - time = time * (1 - (float)varcast_r / 100); - if( !(skill_get_castnodex(skill_id, skill_lv)&1) )// reduction from status point - time = (1 - sqrt( ((float)(status_get_dex(bl)*2 + status_get_int(bl)) / battle_config.vcast_stat_scale) )) * time; - // underflow checking/capping - time = max(time, 0) + (1 - (float)min(fixcast_r, 100) / 100) * max(fixed,0); +#undef FIXEDCASTRATE2 - return (int)time; + return (int)max(time + fixed, 0); } #endif diff --git a/src/map/status.c b/src/map/status.c index 29a190f12f4..4e3d7f2b27c 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2939,7 +2939,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) + sizeof(sd->skillheal) + sizeof(sd->skillheal2) + sizeof(sd->skillblown) - + sizeof(sd->skillcast) + + sizeof(sd->skillcastrate) + sizeof(sd->skillcooldown) + sizeof(sd->skillfixcast) + sizeof(sd->skillvarcast)