Created
January 10, 2010 21:42
-
-
Save pasdVn/273788 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From d85316e8d2e60481fa6d5e1ebf9525aad1be2bef Mon Sep 17 00:00:00 2001 | |
From: pasdVn <[email protected]> | |
Date: Fri, 2 Oct 2009 18:48:00 +0200 | |
Subject: [PATCH 1/6] reworked pet stats and dynamic stat scaling | |
* added mindmg and maxdmg field to pet_levelstats | |
* cleanup in Pet::InitStatsForLevel() | |
* apply bonuses for pets without scaling aura only static - at summon | |
-> added ap bonus for "shadow fiend" (34433) | |
-> added bonuses and glyph modification (63271) | |
for "Feral Spirit" wolves (51533) | |
-> added spelldamage bonus for "Mirror Image" (55342) | |
* added support for basepoints calculation of dynamic pet scaling auras | |
-> corrected scaling values for hunter pets and implemented scaling | |
modifications ("Wild Hunt" (62758 & ranks), "Hunter vs. Wild" (56339 & ranks)) | |
-> added scaling factors for death knight ghoul and scaling modifications | |
("Glyph of the Ghoul" (58686) | |
-> added calculation for expertise and +hit scaling auras | |
* removed redundant code of old scaling system in pet stat update methods | |
--- | |
src/game/ObjectMgr.cpp | 6 +- | |
src/game/ObjectMgr.h | 4 +- | |
src/game/Pet.cpp | 505 ++++++++++++++++++++++++++++++++++------------ | |
src/game/Pet.h | 6 +- | |
src/game/Player.cpp | 28 +++- | |
src/game/Player.h | 3 + | |
src/game/SharedDefines.h | 2 +- | |
src/game/SpellAuras.cpp | 16 ++ | |
src/game/SpellAuras.h | 1 + | |
src/game/StatSystem.cpp | 101 ++-------- | |
src/game/Unit.cpp | 36 +++- | |
src/game/Unit.h | 1 + | |
12 files changed, 480 insertions(+), 229 deletions(-) | |
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp | |
index dad5410..6c6bb94 100644 | |
--- a/src/game/ObjectMgr.cpp | |
+++ b/src/game/ObjectMgr.cpp | |
@@ -2290,8 +2290,8 @@ void ObjectMgr::LoadPetLevelInfo() | |
{ | |
// Loading levels data | |
{ | |
- // 0 1 2 3 4 5 6 7 8 9 | |
- QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats"); | |
+ // 0 1 2 3 4 5 6 7 8 9 10 11 | |
+ QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor, mindmg, maxdmg FROM pet_levelstats"); | |
uint32 count = 0; | |
@@ -2348,6 +2348,8 @@ void ObjectMgr::LoadPetLevelInfo() | |
pLevelInfo->health = fields[2].GetUInt16(); | |
pLevelInfo->mana = fields[3].GetUInt16(); | |
pLevelInfo->armor = fields[9].GetUInt16(); | |
+ pLevelInfo->mindmg = fields[10].GetUInt16(); | |
+ pLevelInfo->maxdmg = fields[11].GetUInt16(); | |
for (int i = 0; i < MAX_STATS; i++) | |
{ | |
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h | |
index 7e51ba9..f3feea9 100644 | |
--- a/src/game/ObjectMgr.h | |
+++ b/src/game/ObjectMgr.h | |
@@ -172,12 +172,14 @@ typedef std::pair<ItemRequiredTargetMap::const_iterator, ItemRequiredTargetMap:: | |
struct PetLevelInfo | |
{ | |
- PetLevelInfo() : health(0), mana(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } | |
+ PetLevelInfo() : health(0), mana(0), armor(0), mindmg(0), maxdmg(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; } | |
uint16 stats[MAX_STATS]; | |
uint16 health; | |
uint16 mana; | |
uint16 armor; | |
+ uint16 mindmg; | |
+ uint16 maxdmg; | |
}; | |
struct MailLevelReward | |
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp | |
index c077d0a..d67d9a9 100644 | |
--- a/src/game/Pet.cpp | |
+++ b/src/game/Pet.cpp | |
@@ -799,10 +799,12 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) | |
CreatureInfo const *cinfo = GetCreatureInfo(); | |
ASSERT(cinfo); | |
- if(!owner) | |
+ if (!owner) | |
{ | |
+ // Do not remove *owner as function argument, GetOwner() won't work on summoning pet if the owner | |
+ // is no player, because pet is not yet in world; see ObjectAccessor::GetUnit | |
owner = GetOwner(); | |
- if(!owner) | |
+ if (!owner) | |
{ | |
sLog.outError("attempt to summon pet (Entry %u) without owner! Attempt terminated.", cinfo->Entry); | |
return false; | |
@@ -813,172 +815,156 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) | |
SetLevel(petlevel); | |
- SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); | |
+ SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0); | |
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel*50)); | |
+ // find stored pet level stats | |
+ PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(creature_ID, petlevel); | |
+ if (pInfo) | |
+ { | |
+ SetCreateHealth(pInfo->health); | |
+ SetCreateMana(pInfo->mana); | |
- SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME); | |
- SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME); | |
- SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME); | |
+ SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); | |
- SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0); | |
+ SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(pInfo->mindmg)); | |
+ SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(pInfo->maxdmg)); | |
- CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family); | |
- if(cFamily && cFamily->minScale > 0.0f && getPetType()==HUNTER_PET) | |
+ for( int i = STAT_STRENGTH; i < MAX_STATS; ++i) | |
+ { | |
+ SetCreateStat(Stats(i), float(pInfo->stats[i])); | |
+ } | |
+ } | |
+ else | |
{ | |
- float scale; | |
- if (getLevel() >= cFamily->maxScaleLevel) | |
- scale = cFamily->maxScale; | |
- else if (getLevel() <= cFamily->minScaleLevel) | |
- scale = cFamily->minScale; | |
- else | |
- scale = cFamily->minScale + float(getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale); | |
+ //maybe different handling for pets summoned by creatures (fixed states from creatureinfo?) | |
- SetFloatValue(OBJECT_FIELD_SCALE_X, scale); | |
- } | |
- m_bonusdamage = 0; | |
+ // use some fake values | |
+ SetCreateHealth(28 + 30*petlevel); | |
+ SetCreateMana(28 + 10*petlevel); | |
- int32 createResistance[MAX_SPELL_SCHOOL] = {0,0,0,0,0,0,0}; | |
+ SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel*50)); | |
- if(cinfo && getPetType() != HUNTER_PET) | |
- { | |
- createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1; | |
- createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2; | |
- createResistance[SPELL_SCHOOL_NATURE] = cinfo->resistance3; | |
- createResistance[SPELL_SCHOOL_FROST] = cinfo->resistance4; | |
- createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5; | |
- createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6; | |
+ // 0.5dps/lvl, damagerange = petlevel/2 | |
+ SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4))); | |
+ SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); | |
+ | |
+ SetCreateStat(STAT_STRENGTH, 22 + petlevel ); | |
+ SetCreateStat(STAT_AGILITY, 22 + petlevel/2); | |
+ SetCreateStat(STAT_STAMINA, 25 + petlevel ); | |
+ SetCreateStat(STAT_INTELLECT, 28 + petlevel/2); | |
+ SetCreateStat(STAT_SPIRIT, 27 + petlevel/2); | |
} | |
- switch(getPetType()) | |
+ // custom stat calculation | |
+ switch (getPetType()) | |
{ | |
case SUMMON_PET: | |
+ case GUARDIAN_PET: | |
{ | |
- if(owner->GetTypeId() == TYPEID_PLAYER) | |
+ // as the creature_template entries for summoned and guardian pets are just used for | |
+ // pets (not for normal creatures as well), we can use some entries | |
+ SetAttackTime(BASE_ATTACK, cinfo->baseattacktime); | |
+ SetAttackTime(OFF_ATTACK, cinfo->baseattacktime); | |
+ SetAttackTime(RANGED_ATTACK, cinfo->rangeattacktime); | |
+ SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); | |
+ | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cinfo->resistance1)); | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cinfo->resistance2)); | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cinfo->resistance3)); | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cinfo->resistance4)); | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cinfo->resistance5)); | |
+ SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cinfo->resistance6)); | |
+ | |
+ float statBonus[MAX_STATS] = {0, 0, 0, 0, 0}, | |
+ armorBonus = 0, | |
+ apBonus = 0, | |
+ bonusDamage = 0; | |
+ | |
+ // some pets scale not dynamically with master's stats (don't have scaling auras), | |
+ // we just add the bonus here as unit mods | |
+ switch (cinfo->Entry) | |
{ | |
- switch(owner->getClass()) | |
+ // mage's Water Elemental | |
+ case 510: | |
+ case 37994: | |
{ | |
- case CLASS_WARLOCK: | |
- { | |
- | |
- //the damage bonus used for pets is either fire or shadow damage, whatever is higher | |
- uint32 fire = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE); | |
- uint32 shadow = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW); | |
- uint32 val = (fire > shadow) ? fire : shadow; | |
- | |
- SetBonusDamage(int32 (val * 0.15f)); | |
- //bonusAP += val * 0.57; | |
- break; | |
- } | |
- case CLASS_MAGE: | |
- { | |
- //40% damage bonus of mage's frost damage | |
- float val = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST) * 0.4f; | |
- if(val < 0) | |
- val = 0; | |
- SetBonusDamage( int32(val)); | |
- break; | |
- } | |
- default: | |
- break; | |
+ statBonus[STAT_STAMINA] = owner->GetStat(STAT_STAMINA) * 0.3f; | |
+ statBonus[STAT_INTELLECT] = owner->GetStat(STAT_INTELLECT) * 0.3f; | |
+ armorBonus = owner->GetArmor() * 0.35f; | |
+ bonusDamage = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FROST) * 0.4f; | |
+ break; | |
} | |
- } | |
- | |
- SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)) ); | |
- SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)) ); | |
- | |
- //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower)); | |
- | |
- PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(creature_ID, petlevel); | |
- if(pInfo) // exist in DB | |
- { | |
- SetCreateHealth(pInfo->health); | |
- SetCreateMana(pInfo->mana); | |
+ // priest's Shadowfiend | |
+ case 19668: | |
+ { | |
+ apBonus = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW) * 0.565f; | |
+ break; | |
+ } | |
+ // Feral Spirit Wolves | |
+ case 29264: | |
+ { | |
+ // 30% of owners stamina, 35% of owners armor | |
+ statBonus[STAT_STAMINA] = owner->GetStat(STAT_STAMINA) * 0.3f; | |
+ armorBonus = owner->GetArmor() * 0.35f; | |
- if(pInfo->armor > 0) | |
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); | |
+ // 30% of masters attack power, modified by dummy aura | |
+ apBonus = 30; | |
+ if (Aura* pDummy = owner->GetDummyAura(63271)) | |
+ apBonus += pDummy->GetModifier()->m_miscvalue; | |
+ apBonus = apBonus * owner->GetTotalAttackPowerValue(BASE_ATTACK) / 100; | |
- for(int stat = 0; stat < MAX_STATS; ++stat) | |
+ // TODO: hitchance with spell 61783 (cast manually...? not in petspell dbc's :-/) | |
+ break; | |
+ } | |
+ // Mirror Image | |
+ case 31216: | |
{ | |
- SetCreateStat(Stats(stat), float(pInfo->stats[stat])); | |
+ bonusDamage = owner->GetMaxSpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC); | |
+ break; | |
} | |
+ default: | |
+ break; | |
} | |
- else // not exist in DB, use some default fake data | |
- { | |
- sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB",cinfo->Entry); | |
- // remove elite bonuses included in DB values | |
- SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); | |
- SetCreateMana( uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); | |
+ for (uint8 i = 0; i < MAX_STATS; i++) | |
+ HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, statBonus[i] > 0 ? statBonus[i] : 0, true); | |
+ | |
+ HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, armorBonus > 0 ? armorBonus : 0, true); | |
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, apBonus > 0 ? apBonus : 0, true); | |
+ SetBonusDamage(bonusDamage > 0 ? bonusDamage : 0); | |
- SetCreateStat(STAT_STRENGTH, 22); | |
- SetCreateStat(STAT_AGILITY, 22); | |
- SetCreateStat(STAT_STAMINA, 25); | |
- SetCreateStat(STAT_INTELLECT, 28); | |
- SetCreateStat(STAT_SPIRIT, 27); | |
- } | |
break; | |
} | |
case HUNTER_PET: | |
{ | |
+ // hunter pets always use base attack time and do physical damage | |
+ SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME); | |
+ SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME); | |
+ SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME); | |
+ SetMeleeDamageSchool(SPELL_SCHOOL_NORMAL); | |
+ | |
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(petlevel)); | |
- //these formula may not be correct; however, it is designed to be close to what it should be | |
- //this makes dps 0.5 of pets level | |
- SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)) ); | |
- //damage range is then petlevel / 2 | |
- SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)) ); | |
- //damage is increased afterwards as strength and pet scaling modify attack power | |
- | |
- //stored standard pet stats are entry 1 in pet_levelinfo | |
- PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(creature_ID, petlevel); | |
- if(pInfo) // exist in DB | |
- { | |
- SetCreateHealth(pInfo->health); | |
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor)); | |
- //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower)); | |
- for( int i = STAT_STRENGTH; i < MAX_STATS; ++i) | |
- { | |
- SetCreateStat(Stats(i), float(pInfo->stats[i])); | |
- } | |
- } | |
- else // not exist in DB, use some default fake data | |
+ // size scaling | |
+ CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family); | |
+ if (cFamily && cFamily->minScale > 0.0f && getPetType()==HUNTER_PET) | |
{ | |
- sLog.outErrorDb("Hunter pet levelstats missing in DB"); | |
- | |
- // remove elite bonuses included in DB values | |
- SetCreateHealth( uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); | |
+ float scale; | |
+ if (getLevel() >= cFamily->maxScaleLevel) | |
+ scale = cFamily->maxScale; | |
+ else if (getLevel() <= cFamily->minScaleLevel) | |
+ scale = cFamily->minScale; | |
+ else | |
+ scale = cFamily->minScale + float(getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale); | |
- SetCreateStat(STAT_STRENGTH, 22); | |
- SetCreateStat(STAT_AGILITY, 22); | |
- SetCreateStat(STAT_STAMINA, 25); | |
- SetCreateStat(STAT_INTELLECT, 28); | |
- SetCreateStat(STAT_SPIRIT, 27); | |
+ SetFloatValue(OBJECT_FIELD_SCALE_X, scale); | |
} | |
break; | |
} | |
- case GUARDIAN_PET: | |
- SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); | |
- SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000); | |
- | |
- SetCreateMana(28 + 10*petlevel); | |
- SetCreateHealth(28 + 30*petlevel); | |
- | |
- // FIXME: this is wrong formula, possible each guardian pet have own damage formula | |
- //these formula may not be correct; however, it is designed to be close to what it should be | |
- //this makes dps 0.5 of pets level | |
- SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4))); | |
- //damage range is then petlevel / 2 | |
- SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); | |
- break; | |
default: | |
- sLog.outError("Pet have incorrect type (%u) for levelup.", getPetType()); | |
- break; | |
+ break; | |
} | |
- for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) | |
- SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i])); | |
- | |
UpdateAllStats(); | |
SetHealth(GetMaxHealth()); | |
@@ -1904,6 +1890,263 @@ void Pet::CastPetAura(PetAura const* aura) | |
CastSpell(this, auraId, true); | |
} | |
+void Pet::UpdateScalingAuras() | |
+{ | |
+ // there exists temp. summoned pets with scaling auras | |
+ // they should not scale dynamically | |
+ if (isTemporarySummoned()) | |
+ return; | |
+ | |
+ for (AuraList::const_iterator itr = m_scalingauras.begin(); itr != m_scalingauras.end(); ++itr) | |
+ { | |
+ SpellEntry const* spellInfo = (*itr)->GetSpellProto(); | |
+ // check if we need to update aura | |
+ int32 amount = CalculateSpellDamage(this, spellInfo, (*itr)->GetEffIndex()); | |
+ if ((*itr)->GetModifier()->m_amount == amount) | |
+ continue; | |
+ | |
+ // update aura amount | |
+ (*itr)->UpdateModifierAmount(amount); | |
+ } | |
+} | |
+ | |
+uint32 Pet::CalcScalingAuraBonus(SpellEntry const* spellInfo, uint8 effect_index) | |
+{ | |
+ Player* owner = GetCharmerOrOwnerPlayerOrPlayerItself(); | |
+ if (!owner || spellInfo->Effect[effect_index] != SPELL_EFFECT_APPLY_AURA) | |
+ return 0; | |
+ | |
+ uint32 ownerValue = 0; | |
+ uint32 bonusValue = 0; | |
+ float scale = 0; | |
+ | |
+ switch (spellInfo->EffectApplyAuraName[effect_index]) | |
+ { | |
+ case SPELL_AURA_MOD_DAMAGE_DONE: | |
+ { | |
+ switch (spellInfo->Id) | |
+ { | |
+ // hunter pet scaling aura | |
+ case 34902: | |
+ { | |
+ ownerValue = owner->GetTotalAttackPowerValue(RANGED_ATTACK); | |
+ scale = 0.1287f; | |
+ | |
+ // search for "Wild Hunt" | |
+ for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) | |
+ if (itr->second.state != PETSPELL_REMOVED) | |
+ { | |
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); | |
+ if (!spellInfo || spellInfo->SpellIconID == 3748) | |
+ continue; | |
+ scale *= float(spellInfo->EffectBasePoints[1] +101) / 100.0f; | |
+ break; | |
+ } | |
+ break; | |
+ } | |
+ // warlock pet scaling aura | |
+ case 34947: | |
+ { | |
+ ownerValue = owner->GetMaxSpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_FIRE | SPELL_SCHOOL_MASK_SHADOW)); | |
+ scale = 0.15f; | |
+ break; | |
+ } | |
+ // dk pet scaling aura, unknown for now | |
+ case 54566: | |
+ break; | |
+ } | |
+ break; | |
+ } | |
+ case SPELL_AURA_MOD_STAT: | |
+ { | |
+ // only single stats in scaling auras (otherwise scaling not possible) | |
+ if (spellInfo->EffectMiscValue[effect_index] < 0 || spellInfo->EffectMiscValue[effect_index] > 4) | |
+ return 0; | |
+ | |
+ ownerValue = uint32(owner->GetTotalStatValue(Stats(spellInfo->EffectMiscValue[effect_index]))); | |
+ | |
+ switch(spellInfo->EffectMiscValue[effect_index]) | |
+ { | |
+ case STAT_STRENGTH: | |
+ { | |
+ // just dk scaling aura here | |
+ scale = 0.678f; | |
+ | |
+ // search for "Ravenous Dead" and "Glyph of Ghoul" | |
+ AuraList const& mDummy = owner->GetAurasByType(SPELL_AURA_DUMMY); | |
+ for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) | |
+ if ((*itr)->GetSpellProto()->SpellIconID == 3010 || (*itr)->GetId() == 58686) | |
+ scale *= float((*itr)->GetModifier()->m_amount + 100) / 100.0f; | |
+ | |
+ break; | |
+ } | |
+ case STAT_STAMINA: | |
+ { | |
+ scale = 0.3f; | |
+ | |
+ switch (spellInfo->Id) | |
+ { | |
+ // hunter pet scaling aura | |
+ case 34902: | |
+ { | |
+ scale = 0.4493f; | |
+ | |
+ // search for "Wild Hunt" | |
+ for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) | |
+ if (itr->second.state != PETSPELL_REMOVED) | |
+ { | |
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); | |
+ if (!spellInfo || spellInfo->SpellIconID != 3748) | |
+ continue; | |
+ scale *= float(spellInfo->EffectBasePoints[0] +101) / 100.0f; | |
+ break; | |
+ } | |
+ break; | |
+ } | |
+ // wl scaling aura | |
+ case 34947: | |
+ { | |
+ scale = 0.7f; | |
+ break; | |
+ } | |
+ // dk pet scaling aura | |
+ case 54566: | |
+ { | |
+ scale = 0.3928f; | |
+ | |
+ // search for "Ravenous Dead" and "Glyph of Ghoul" | |
+ AuraList const& mDummy = owner->GetAurasByType(SPELL_AURA_DUMMY); | |
+ for(AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) | |
+ if ((*itr)->GetSpellProto()->SpellIconID == 3010 || (*itr)->GetId() == 58686) | |
+ scale *= float((*itr)->GetModifier()->m_amount +100) / 100.0f; | |
+ break; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ case STAT_INTELLECT: | |
+ { | |
+ // just warlock pet aura here | |
+ scale = 0.3f; | |
+ break; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ case SPELL_AURA_MOD_ATTACK_POWER: | |
+ { | |
+ switch (spellInfo->Id) | |
+ { | |
+ // hunter pet scaling aura | |
+ case 34902: | |
+ { | |
+ ownerValue = uint32(owner->GetTotalAttackPowerValue(RANGED_ATTACK)); | |
+ scale = 0.22f; | |
+ | |
+ // search for "Wild Hunt" | |
+ for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) | |
+ if (itr->second.state != PETSPELL_REMOVED) | |
+ { | |
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); | |
+ if (!spellInfo || spellInfo->SpellIconID != 3748) | |
+ continue; | |
+ scale *= float(spellInfo->EffectBasePoints[1] + 101) / 100.0f; | |
+ break; | |
+ } | |
+ | |
+ // search for "Hunter vs. Wild" | |
+ AuraList const& mAttackPowerMod = owner->GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT); | |
+ for(AuraList::const_iterator itr = mAttackPowerMod.begin(); itr != mAttackPowerMod.end(); ++itr) | |
+ if ((*itr)->GetSpellProto()->SpellIconID == 3647) | |
+ bonusValue += (*itr)->GetModifier()->m_amount * owner->GetTotalStatValue(Stats((*itr)->GetModifier()->m_miscvalue)) / 100; | |
+ | |
+ break; | |
+ } | |
+ // warlock pet scaling aura | |
+ case 34947: | |
+ { | |
+ ownerValue = owner->GetMaxSpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_FIRE | SPELL_SCHOOL_MASK_SHADOW)); | |
+ scale = 0.57f; | |
+ break; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ case SPELL_AURA_MOD_RESISTANCE: | |
+ { | |
+ // only single schools in scaling auras (otherwise scaling not possible) | |
+ SpellSchools school = GetFirstSchoolInMask(SpellSchoolMask(spellInfo->EffectMiscValue[effect_index])); | |
+ ownerValue = owner->GetResistance(school); | |
+ | |
+ switch(school) | |
+ { | |
+ // armor | |
+ case SPELL_SCHOOL_NORMAL: | |
+ { | |
+ scale = 0.35f; | |
+ | |
+ // hunter pet scaling aura | |
+ if (spellInfo->Id == 34904) | |
+ scale = 0.4497f; | |
+ break; | |
+ } | |
+ // all other resistances | |
+ default: | |
+ { | |
+ scale = 0.4f; | |
+ break; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: | |
+ case SPELL_AURA_MOD_POWER_REGEN: | |
+ // no information here for now | |
+ break; | |
+ case SPELL_AURA_MOD_SPELL_HIT_CHANCE: | |
+ case SPELL_AURA_MOD_HIT_CHANCE: | |
+ { | |
+ // find maximum of owners hit chances (fractions dropped) | |
+ float hit[3] = {owner->m_modMeleeHitChance, owner->m_modRangedHitChance, owner->m_modSpellHitChance}; | |
+ for (uint8 i = 0; i<3; i++) | |
+ if (ownerValue < uint32(hit[i])) | |
+ ownerValue = uint32(hit[i]); | |
+ // all known auras scale 1:1 | |
+ scale = 1.0f; | |
+ break; | |
+ } | |
+ case SPELL_AURA_HASTE_MELEE: | |
+ { | |
+ // find owners maximum haste (== minimum speedPct factor) | |
+ float cur = 1.0f, factor[3] = {owner->m_modAttackSpeedPct[BASE_ATTACK], m_modAttackSpeedPct[RANGED_ATTACK], owner->GetFloatValue(UNIT_MOD_CAST_SPEED)}; | |
+ for (uint8 i = 0; i<3; i++) | |
+ if (cur > factor[i]) | |
+ cur = factor[i]; | |
+ // get percent haste out of factor | |
+ ownerValue = uint32(100.0f/cur -100); | |
+ | |
+ // just death knight ghoul aura here for now, 1:1 | |
+ scale = 1.0f; | |
+ } | |
+ case SPELL_AURA_MOD_EXPERTISE: | |
+ { | |
+ // expertise scales proportional to owners hitchance (fractions dropped) | |
+ // (e.g. 5% hitchance owner -> 5% less chance, that the attack ist dodged/parried) | |
+ // note: 1 point expertise gives 0.25% less chance to fail | |
+ float cur = 0, hit[3] = {owner->m_modMeleeHitChance, owner->m_modRangedHitChance, owner->m_modSpellHitChance}; | |
+ for (uint8 i = 0; i<3; i++) | |
+ if (cur < hit[i]) | |
+ cur = hit[i]; | |
+ bonusValue = uint32(4*cur); | |
+ break; | |
+ } | |
+ default: | |
+ return 0; | |
+ } | |
+ | |
+ return uint32(ownerValue * scale) + bonusValue; | |
+} | |
+ | |
struct DoPetLearnSpell | |
{ | |
DoPetLearnSpell(Pet& _pet) : pet(_pet) {} | |
diff --git a/src/game/Pet.h b/src/game/Pet.h | |
index efc9ecd..b58731b 100644 | |
--- a/src/game/Pet.h | |
+++ b/src/game/Pet.h | |
@@ -183,12 +183,15 @@ class Pet : public Creature | |
bool UpdateStats(Stats stat); | |
bool UpdateAllStats(); | |
- void UpdateResistances(uint32 school); | |
+ // void UpdateResistances(uint32 school); | |
void UpdateArmor(); | |
void UpdateMaxHealth(); | |
void UpdateMaxPower(Powers power); | |
void UpdateAttackPowerAndDamage(bool ranged = false); | |
void UpdateDamagePhysical(WeaponAttackType attType); | |
+ void UpdateScalingAuras(); | |
+ | |
+ uint32 CalcScalingAuraBonus(SpellEntry const* spellInfo, uint8 effect_index); | |
bool CanTakeMoreActiveSpells(uint32 SpellIconID); | |
void ToggleAutocast(uint32 spellid, bool apply); | |
@@ -219,6 +222,7 @@ class Pet : public Creature | |
PetSpellMap m_spells; | |
AutoSpellList m_autospells; | |
+ AuraList m_scalingauras; | |
void InitPetCreateSpells(); | |
diff --git a/src/game/Player.cpp b/src/game/Player.cpp | |
index 53706be..fa611ca 100644 | |
--- a/src/game/Player.cpp | |
+++ b/src/game/Player.cpp | |
@@ -440,6 +440,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa | |
m_regenTimer = 0; | |
m_weaponChangeTimer = 0; | |
+ m_petScalingUpdateTimer = 0; | |
m_zoneUpdateId = 0; | |
m_zoneUpdateTimer = 0; | |
@@ -1468,10 +1469,20 @@ void Player::Update( uint32 p_time ) | |
// group update | |
SendUpdateToOutOfRangeGroupMembers(); | |
- Pet* pet = GetPet(); | |
- if(pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID()))) | |
+ if (Pet* pet = GetPet()) | |
{ | |
- RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); | |
+ if (!pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID()))) | |
+ RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); | |
+ else if (m_petScalingUpdateTimer) | |
+ { | |
+ if (m_petScalingUpdateTimer <= p_time) | |
+ { | |
+ pet->UpdateScalingAuras(); | |
+ m_petScalingUpdateTimer = 0; | |
+ } | |
+ else | |
+ m_petScalingUpdateTimer -= p_time; | |
+ } | |
} | |
//we should execute delayed teleports only for alive(!) players | |
@@ -17865,6 +17876,17 @@ void Player::RemovePetActionBar() | |
SendDirectMessage(&data); | |
} | |
+void Player::UpdatePetScalingAuras() | |
+{ | |
+ Pet* pet = GetPet(); | |
+ if (!pet) | |
+ return; | |
+ | |
+ // pet scaling auras will be updated with delay, to minimize cpu cycles | |
+ if (!m_petScalingUpdateTimer) | |
+ m_petScalingUpdateTimer = 1000; | |
+} | |
+ | |
bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) | |
{ | |
if (!mod || !spellInfo) | |
diff --git a/src/game/Player.h b/src/game/Player.h | |
index bdaa399..d697f58 100644 | |
--- a/src/game/Player.h | |
+++ b/src/game/Player.h | |
@@ -1608,6 +1608,7 @@ class MANGOS_DLL_SPEC Player : public Unit | |
void CharmSpellInitialize(); | |
void PossessSpellInitialize(); | |
void RemovePetActionBar(); | |
+ void UpdatePetScalingAuras(); | |
bool HasSpell(uint32 spell) const; | |
bool HasActiveSpell(uint32 spell) const; // show in spellbook | |
@@ -2637,6 +2638,8 @@ class MANGOS_DLL_SPEC Player : public Unit | |
uint32 m_temporaryUnsummonedPetNumber; | |
uint32 m_oldpetspell; | |
+ uint32 m_petScalingUpdateTimer; | |
+ | |
AchievementMgr m_achievementMgr; | |
ReputationMgr m_reputationMgr; | |
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h | |
index e7c3c4f..d03847c 100644 | |
--- a/src/game/SharedDefines.h | |
+++ b/src/game/SharedDefines.h | |
@@ -377,7 +377,7 @@ const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = { | |
#define SPELL_ATTR_EX4_UNK22 0x00400000 // 22 | |
#define SPELL_ATTR_EX4_UNK23 0x00800000 // 23 | |
#define SPELL_ATTR_EX4_UNK24 0x01000000 // 24 | |
-#define SPELL_ATTR_EX4_UNK25 0x02000000 // 25 pet scaling auras | |
+#define SPELL_ATTR_EX4_PET_SCALING_AURA 0x02000000 // 25 pet scaling auras | |
#define SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND 0x04000000 // 26 Can only be used in Outland. | |
#define SPELL_ATTR_EX4_UNK27 0x08000000 // 27 | |
#define SPELL_ATTR_EX4_UNK28 0x10000000 // 28 | |
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp | |
index f6badb4..562f13b 100644 | |
--- a/src/game/SpellAuras.cpp | |
+++ b/src/game/SpellAuras.cpp | |
@@ -598,6 +598,22 @@ void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue) | |
m_modifier.periodictime = pt; | |
} | |
+void Aura::UpdateModifierAmount(int32 amount) | |
+{ | |
+ // use this method, to modify modifier.amount when aura is already applied | |
+ AuraType aura = m_modifier.m_auraname; | |
+ | |
+ SetInUse(true); | |
+ if(aura < TOTAL_AURAS) | |
+ { | |
+ // maybe we can find a better way here? | |
+ (*this.*AuraHandler [aura])(false, true); | |
+ m_modifier.m_amount = amount; | |
+ (*this.*AuraHandler [aura])(true, true); | |
+ } | |
+ SetInUse(false); | |
+} | |
+ | |
void Aura::Update(uint32 diff) | |
{ | |
if (m_duration > 0) | |
diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h | |
index 89918a8..9de2668 100644 | |
--- a/src/game/SpellAuras.h | |
+++ b/src/game/SpellAuras.h | |
@@ -224,6 +224,7 @@ class MANGOS_DLL_SPEC Aura | |
virtual ~Aura(); | |
void SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue); | |
+ void UpdateModifierAmount(int32 amount); | |
Modifier* GetModifier() { return &m_modifier; } | |
Modifier const* GetModifier() const { return &m_modifier; } | |
int32 GetMiscValue() const { return m_spellProto->EffectMiscValue[m_effIndex]; } | |
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp | |
index f6e30e1..8a829cb 100644 | |
--- a/src/game/StatSystem.cpp | |
+++ b/src/game/StatSystem.cpp | |
@@ -39,13 +39,6 @@ bool Player::UpdateStats(Stats stat) | |
SetStat(stat, int32(value)); | |
- if(stat == STAT_STAMINA || stat == STAT_INTELLECT) | |
- { | |
- Pet *pet = GetPet(); | |
- if(pet) | |
- pet->UpdateStats(stat); | |
- } | |
- | |
switch(stat) | |
{ | |
case STAT_STRENGTH: | |
@@ -76,6 +69,8 @@ bool Player::UpdateStats(Stats stat) | |
UpdateSpellDamageAndHealingBonus(); | |
UpdateManaRegen(); | |
+ UpdatePetScalingAuras(); | |
+ | |
// Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat | |
uint32 mask = 0; | |
AuraList const& modRatingFromStat = GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT); | |
@@ -151,9 +146,7 @@ void Player::UpdateResistances(uint32 school) | |
float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); | |
SetResistance(SpellSchools(school), int32(value)); | |
- Pet *pet = GetPet(); | |
- if(pet) | |
- pet->UpdateResistances(school); | |
+ UpdatePetScalingAuras(); | |
} | |
else | |
UpdateArmor(); | |
@@ -182,9 +175,7 @@ void Player::UpdateArmor() | |
SetArmor(int32(value)); | |
- Pet *pet = GetPet(); | |
- if(pet) | |
- pet->UpdateArmor(); | |
+ UpdatePetScalingAuras(); | |
UpdateAttackPowerAndDamage(); // armor dependent auras update for SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR | |
} | |
@@ -380,10 +371,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged ) | |
if(ranged) | |
{ | |
UpdateDamagePhysical(RANGED_ATTACK); | |
- | |
- Pet *pet = GetPet(); //update pet's AP | |
- if(pet) | |
- pet->UpdateAttackPowerAndDamage(); | |
+ UpdatePetScalingAuras(); | |
} | |
else | |
{ | |
@@ -612,18 +600,21 @@ void Player::UpdateMeleeHitChances() | |
{ | |
m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); | |
m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE); | |
+ UpdatePetScalingAuras(); | |
} | |
void Player::UpdateRangedHitChances() | |
{ | |
m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); | |
m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED); | |
+ UpdatePetScalingAuras(); | |
} | |
void Player::UpdateSpellHitChances() | |
{ | |
m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE); | |
m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL); | |
+ UpdatePetScalingAuras(); | |
} | |
void Player::UpdateAllSpellCritChances() | |
@@ -871,20 +862,6 @@ bool Pet::UpdateStats(Stats stat) | |
// value = ((base_value * base_pct) + total_value) * total_pct | |
float value = GetTotalStatValue(stat); | |
- | |
- Unit *owner = GetOwner(); | |
- if ( stat == STAT_STAMINA ) | |
- { | |
- if(owner) | |
- value += float(owner->GetStat(stat)) * 0.3f; | |
- } | |
- //warlock's and mage's pets gain 30% of owner's intellect | |
- else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET ) | |
- { | |
- if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) ) | |
- value += float(owner->GetStat(stat)) * 0.3f; | |
- } | |
- | |
SetStat(stat, int32(value)); | |
switch(stat) | |
@@ -915,38 +892,16 @@ bool Pet::UpdateAllStats() | |
return true; | |
} | |
-void Pet::UpdateResistances(uint32 school) | |
-{ | |
- if(school > SPELL_SCHOOL_NORMAL) | |
- { | |
- float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); | |
- | |
- Unit *owner = GetOwner(); | |
- // hunter and warlock pets gain 40% of owner's resistance | |
- if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))) | |
- value += float(owner->GetResistance(SpellSchools(school))) * 0.4f; | |
- | |
- SetResistance(SpellSchools(school), int32(value)); | |
- } | |
- else | |
- UpdateArmor(); | |
-} | |
- | |
void Pet::UpdateArmor() | |
{ | |
float value = 0.0f; | |
float bonus_armor = 0.0f; | |
UnitMods unitMod = UNIT_MOD_ARMOR; | |
- Unit *owner = GetOwner(); | |
- // hunter and warlock pets gain 35% of owner's armor value | |
- if(owner && (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK))) | |
- bonus_armor = 0.35f * float(owner->GetArmor()); | |
- | |
+ // note that pets gain only 1 armor per agility | |
value = GetModifierValue(unitMod, BASE_VALUE); | |
value *= GetModifierValue(unitMod, BASE_PCT); | |
- value += GetStat(STAT_AGILITY) * 2.0f; | |
- value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; | |
+ value += GetModifierValue(unitMod, TOTAL_VALUE) + GetStat(STAT_AGILITY); | |
value *= GetModifierValue(unitMod, TOTAL_PCT); | |
SetArmor(int32(value)); | |
@@ -985,44 +940,14 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged) | |
return; | |
float val = 0.0f; | |
- float bonusAP = 0.0f; | |
UnitMods unitMod = UNIT_MOD_ATTACK_POWER; | |
- if(GetEntry() == 416) // imp's attack power | |
- val = GetStat(STAT_STRENGTH) - 10.0f; | |
+ if(GetEntry() == 416) // imp's attack power (probably this is correct for all "casters", | |
+ val = GetStat(STAT_STRENGTH) - 10.0f; // e.g. also mage's water elemental | |
else | |
val = 2 * GetStat(STAT_STRENGTH) - 20.0f; | |
- Unit* owner = GetOwner(); | |
- if( owner && owner->GetTypeId()==TYPEID_PLAYER) | |
- { | |
- if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power | |
- { | |
- bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; | |
- SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f)); | |
- } | |
- //demons benefit from warlocks shadow or fire damage | |
- else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) | |
- { | |
- int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); | |
- int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); | |
- int32 maximum = (fire > shadow) ? fire : shadow; | |
- if(maximum < 0) | |
- maximum = 0; | |
- SetBonusDamage( int32(maximum * 0.15f)); | |
- bonusAP = maximum * 0.57f; | |
- } | |
- //water elementals benefit from mage's frost damage | |
- else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE) | |
- { | |
- int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); | |
- if(frost < 0) | |
- frost = 0; | |
- SetBonusDamage( int32(frost * 0.4f)); | |
- } | |
- } | |
- | |
- SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); | |
+ SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val); | |
//in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB | |
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); | |
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp | |
index ae03a34..e3aedb6 100644 | |
--- a/src/game/Unit.cpp | |
+++ b/src/game/Unit.cpp | |
@@ -3957,6 +3957,10 @@ bool Unit::AddAura(Aura *Aur) | |
{ | |
m_modAuras[aurName].push_back(Aur); | |
} | |
+ if (aurSpellInfo->AttributesEx4 & SPELL_ATTR_EX4_PET_SCALING_AURA && GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) | |
+ { | |
+ ((Pet*)this)->m_scalingauras.push_back(Aur); | |
+ } | |
Aur->ApplyModifier(true,true); | |
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura %u now is in use", aurName); | |
@@ -4492,6 +4496,10 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) | |
{ | |
m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur); | |
} | |
+ if (AurSpellInfo->AttributesEx4 & SPELL_ATTR_EX4_PET_SCALING_AURA && GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) | |
+ { | |
+ ((Pet*)this)->m_scalingauras.remove(Aur); | |
+ } | |
// Set remove mode | |
Aur->SetRemoveMode(mode); | |
@@ -9368,6 +9376,19 @@ int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) | |
return TakenAdvertisedBenefit; | |
} | |
+int32 Unit::GetMaxSpellBaseDamageBonusDone(SpellSchoolMask schoolMask) | |
+{ | |
+ int32 bonus = 0; | |
+ for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) | |
+ if (schoolMask & SpellSchoolMask(1 << i)) | |
+ { | |
+ int32 current = SpellBaseDamageBonusDone(SpellSchoolMask(1 << i)); | |
+ if (current > bonus) | |
+ bonus = current; | |
+ } | |
+ return bonus > 0 ? bonus : 0; | |
+} | |
+ | |
bool Unit::IsSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) | |
{ | |
// not critting spell | |
@@ -9953,7 +9974,8 @@ uint32 Unit::MeleeDamageBonusDone(Unit *pVictim, uint32 pdamage,WeaponAttackType | |
AuraList const& mModDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE); | |
for(AuraList::const_iterator i = mModDamageDone.begin(); i != mModDamageDone.end(); ++i) | |
{ | |
- if ((*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school | |
+ if ((*i)->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_PET_SCALING_AURA || // completely schoolmask-independend: pet scaling auras, see note | |
+ (*i)->GetModifier()->m_miscvalue & schoolMask && // schoolmask has to fit with the intrinsic spell school | |
(*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask() && // AND schoolmask has to fit with weapon damage school (essential for non-physical spells) | |
((*i)->GetSpellProto()->EquippedItemClass == -1 || // general, weapon independent | |
pWeapon && pWeapon->IsFitToSpellRequirements((*i)->GetSpellProto()))) // OR used weapon fits aura requirements | |
@@ -9961,8 +9983,14 @@ uint32 Unit::MeleeDamageBonusDone(Unit *pVictim, uint32 pdamage,WeaponAttackType | |
DoneFlat += (*i)->GetModifier()->m_amount; | |
} | |
} | |
+ /* Additional note to pet scaling auras: | |
+ Those auras have SPELL_SCHOOL_MASK_MAGIC, but anyway should also | |
+ affect physical damage from non-weapon-damage-based spells (claw, swipe etc.). | |
+ Alternatively we could use pet::m_bonusdamage (that is currently still used for pet's | |
+ without dynamic scaling auras), but this would make the scaling aura idea inconsistent in some way :-/ | |
+ */ | |
- // Pets just add their bonus damage to their melee damage | |
+ // Pets (without scaling auras) just add their bonus damage to their melee damage | |
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) | |
DoneFlat += ((Pet*)this)->GetBonusDamage(); | |
} | |
@@ -11426,6 +11454,10 @@ int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProt | |
(spellProto->Effect[effect_index] != SPELL_EFFECT_APPLY_AURA || spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED)) | |
value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); | |
+ if(spellProto->AttributesEx4 & SPELL_ATTR_EX4_PET_SCALING_AURA && GetTypeId() == TYPEID_UNIT && | |
+ ((Creature*)this)->isPet()) | |
+ value += ((Pet*)this)->CalcScalingAuraBonus(spellProto, effect_index); | |
+ | |
return value; | |
} | |
diff --git a/src/game/Unit.h b/src/game/Unit.h | |
index b4b4077..a5edd64 100644 | |
--- a/src/game/Unit.h | |
+++ b/src/game/Unit.h | |
@@ -1722,6 +1722,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject | |
int32 SpellBonusWithCoeffs(SpellEntry const *spellProto, int32 total, int32 benefit, int32 ap_benefit, DamageEffectType damagetype, bool donePart, float defCoeffMod = 1.0f); | |
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask); | |
+ int32 GetMaxSpellBaseDamageBonusDone(SpellSchoolMask schoolMask); | |
int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask); | |
uint32 SpellDamageBonusDone(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1); | |
uint32 SpellDamageBonusTaken(Unit *pCaster, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1); | |
-- | |
1.6.5.1.1367.gcd48 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment