From 0e434aa73bb0bbde280c49e1b72187e1b0a199da Mon Sep 17 00:00:00 2001 From: Playtester <3785983+Playtester@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:22:50 +0200 Subject: [PATCH] Grand Cross Damage and Trigger Rework (#8283) - Grand Cross on target is now considered a full magic attack and no longer triggers drain and similar effects that only work with physical attacks * This problem as was introduced in d8a02e9 to fix Coma not working on Grand Cross, but the reason that Coma works on Grand Cross is because it can also trigger on Magic skills (this is already working) - Grand Cross damage on self is still considered as "physical damage received" for reactive cards (e.g. Alarm Card), but no longer as "magical damage received" (e.g. Platinum Shield does not trigger) - Grand Cross no longer channels through the whole "weapon attack" code and just calls the necessary parts directly (it only considers ATK, DEF/VIT_DEF and refine) - Damage parts of Grand Cross can now go below 1 and reduce the other part (e.g. -5 physical damage and 15 magical damage now results in 10 damage instead of 16) - Implemented the official renewal damage formula for Grand Cross: [((ATK+MATK)/2)*RATIO - DEF - VIT_DEF - MDEF - MDEF2] - Fixed the order of damage processing for Grand Cross for fully accurate damage (there were a lot of rounding issues before) - The attribute table is no longer applied twice on self damage (still applied twice on target) - Cards that increase magic damage now work with Grand Cross (e.g. Skeggiold Card) - Changed Grand Cross range to 9 as that's the official range (you never know when it matters) - Fixes #1140 --- db/pre-re/skill_db.yml | 5 +-- db/re/skill_db.yml | 5 +-- src/map/battle.cpp | 87 +++++++++++++++++++++++++++++------------- src/map/skill.cpp | 12 +++--- 4 files changed, 68 insertions(+), 41 deletions(-) diff --git a/db/pre-re/skill_db.yml b/db/pre-re/skill_db.yml index 0e04d253ac..dd1913a72c 100644 --- a/db/pre-re/skill_db.yml +++ b/db/pre-re/skill_db.yml @@ -6887,12 +6887,9 @@ Body: MaxLevel: 10 Type: Magic TargetType: Self - DamageFlags: - IgnoreAtkCard: true - IgnoreFlee: true Flags: TargetSelf: true - Range: 5 + Range: 9 Hit: Single HitCount: 1 Element: Holy diff --git a/db/re/skill_db.yml b/db/re/skill_db.yml index 2e5c1c9b61..6e8bda5fa0 100644 --- a/db/re/skill_db.yml +++ b/db/re/skill_db.yml @@ -7234,9 +7234,8 @@ Body: Type: Magic TargetType: Self DamageFlags: - IgnoreAtkCard: true - IgnoreFlee: true - Range: 5 + IgnoreDefense: true + Range: 9 Hit: Single HitCount: 1 Element: Holy diff --git a/src/map/battle.cpp b/src/map/battle.cpp index a0d026213c..a617acdeb8 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -3378,12 +3378,6 @@ static bool battle_skill_stacks_masteries_vvs(uint16 skill_id, e_bonus_chk_flag case LG_EARTHDRIVE: case NPC_DRAGONBREATH: return false; - case CR_GRANDCROSS: - case NPC_GRANDDARKNESS: - // Grand Cross is influenced by refine bonus but not by atkpercent / masteries / Star Crumbs / Spirit Spheres - if (chk_flag != BCHK_REFINE) - return false; - break; case LK_SPIRALPIERCE: // Spiral Pierce is influenced only by refine bonus and Star Crumbs for players if (chk_flag != BCHK_REFINE && chk_flag != BCHK_STAR) @@ -6627,7 +6621,9 @@ static void battle_calc_defense_reduction(struct Damage* wd, struct block_list * return; if (is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_R) || is_attack_piercing(wd, src, target, skill_id, skill_lv, EQI_HAND_L)) return; - + [[fallthrough]]; + case CR_GRANDCROSS: // Grand Cross is marked as "IgnoreDefense" in renewal as it's applied at the end after already combining ATK and MATK + case NPC_GRANDDARKNESS: // Defense reduction by flat value. // This completely bypasses the normal RE DEF Reduction formula. wd->damage -= (def1 + vit_def); @@ -7537,9 +7533,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl battle_calc_element_damage(&wd, src, target, skill_id, skill_lv); - if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) - return wd; //Enough, rest is not needed. - #ifdef RENEWAL if (is_attack_critical(&wd, src, target, skill_id, skill_lv, false)) { if (sd) { //Check for player so we don't crash out, monsters don't have bonus crit rates [helvetica] @@ -8812,6 +8805,46 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = ad.damage * (100-mdef)/100 - mdef2; #endif } + + //Apply the physical part of the skill's damage. [Skotlex] + switch (skill_id) { + case CR_GRANDCROSS: + case NPC_GRANDDARKNESS: { + // Pre-re ATK = Take atk, apply def reduction and add refine bonus + // Final Damage = (ATK+MATK)*RATIO + // Renewal ATK = Take total atk + // Final Damage = ((ATK+MATK)/2)*RATIO - (tDEF + tMDEF) + // No need to go through the whole physical damage code + struct Damage wd = initialize_weapon_data(src, target, skill_id, skill_lv, mflag); + battle_calc_skill_base_damage(&wd, src, target, skill_id, skill_lv); + // Calculate ATK +#ifdef RENEWAL + if (sd) + wd.damage = wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.percentAtk; +#else + battle_calc_defense_reduction(&wd, src, target, skill_id, skill_lv); + if (sd) { + wd.damage += sstatus->rhw.atk2; + } +#endif + // Combine ATK and MATK +#ifdef RENEWAL + ad.damage = (wd.damage + ad.damage) / 2; +#else + ad.damage = std::max((int64)1, wd.damage + ad.damage); +#endif + // Ratio + skillratio += 40 * skill_lv; + MATK_RATE(skillratio); +#ifdef RENEWAL + // Total defense reduction (renewal only) + battle_calc_defense_reduction(&ad, src, target, skill_id, skill_lv); + ad.damage -= (tstatus->mdef + tstatus->mdef2); +#endif + } + break; + } + if(ad.damage<1) ad.damage=1; else if(sc) { //only applies when hit @@ -8842,26 +8875,26 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (!nk[NK_IGNOREELEMENT]) ad.damage = battle_attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); - //Apply the physical part of the skill's damage. [Skotlex] - switch(skill_id) { - case CR_GRANDCROSS: - case NPC_GRANDDARKNESS: { - struct Damage wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag); - - ad.damage = battle_attr_fix(src, target, wd.damage + ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv) * (100 + 40 * skill_lv) / 100; - if(src == target) { - if(src->type == BL_PC) - ad.damage = ad.damage / 2; - else - ad.damage = 0; - } - } - break; - } - #ifndef RENEWAL ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); #endif + + switch (skill_id) { + case CR_GRANDCROSS: + case NPC_GRANDDARKNESS: + if (src == target) { + // Grand Cross on self first applies attr_fix, then cardfix and finally halves the damage + if (src->type == BL_PC) + ad.damage = ad.damage / 2; + else + ad.damage = 0; + } + else + // Grand Cross on target applies attr_fix, then cardfix and then attr_fix a second time + ad.damage = battle_attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); + break; + } + } //Hint: Against plants damage will still be 1 at this point //Apply DAMAGE_DIV_FIX and check for min damage diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 2232fdb5dc..782c7251fc 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -1540,14 +1540,12 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint case NPC_GRANDDARKNESS: sc_start(src, bl, SC_BLIND, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); - attack_type |= BF_WEAPON; break; case CR_GRANDCROSS: //Chance to cause blind status vs demon and undead element, but not against players if(!dstsd && (battle_check_undead(tstatus->race,tstatus->def_ele) || tstatus->race == RC_DEMON)) sc_start(src,bl,SC_BLIND,100,skill_lv,skill_get_time2(skill_id,skill_lv)); - attack_type |= BF_WEAPON; break; case AM_ACIDTERROR: @@ -2626,8 +2624,11 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * } break; case CR_GRANDCROSS: - case NPC_GRANDDARKNESS: - attack_type |= BF_WEAPON; + if (src == bl) { + // Grand Cross on self specifically only triggers "When hit by physical attack" autospells and ignores everything else + attack_type |= BF_WEAPON; + attack_type &= ~BF_MAGIC; + } break; case LG_HESPERUSLIT: { @@ -4111,9 +4112,6 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * } } - if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) - dmg.flag |= BF_WEAPON; - if( sd && src != bl && damage > 0 && ( dmg.flag&BF_WEAPON || (dmg.flag&BF_MISC && (skill_id == RA_CLUSTERBOMB || skill_id == RA_FIRINGTRAP || skill_id == RA_ICEBOUNDTRAP)) ) ) {