Skip to content

Loading…

[Fix] Binary Resistance #4831

Closed
wants to merge 4 commits into from
@Retriman

Its a patch to implement binary resistances. So characters can fully resists spells like fear, purge, polymorph etc, those spells that dont have a "damage" part or have both, damage and effect.
http://www.wowwiki.com/Resistance and http://www.wowwiki.com/Talk:Resistance

Patch based in Dr.Temma Patchs.

Close #1478
Close #4116

Retriman [Fix] Binary Resistance:
Its a patch to implement binary resistances. So characters can fully resists spells like fear, purge, polymorph etc, those spells that dont have a "damage" part or have both, damage and effect.
http://www.wowwiki.com/Resistance and http://www.wowwiki.com/Talk:Resistance

Patch based in Dr.Temma Patchs.
23ad608
@PanDaemonAeon

perfect work!

BUG: Some self buff by Talent (ex: Clearcasting 12536) and npc spell buff on player (ex: Rune Of Power 64320) result full Resist.

@MilleTest : caused by trigger level = 1

-- Rune Of Power
UPDATE creature_template SET minlevel = 83, maxlevel = 83 WHERE entry = 33705;

-- Rotface Ooze Puddle Dummy
UPDATE creature_template SET minlevel = 83, maxlevel = 83 WHERE entry = 37013;

@PanDaemonAeon

Retriman in your patch old identificators

@Retriman

@PanDaemonAeon what old identificators?, spellProto?. if so, I am now upgrading to the new system that SpellInfo.

@PanDaemonAeon

SPELL_ATTR3_IGNORE_HIT_RESULT

@zouzoul

Now possible to fully resist Frostfire Bolt. Normal ?

@Cepox

Yes @zouzoul, since frostfire bolt is a spell that has a snare effect it should be fully resisted or not resisted at all. Frostbolt is the same.

@PanDaemonAeon

if (!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))

line not in kernel

@Retriman

@PanDaemonAeon you talking about? . I do not understand what you mean....

@PanDaemonAeon

Retriman in darkman1983 repo not line...

if (!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))

@Amit86

@pandaemonaeon uh,
src/server/game/Miscellaneous/SharedDefines.h: SPELL_ATTR3_IGNORE_HIT_RESULT = 0x00040000, // 18 Spell should always hit its target

@SignFinder

Retriman - 10x for your work

This pull request close issues:
#1478
#4116

@MilleTest

Crash:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fa7d6fff700 (LWP 10836)]
0x00007fa803f224ac in Unit::CalcSpellResistance (this=0x7fa75a126000,
victim=0x7fa7b0dd5000, schoolMask=SPELL_SCHOOL_MASK_FIRE, binary=false,
spellProto=0x0)
.../src/server/game/Entities/Unit/Unit.cpp:1546
1546 if (spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
<><>STACKTRACE><><>

@Subv

spellProto was NULL in that case, you should check for NULLness before accessing the attributes

@Subv Subv commented on an outdated diff
src/server/game/Entities/Unit/Unit.cpp
((142 lines not shown))
+ if (discreteResistProbability[i] < 0.0f)
+ discreteResistProbability[i] = 0.0f;
+ }
+
+ if (averageResist <= 0.1f)
+ {
+ discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
+ discreteResistProbability[1] = 5.0f * averageResist;
+ discreteResistProbability[2] = 2.5f * averageResist;
+ }
+
+ uint32 resistance = 0;
+ float r = float(rand_norm());
+ float probabilitySum = discreteResistProbability[0];
+
+ while ((r >= probabilitySum) && (resistance < 10))
@Subv
Subv added a note

Why 10? magic numbers :/
why a while loop? if the max is always 10 then use a for loop

@Faq
Faq added a note

hmm

for (uint32 resistance = 1; resistance < 10, r>=probabilitySum; ++resistance)
    probabilitySum += discreteResistProbrability[resistance];
@boomy
boomy added a note

why do you use uint32 in a for loop, when the counter can only be 10? this is senseless, isn't it?

@Faq
Faq added a note

and u prefer what and why?

@boomy
boomy added a note

maybe uint8?!
//EDIT
Sorry forgot the why, because you already know that the variable can only reach 10 and not more. So it it senseless if you use a data type, which range of values is much higher than you need. Programming Basics ;)
(Sorry for bad articulation)

With processors having 32- or 64-bit word length, performing arithmetic operations on all bits "at once", and disk memory aligned to the 32th / 64th bit, I can hardly see any difference, practical or theoretical. If you would be so kind to explain these basics...

@Subv
Subv added a note

^What @Moriquendu said, the variable will be stored in a 32bits register anyways

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@MilleTest

The patch caused bug on dot, removet on resist

@MilleTest

Crash Fix

if (spellProto && spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)

if (spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
if (victim->GetTypeId() == TYPEID_PLAYER)
if(victim != this)
{
int32 tmp = int32(averageResist * 10000);
int32 rand = irand(0, 10000);
return rand < tmp ? 100 : 0;
}
return 0;

Possibile Fix problem for self cast

@zouzoul

@MilleTest : Which DOT ?

DOT do only damage, so it's not binary and cannot be fully resisted (so can't be removed on resist)

Tested with affli warlock

@QAston QAston was assigned
@Cepox

You can resist the application of the Dot and can partialy resist every tick of the dot. I think thats the way it should work because putting a dot on somebody is binary and the damge isnt.

@QAston

Please stick to the codestyle guidelines (Type* var not Type * var for example)
Also, existing reports with bugs with this patch must be fixed before this gets accepted.

@Retriman

Ok. @QAston update now :)! and This pull request close issues:
#1478
#4116

@FilipLukac

old codestyle :) Unit* victim :)

@FilipLukac

I know it's old, but if you see in the line below. is still used.

@zouzoul

Channeled spells start with caster as victim in Unit::CalcSpellResistance
In raid result a lot of Resist due to caster magic resistance buff :s

Tested with Mind Flay

Due to Spell.cpp
m_resist = m_caster->CalcSpellResistance(unit, m_spellSchoolMask , binary, m_spellInfo); ?????????
unit = m_caster when apply the aura but good for DOT

@Moriquendu

m_caster calculates spell resistance AGAINST unit (To take into consideration spell penetration of the caster, for example).

@Aokromes
TrinityCore member

@retriman even if it's still used new code must avoid adding more rows of old coding styles, the target is to remove old coding styles.

@Retriman

Ok, @Aokromes update now ;)

@Dulumun

Retriman why you don't Update your core ?

@QAston

Ok, are problems with this patch solved now? It affects a lot of spells so needs to be tested before applying.

@zouzoul

@QAston :

/// Maybe disable binary resist in PVE ?

-if (spellProto && spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
+if (spellProto && spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY && victim->GetTypeId() == TYPEID_PLAYER)

/// Check if victim = caster then Return 0 (Self cast, Mind flay, Arcane blast debuff, etc.)

@MilleTest

Patch create problem on GO apply buff exp: http://www.wowhead.com/spell=64320 buff result full resist

@Chaplain Chaplain commented on the diff
src/server/game/Entities/GameObject/GameObject.cpp
@@ -1629,6 +1629,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
if (Unit* owner = GetOwner())
{
trigger->setFaction(owner->getFaction());
+ trigger->SetLevel(owner->getLevel());

How this related to binary spells?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@MilleTest

The Self Buff of channeling Mind Flay or Drain Life or Drain Mana, are resistibili, this is to be considered bugs?, or rightly so? self buff on caster not the debuff on the target.

@MilleTest

if (spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
if (victim->GetTypeId() == TYPEID_PLAYER)
if(victim != this)
{
int32 tmp = int32(averageResist * 10000);
int32 rand = irand(0, 10000);
return rand < tmp ? 100 : 0;
}
return 0;

Possibile Fix problem for self cast

@QAston

Well, imo there should be no resist chance for all "assist" targets. @Retriman are you still working on this patch?

@zouzoul

// Magic damage, check for resists
if (uint32(schoolMask & (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_HOLY)) > 0)

SPELL_SCHOOL_HOLY should be --->>> SPELL_SCHOOL_MASK_HOLY

@FilipLukac FilipLukac commented on the diff
src/server/game/Entities/Unit/Unit.cpp
((21 lines not shown))
- if (Player* player = ToPlayer())
- victimResistance -= float(player->GetSpellPenetrationItemMod());
+ if (source)

wtf?:D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Retriman

@QAston, yes working in patch

@FilipLukac

You was removed resistance for players in pve, players must resist too damage from bosses, and you have issue with full resist in pve... Boses cant full resist damage from players. I was fixed it, if u want ill make pull request

@Retriman

we have completely "solved" the resistance binary. I expect soon we will have news of a new patch 100% optimal

@click
TrinityCore member

Cleaned up comments and reopened original issue, as it has not been resolved. Awaiting further information from @Retriman or other pullrequests handling the same issue.

@Faq

made it all in 1 commit+cleanup
Faq@e93bab2

Pls review and suggest any corrections.
Lets get this pats done together.

@FilipLukac

You still have removed resistances in PvE ;]

  • You have deleted method wich you can resist damage from bosses ^_^ its currently working
  • You CAN'T full resist dmg to bosses and bosses dmg to you
  • You must rewrite some variables, and make some corections in math
  • You will win this figt :>
@Faq
  • i havnt deleted anything there, show where and what i deleted?
@saqirmdev

game/Entities/Unit/Unit.cpp:2451: error: no 'uint32 Unit::CalcMagicSpellHitChance(Unit, SpellSchoolMask, const SpellInfo)' member function declared in class 'Unit'
game/Entities/Unit/Unit.cpp: In member function 'SpellMissInfo Unit::MagicSpellHitResult(Unit, const SpellInfo)':
game/Entities/Unit/Unit.cpp:2576: error: 'CalcMagicSpellHitChance' was not declared in this scope
make[2]: *** [src/server/game/CMakeFiles/game.dir/Entities/Unit/Unit.cpp.o] Error 1

@Faq

in unit.h there is

uint32 CalcMagicSpellHitChance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellProto);

I guess, u have bad merge?

@Aokromes
TrinityCore member

Plz create a new PR for this. #1478

@Aokromes Aokromes closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 15, 2012
  1. [Fix] Binary Resistance:

    Retriman committed
    Its a patch to implement binary resistances. So characters can fully resists spells like fear, purge, polymorph etc, those spells that dont have a "damage" part or have both, damage and effect.
    http://www.wowwiki.com/Resistance and http://www.wowwiki.com/Talk:Resistance
    
    Patch based in Dr.Temma Patchs.
Commits on Jan 31, 2012
  1. [Fix] Binary Resistance: remove blank space

    Retriman committed
View
2 src/server/game/Entities/GameObject/GameObject.cpp
@@ -1629,6 +1629,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
if (Unit* owner = GetOwner())
{
trigger->setFaction(owner->getFaction());
+ trigger->SetLevel(owner->getLevel());

How this related to binary spells?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
// needed for GO casts for proper target validation checks
trigger->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, owner->GetGUID());
trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID());
@@ -1636,6 +1637,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId)
else
{
trigger->setFaction(14);
+ trigger->SetLevel(target ? target->getLevel() : 255);
// Set owner guid for target if no owner avalible - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0);
View
6 src/server/game/Entities/Player/Player.cpp
@@ -7857,8 +7857,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
ApplyHealthRegenBonus(int32(val), apply);
break;
case ITEM_MOD_SPELL_PENETRATION:
- ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -val, apply);
- m_spellPenetrationItemMod += apply ? val : -val;
+ ApplySpellPenetrationBonus(int32(val), apply);
break;
// deprecated item mods
case ITEM_MOD_SPELL_HEALING_DONE:
@@ -13884,8 +13883,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "+ %u HEALTH_REGENERATION", enchant_amount);
break;
case ITEM_MOD_SPELL_PENETRATION:
- ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, enchant_amount, apply);
- m_spellPenetrationItemMod += apply ? int32(enchant_amount) : -int32(enchant_amount);
+ ApplySpellPenetrationBonus(enchant_amount, apply);
sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "+ %u SPELL_PENETRATION", enchant_amount);
break;
case ITEM_MOD_BLOCK_VALUE:
View
3 src/server/game/Entities/Player/Player.h
@@ -1875,6 +1875,7 @@ class Player : public Unit, public GridObject<Player>
bool UpdateStats(Stats stat);
bool UpdateAllStats();
+ void ApplySpellPenetrationBonus(int32 amount, bool apply);
void UpdateResistances(uint32 school);
void UpdateArmor();
void UpdateMaxHealth();
@@ -1901,7 +1902,7 @@ class Player : public Unit, public GridObject<Player>
float OCTRegenMPPerSpirit();
float GetRatingMultiplier(CombatRating cr) const;
float GetRatingBonusValue(CombatRating cr) const;
- uint32 GetBaseSpellPowerBonus() { return m_baseSpellPower; }
+ uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; }
int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; }
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const;
View
6 src/server/game/Entities/Unit/StatSystem.cpp
@@ -183,6 +183,12 @@ bool Player::UpdateAllStats()
return true;
}
+void Player::ApplySpellPenetrationBonus(int32 amount, bool apply)
+{
+ ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -amount, apply);
+ m_spellPenetrationItemMod += apply ? amount : -amount;
+}
+
void Player::UpdateResistances(uint32 school)
{
if (school > SPELL_SCHOOL_NORMAL)
View
300 src/server/game/Entities/Unit/Unit.cpp
@@ -902,7 +902,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
return damageInfo.damage;
}
-void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit)
+void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit, int32 calc_resist)
{
if (damage < 0)
return;
@@ -999,7 +999,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
// Calculate absorb resist
if (damage > 0)
{
- CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
+ CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo, calc_resist);
damage -= damageInfo->absorb + damageInfo->resist;
}
else
@@ -1467,74 +1467,132 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo
return (newdamage > 1) ? newdamage : 1;
}
-void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32 *absorb, uint32 *resist, SpellInfo const* spellInfo)
+uint32 Unit::GetSpellPenetration(SpellSchoolMask schoolMask) const
{
- if (!victim || !victim->isAlive() || !damage)
- return;
+ int32 spellPenetration = 0;
- DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
+ const Unit * source = ToPlayer();
- // Magic damage, check for resists
- if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
+ if (!source)
{
- float victimResistance = float(victim->GetResistance(schoolMask));
- victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ source = ToCreature();
- if (Player* player = ToPlayer())
- victimResistance -= float(player->GetSpellPenetrationItemMod());
+ if (source)

wtf?:D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ source = source->ToCreature()->GetOwner();
+ if (source)
+ source = source->ToPlayer();
+ }
+ }
+
+ if (source && !isTotem())
+ spellPenetration += source->ToPlayer()->GetSpellPenetrationItemMod();
+ else
+ source = this;
- // Resistance can't be lower then 0.
- if (victimResistance < 0.0f)
- victimResistance = 0.0f;
+ spellPenetration += -source->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
- static uint32 const BOSS_LEVEL = 83;
- static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
- uint32 level = victim->getLevel();
- float resistanceConstant = 0.0f;
+ return uint32(std::max<int32>(spellPenetration, 0));
+}
- if (level == BOSS_LEVEL)
- resistanceConstant = BOSS_RESISTANCE_CONSTANT;
- else
- resistanceConstant = level * 5.0f;
+uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, bool binary, SpellInfo const* spellProto) const
+{
+ // Magic damage, check for resists
+ if (uint32(schoolMask & (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_HOLY)) > 0)
+ return 0;
- float averageResist = victimResistance / (victimResistance + resistanceConstant);
- float discreteResistProbability[11];
- for (uint32 i = 0; i < 11; ++i)
- {
- discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
- if (discreteResistProbability[i] < 0.0f)
- discreteResistProbability[i] = 0.0f;
- }
+ // These spells should ignore any resistances
+ if (spellProto && spellProto->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ return 0;
- if (averageResist <= 0.1f)
- {
- discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
- discreteResistProbability[1] = 5.0f * averageResist;
- discreteResistProbability[2] = 2.5f * averageResist;
- }
+ uint8 BOSS_LEVEL = 83;
+ int32 BOSS_RESISTANCE_CONSTANT = 510;
+ int32 resistanceConstant = 0;
+
+ if (getLevel() >= BOSS_LEVEL)
+ resistanceConstant = BOSS_RESISTANCE_CONSTANT;
+ else
+ resistanceConstant = getLevel() * 5;
+
+ int32 levelDiff = std::max<int32>(victim->getLevel() - getLevel(), 0);
+ int32 baseVictimResistance = victim->GetResistance(GetFirstSchoolInMask(schoolMask));
+ uint32 spellPenetration = GetSpellPenetration(schoolMask);
+ int32 victimResistance = std::max<int32>(baseVictimResistance - spellPenetration, 0);
+ int32 ignoredResistance = 0;
+
+ if (victimResistance > 0)
+ {
+ AuraEffectList const & aurasA = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasA.begin(); itr != aurasA.end(); ++itr)
+ if (((*itr)->GetMiscValue() & schoolMask) && (*itr)->IsAffectedOnSpell(spellProto))
+ ignoredResistance += (*itr)->GetAmount();
+
+ AuraEffectList const & aurasB = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasB.begin(); itr != aurasB.end(); ++itr)
+ if ((*itr)->GetMiscValue() & schoolMask)
+ ignoredResistance += (*itr)->GetAmount();
+
+ ignoredResistance = std::min<int32>(ignoredResistance, 100);
+ }
+
+ victimResistance = victimResistance * (100 - ignoredResistance) / 100;
+ victimResistance += (levelDiff * 5); // Level diff resistance cannot be pierced
+
+ if (victimResistance <= 0)
+ return 0;
- float r = float(rand_norm());
- uint32 i = 0;
- float probabilitySum = discreteResistProbability[0];
+ float averageResist = float(victimResistance) / float(victimResistance + resistanceConstant);
+
+ if (spellProto && spellProto->AttributesCu & SPELL_ATTR0_CU_BINARY)
+ {
+ int32 tmp = int32(averageResist * 10000);
+ int32 rand = irand(0, 10000);
+ return rand < tmp ? 100 : 0;
+ }
- while (r >= probabilitySum && i < 10)
- probabilitySum += discreteResistProbability[++i];
+ float discreteResistProbability[11];
- float damageResisted = float(damage * i / 10);
+ for (uint32 i = 0; i < 11; i++)
+ {
+ discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
+ if (discreteResistProbability[i] < 0.0f)
+ discreteResistProbability[i] = 0.0f;
+ }
- AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
- if (((*j)->GetMiscValue() & schoolMask) && (*j)->IsAffectedOnSpell(spellInfo))
- AddPctN(damageResisted, -(*j)->GetAmount());
+ if (averageResist <= 0.1f)
+ {
+ discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
+ discreteResistProbability[1] = 5.0f * averageResist;
+ discreteResistProbability[2] = 2.5f * averageResist;
+ }
- AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
- if ((*j)->GetMiscValue() & schoolMask)
- AddPctN(damageResisted, -(*j)->GetAmount());
+ uint32 resistance = 0;
+ float r = float(rand_norm());
+ float probabilitySum = discreteResistProbability[0];
- dmgInfo.ResistDamage(uint32(damageResisted));
+ while ((r >= probabilitySum) && (resistance < 10))
+ {
+ ++resistance;
+ probabilitySum += discreteResistProbability[resistance];
}
+ return (resistance * 10);
+}
+
+void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo, int32 calc_resist)
+{
+ if (!victim || !victim->isAlive() || !damage)
+ return;
+
+ DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
+
+ bool binary = (spellInfo && (uint32(spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY) > 0));
+ if (!binary)
+ if (calc_resist >= 0)
+ dmgInfo.ResistDamage(damage * calc_resist / 100);
+ else
+ dmgInfo.ResistDamage(damage * CalcSpellResistance(victim, schoolMask, binary, spellInfo) / 100);
+
// Ignore Absorption Auras
float auraAbsorbMod = 0;
AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
@@ -2155,7 +2213,7 @@ bool Unit::isBlockCritical()
return false;
}
-int32 Unit::GetMechanicResistChance(const SpellInfo* spell)
+int32 Unit::GetMechanicResistChance(const SpellInfo* spell) const
{
if (!spell)
return 0;
@@ -2349,19 +2407,13 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
return SPELL_MISS_NONE;
}
-// TODO need use unit spell resistances in calculations
-SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
+uint32 Unit::CalcMagicSpellHitChance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellProto)
{
- // Can`t miss on dead target (on skinning for example)
- if (!victim->isAlive() && victim->GetTypeId() != TYPEID_PLAYER)
- return SPELL_MISS_NONE;
-
- SpellSchoolMask schoolMask = spell->GetSchoolMask();
// PvP - PvE spell misschances per leveldif > 2
int32 lchance = victim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
int32 thisLevel = getLevelForTarget(victim);
if (GetTypeId() == TYPEID_UNIT && ToCreature()->isTrigger())
- thisLevel = std::max<int32>(thisLevel, spell->SpellLevel);
+ thisLevel = std::max<int32>(thisLevel, spellProto->SpellLevel);
int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel;
// Base hit chance from attacker and victim levels
@@ -2371,59 +2423,54 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
else
modHitChance = 94 - (leveldif - 2) * lchance;
+ Unit * source = ToPlayer();
+ if (!source)
+ {
+ source = ToCreature();
+ if (source)
+ {
+ source = source->ToCreature()->GetOwner();
+ if (source)
+ source = source->ToPlayer();
+ }
+ }
+ if (source && !isTotem())
+ source->ToPlayer()->ApplySpellMod(spellProto->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
+ else
+ source = this;
+
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
// Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
- if (!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if (!(spellProto->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
{
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
- modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
+ if (!(spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellIconID == 3178)) // Chaos Bolt should ignore it
+ modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
// Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
- if (spell->IsAOE())
+ if (spellProto->IsAOE())
modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
// Decrease hit chance from victim rating bonus
if (victim->GetTypeId() == TYPEID_PLAYER)
modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
- }
-
- int32 HitChance = modHitChance * 100;
- // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
- HitChance += int32(m_modSpellHitChance * 100.0f);
-
- if (HitChance < 100)
- HitChance = 100;
- else if (HitChance > 10000)
- HitChance = 10000;
-
- int32 tmp = 10000 - HitChance;
-
- int32 rand = irand(0, 10000);
-
- if (rand < tmp)
- return SPELL_MISS_MISS;
-
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if (spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- return SPELL_MISS_NONE;
+ }
// Chance resist mechanic (select max value from every mechanic spell effect)
- int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
- tmp += resist_chance;
+ modHitChance -= victim->GetMechanicResistChance(spellProto);
// Chance resist debuff
- if (!spell->IsPositive())
+ if (!spellProto->IsPositive())
{
bool bNegativeAura = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (spell->Effects[i].ApplyAuraName != 0)
+ if (spellProto->Effects[i].ApplyAuraName != 0)
{
bNegativeAura = true;
break;
@@ -2432,25 +2479,70 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
if (bNegativeAura)
{
- tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
- tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
+ modHitChance -= victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellProto->Dispel));
+ modHitChance -= victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellProto->Dispel));
}
}
- // Roll chance
- if (rand < tmp)
- return SPELL_MISS_RESIST;
+ int32 hit = modHitChance * 100;
+ // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
+ hit += int32(source->m_modSpellHitChance * 100.0f);
+
+ // Decrease hit chance from victim rating bonus
+ if (victim->ToPlayer())
+ hit -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL) * 100.0f);
+
+ hit = std::min<int32>(std::max<int32>(hit, 100), 10000);
+
+ return uint32(hit);
+}
+
+SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
+{
+ // Can`t miss on dead target (on skinning for example)
+ if (!victim->isAlive() && victim->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_MISS_NONE;
+
+ SpellSchoolMask schoolMask = spell->GetSchoolMask();
+
+ int32 ignoredResistance = 0;
+
+ AuraEffectList const & aurasA = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasA.begin(); itr != aurasA.end(); ++itr)
+ if (((*itr)->GetMiscValue() & schoolMask) && (*itr)->IsAffectedOnSpell(spell))
+ ignoredResistance += (*itr)->GetAmount();
+
+ AuraEffectList const & aurasB = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for (AuraEffectList::const_iterator itr = aurasB.begin(); itr != aurasB.end(); ++itr)
+ if ((*itr)->GetMiscValue() & schoolMask)
+ ignoredResistance += (*itr)->GetAmount();
+
+ ignoredResistance = std::min(ignoredResistance, int32(100));
// cast by caster in front of victim
- if (victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
- tmp += deflect_chance;
- if (rand < tmp)
- return SPELL_MISS_DEFLECT;
- }
+ int32 deflect_chance = (victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * (100 - ignoredResistance) / 100) * 100;
- return SPELL_MISS_NONE;
+ if (deflect_chance > 0)
+ if (victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
+ {
+ int32 rand = irand(0, 10000);
+
+ if (rand < deflect_chance)
+ return SPELL_MISS_DEFLECT;
+ }
+
+ int32 miss = (10000 - CalcMagicSpellHitChance(victim, schoolMask, spell)) * (100 - ignoredResistance) / 100;
+
+ int32 rand = irand(0, 10000);
+
+ if (rand < miss)
+ return SPELL_MISS_MISS;
+
+ // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
+ // resist and deflect chances
+ if (spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ return SPELL_MISS_NONE;
+ return SPELL_MISS_NONE;
}
// Calculate spell hit result can be:
View
11 src/server/game/Entities/Unit/Unit.h
@@ -1319,6 +1319,7 @@ class Unit : public WorldObject
uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); }
uint32 GetResistance(SpellSchoolMask mask) const;
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); }
+ uint32 GetSpellPenetration(SpellSchoolMask schoolMask) const;
uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
@@ -1435,7 +1436,7 @@ class Unit : public WorldObject
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
void HandleProcExtraAttackFor(Unit* victim);
- void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false);
+ void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false, int32 calc_resist = -1);
void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss);
// player or player's pet resilience (-1%)
@@ -1458,14 +1459,15 @@ class Unit : public WorldObject
float MeleeSpellMissChance(const Unit* pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
SpellMissInfo MeleeSpellHitResult(Unit* pVictim, SpellInfo const* spell);
SpellMissInfo MagicSpellHitResult(Unit* pVictim, SpellInfo const* spell);
- SpellMissInfo SpellHitResult(Unit* pVictim, SpellInfo const* spell, bool canReflect = false);
+ SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spell, bool canReflect = false);
+ uint32 CalcMagicSpellHitChance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellProto);
float GetUnitDodgeChance() const;
float GetUnitParryChance() const;
float GetUnitBlockChance() const;
float GetUnitMissChance(WeaponAttackType attType) const;
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* pVictim) const;
- int32 GetMechanicResistChance(const SpellInfo* spell);
+ int32 GetMechanicResistChance(const SpellInfo* spell) const;
bool CanUseAttackType(uint8 attacktype) const
{
switch (attacktype)
@@ -2020,7 +2022,8 @@ class Unit : public WorldObject
// redefined in Creature
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS);
uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType=MAX_ATTACK);
- void CalcAbsorbResist(Unit* pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellInfo const* spellInfo = NULL);
+ void CalcAbsorbResist(Unit* pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL, int32 calc_resist = -1);
+ uint32 CalcSpellResistance(Unit* pVictim, SpellSchoolMask schoolMask, bool binary, SpellInfo const* spellProto) const;
void CalcHealAbsorb(Unit* pVictim, const SpellInfo* spellProto, uint32 &healAmount, uint32 &absorb);
void UpdateSpeed(UnitMoveType mtype, bool forced);
View
25 src/server/game/Spells/Spell.cpp
@@ -999,7 +999,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.missCondition = SPELL_MISS_NONE;
}
else
- targetInfo.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
+ targetInfo.missCondition = SPELL_MISS_EVADE;
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
@@ -1193,6 +1193,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Reset damage/healing counter
m_damage = target->damage;
m_healing = -target->damage;
+ m_resist = 0;
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
@@ -1219,11 +1220,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (spellHitTarget)
{
- SpellMissInfo missInfo2 = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura);
- if (missInfo2 != SPELL_MISS_NONE)
+ SpellMissInfo tmp = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura);
+ if (tmp != SPELL_MISS_NONE)
{
- if (missInfo2 != SPELL_MISS_MISS)
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
+ if (tmp != SPELL_MISS_MISS)
+ m_caster->SendSpellMiss(unit, m_spellInfo->Id, tmp);
m_damage = 0;
spellHitTarget = NULL;
}
@@ -1316,7 +1317,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
// Add bonuses and fill damageInfo struct
- caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
+ caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit, m_resist);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
// Send log damage message to client
@@ -1438,6 +1439,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, const uint32 effectMask, bool
//TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
+
+ bool binary = uint32(m_spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY);
+ m_resist = m_caster->CalcSpellResistance(unit, m_spellSchoolMask , binary, m_spellInfo);
+ if (m_resist >= 100)
+ return SPELL_MISS_RESIST;
}
else if (m_caster->IsFriendlyTo(unit))
{
@@ -1460,6 +1466,13 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, const uint32 effectMask, bool
}
}
}
+ else if (!m_spellInfo->IsPositive())
+ {
+ bool binary = uint32(m_spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY);
+ m_resist = m_caster->CalcSpellResistance(unit, m_spellSchoolMask , binary, m_spellInfo);
+ if (m_resist >= 100)
+ return SPELL_MISS_RESIST;
+ }
// Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell);
View
1 src/server/game/Spells/Spell.h
@@ -551,6 +551,7 @@ class Spell
// Damage and healing in effects need just calculate
int32 m_damage; // Damge in effects count here
int32 m_healing; // Healing in effects count here
+ int32 m_resist; // Resist in effects count here
// ******************************************
// Spell trigger system
View
1 src/server/game/Spells/SpellInfo.h
@@ -201,6 +201,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
+ SPELL_ATTR0_CU_BINARY = 0x00100000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2,
};
View
44 src/server/game/Spells/SpellMgr.cpp
@@ -2676,17 +2676,32 @@ void SpellMgr::LoadSpellCustomAttr()
spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_OBS_MOD_POWER:
case SPELL_AURA_POWER_BURN:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ break;
+ }
+
+ switch (spellInfo->Effects[j].Mechanic)
+ {
+ case MECHANIC_SNARE:
+ case MECHANIC_ROOT:
+ case MECHANIC_INTERRUPT:
+ case MECHANIC_SILENCE:
+ case MECHANIC_HORROR:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
}
switch (spellInfo->Effects[j].Effect)
@@ -2699,8 +2714,6 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_EFFECT_HEAL:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
break;
- case SPELL_EFFECT_POWER_DRAIN:
- case SPELL_EFFECT_POWER_BURN:
case SPELL_EFFECT_HEAL_MAX_HEALTH:
case SPELL_EFFECT_HEALTH_LEECH:
case SPELL_EFFECT_HEAL_PCT:
@@ -2716,6 +2729,16 @@ void SpellMgr::LoadSpellCustomAttr()
case SPELL_EFFECT_LEAP_BACK:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
break;
+ case SPELL_EFFECT_DISPEL:
+ case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF:
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
+ case SPELL_EFFECT_POWER_DRAIN:
+ case SPELL_EFFECT_POWER_BURN:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
case SPELL_EFFECT_PICKPOCKET:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
break;
@@ -2752,6 +2775,17 @@ void SpellMgr::LoadSpellCustomAttr()
}
}
+ switch (spellInfo->Mechanic)
+ {
+ case MECHANIC_FEAR:
+ case MECHANIC_CHARM:
+ case MECHANIC_SNARE:
+ case MECHANIC_FREEZE:
+ case MECHANIC_BANISH:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY;
+ break;
+ }
+
if (!spellInfo->_IsPositiveEffect(EFFECT_0, false))
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
Something went wrong with that request. Please try again.