Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 5216) +++ game/Unit.cpp (working copy) @@ -6054,52 +6054,8 @@ } // Exceptions - switch(spellProto->SpellFamilyName) - { - case SPELLFAMILY_WARLOCK: - // Life Tap - if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208) - { - CastingTime = 2800; // 80% from +shadow damage - DoneTotalMod = 1.0f; - TakenTotalMod = 1.0f; - } - // Dark Pact - else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID()) - { - CastingTime = 3360; // 96% from +shadow damage - DoneTotalMod = 1.0f; - TakenTotalMod = 1.0f; - } - break; - case SPELLFAMILY_MAGE: - // Ice Lance - if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186) - { - CastingTime /= 3; // applied 1/3 bonuses in case generic target - if(pVictim->isFrozen()) // and compensate this for frozen target. - TakenTotalMod *= 3.0f; - } - // Molten armor - else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL) - CastingTime = 0; - break; - case SPELLFAMILY_SHAMAN: - // totem attack - if (spellProto->SpellFamilyFlags & 0x000040000000LL) - { - if (spellProto->SpellIconID == 33) // Fire Nova totem attack must be 21.4%(untested) - CastingTime = 749; // ignore CastingTime and use as modifier - else if (spellProto->SpellIconID == 680) // Searing Totem attack 8% - CastingTime = 280; // ignore CastingTime and use as modifier - else if (spellProto->SpellIconID == 37) // Magma totem attack must be 6.67%(untested) - CastingTime = 234; // ignore CastingTimePenalty and use as modifier - } - // Lighting Shield 33% per charge - else if (spellProto->SpellFamilyFlags & 000000400LL) - CastingTime = 1155; // ignore CastingTimePenalty and use as modifier - break; - } + DoSpellBonusCalculations( spellProto, damagetype, CastingTime ); + DoSpellBonusExceptions( spellProto, damagetype, CastingTime, pVictim, DotFactor, DoneTotalMod, TakenTotalMod ); // Level Factor float LvlPenalty = 0.0f; @@ -6344,14 +6300,10 @@ AdvertisedBenefit /= DotTicks; } } - // Exception - switch (spellProto->SpellFamilyName) - { - case SPELLFAMILY_SHAMAN: - if (spellProto->SpellFamilyFlags & 0x000000002000LL) // Healing stream from totem (add 6% per tick from hill bonus owner) - CastingTime = 210; // - break; - } + + DoSpellBonusCalculations( spellProto, damagetype, CastingTime ); + DoSpellBonusExceptions( spellProto, damagetype, CastingTime, pVictim, DotFactor, NULL, NULL ); + // Level Factor float LvlPenalty = 0.0f; if(spellProto->spellLevel < 20) @@ -8759,3 +8711,253 @@ else ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply); } + +void Unit::DoSpellBonusCalculations( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ) +{ + int32 overTime=0; + bool direct=false; + bool AreaEffect=false; + + for ( uint32 i=0; i<3;i++) + { + switch ( spellProto->Effect[i] ) + { + case SPELL_EFFECT_DUMMY: + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + case SPELL_EFFECT_MANA_DRAIN: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_POWER_BURN: + direct = true; + break; + case SPELL_EFFECT_APPLY_AURA: + switch ( spellProto->EffectApplyAuraName[i] ) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_PERIODIC_LEECH: + if ( GetDuration(spellProto) ) + overTime = GetDuration(spellProto); + + break; + default: + // -5% per additional effect + CastingTime *= 0.95f; + break; + } + default: + // -5% per additional effect + CastingTime *= 0.95f; + break; + } + + switch (spellProto->EffectImplicitTargetA[i]) + { + case TARGET_ALL_AROUND_CASTER: + case TARGET_ALL_PARTY_AROUND_CASTER: + case TARGET_ALL_PARTY: + case TARGET_ALL_ENEMY_IN_AREA: + case TARGET_ALL_ENEMY_IN_AREA_INSTANT: + case TARGET_IN_FRONT_OF_CASTER: + AreaEffect = true; + break; + default: + break; + } + } + + // Combined Spells with Both Over Time and Direct Damage + if ( overTime > 0 && CastingTime > 0 && direct ) + { + // Portion to Over Time + float PtOT = (overTime / 15000.f) / ((overTime / 15000.f) + (CastingTime / 3500.f)); + + if ( damagetype == DOT ) + CastingTime *= PtOT; + else if ( PtOT < 1 ) + CastingTime *= 1 - PtOT; + else + CastingTime = 0; + } + + // Area Effect Spells recieve only half of bonus + if ( AreaEffect ) + CastingTime *= 0.5f; + +} + +void Unit::DoSpellBonusExceptions( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime, Unit *pVictim, float DotFactor, float DoneTotalMod, float TakenTotalMod ) +{ + switch(spellProto->SpellFamilyName) + { + case SPELLFAMILY_PALADIN: + // Consecration - 95% of Holy Damage + if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51 ) + { + DotFactor = 0.95f; + return; + } + // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed + else if((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 25) + { + Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + if(item){ + float wspeed = item->GetProto()->Delay/1000.0f; + + if( item->GetProto()->InventoryType == INVTYPE_2HWEAPON) + CastingTime = wspeed*3500*0.102f; + else + CastingTime = wspeed*3500*0.098f; + } + return; + } + // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications + else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2040) + { + // Ignore duration of DoT as only per Tick damage is known + DotFactor = 0.034; + DoneTotalMod = 1.0f; + TakenTotalMod = 1.0f; + return; + } + // Seal of Command - 20% of Done Holy Damage, 29% of Taken Holy Damage + else if (spellProto->Id == 20424) + { + CastingTime = 3500; + DoneTotalMod = 0.2f; + TakenTotalMod = 0.29f; + return; + } + // Holy shield - 5% of Holy Damage + else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453) + { + CastingTime = 175; + return; + } + break; + case SPELLFAMILY_WARLOCK: + // Life Tap - 80% of Shadow Damage + if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208) + { + CastingTime = 2800; + DoneTotalMod = 1.0f; + TakenTotalMod = 1.0f; + return; + } + // Dark Pact - 96% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID()) + { + CastingTime = 3360; + DoneTotalMod = 1.0f; + TakenTotalMod = 1.0f; + return; + } + // Soul Fire - 115% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184) + { + CastingTime = 4025; + return; + } + // Death Coil - 21.4% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 177) + { + CastingTime = 749; + return; + } + // Curse of Agony - 120% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544) + { + DotFactor = 1.2f; + return; + } + // Siphon Life - 100% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x0100000000LL) && spellProto->SpellIconID == 152) + { + DotFactor = 1.0f; + return; + } + // Drain Mana - 0% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548) + { + CastingTime = 0; + return; + } + // Seed of Corruption 22% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x1000000000LL) && spellProto->SpellIconID == 1932 && damagetype == DOT) + { + DotFactor = 0.22f; + return; + } + break; + case SPELLFAMILY_MAGE: + // Ice Lance + if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186) + { + CastingTime /= 3; // applied 1/3 bonuses in case generic target + if(pVictim->isFrozen()) // and compensate this for frozen target. + TakenTotalMod *= 3.0f; + return; + } + // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 ) + { + DotFactor = 0.2f; + CastingTime = damagetype == DOT ? 3500 : 4025; + return; + } + // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185) + { + CastingTime = 3500; + DotFactor = 0; + return; + } + break; + case SPELLFAMILY_SHAMAN: + // Totem attack + if (spellProto->SpellFamilyFlags & 0x000040000000LL) + { + // Fire Nova totem - 21.4% of Fire Damage + if (spellProto->SpellIconID == 33) + CastingTime = 749; + // Searing Totem attack - 8% of Fire Damage + else if (spellProto->SpellIconID == 680) + CastingTime = 280; + // Magma totem attack - 6.67% of Fire Damage + else if (spellProto->SpellIconID == 37) + CastingTime = 234; + return; + } + // Lighting Shield - 33% of Nature Damage per charge + else if (spellProto->SpellFamilyFlags & 000000400LL) + { + CastingTime = 1155; + return; + } + // Healing stream from totem - 6% of Spell Healing per tick + else if (spellProto->SpellFamilyFlags & 0x000000002000LL) + { + CastingTime = 210; + return; + } + break; + case SPELLFAMILY_PRIEST: + // Mana Burn - 0% of Shadow Damage + if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212 ) + { + CastingTime = 0; + return; + } + // Mind Flay - 59% of Shadow Damage + else if(spellProto->SpellFamilyFlags & 0x000000800000LL) + { + DotFactor = 0.59f; + return; + } + } + // Don't use Spell Damage and Healing if not explicitly given above for non-magic spells + if ( spellProto->DmgType != SPELL_DAMAGE_CLASS_MAGIC ) + CastingTime = 0; +} \ No newline at end of file Index: game/Unit.h =================================================================== --- game/Unit.h (revision 5216) +++ game/Unit.h (working copy) @@ -960,7 +960,11 @@ int32 SpellBaseHealingBonusForVictim(int32 SchoolMask, Unit *pVictim); uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype); uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim); - bool SpellCriticalBonus(SpellEntry const *spellProto, uint32 *damage, Unit *pVictim); + + void DoSpellBonusCalculations( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ); + void DoSpellBonusExceptions( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime, Unit *pVictim, float DotFactor, float DoneTotalMod, float TakenTotalMod ); + + bool SpellCriticalBonus(SpellEntry const *spellProto, uint32 *damage, Unit *pVictim); void MeleeDamageBonus(Unit *pVictim, uint32 *damage, WeaponAttackType attType, SpellEntry const *spellProto = NULL); void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply); virtual bool IsImmunedToSpell(SpellEntry const* spellInfo) const; Index: shared/Database/DBCfmt.cpp =================================================================== --- shared/Database/DBCfmt.cpp (revision 5216) +++ shared/Database/DBCfmt.cpp (working copy) @@ -52,7 +52,7 @@ const char SkillLineAbilityfmt[]="xiniixxiixiixxi"; const char SpellCastTimefmt[]="nixx"; const char SpellDurationfmt[]="niii"; -const char SpellEntryfmt[]="niixiiiiiiixixiiiiixxiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiifffixiiissssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiixxfffxxxiii"; +const char SpellEntryfmt[]="niixiiiiiiixixiiiiixxiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiifffixiiissssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiixfffxxxiii"; //const char SpellFocusObjectfmt[]="nsxxxxxxxx"; const char SpellItemEnchantmentfmt[]="niiiiiixxxiiissssssssssssssssxiiii"; const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; Index: shared/Database/DBCStructure.h =================================================================== --- shared/Database/DBCStructure.h (revision 5216) +++ shared/Database/DBCStructure.h (working copy) @@ -495,7 +495,8 @@ uint64 SpellFamilyFlags; // 196+197 uint32 MaxAffectedTargets; // 198 uint32 DmgClass; // 199 - //uint32 unk2[2]; // 200-201 not used + uint32 DmgType; // 200 + //uint32 unk2; // 201 not used float DmgMultiplier[3]; // 202-204 //uint32 unk3[3]; // 205-207 not used null uint32 TotemCategory[2]; // 208-209