Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 5323) +++ game/Unit.cpp (working copy) @@ -6321,6 +6321,7 @@ uint32 CastingTime = GetSpellCastTime(sCastTimesStore.LookupEntry(spellProto->CastingTimeIndex)); if (CastingTime > 7000) CastingTime = 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds ) if (CastingTime < 1500) CastingTime = 1500; + bool Channeled = (bool)(spellProto->ChannelInterruptFlags); // Taken/Done fixed damage bonus auras int32 DoneAdvertisedBenefit = SpellBaseDamageBonus((int32)(1<School)); @@ -6330,13 +6331,14 @@ float DotFactor = 1.0f; if(damagetype == DOT) { - CastingTime = 3500; + if ( !Channeled ) + CastingTime = 3500; int32 DotDuration = GetSpellDuration(spellProto); // 200% limit if(DotDuration > 0) { if(DotDuration > 30000) DotDuration = 30000; - DotFactor = DotDuration / 15000.0f; + if(!Channeled) DotFactor = DotDuration / 15000.0f; int x = 0; for(int j = 0; j < 3; j++) if(spellProto->Effect[j] == 6) x = j; @@ -6387,10 +6389,55 @@ TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; break; } } + + // Distribute Damage over multiple effects, reduce by AoE + CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); // Exceptions switch(spellProto->SpellFamilyName) { + case SPELLFAMILY_PALADIN: + // Consecration - 95% of Holy Damage + if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51) + { + DotFactor = 0.95f; + CastingTime = 3500; + } + // 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); + float wspeed = GetAttackTime(BASE_ATTACK)/1000; + + if( item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON) + CastingTime = (uint32)wspeed*3500*0.102f; + else + CastingTime = (uint32)wspeed*3500*0.098f; + } + // Judgement of Righteousness - 73% + else if ((spellProto->SpellFamilyFlags & 1024) && spellProto->SpellIconID == 25) + { + CastingTime = 3555; + } + // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications + else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2040) + { + DotFactor = 0.136; + CastingTime = 3500; + } + // 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; + } + // Holy shield - 5% of Holy Damage + else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453) + { + CastingTime = 175; + } + break; case SPELLFAMILY_WARLOCK: // Life Tap if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208) @@ -6406,6 +6453,42 @@ DoneTotalMod = 1.0f; TakenTotalMod = 1.0f; } + // Soul Fire - 115% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184) + { + CastingTime = 4025; + } + // Death Coil - 21.4% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 88) + { + CastingTime = 749; + } + // Curse of Agony - 120% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544) + { + DotFactor = 1.2f; + } + // Siphon Life - 100% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x0100000000LL) && spellProto->SpellIconID == 152) + { + DotFactor = 1.0f; + CastingTime = 3500; + } + // Drain Mana - 0% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548) + { + CastingTime = 0; + } + // Drain Soul 214.3% + else if ((spellProto->SpellFamilyFlags & 0x4000LL) && spellProto->SpellIconID == 113 ) + { + CastingTime = 7500; + } + // Hellfire + else if ((spellProto->SpellFamilyFlags & 0x40LL) && spellProto->SpellIconID == 937) + { + CastingTime = damagetype == DOT ? 5000 : 500; // self damage seems to be so + } break; case SPELLFAMILY_MAGE: // Ice Lance @@ -6415,9 +6498,33 @@ if(pVictim->isFrozen()) // and compensate this for frozen target. TakenTotalMod *= 3.0f; } + // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 ) + { + DotFactor = damagetype == DOT ? 0.2f : 1.0f; + CastingTime = damagetype == DOT ? 3500 : 4025; + } + // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage + else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185) + { + CastingTime = 3500; + DotFactor = damagetype == DOT ? 0 : 1.0f; + } // Molten armor else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL) + { CastingTime = 0; + } + // Arcane Missiles triggered spell + else if ((spellProto->SpellFamilyFlags & 0x200000LL) && spellProto->SpellIconID == 225) + { + CastingTime = 1000; + } + // Blizzard triggered spell + else if ((spellProto->SpellFamilyFlags & 0x80080LL) && spellProto->SpellIconID == 285) + { + CastingTime = 500; + } break; case SPELLFAMILY_SHAMAN: // totem attack @@ -6434,6 +6541,33 @@ else if (spellProto->SpellFamilyFlags & 000000400LL) CastingTime = 1155; // ignore CastingTimePenalty and use as modifier break; + case SPELLFAMILY_PRIEST: + // Mana Burn - 0% of Shadow Damage + if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212) + { + CastingTime = 0; + } + // Mind Flay - 59% of Shadow Damage + else if((spellProto->SpellFamilyFlags & 0x800000LL) && spellProto->SpellIconID == 548) + { + CastingTime = 2065; + } + // Holy Fire - 86.71%, DoT - 16.5% + else if ((spellProto->SpellFamilyFlags & 0x100000LL) && spellProto->SpellIconID == 156) + { + DotFactor = damagetype == DOT ? 0.165f : 1.0f; + CastingTime = damagetype == DOT ? 3500 : 3035; + } + break; + case SPELLFAMILY_DRUID: + // Hurricane triggered spell + if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220) + { + CastingTime = 500; + } + break; + default: + break; } // Level Factor @@ -6680,6 +6814,10 @@ AdvertisedBenefit /= DotTicks; } } + + // distribute healing to all effects, reduce AoE damage + CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); + // Exception switch (spellProto->SpellFamilyName) { @@ -8991,3 +9129,103 @@ else ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply); } + + +uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ) +{ + int32 overTime=0; + bool DirectDamage=false; + bool AreaEffect=false; + + for ( uint32 i=0; i<3;i++) + { + switch ( spellProto->Effect[i] ) + { + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_MANA_DRAIN: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_POWER_BURN: + case SPELL_EFFECT_HEAL: + DirectDamage = 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 ( GetSpellDuration(spellProto) ) + overTime = GetSpellDuration(spellProto); + break; + default: + // -5% per additional effect + CastingTime *= 0.95f; + break; + } + default: + break; + } + + switch (spellProto->EffectImplicitTargetA[i]) + { + case TARGET_AREAEFFECT_CUSTOM: + case TARGET_ALL_ENEMY_IN_AREA: + case TARGET_ALL_ENEMY_IN_AREA_INSTANT: + case TARGET_ALL_PARTY_AROUND_CASTER: + case TARGET_ALL_AROUND_CASTER: + case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: + case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: + case TARGET_ALL_PARTY: + case TARGET_ALL_PARTY_AROUND_CASTER_2: + case TARGET_AREAEFFECT_PARTY: + case TARGET_AREAEFFECT_CUSTOM_2: + case TARGET_AREAEFFECT_PARTY_AND_CLASS: + AreaEffect = true; + break; + default: + break; + } + + switch (spellProto->EffectImplicitTargetB[i]) + { + case TARGET_AREAEFFECT_CUSTOM: + case TARGET_ALL_ENEMY_IN_AREA: + case TARGET_ALL_ENEMY_IN_AREA_INSTANT: + case TARGET_ALL_PARTY_AROUND_CASTER: + case TARGET_ALL_AROUND_CASTER: + case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: + case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: + case TARGET_ALL_PARTY: + case TARGET_ALL_PARTY_AROUND_CASTER_2: + case TARGET_AREAEFFECT_PARTY: + case TARGET_AREAEFFECT_CUSTOM_2: + case TARGET_AREAEFFECT_PARTY_AND_CLASS: + AreaEffect = true; + break; + default: + break; + } + } + + // Combined Spells with Both Over Time and Direct Damage + if ( overTime > 0 && CastingTime > 0 && DirectDamage ) + { + // 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; + + return CastingTime; +} + Index: game/Unit.h =================================================================== --- game/Unit.h (revision 5323) +++ game/Unit.h (working copy) @@ -962,6 +962,7 @@ 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); + uint32 GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime ); 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);