ATKpercent, Base Damage, Occult Impaction, Freezing Trap, Acid Terror, Paladin skills (#8210)

- A handful of skills grant status changes that actually are calculated together into a value "ATKpercent" rather than increasing BATK/WATK, this value is then applied to most weapon skills
  * Pre-re - Damage after skill ratio but before DEF reduction is multiplied with ATKpercent
  * Renewal - Is a linear addition to skill ratio instead (ATKpercent of 200 means +100% to any skill ratio, so 100% becomes 200%, but 500% only becomes 600%)
  * For further information which status changes go into ATKpercent and which skills are not influenced by it, please see the battle_get_atkpercent function
- Fixed base damage not being calculated correctly for certain skills
- MO_INVESTIGATE is no longer influenced by Spirit Spheres except when you have the WATK_ELEMENT effect (Magnum Break)
- Freezing trap now deals 100% damage on all levels and can miss
- Acid Terror now ignores DEF, but its base attack is reduced by VIT
- Acid Terror skill ratio is now 50%+50%*level
- Acid Terror and Martyr's Reckoning (PA_SACRIFICE) are no longer affected by refine and mastery bonus
- Magnum Break/EDP bonus no longer affects Acid Terror and unit skills
- Fixed damage formula of Shield Boomerang and Rapid Smiting
- Code improvements
- Fixes #8193
This commit is contained in:
Playtester 2024-04-01 15:15:41 +02:00 committed by GitHub
parent 23787bdfa4
commit 4247bc50c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 138 additions and 84 deletions

View File

@ -4408,7 +4408,6 @@ Body:
TargetType: Ground
DamageFlags:
Splash: true
IgnoreFlee: true
Flags:
IsTrap: true
AlterRangeResearchTrap: true
@ -6461,6 +6460,7 @@ Body:
TargetType: Attack
DamageFlags:
IgnoreAtkCard: true
IgnoreDefense: true
IgnoreFlee: true
Flags:
IgnoreAutoGuard: true
@ -32636,7 +32636,6 @@ Body:
TargetType: Ground
DamageFlags:
Splash: true
IgnoreFlee: true
Flags:
IsTrap: true
AlterRangeResearchTrap: true

View File

@ -41,6 +41,7 @@ static struct eri *delay_damage_ers; //For battle delay damage structures.
int battle_get_weapon_element(struct Damage *wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, short weapon_position, bool calc_for_damage_only);
int battle_get_magic_element(struct block_list* src, struct block_list* target, uint16 skill_id, uint16 skill_lv, int mflag);
int battle_get_misc_element(struct block_list* src, struct block_list* target, uint16 skill_id, uint16 skill_lv, int mflag);
static void battle_calc_defense_reduction(struct Damage* wd, struct block_list* src, struct block_list* target, uint16 skill_id, uint16 skill_lv);
/**
* Returns the current/list skill used by the bl
@ -3365,7 +3366,9 @@ static bool battle_skill_stacks_masteries_vvs(uint16 skill_id)
if (
#ifndef RENEWAL
skill_id == PA_SHIELDCHAIN || skill_id == CR_SHIELDBOOMERANG ||
skill_id == PA_SACRIFICE || skill_id == AM_ACIDTERROR ||
#endif
skill_id == MO_INVESTIGATE || skill_id == MO_EXTREMITYFIST ||
skill_id == RK_DRAGONBREATH || skill_id == RK_DRAGONBREATH_WATER || skill_id == NC_SELFDESTRUCTION ||
skill_id == LG_SHIELDPRESS || skill_id == LG_EARTHDRIVE)
return false;
@ -3657,11 +3660,13 @@ static void battle_calc_element_damage(struct Damage* wd, struct block_list *src
#ifndef RENEWAL
if (sd && (wd->damage > 0 || wd->damage2 > 0)) { // Applies only to player damage, monsters and mercenaries don't get this damage boost
if (sc && sc->getSCE(SC_WATK_ELEMENT)) { // Descriptions indicate this means adding a percent of a normal attack in another element [Skotlex]
// This adds a percentual damage bonus based on the damage you would deal with a normal attack
// Does not apply to unit skills or skills that have their own base damage formula such as AM_ACIDTERROR
if (sc && sc->getSCE(SC_WATK_ELEMENT) && !skill_get_unit_id(skill_id) && skill_id != AM_ACIDTERROR) {
int64 damage = wd->basedamage * sc->getSCE(SC_WATK_ELEMENT)->val2;
damage = battle_attr_fix(src, target, damage, sc->getSCE(SC_WATK_ELEMENT)->val1, tstatus->def_ele, tstatus->ele_lv, 1);
//Spirit Sphere bonus damage is not affected by element
if (skill_id == MO_FINGEROFFENSIVE) { //Need to calculate number of Spirit Balls you had before cast
if (skill_id == MO_FINGEROFFENSIVE || skill_id == MO_INVESTIGATE) { //Need to calculate number of Spirit Balls you had before cast
damage += ((wd->div_ + sd->spiritball) * 3 * sc->getSCE(SC_WATK_ELEMENT)->val2);
}
else
@ -3720,21 +3725,24 @@ static void battle_calc_attack_masteries(struct Damage* wd, struct block_list *s
struct status_data *sstatus = status_get_status_data(src);
int t_class = status_get_class(target);
if (sd && battle_skill_stacks_masteries_vvs(skill_id) &&
skill_id != MO_INVESTIGATE &&
skill_id != MO_EXTREMITYFIST &&
skill_id != CR_GRANDCROSS)
if (sd) {
wd->basedamage = battle_addmastery(sd, target, wd->basedamage, 0);
if (is_attack_left_handed(src, skill_id)) {
wd->basedamage2 = battle_addmastery(sd, target, wd->basedamage2, 1);
}
}
// Grand Cross is confirmed to be affected by refine bonus but not masteries
if (sd && battle_skill_stacks_masteries_vvs(skill_id) && skill_id != CR_GRANDCROSS)
{ //Add mastery damage
uint16 skill;
wd->damage = battle_addmastery(sd,target,wd->damage,0);
wd->basedamage = battle_addmastery(sd, target, wd->basedamage, 0);
#ifdef RENEWAL
wd->masteryAtk = battle_addmastery(sd,target,wd->weaponAtk,0);
#endif
if (is_attack_left_handed(src, skill_id)) {
wd->damage2 = battle_addmastery(sd,target,wd->damage2,1);
wd->basedamage2 = battle_addmastery(sd, target, wd->basedamage2, 1);
#ifdef RENEWAL
wd->masteryAtk2 = battle_addmastery(sd,target,wd->weaponAtk2,1);
#endif
@ -3972,12 +3980,19 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list *
if (sd) {
short index = sd->equip_index[EQI_HAND_L];
//Base damage of shield skills is [batk + 4*refine + weight]
if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR) {
ATK_ADD(wd->damage, wd->damage2, 4 * sd->inventory.u.items_inventory[index].refine);
ATK_ADD(wd->damage, wd->damage2, sd->inventory_data[index]->weight / 10);
#ifdef RENEWAL
ATK_ADD(wd->weaponAtk, wd->weaponAtk2, 4 * sd->inventory.u.items_inventory[index].refine);
ATK_ADD(wd->weaponAtk, wd->weaponAtk2, sd->inventory_data[index]->weight / 10);
#endif
}
#ifndef RENEWAL
// Shield Boomerang and Rapid Smiting calculate DEF before the skill ratio
battle_calc_defense_reduction(wd, src, target, skill_id, skill_lv);
#endif
} else
ATK_ADD(wd->damage, wd->damage2, sstatus->rhw.atk2); //Else use Atk2
break;
@ -4119,6 +4134,9 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list *
if (tsd != nullptr && tsd->bonus.crit_def_rate != 0 && !skill_id && (bflag & BDMG_CRIT)) {
ATK_ADDRATE(wd->damage, wd->damage2, -tsd->bonus.crit_def_rate);
}
//Acid Terror ignores DEF but will substract VIT from base attack value instead
if (skill_id == AM_ACIDTERROR)
ATK_ADD(wd->damage, wd->damage2, -tstatus->def2);
#endif
break;
} //End switch(skill_id)
@ -4287,6 +4305,74 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
}
}
/**
* Calculates the percentual attack modificator (ATKpercent) based on status changes
* These bonuses are added together and the percent is applied to the damage before the defense reduction in pre-renewal
* In renewal this simply sets the base skillratio before the actual skill ratio of the skill used is added
* This bonus works as a separate unit to the rest (e.g., if one of these is not applied to a skill, then we know none are)
* Do not add additional status changes here unless they are confirmed to use ATKpercent
* @param bl: Object to calc atkpercent for
* @param skill_id: Skill used by object
* @param sc: Object's status change information
* @return atkpercent with cap_value(watk,0,USHRT_MAX)
*/
static unsigned short battle_get_atkpercent(struct block_list* bl, uint16 skill_id, status_change* sc)
{
//These skills are not affected by ATKpercent
switch (skill_id) {
#ifndef RENEWAL
// Need to be confirmed for renewal as masteries have been coded to apply to those two in renewal
case PA_SHIELDCHAIN:
case CR_SHIELDBOOMERANG:
#endif
case AM_ACIDTERROR:
case CR_GRANDCROSS:
case NPC_GRANDDARKNESS:
case MO_INVESTIGATE:
case MO_EXTREMITYFIST:
case PA_SACRIFICE:
case NPC_DRAGONBREATH:
case RK_DRAGONBREATH:
case RK_DRAGONBREATH_WATER:
return 100;
}
int atkpercent = 100;
if (sc->getSCE(SC_CURSE))
atkpercent -= 25;
if (sc->getSCE(SC_PROVOKE))
atkpercent += sc->getSCE(SC_PROVOKE)->val2;
if (sc->getSCE(SC_STRIPWEAPON) && bl->type != BL_PC)
atkpercent -= sc->getSCE(SC_STRIPWEAPON)->val2;
if (sc->getSCE(SC_CONCENTRATION))
atkpercent += sc->getSCE(SC_CONCENTRATION)->val2;
if (sc->getSCE(SC_TRUESIGHT))
atkpercent += 2 * sc->getSCE(SC_TRUESIGHT)->val1;
if (sc->getSCE(SC_JOINTBEAT) && sc->getSCE(SC_JOINTBEAT)->val2 & BREAK_WAIST)
atkpercent -= 25;
if (sc->getSCE(SC_INCATKRATE))
atkpercent += sc->getSCE(SC_INCATKRATE)->val1;
if (sc->getSCE(SC_SKE))
atkpercent += 300;
if (sc->getSCE(SC_BLOODLUST))
atkpercent += sc->getSCE(SC_BLOODLUST)->val2;
if (sc->getSCE(SC_FLEET))
atkpercent += sc->getSCE(SC_FLEET)->val3;
/* Only few selected skills should use this function, DO NOT ADD any that are not caused by the skills listed below
* TODO:
* NPC_INVINCIBLE (+100)
* GD_GUARDUP (2*skLevel+8)
* EL_WATERBARRIER (-3)
* SC_ENERVATION (-30/-40/-50)
* MH_EQC (skLevel*5)
* MH_VOLCANIC_ASH (-50)
*/
return (unsigned short)cap_value(atkpercent, 0, USHRT_MAX);
}
/*======================================================
* Calculate skill level ratios for weapon-based skills
*------------------------------------------------------
@ -4308,6 +4394,10 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
//Skill damage modifiers that stack linearly
if(sc && skill_id != PA_SACRIFICE) {
#ifdef RENEWAL
//ATK percent modifier (in renewal, it's applied before the skillratio)
skillratio = battle_get_atkpercent(src, skill_id, sc);
#endif
if(sc->getSCE(SC_OVERTHRUST))
skillratio += sc->getSCE(SC_OVERTHRUST)->val3;
if(sc->getSCE(SC_MAXOVERTHRUST))
@ -4317,10 +4407,6 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
skillratio += 100;
#else
skillratio += 200;
if (sc && sc->getSCE(SC_TRUESIGHT))
skillratio += 2 * sc->getSCE(SC_TRUESIGHT)->val1;
if (sc->getSCE(SC_CONCENTRATION) && (skill_id != RK_DRAGONBREATH && skill_id != RK_DRAGONBREATH_WATER && skill_id != NPC_DRAGONBREATH))
skillratio += sc->getSCE(SC_CONCENTRATION)->val2;
#endif
if (!skill_id || skill_id == KN_AUTOCOUNTER) {
if (sc->getSCE(SC_CRUSHSTRIKE)) {
@ -4378,12 +4464,6 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
case MA_CHARGEARROW:
skillratio += 50;
break;
#ifndef RENEWAL
case HT_FREEZINGTRAP:
case MA_FREEZINGTRAP:
skillratio += -50 + 10 * skill_lv;
break;
#endif
case KN_PIERCE:
skillratio += 10 * skill_lv;
if (sc && sc->getSCE(SC_CHARGINGPIERCE_COUNT) && sc->getSCE(SC_CHARGINGPIERCE_COUNT)->val1 >= 10)
@ -4533,7 +4613,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
if (sd && pc_checkskill(sd, AM_LEARNINGPOTION))
skillratio += 100; // !TODO: What's this bonus increase?
#else
skillratio += 40 * skill_lv;
skillratio += -50 + 50 * skill_lv;
#endif
break;
case MO_FINGEROFFENSIVE:
@ -6151,10 +6231,9 @@ static void battle_attack_sc_bonus(struct Damage* wd, struct block_list *src, st
if (sc->getSCE(SC_GATLINGFEVER))
ATK_ADD(wd->equipAtk, wd->equipAtk2, sc->getSCE(SC_GATLINGFEVER)->val3);
#else
if (sc->getSCE(SC_TRUESIGHT)) {
ATK_ADDRATE(wd->damage, wd->damage2, 2 * sc->getSCE(SC_TRUESIGHT)->val1);
ATK_ADDRATE(wd->basedamage, wd->basedamage2, 2 * sc->getSCE(SC_TRUESIGHT)->val1);
}
//ATK percent modifier (in pre-renewal, it's applied multiplicatively after the skill ratio)
ATK_RATE(wd->damage, wd->damage2, battle_get_atkpercent(src, skill_id, sc));
ATK_RATE(wd->basedamage, wd->basedamage2, battle_get_atkpercent(src, 0, sc));
#endif
if (sc->getSCE(SC_SPIRIT)) {
if (skill_id == AS_SONICBLOW && sc->getSCE(SC_SPIRIT)->val2 == SL_ASSASIN) {
@ -6377,16 +6456,15 @@ static void battle_calc_defense_reduction(struct Damage* wd, struct block_list *
def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num;
}
}
if (skill_id == AM_ACIDTERROR)
#ifdef RENEWAL
def2 = 0; //Ignore only status defense. [FatalEror]
#else
def1 = 0; //Ignores only armor defense. [Skotlex]
#endif
if(def2 < 1)
def2 = 1;
}
#ifdef RENEWAL
if (skill_id == AM_ACIDTERROR)
def2 = 0; // Ignore only status defense.
#endif
//Damage reduction based on vitality
if (tsd) { //Sd vit-eq
int skill;
@ -6466,18 +6544,12 @@ static void battle_calc_defense_reduction(struct Damage* wd, struct block_list *
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ?100:(is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R)*(def1+vit_def) : (100-def1)),
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ?100:(is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)*(def1+vit_def) : (100-def1))
);
ATK_RATE2(wd->basedamage, wd->basedamage2,
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ? 100 : (is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) * (def1 + vit_def) : (100 - def1)),
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ? 100 : (is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ? (int64)is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) * (def1 + vit_def) : (100 - def1))
);
ATK_RATE(wd->basedamage, wd->basedamage2, 100 - def1);
ATK_ADD2(wd->damage, wd->damage2,
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ?0:-vit_def,
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ?0:-vit_def
);
ATK_ADD2(wd->basedamage, wd->basedamage2,
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_R) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) ? 0 : -vit_def,
attack_ignores_def(wd, src, target, skill_id, skill_lv, EQI_HAND_L) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L) ? 0 : -vit_def
);
ATK_ADD(wd->basedamage, wd->basedamage2, -vit_def);
#endif
}
@ -6517,8 +6589,10 @@ static void battle_calc_attack_post_defense(struct Damage* wd, struct block_list
// Post skill/vit reduction damage increases
#ifndef RENEWAL
//Refine bonus
if (sd && battle_skill_stacks_masteries_vvs(skill_id) && skill_id != MO_INVESTIGATE && skill_id != MO_EXTREMITYFIST) { // Counts refine bonus multiple times
ATK_ADD2(wd->damage, wd->damage2, sstatus->rhw.atk2, sstatus->lhw.atk2);
if (sd) {
if (battle_skill_stacks_masteries_vvs(skill_id)) {
ATK_ADD2(wd->damage, wd->damage2, sstatus->rhw.atk2, sstatus->lhw.atk2);
}
ATK_ADD2(wd->basedamage, wd->basedamage2, sstatus->rhw.atk2, sstatus->lhw.atk2);
}
@ -7184,9 +7258,13 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
wd.dmg_lv = ATK_FLEE;
else if(!(infdef = is_infinite_defense(target, wd.flag))) { //no need for math against plants
battle_calc_skill_base_damage(&wd, src, target, skill_id, skill_lv); // base skill damage
// First call function with skill_id 0 to get base damage of a normal attack
battle_calc_skill_base_damage(&wd, src, target, 0, 0); // base damage
wd.basedamage = wd.damage;
wd.basedamage2 = wd.damage2;
// Now get actual skill damage
if (skill_id != 0)
battle_calc_skill_base_damage(&wd, src, target, skill_id, skill_lv); // base skill damage
int64 ratio = 0;
@ -7347,8 +7425,14 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
battle_attack_sc_bonus(&wd, src, target, skill_id, skill_lv);
#endif
if (wd.damage + wd.damage2) { //Check if attack ignores DEF
if (wd.damage + wd.damage2) {
#ifdef RENEWAL
// Check if attack ignores DEF (in pre-renewal we need to update base damage even when the skill ignores DEF)
if(!attack_ignores_def(&wd, src, target, skill_id, skill_lv, EQI_HAND_L) || !attack_ignores_def(&wd, src, target, skill_id, skill_lv, EQI_HAND_R))
#else
// Shield Boomerang and Rapid Smiting already calculated the defense before the skill ratio was applied
if(skill_id != PA_SHIELDCHAIN && skill_id != CR_SHIELDBOOMERANG)
#endif
battle_calc_defense_reduction(&wd, src, target, skill_id, skill_lv);
battle_calc_attack_post_defense(&wd, src, target, skill_id, skill_lv);
@ -7455,14 +7539,20 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
ATK_ADD(wd.damage, wd.damage2, 4);
if (skill_id == MO_FINGEROFFENSIVE) { //Need to calculate number of Spirit Balls you had before cast
ATK_ADD(wd.damage, wd.damage2, (wd.div_ + sd->spiritball) * 3);
} else
} else if (skill_id != MO_INVESTIGATE)
ATK_ADD(wd.damage, wd.damage2, ((wd.div_ < 1) ? 1 : wd.div_) * sd->spiritball * 3);
#endif
if( skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN ) { //Refine bonus applies after cards and elements.
if (sd && skill_id == PA_SHIELDCHAIN) { //Rapid Smiting has a unique mastery bonus
short index = sd->equip_index[EQI_HAND_L];
if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR )
ATK_ADD(wd.damage, wd.damage2, 10*sd->inventory.u.items_inventory[index].refine);
//The bonus is [max(100, Random(100, 0.7*weight + pow(skill level + refine)))]
if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR) {
//First calculate the random part of the bonus
int bonus = (7 * sd->inventory_data[index]->weight) / 100;
bonus += pow(skill_lv + sd->inventory.u.items_inventory[index].refine, 2);
//Now get a random value between 100 and the random part
bonus = max(100, rnd_value(100, bonus));
ATK_ADD(wd.damage, wd.damage2, bonus);
}
}
#ifndef RENEWAL
//Card Fix for attacker (sd), 2 is added to the "left" flag meaning "attacker cards only"

View File

@ -7027,27 +7027,6 @@ static unsigned short status_calc_batk(struct block_list *bl, status_change *sc,
batk += sc->getSCE(SC_ANGRIFFS_MODUS)->val2;
if(sc->getSCE(SC_2011RWC_SCROLL))
batk += 30;
if(sc->getSCE(SC_INCATKRATE))
batk += batk * sc->getSCE(SC_INCATKRATE)->val1/100;
if(sc->getSCE(SC_PROVOKE))
batk += batk * sc->getSCE(SC_PROVOKE)->val2/100;
#ifndef RENEWAL
if(sc->getSCE(SC_CONCENTRATION))
batk += batk * sc->getSCE(SC_CONCENTRATION)->val2/100;
#endif
if(sc->getSCE(SC_SKE))
batk += batk * 3;
if(sc->getSCE(SC_BLOODLUST))
batk += batk * sc->getSCE(SC_BLOODLUST)->val2/100;
if(sc->getSCE(SC_JOINTBEAT) && sc->getSCE(SC_JOINTBEAT)->val2&BREAK_WAIST)
batk -= batk * 25/100;
if(sc->getSCE(SC_CURSE))
batk -= batk * 25/100;
/* Curse shouldn't effect on this? <- Curse OR Bleeding??
if(sc->getSCE(SC_BLEEDING))
batk -= batk * 25 / 100; */
if(sc->getSCE(SC_FLEET))
batk += batk * sc->getSCE(SC_FLEET)->val3/100;
if(sc->getSCE(SC__ENERVATION))
batk -= batk * sc->getSCE(SC__ENERVATION)->val2 / 100;
if( sc->getSCE(SC_ZANGETSU) )
@ -7122,21 +7101,7 @@ static unsigned short status_calc_watk(struct block_list *bl, status_change *sc,
watk += sc->getSCE(SC_NIBELUNGEN)->val2;
}
}
if(sc->getSCE(SC_CONCENTRATION))
watk += watk * sc->getSCE(SC_CONCENTRATION)->val2 / 100;
#endif
if(sc->getSCE(SC_INCATKRATE))
watk += watk * sc->getSCE(SC_INCATKRATE)->val1/100;
if(sc->getSCE(SC_PROVOKE))
watk += watk * sc->getSCE(SC_PROVOKE)->val2/100;
if(sc->getSCE(SC_SKE))
watk += watk * 3;
if(sc->getSCE(SC_FLEET))
watk += watk * sc->getSCE(SC_FLEET)->val3/100;
if(sc->getSCE(SC_CURSE))
watk -= watk * 25/100;
if(sc->getSCE(SC_STRIPWEAPON) && bl->type != BL_PC)
watk -= watk * sc->getSCE(SC_STRIPWEAPON)->val2/100;
if(sc->getSCE(SC_FIGHTINGSPIRIT))
watk += sc->getSCE(SC_FIGHTINGSPIRIT)->val1;
if (sc->getSCE(SC_SHIELDSPELL_ATK))
@ -12228,7 +12193,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_ASH:
val2 = 0; // hit % reduc
val3 = 0; // def % reduc
val4 = 0; // atk flee & reduc
val4 = 0; // atk flee % reduc
if (!status_bl_has_mode(bl,MD_STATUSIMMUNE)) {
val2 = 50;
if (status_get_race(bl) == RC_PLANT) // plant type