Use spell_bonus_data table for store custom damage/healing bonus coefficients

Big thanks ApoC for help create table.
Fixed bonuses for stacked periodic
Warning need test all coefficients for correct bonus amount.
TODO:
 use this table for absorb bonus calculation
 use this table for melee spells AP bonuses
 use chain multipler in final damage/heal amount

Signed-off-by: DiSlord <dislord@nomail.com>
This commit is contained in:
DiSlord 2009-01-28 02:23:16 +03:00
parent 6d9a099a19
commit 4ecfbcc2f5
13 changed files with 711 additions and 402 deletions

View file

@ -303,6 +303,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
{ "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
{ "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL },
{ "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },

View file

@ -252,6 +252,7 @@ class ChatHandler
bool HandleReloadSpellElixirCommand(const char* args);
bool HandleReloadSpellLearnSpellCommand(const char* args);
bool HandleReloadSpellProcEventCommand(const char* args);
bool HandleReloadSpellBonusesCommand(const char* args);
bool HandleReloadSpellScriptTargetCommand(const char* args);
bool HandleReloadSpellScriptsCommand(const char* args);
bool HandleReloadSpellTargetPositionCommand(const char* args);

View file

@ -137,6 +137,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
HandleReloadSpellElixirCommand("a");
HandleReloadSpellLearnSpellCommand("a");
HandleReloadSpellProcEventCommand("a");
HandleReloadSpellBonusesCommand("a");
HandleReloadSpellScriptTargetCommand("a");
HandleReloadSpellTargetPositionCommand("a");
HandleReloadSpellThreatsCommand("a");
@ -460,6 +461,14 @@ bool ChatHandler::HandleReloadSpellProcEventCommand(const char*)
return true;
}
bool ChatHandler::HandleReloadSpellBonusesCommand(const char*)
{
sLog.outString( "Re-Loading Spell Bonus Data..." );
spellmgr.LoadSpellBonusess();
SendGlobalSysMessage("DB table `spell_bonus_data` (spell damage/healing coefficients) reloaded.");
return true;
}
bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*)
{
sLog.outString( "Re-Loading SpellsScriptTarget..." );

View file

@ -2055,7 +2055,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
{
// prevent double apply bonuses
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
m_modifier.m_amount = caster->SpellHealingBonus(GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE, m_target);
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
return;
}
}
@ -2252,7 +2252,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
if ( caster )
// prevent double apply bonuses
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
m_modifier.m_amount = caster->SpellHealingBonus(GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE, m_target);
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
}
else
{
@ -4240,29 +4240,6 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Consecration
if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
{
// ($m1+0.04*$SPH+0.04*$AP)
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) +
caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellProto), m_target);
m_modifier.m_amount += int32(0.04f*holy + 0.04f*ap);
return;
}
// Seal of Vengeance 0.013*$SPH+0.025*$AP per tick (also can stack)
if(m_spellProto->SpellFamilyFlags & 0x0000080000000000LL)
{
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) +
caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellProto), m_target);
m_modifier.m_amount += int32((0.013f*holy + 0.025f*ap) * GetStackAmount());
return;
}
break;
}
default:
break;
}
@ -5619,7 +5596,7 @@ void Aura::PeriodicTick()
pdamage = pdamageReductedArmor;
}
pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),pdamage,DOT);
pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
// Curse of Agony damage-per-tick calculation
if (GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 0x0000000000000400LL) && GetSpellProto()->SpellIconID==544)
@ -5705,7 +5682,7 @@ void Aura::PeriodicTick()
pdamage = pdamageReductedArmor;
}
pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),pdamage,DOT);
pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
// Reduce dot damage from resilience for players
@ -5749,7 +5726,7 @@ void Aura::PeriodicTick()
if(Player *modOwner = pCaster->GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
uint32 heal = pCaster->SpellHealingBonus(spellProto, uint32(new_damage * multiplier), DOT, pCaster);
uint32 heal = pCaster->SpellHealingBonus(pCaster, spellProto, uint32(new_damage * multiplier), DOT, GetStackAmount());
int32 gain = pCaster->ModifyHealth(heal);
pCaster->getHostilRefManager().threatAssist(pCaster, gain * 0.5f, spellProto);
@ -5778,7 +5755,7 @@ void Aura::PeriodicTick()
else
pdamage = amount;
pdamage = pCaster->SpellHealingBonus(GetSpellProto(), pdamage, DOT, m_target);
pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());

View file

@ -567,7 +567,7 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
if(stacks)
damage += damage * stacks * 10 /100;
}
// Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
// Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
@ -575,15 +575,7 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
}
// Exorcism ($m1+0.15*$SPH+0.15*$AP)
else if(m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
}
// Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP)
// Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
@ -591,14 +583,6 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
}
// Holy Wrath ($m1+0.07*$SPH+0.07*$AP)
else if(m_spellInfo->SpellFamilyFlags & 0x0020000000000000LL)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
}
break;
}
}
@ -2466,14 +2450,14 @@ void Spell::EffectHeal( uint32 /*i*/ )
idx++;
}
int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
addhealth += tickheal * tickcount;
}
else
addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
m_healing+=addhealth;
}
@ -2514,7 +2498,7 @@ void Spell::EffectHealMechanical( uint32 /*i*/ )
if (!caster)
return;
uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
unitTarget->ModifyHealth( int32(damage) );
}
@ -2545,7 +2529,7 @@ void Spell::EffectHealthLeech(uint32 i)
if(m_caster->isAlive())
{
new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
m_caster->ModifyHealth(new_damage);

View file

@ -834,7 +834,7 @@ void SpellMgr::LoadSpellProcEvents()
bar.step();
uint16 entry = fields[0].GetUInt16();
uint32 entry = fields[0].GetUInt32();
const SpellEntry *spell = sSpellStore.LookupEntry(entry);
if (!spell)
@ -878,6 +878,50 @@ void SpellMgr::LoadSpellProcEvents()
sLog.outString( ">> Loaded %u extra spell proc event conditions", count );
}
void SpellMgr::LoadSpellBonusess()
{
mSpellBonusMap.clear(); // need for reload case
uint32 count = 0;
// 0 1 2 3
QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> Loaded %u spell bonus data", count);
return;
}
barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
bar.step();
uint32 entry = fields[0].GetUInt32();
const SpellEntry *spell = sSpellStore.LookupEntry(entry);
if (!spell)
{
sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry);
continue;
}
SpellBonusEntry sbe;
sbe.direct_damage = fields[1].GetFloat();
sbe.dot_damage = fields[2].GetFloat();
sbe.ap_bonus = fields[3].GetFloat();
mSpellBonusMap[entry] = sbe;
} while( result->NextRow() );
delete result;
sLog.outString();
sLog.outString( ">> Loaded %u extra spell bonus data", count);
}
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
{
// No extra req need

View file

@ -580,7 +580,15 @@ struct SpellProcEventEntry
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
};
struct SpellBonusEntry
{
float direct_damage;
float dot_damage;
float ap_bonus;
};
typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap;
typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap;
#define ELIXIR_BATTLE_MASK 0x1
#define ELIXIR_GUARDIAN_MASK 0x2
@ -786,6 +794,23 @@ class SpellMgr
static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
// Spell bonus data
SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const
{
// Lookup data
SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId);
if( itr != mSpellBonusMap.end( ) )
return &itr->second;
// Not found, try lookup for 1 spell rank if exist
if (uint32 rank_1 = GetFirstSpellInChain(spellId))
{
SpellBonusMap::const_iterator itr = mSpellBonusMap.find(rank_1);
if( itr != mSpellBonusMap.end( ) )
return &itr->second;
}
return NULL;
}
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const
{
@ -954,6 +979,7 @@ class SpellMgr
void LoadSpellAffects();
void LoadSpellElixirs();
void LoadSpellProcEvents();
void LoadSpellBonusess();
void LoadSpellTargetPositions();
void LoadSpellThreats();
void LoadSkillLineAbilityMap();
@ -970,6 +996,7 @@ class SpellMgr
SpellAffectMap mSpellAffectMap;
SpellElixirMap mSpellElixirs;
SpellProcEventMap mSpellProcEventMap;
SpellBonusMap mSpellBonusMap;
SkillLineAbilityMap mSkillLineAbilityMap;
SpellPetAuraMap mSpellPetAuraMap;
PetLevelupSpellMap mPetLevelupSpellMap;

View file

@ -7361,7 +7361,7 @@ void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Po
SendMessageToSet(&data, true);
}
uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
{
if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
return pdamage;
@ -7571,23 +7571,15 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
// .. taken pct: dummy auras
AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
if (pVictim->GetTypeId() == TYPEID_PLAYER)
{
switch((*i)->GetSpellProto()->SpellIconID)
//Cheat Death
if (Aura *dummy = pVictim->GetDummyAura(45182))
{
//Cheat Death
case 2109:
if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) )
{
if(pVictim->GetTypeId() != TYPEID_PLAYER)
continue;
float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
if (mod < (*i)->GetModifier()->m_amount)
mod = (*i)->GetModifier()->m_amount;
TakenTotalMod *= (mod+100.0f)/100.0f;
}
break;
float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
if (mod < dummy->GetModifier()->m_amount)
mod = dummy->GetModifier()->m_amount;
TakenTotalMod *= (mod+100.0f)/100.0f;
}
}
@ -7607,274 +7599,93 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
}
// Damage Done from spell damage bonus
uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
// Taken/Done fixed damage bonus auras
int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto));
int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
// Pets just add their bonus damage to their spell damage
// note that their spell damage is just gain of their own auras
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
DoneAdvertisedBenefit += ((Pet*)this)->GetBonusDamage();
// Damage over Time spells bonus calculation
float DotFactor = 1.0f;
if(damagetype == DOT)
{
int32 DotDuration = GetSpellDuration(spellProto);
// 200% limit
if(DotDuration > 0)
{
if(DotDuration > 30000) DotDuration = 30000;
if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
int x = 0;
for(int j = 0; j < 3; j++)
{
if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
{
x = j;
break;
}
}
int DotTicks = 6;
if(spellProto->EffectAmplitude[x] != 0)
DotTicks = DotDuration / spellProto->EffectAmplitude[x];
if(DotTicks)
{
DoneAdvertisedBenefit /= DotTicks;
TakenAdvertisedBenefit /= DotTicks;
}
}
}
// Distribute Damage over multiple effects, reduce by AoE
CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
// 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
for(int j = 0; j < 3; ++j)
{
if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
{
CastingTime /= 2;
break;
}
}
switch(spellProto->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
// Ignite - do not modify, it is (8*Rank)% damage of procing Spell
if(spellProto->Id==12654)
{
return pdamage;
}
// Ice Lance
else 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;
}
// 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.0f : 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_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;
}
// Soul Fire - 115% of Fire Damage
else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184)
{
CastingTime = 4025;
}
// Curse of Agony - 120% of Shadow Damage
else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544)
{
DotFactor = 1.2f;
}
// 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
}
// Unstable Affliction - 180%
else if (spellProto->Id == 31117 && spellProto->SpellIconID == 232)
{
CastingTime = 6300;
}
// Corruption 93%
else if ((spellProto->SpellFamilyFlags & 0x2LL) && spellProto->SpellIconID == 313)
{
DotFactor = 0.93f;
}
break;
case SPELLFAMILY_PALADIN:
// Consecration - 95% of Holy Damage
if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51)
{
DotFactor = 0.95f;
CastingTime = 3500;
}
// Judgement of Righteousness - 32%
else if (spellProto->SpellFamilyFlags & 0x0000000000000400LL)
{
CastingTime = 1120;
}
// Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292)
{
DotFactor = 0.17f;
CastingTime = 3500;
}
// Holy shield - 5% of Holy Damage
else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453)
{
CastingTime = 175;
}
// Blessing of Sanctuary - 0%
else if ((spellProto->SpellFamilyFlags & 0x10000000LL) && spellProto->SpellIconID == 29)
{
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
}
// Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
else if( (spellProto->SpellFamilyFlags & 0x00000000400LL) || spellProto->Id == 23552)
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;
}
// Shadowguard - 28% per charge
else if ((spellProto->SpellFamilyFlags & 0x2000000LL) && spellProto->SpellIconID == 19)
{
CastingTime = 980;
}
// Touch of Weakeness - 10%
else if ((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 1591)
{
CastingTime = 350;
}
// Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
else if (spellProto->SpellFamilyFlags == 0 && spellProto->SpellIconID == 566)
{
CastingTime = 0;
}
// Holy Nova - 14%
else if ((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 1874)
{
CastingTime = 500;
}
break;
case SPELLFAMILY_DRUID:
// Hurricane triggered spell
if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220)
{
CastingTime = 500;
}
break;
case SPELLFAMILY_WARRIOR:
case SPELLFAMILY_HUNTER:
case SPELLFAMILY_ROGUE:
CastingTime = 0;
break;
default:
break;
}
float LvlPenalty = CalculateLevelPenalty(spellProto);
// Spellmod SpellDamage
float SpellModSpellDamage = 100.0f;
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
SpellModSpellDamage /= 100.0f;
float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
float TakenActualBenefit = TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty;
// Check for table values
SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
if (bonus)
{
float coeff;
if (damagetype == DOT)
coeff = bonus->dot_damage * LvlPenalty * stack;
else
coeff = bonus->direct_damage * LvlPenalty * stack;
if (bonus->ap_bonus)
coeff*=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK);
DoneTotal += DoneAdvertisedBenefit * coeff * SpellModSpellDamage;
TakenTotal+= TakenAdvertisedBenefit * coeff;
}
// Default calculation
else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
// Damage Done from spell damage bonus
uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
// Damage over Time spells bonus calculation
float DotFactor = 1.0f;
if(damagetype == DOT)
{
int32 DotDuration = GetSpellDuration(spellProto);
// 200% limit
if(DotDuration > 0)
{
if(DotDuration > 30000) DotDuration = 30000;
if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
int x = 0;
for(int j = 0; j < 3; j++)
{
if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
{
x = j;
break;
}
}
int DotTicks = 6;
if(spellProto->EffectAmplitude[x] != 0)
DotTicks = DotDuration / spellProto->EffectAmplitude[x];
if(DotTicks)
{
DoneAdvertisedBenefit /= DotTicks*stack;
TakenAdvertisedBenefit /= DotTicks*stack;
}
}
}
// Distribute Damage over multiple effects, reduce by AoE
CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
// 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
for(int j = 0; j < 3; ++j)
{
if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
{
CastingTime /= 2;
break;
}
}
DoneTotal += DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage;
TakenTotal+= TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty;
}
float tmpDamage = (float(pdamage)+DoneActualBenefit + DoneTotal)*DoneTotalMod;
float tmpDamage = (pdamage + DoneTotal) * DoneTotalMod;
// apply spellmod to Done damage (flat and pct)
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
tmpDamage = (tmpDamage + TakenActualBenefit + TakenTotal)*TakenTotalMod;
tmpDamage = (tmpDamage + TakenTotal) * TakenTotalMod;
return tmpDamage > 0 ? uint32(tmpDamage) : 0;
}
@ -8101,21 +7912,18 @@ uint32 Unit::SpellCriticalHealingBonus(SpellEntry const *spellProto, uint32 dama
return damage;
}
uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack)
{
// No heal amount for this class spells
if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
return healamount;
// For totems get healing bonus from owner (statue isn't totem in fact)
if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
if(Unit* owner = GetOwner())
return owner->SpellHealingBonus(spellProto, healamount, damagetype, pVictim);
return owner->SpellHealingBonus(pVictim, spellProto, healamount, damagetype, stack);
// Healing Done
// These Spells are doing fixed amount of healing (TODO found less hack-like check)
if (spellProto->Id == 15290 || spellProto->Id == 39373 ||
spellProto->Id == 33778 || spellProto->Id == 379 ||
spellProto->Id == 38395 || spellProto->Id == 40972)
return healamount;
// Taken/Done total percent damage auras
float DoneTotalMod = 1.0f;
float TakenTotalMod = 1.0f;
@ -8208,25 +8016,51 @@ uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount,
}
}
// Taken/Done fixed damage bonus auras
int32 DoneAdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
int32 TakenAdvertisedBenefit = SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
if (DoneAdvertisedBenefit != 0 && TakenAdvertisedBenefit!=0)
float LvlPenalty = CalculateLevelPenalty(spellProto);
// Spellmod SpellDamage
float SpellModSpellDamage = 100.0f;
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, SpellModSpellDamage);
SpellModSpellDamage /= 100.0f;
// Check for table values
SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
if (bonus)
{
// Healing over Time spells
float coeff;
if (damagetype == DOT)
coeff = bonus->dot_damage * LvlPenalty * stack;
else
coeff = bonus->direct_damage * LvlPenalty * stack;
if (bonus->ap_bonus)
coeff*=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK);
DoneTotal += DoneAdvertisedBenefit * coeff * SpellModSpellDamage;
TakenTotal+= TakenAdvertisedBenefit * coeff;
}
// Default calculation
else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
// Damage Done from spell damage bonus
uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
// Damage over Time spells bonus calculation
float DotFactor = 1.0f;
if(damagetype == DOT)
{
int32 DotDuration = GetSpellDuration(spellProto);
// 200% limit
if(DotDuration > 0)
{
// 200% limit
if(DotDuration > 30000) DotDuration = 30000;
if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
int x = 0;
for(int j = 0; j < 3; j++)
{
if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL ||
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
{
x = j;
@ -8243,85 +8077,20 @@ uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount,
}
}
}
uint32 CastingTime = GetSpellCastTime(spellProto);
// distribute healing to all effects, reduce AoE damage
// Distribute Damage over multiple effects, reduce by AoE
CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
// 0% bonus for damage and healing spells for leech spells from healing bonus
// 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
for(int j = 0; j < 3; ++j)
{
if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
{
CastingTime = 0;
CastingTime /= 2;
break;
}
}
// Exception
switch (spellProto->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
// Healing stream from totem (add 6% per tick from hill bonus owner)
// Possibly need do it on apply dummy aura
if (spellProto->Id == 52042)
CastingTime = 210;
break;
case SPELLFAMILY_SHAMAN:
// Earth Shield 30% per charge
if (spellProto->SpellFamilyFlags & 0x40000000000LL)
CastingTime = 1050;
break;
case SPELLFAMILY_DRUID:
// Lifebloom
if (spellProto->SpellFamilyFlags & 0x1000000000LL)
{
CastingTime = damagetype == DOT ? 3500 : 1200;
DotFactor = damagetype == DOT ? 0.519f : 1.0f;
}
// Tranquility triggered spell
else if (spellProto->SpellFamilyFlags & 0x80LL)
CastingTime = 667;
// Rejuvenation
else if (spellProto->SpellFamilyFlags & 0x10LL)
DotFactor = 0.845f;
// Regrowth
else if (spellProto->SpellFamilyFlags & 0x40LL)
{
DotFactor = damagetype == DOT ? 0.705f : 1.0f;
CastingTime = damagetype == DOT ? 3500 : 1010;
}
break;
case SPELLFAMILY_PRIEST:
// Holy Nova - 14%
if ((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 1874)
CastingTime = 500;
break;
case SPELLFAMILY_PALADIN:
// Seal and Judgement of Light
if ( spellProto->SpellFamilyFlags & 0x100040000LL )
CastingTime = 0;
break;
case SPELLFAMILY_WARRIOR:
case SPELLFAMILY_ROGUE:
case SPELLFAMILY_HUNTER:
CastingTime = 0;
break;
}
float LvlPenalty = CalculateLevelPenalty(spellProto);
// Spellmod SpellDamage
float SpellModSpellDamage = 100.0f;
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
SpellModSpellDamage /= 100.0f;
DoneTotal += (float)DoneAdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
TakenTotal += (float)TakenAdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
DoneTotal += DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f;
TakenTotal+= TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * 1.88f;
}
// use float as more appropriate for negative values and percent applying

View file

@ -1293,8 +1293,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
int32 SpellBaseHealingBonus(SpellSchoolMask schoolMask);
int32 SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim);
int32 SpellBaseHealingBonusForVictim(SpellSchoolMask 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 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype, uint32 stack = 1);
uint32 SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
bool isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType = BASE_ATTACK);
bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK);
uint32 SpellCriticalDamageBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);

View file

@ -1118,6 +1118,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell Proc Event conditions..." );
spellmgr.LoadSpellProcEvents();
sLog.outString( "Loading Spell Bonus Data..." );
spellmgr.LoadSpellBonusess();
sLog.outString( "Loading Aggro Spells Definitions...");
spellmgr.LoadSpellThreats();