From 434586db987e88af516ff1cf1a9f332955451fbd Mon Sep 17 00:00:00 2001 From: Xaver-DaRed Date: Fri, 3 May 2024 21:34:47 +0200 Subject: [PATCH] Make TryInterruptSpell more understandable --- src/map/utils/battleutils.cpp | 93 +++++++++++++---------------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/src/map/utils/battleutils.cpp b/src/map/utils/battleutils.cpp index 592c80d033e..10245b2190f 100644 --- a/src/map/utils/battleutils.cpp +++ b/src/map/utils/battleutils.cpp @@ -1714,91 +1714,68 @@ namespace battleutils bool TryInterruptSpell(CBattleEntity* PAttacker, CBattleEntity* PDefender, CSpell* PSpell) { - if (PDefender->objtype == TYPE_TRUST) + // Exceptions. + if (PDefender->objtype == TYPE_TRUST || // Caster is a trust. + PDefender->StatusEffectContainer->HasStatusEffect(EFFECT_MANAFONT) || // Caster has Manafont. + (SKILLTYPE)PSpell->getSkillType() == SKILL_SINGING) // Spell is a song. { return false; } - // cannot interrupt when manafont is active - if (PDefender->StatusEffectContainer->HasStatusEffect(EFFECT_MANAFONT)) - { - return false; - } - - // Songs cannot be interrupted by physical attacks. - if ((SKILLTYPE)PSpell->getSkillType() == SKILL_SINGING) - { - return false; - } - - // Reasonable assumption for the time being. - int base = 40; - - int diff = PAttacker->GetMLevel() - PDefender->GetMLevel(); + // Calculate level ratio. + int baseRate = (PDefender->objtype == TYPE_MOB) ? 5 : 50; + float levelRatio = (float)(baseRate + PAttacker->GetMLevel() - PDefender->GetMLevel()) / 100.0f; - if (PDefender->objtype == TYPE_MOB) + if (levelRatio < 0.01) { - base = 5; + levelRatio = 0.01f; } - float check = (float)(base + diff); + // Calculate skill ratio. + float skillRatio = 1.0f; uint8 meritReduction = 0; if (PDefender->objtype == TYPE_PC) - { // Check player's skill. - // For mobs, we can assume their skill is capped at their level, so this term is 1 anyway. - CCharEntity* PChar = (CCharEntity*)PDefender; - float skill = PChar->GetSkill(PSpell->getSkillType()); - if (skill <= 0) - { - skill = 1; - } - - float cap = GetMaxSkill((SKILLTYPE)PSpell->getSkillType(), PChar->GetMJob(), PChar->GetMLevel()); + { + CCharEntity* PChar = (CCharEntity*)PDefender; + float skillCap = GetMaxSkill((SKILLTYPE)PSpell->getSkillType(), PChar->GetMJob(), PChar->GetMLevel()); + float skillLevel = PChar->GetSkill(PSpell->getSkillType()); - // if cap is 0 then player is using a spell from their subjob - if (cap == 0) + // If skill cap is 0, player may be using a spell from their subjob. + if (skillCap == 0) { - cap = GetMaxSkill((SKILLTYPE)PSpell->getSkillType(), PChar->GetSJob(), - PChar->GetMLevel()); // This may need to be re-investigated in the future... + skillCap = GetMaxSkill((SKILLTYPE)PSpell->getSkillType(), PChar->GetSJob(), PChar->GetMLevel()); // This may need to be re-investigated in the future. } - if (skill > cap) + // If skill level is 0, set ratio to 10. + if (skillLevel <= 0) { - skill = cap; + skillRatio = 10.0f; } - - float ratio = cap / skill; - check *= ratio; - - // prevent from spilling over 100 - resulting in players never being interupted - if (check > 100) + else { - check = 100; + skillRatio = skillCap / skillLevel; } - // apply any merit reduction + // Fetch player-only interruption rate reduction from merits. meritReduction = ((CCharEntity*)PDefender)->PMeritPoints->GetMeritValue(MERIT_SPELL_INTERUPTION_RATE, (CCharEntity*)PDefender); } - float interruptRate = ((100.0f - (meritReduction + (float)PDefender->getMod(Mod::SPELLINTERRUPT))) / 100.0f); - - float chance = xirand::GetRandomNumber(1.0f); - - // caps, always give a 1% chance of interrupt // TODO: verify, perhaps there is a breakpoint where this no longer happens. - if (check < 0.01) - { - check = 0.01; - } - // SIRD reduces the interrupt after all the calculations are done -- as evidenced by the infamous "102% SIRD" builds. // Anything less than 102% interrupt results in the ability to be interrupted. // Note: the 102% is probably an x/256 x/1024 nonsense -- sometimes 101% works. - check *= interruptRate; + float SIRDRatio = (100.0f - meritReduction - (float)PDefender->getMod(Mod::SPELLINTERRUPT)) / 100.0f; + float chance = xirand::GetRandomNumber(1.0f); + + // This are all ratios. + // levelRatio : 0.01 to infinity. + // skillRatio: 1.0 to infinity. + // SIRDRatio: No limits. Can be negative. A negative value will guarantee NOT being interrupted. + float finalRatio = levelRatio * skillRatio * SIRDRatio; // TL;DR Higher = Worse = More chances to get interrupted. - if (chance < check) + // You get interrupted. Handle aquaveil. + if (chance < finalRatio) { - // Prevent interrupt if Aquaveil is active, if it were to interrupt. if (PDefender->StatusEffectContainer->HasStatusEffect(EFFECT_AQUAVEIL)) { auto aquaCount = PDefender->StatusEffectContainer->GetStatusEffect(EFFECT_AQUAVEIL)->GetPower(); @@ -1812,7 +1789,7 @@ namespace battleutils } return false; } - // Otherwise interrupt the spell cast. + return true; }