Core/Spells: rework part 5: GameObject casting
This commit is contained in:
1 parent
c901772640
commit
b6fac86b71
43 files changed
+2638
-2337
No files matched your search
@@ -24,8 +24,9 @@
|
||||
#include "QuestDef.h"
|
||||
|
||||
class GameObject;
|
||||
class Unit;
|
||||
class SpellInfo;
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
|
||||
class TC_GAME_API GameObjectAI
|
||||
{
|
||||
@@ -72,8 +73,9 @@ class TC_GAME_API GameObjectAI
|
||||
// prevents achievement tracking if returning true
|
||||
virtual bool OnReportUse(Player* /*player*/) { return false; }
|
||||
|
||||
virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) { }
|
||||
virtual void Damaged(Player* /*player*/, uint32 /*eventId*/) { }
|
||||
|
||||
virtual void Destroyed(WorldObject* /*attacker*/, uint32 /*eventId*/) { }
|
||||
virtual void Damaged(WorldObject* /*attacker*/, uint32 /*eventId*/) { }
|
||||
|
||||
virtual uint32 GetData(uint32 /*id*/) const { return 0; }
|
||||
virtual void SetData64(uint32 /*id*/, uint64 /*value*/) { }
|
||||
@@ -84,7 +86,14 @@ class TC_GAME_API GameObjectAI
|
||||
virtual void OnLootStateChanged(uint32 /*state*/, Unit* /*unit*/) { }
|
||||
virtual void OnStateChanged(uint32 /*state*/) { }
|
||||
virtual void EventInform(uint32 /*eventId*/) { }
|
||||
virtual void SpellHit(Unit* /*unit*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spellInfo*/) { }
|
||||
virtual void SpellHit(GameObject* /*caster*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spellInfo*/) { }
|
||||
virtual void SpellHitTarget(GameObject* /*target*/, SpellInfo const* /*spellInfo*/) { }
|
||||
};
|
||||
|
||||
class TC_GAME_API NullGameObjectAI : public GameObjectAI
|
||||
|
||||
@@ -142,10 +142,12 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
virtual void JustUnregisteredDynObject(DynamicObject* /*dynObject*/) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) { }
|
||||
virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spellInfo*/) { }
|
||||
virtual void SpellHit(GameObject* /*caster*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) { }
|
||||
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spellInfo*/) { }
|
||||
virtual void SpellHitTarget(GameObject* /*target*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Should return true if the NPC is currently being escorted
|
||||
virtual bool IsEscorted() const { return false; }
|
||||
|
||||
@@ -140,36 +140,9 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
|
||||
|
||||
void AttackStartNoMove(Unit* target);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override { }
|
||||
|
||||
//Called at World update tick
|
||||
virtual void UpdateAI(uint32 diff) override;
|
||||
|
||||
//Called at creature death
|
||||
void JustDied(Unit* /*killer*/) override { }
|
||||
|
||||
//Called at creature killing another unit
|
||||
void KilledUnit(Unit* /*victim*/) override { }
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
void JustSummoned(Creature* /*summon*/) override { }
|
||||
|
||||
// Called when a summoned creature is despawned
|
||||
void SummonedCreatureDespawn(Creature* /*summon*/) override { }
|
||||
|
||||
// Called when hit by a spell
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) override { }
|
||||
|
||||
// Called when spell hits a target
|
||||
void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) override { }
|
||||
|
||||
//Called at waypoint reached or PointMovement end
|
||||
void MovementInform(uint32 /*type*/, uint32 /*id*/) override { }
|
||||
|
||||
// Called when AI is temporarily replaced or put back when possess is applied or removed
|
||||
void OnPossess(bool /*apply*/) { }
|
||||
|
||||
// *************
|
||||
// Variables
|
||||
// *************
|
||||
@@ -181,12 +154,6 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
|
||||
//Pure virtual functions
|
||||
// *************
|
||||
|
||||
//Called at creature reset either by death or evade
|
||||
void Reset() override { }
|
||||
|
||||
//Called at creature aggro either by MoveInLOS or Attack Start
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
|
||||
// Called before JustEngagedWith even before the creature is in combat.
|
||||
void AttackStart(Unit* /*target*/) override;
|
||||
|
||||
@@ -274,8 +241,8 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
|
||||
// return true for 25 man or 25 man heroic mode
|
||||
bool Is25ManRaid() const { return _difficulty & RAID_DIFFICULTY_MASK_25MAN; }
|
||||
|
||||
template<class T> inline
|
||||
const T& DUNGEON_MODE(const T& normal5, const T& heroic10) const
|
||||
template <class T>
|
||||
inline T const& DUNGEON_MODE(T const& normal5, T const& heroic10) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
@@ -290,8 +257,8 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
|
||||
return heroic10;
|
||||
}
|
||||
|
||||
template<class T> inline
|
||||
const T& RAID_MODE(const T& normal10, const T& normal25) const
|
||||
template <class T>
|
||||
inline T const& RAID_MODE(T const& normal10, T const& normal25) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
@@ -306,8 +273,8 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
|
||||
return normal25;
|
||||
}
|
||||
|
||||
template<class T> inline
|
||||
const T& RAID_MODE(const T& normal10, const T& normal25, const T& heroic10, const T& heroic25) const
|
||||
template <class T>
|
||||
inline T const& RAID_MODE(T const& normal10, T const& normal25, T const& heroic10, T const& heroic25) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
|
||||
@@ -1045,9 +1045,9 @@ void SmartGameObjectAI::QuestReward(Player* player, Quest const* quest, uint32 o
|
||||
}
|
||||
|
||||
// Called when the gameobject is destroyed (destructible buildings only).
|
||||
void SmartGameObjectAI::Destroyed(Player* player, uint32 eventId)
|
||||
void SmartGameObjectAI::Destroyed(WorldObject* attacker, uint32 eventId)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, player, eventId, 0, false, nullptr, me);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, attacker ? attacker->ToUnit() : nullptr, eventId, 0, false, nullptr, me);
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::SetData(uint32 id, uint32 value, Unit* invoker)
|
||||
|
||||
@@ -261,7 +261,7 @@ class TC_GAME_API SmartGameObjectAI : public GameObjectAI
|
||||
bool GossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, char const* code) override;
|
||||
void QuestAccept(Player* player, Quest const* quest) override;
|
||||
void QuestReward(Player* player, Quest const* quest, uint32 opt) override;
|
||||
void Destroyed(Player* player, uint32 eventId) override;
|
||||
void Destroyed(WorldObject* attacker, uint32 eventId) override;
|
||||
void SetData(uint32 id, uint32 value, Unit* invoker);
|
||||
void SetData(uint32 id, uint32 value) override { SetData(id, value, nullptr); }
|
||||
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
|
||||
|
||||
@@ -275,7 +275,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||
}
|
||||
}
|
||||
|
||||
bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
|
||||
bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
@@ -304,23 +304,40 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH:
|
||||
if (!target || target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
return !target->HealthAbovePct(health.percent);
|
||||
return !target->ToPlayer()->HealthAbovePct(health.percent);
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
|
||||
return source->HasAuraEffect(aura.spell_id, aura.effect_idx);
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
|
||||
return target && target->HasAuraEffect(aura.spell_id, aura.effect_idx);
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (!unitTarget)
|
||||
return false;
|
||||
return unitTarget->HasAuraEffect(aura.spell_id, aura.effect_idx);
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE:
|
||||
return CompareValues(ComparisionType(value.compType), miscValue1, value.value);
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL:
|
||||
if (!target)
|
||||
if (!target || !target->IsUnit())
|
||||
return false;
|
||||
return target->getLevel() >= level.minlevel;
|
||||
return target->ToUnit()->getLevel() >= level.minlevel;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER:
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
return target->getGender() == gender.gender;
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (!unitTarget)
|
||||
return false;
|
||||
return unitTarget->getGender() == gender.gender;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT:
|
||||
return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target));
|
||||
{
|
||||
Unit const* unitTarget = nullptr;
|
||||
if (target)
|
||||
unitTarget = target->ToUnit();
|
||||
return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(unitTarget));
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
|
||||
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:
|
||||
@@ -360,7 +377,11 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
dataType, criteria_id, map->GetId());
|
||||
return false;
|
||||
}
|
||||
return instance->CheckAchievementCriteriaMeet(criteria_id, source, target, miscValue1);
|
||||
|
||||
Unit const* unitTarget = nullptr;
|
||||
if (target)
|
||||
unitTarget = target->ToUnit();
|
||||
return instance->CheckAchievementCriteriaMeet(criteria_id, source, unitTarget, miscValue1);
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM:
|
||||
{
|
||||
@@ -395,7 +416,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/) const
|
||||
bool AchievementCriteriaDataSet::Meets(Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/) const
|
||||
{
|
||||
for (Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr)
|
||||
if (!itr->Meets(criteria_id, source, target, miscValue1, miscValue2))
|
||||
@@ -1125,7 +1146,7 @@ template<> bool IsGuild<Guild>() { return true; }
|
||||
* this function will be called whenever the user might have done a criteria relevant action
|
||||
*/
|
||||
template<class T>
|
||||
void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit const* unit /*= nullptr*/, Player* referencePlayer /*= nullptr*/, GameObject* go /*= nullptr*/)
|
||||
void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, WorldObject const* ref /*= nullptr*/, Player* referencePlayer /*= nullptr*/, GameObject* go /*= nullptr*/)
|
||||
{
|
||||
if (type >= ACHIEVEMENT_CRITERIA_TYPE_TOTAL)
|
||||
{
|
||||
@@ -1165,7 +1186,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, miscValue3, unit, referencePlayer, go))
|
||||
if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, miscValue3, ref, referencePlayer, go))
|
||||
continue;
|
||||
|
||||
switch (type)
|
||||
@@ -1177,7 +1198,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
|
||||
break;
|
||||
default:
|
||||
if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
|
||||
if (!data->Meets(referencePlayer, unit, miscValue1, miscValue2))
|
||||
if (!data->Meets(referencePlayer, ref, miscValue1, miscValue2))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
@@ -2330,7 +2351,7 @@ CompletedAchievementData* AchievementMgr<T>::GetCompletedDataForAchievement(uint
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer, GameObject* go)
|
||||
bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* ref, Player* referencePlayer, GameObject* go)
|
||||
{
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, nullptr))
|
||||
{
|
||||
@@ -2361,14 +2382,14 @@ bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criter
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer, go))
|
||||
if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, ref, referencePlayer, go))
|
||||
{
|
||||
TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Requirements not satisfied",
|
||||
criteria->Description, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AdditionalRequirementsSatisfied(criteria, miscValue1, miscValue2, unit, referencePlayer))
|
||||
if (!AdditionalRequirementsSatisfied(criteria, miscValue1, miscValue2, ref, referencePlayer))
|
||||
{
|
||||
TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Additional requirements not satisfied",
|
||||
criteria->Description, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type));
|
||||
@@ -2417,7 +2438,7 @@ bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteriaEntry const* crit
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer, GameObject* go) const
|
||||
bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* ref, Player* referencePlayer, GameObject* go) const
|
||||
{
|
||||
switch (AchievementCriteriaTypes(achievementCriteria->Type))
|
||||
{
|
||||
@@ -2590,7 +2611,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
if (!miscValue1 || !unit || unit->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!miscValue1 || !ref || ref->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
@@ -2613,7 +2634,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
|
||||
}
|
||||
|
||||
if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
|
||||
if (!data->Meets(referencePlayer, unit))
|
||||
if (!data->Meets(referencePlayer, ref))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2721,7 +2742,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
|
||||
return false;
|
||||
|
||||
// map specific case (BG in fact) expected player targeted damage/heal
|
||||
if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!ref || ref->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -2794,7 +2815,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const
|
||||
bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, WorldObject const* ref, Player* referencePlayer) const
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_ADDITIONAL_CRITERIA_CONDITIONS; ++i)
|
||||
{
|
||||
@@ -2812,19 +2833,19 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4
|
||||
if (!unit || unit->GetEntry() != reqValue)
|
||||
if (!ref || ref->GetEntry() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5
|
||||
if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!ref || ref->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6
|
||||
if (!unit || unit->IsAlive())
|
||||
if (!ref || !ref->IsUnit() || ref->ToUnit()->IsAlive())
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7
|
||||
if (!unit || !referencePlayer->IsHostileTo(unit))
|
||||
if (!ref || !referencePlayer->IsHostileTo(ref))
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8
|
||||
@@ -2832,11 +2853,11 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10
|
||||
if (!unit || !unit->HasAura(reqValue))
|
||||
if (!ref || !ref->IsUnit() || !ref->ToUnit()->HasAura(reqValue))
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11
|
||||
if (!unit || !unit->HasAuraType(AuraType(reqValue)))
|
||||
if (!ref || !ref->IsUnit() || !ref->ToUnit()->HasAuraType(AuraType(reqValue)))
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14
|
||||
@@ -2865,10 +2886,10 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18
|
||||
{
|
||||
if (!unit)
|
||||
if (!ref)
|
||||
return false;
|
||||
uint32 zoneId, areaId;
|
||||
unit->GetZoneAndAreaId(zoneId, areaId);
|
||||
ref->GetZoneAndAreaId(zoneId, areaId);
|
||||
if (zoneId != reqValue && areaId != reqValue)
|
||||
return false;
|
||||
break;
|
||||
@@ -2886,11 +2907,11 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27
|
||||
if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue)
|
||||
if (!ref || !ref->IsUnit() || ref->ToUnit()->getRace() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28
|
||||
if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue)
|
||||
if (!ref || !ref->IsUnit() || ref->ToUnit()->getClass() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29
|
||||
@@ -2899,10 +2920,9 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30
|
||||
{
|
||||
if (!unit)
|
||||
if (!ref)
|
||||
return false;
|
||||
Creature const* const creature = unit->ToCreature();
|
||||
if (!creature || creature->GetCreatureType() != reqValue)
|
||||
if (!ref->IsUnit() || ref->ToUnit()->GetCreatureType() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@@ -2936,15 +2956,15 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40
|
||||
if (!unit || unit->getLevel() != reqValue)
|
||||
if (!ref || !ref->IsUnit() || ref->ToUnit()->getLevel() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41
|
||||
if (!unit || unit->GetZoneId() != reqValue)
|
||||
if (!ref || ref->GetZoneId() != reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46
|
||||
if (!unit || unit->GetHealthPct() >= reqValue)
|
||||
if (!ref || !ref->IsUnit() || ref->ToUnit()->GetHealthPct() >= reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_REQUIRES_GUILD_GROUP: // 61
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Unit;
|
||||
class Player;
|
||||
class GameObject;
|
||||
class Player;
|
||||
class WorldObject;
|
||||
class WorldPacket;
|
||||
|
||||
typedef std::vector<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
|
||||
@@ -201,7 +201,7 @@ struct AchievementCriteriaData
|
||||
}
|
||||
|
||||
bool IsValid(AchievementCriteriaEntry const* criteria);
|
||||
bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 = 0, uint32 miscValue2 = 0) const;
|
||||
bool Meets(uint32 criteria_id, Player const* source, WorldObject const* target, uint32 miscValue1 = 0, uint32 miscValue2 = 0) const;
|
||||
};
|
||||
|
||||
struct TC_GAME_API AchievementCriteriaDataSet
|
||||
@@ -209,7 +209,7 @@ struct TC_GAME_API AchievementCriteriaDataSet
|
||||
AchievementCriteriaDataSet() : criteria_id(0) { }
|
||||
typedef std::vector<AchievementCriteriaData> Storage;
|
||||
void Add(AchievementCriteriaData const& data) { storage.push_back(data); }
|
||||
bool Meets(Player const* source, Unit const* target, uint32 miscValue1 = 0, uint32 miscValue2 = 0) const;
|
||||
bool Meets(Player const* source, WorldObject const* target, uint32 miscValue1 = 0, uint32 miscValue2 = 0) const;
|
||||
void SetCriteriaId(uint32 id) {criteria_id = id;}
|
||||
private:
|
||||
uint32 criteria_id;
|
||||
@@ -267,7 +267,7 @@ class TC_GAME_API AchievementMgr
|
||||
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult);
|
||||
void SaveToDB(CharacterDatabaseTransaction& trans);
|
||||
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit const* unit = nullptr, Player* referencePlayer = nullptr, GameObject* go = nullptr);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject const* ref = nullptr, Player* referencePlayer = nullptr, GameObject* go = nullptr);
|
||||
void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer);
|
||||
void CheckAllAchievementCriteria(Player* referencePlayer);
|
||||
void SendAllAchievementData(Player* receiver) const;
|
||||
@@ -291,12 +291,12 @@ class TC_GAME_API AchievementMgr
|
||||
void CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer);
|
||||
bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement);
|
||||
bool IsCompletedAchievement(AchievementEntry const* entry);
|
||||
bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer, GameObject* go = nullptr);
|
||||
bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* ref, Player* referencePlayer, GameObject* go = nullptr);
|
||||
void SendPacket(WorldPacket const* data) const;
|
||||
|
||||
bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const;
|
||||
bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer, GameObject* go = nullptr) const;
|
||||
bool AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const;
|
||||
bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* red, Player* referencePlayer, GameObject* go = nullptr) const;
|
||||
bool AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, WorldObject const* red, Player* referencePlayer) const;
|
||||
|
||||
T* _owner;
|
||||
CriteriaProgressMap m_criteriaProgress;
|
||||
|
||||
@@ -294,7 +294,7 @@ void CheckQuestDisables()
|
||||
TC_LOG_INFO("server.loading", ">> Checked %u quest disables in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags)
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const* ref, uint8 flags /*= 0*/)
|
||||
{
|
||||
ASSERT(type < MAX_DISABLE_TYPES);
|
||||
if (m_DisableMap[type].empty())
|
||||
@@ -309,15 +309,16 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
|
||||
case DISABLE_TYPE_SPELL:
|
||||
{
|
||||
uint8 spellFlags = itr->second.flags;
|
||||
if (unit)
|
||||
if (ref)
|
||||
{
|
||||
if ((spellFlags & SPELL_DISABLE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) ||
|
||||
(unit->GetTypeId() == TYPEID_UNIT && ((unit->IsPet() && spellFlags & SPELL_DISABLE_PET) || spellFlags & SPELL_DISABLE_CREATURE)))
|
||||
if ((ref->GetTypeId() == TYPEID_PLAYER && (spellFlags & SPELL_DISABLE_PLAYER)) ||
|
||||
(ref->GetTypeId() == TYPEID_UNIT && ((spellFlags & SPELL_DISABLE_CREATURE) || (ref->ToUnit()->IsPet() && (spellFlags & SPELL_DISABLE_PET)))) ||
|
||||
(ref->GetTypeId() == TYPEID_GAMEOBJECT && (spellFlags & SPELL_DISABLE_GAMEOBJECT)))
|
||||
{
|
||||
if (spellFlags & SPELL_DISABLE_MAP)
|
||||
{
|
||||
std::set<uint32> const& mapIds = itr->second.params[0];
|
||||
if (mapIds.find(unit->GetMapId()) != mapIds.end())
|
||||
if (mapIds.find(ref->GetMapId()) != mapIds.end())
|
||||
return true; // Spell is disabled on current map
|
||||
|
||||
if (!(spellFlags & SPELL_DISABLE_AREA))
|
||||
@@ -329,7 +330,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
|
||||
if (spellFlags & SPELL_DISABLE_AREA)
|
||||
{
|
||||
std::set<uint32> const& areaIds = itr->second.params[1];
|
||||
if (areaIds.find(unit->GetAreaId()) != areaIds.end())
|
||||
if (areaIds.find(ref->GetAreaId()) != areaIds.end())
|
||||
return true; // Spell is disabled in this area
|
||||
return false; // Spell is disabled in another area, but not this one, return false
|
||||
}
|
||||
@@ -348,7 +349,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
|
||||
}
|
||||
case DISABLE_TYPE_MAP:
|
||||
case DISABLE_TYPE_LFG_MAP:
|
||||
if (Player const* player = unit->ToPlayer())
|
||||
if (Player const* player = ref->ToPlayer())
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
|
||||
if (mapEntry->IsDungeon())
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
|
||||
enum DisableType
|
||||
{
|
||||
@@ -37,16 +37,17 @@ enum DisableType
|
||||
|
||||
enum SpellDisableTypes
|
||||
{
|
||||
SPELL_DISABLE_PLAYER = 0x1,
|
||||
SPELL_DISABLE_CREATURE = 0x2,
|
||||
SPELL_DISABLE_PET = 0x4,
|
||||
SPELL_DISABLE_DEPRECATED_SPELL = 0x8,
|
||||
SPELL_DISABLE_PLAYER = 0x01,
|
||||
SPELL_DISABLE_CREATURE = 0x02,
|
||||
SPELL_DISABLE_PET = 0x04,
|
||||
SPELL_DISABLE_DEPRECATED_SPELL = 0x08,
|
||||
SPELL_DISABLE_MAP = 0x10,
|
||||
SPELL_DISABLE_AREA = 0x20,
|
||||
SPELL_DISABLE_LOS = 0x40,
|
||||
SPELL_DISABLE_GAMEOBJECT = 0x80,
|
||||
MAX_SPELL_DISABLE_TYPE = ( SPELL_DISABLE_PLAYER | SPELL_DISABLE_CREATURE | SPELL_DISABLE_PET |
|
||||
SPELL_DISABLE_DEPRECATED_SPELL | SPELL_DISABLE_MAP | SPELL_DISABLE_AREA |
|
||||
SPELL_DISABLE_LOS)
|
||||
SPELL_DISABLE_LOS | SPELL_DISABLE_GAMEOBJECT)
|
||||
};
|
||||
|
||||
enum MMapDisableTypes
|
||||
@@ -57,7 +58,7 @@ enum MMapDisableTypes
|
||||
namespace DisableMgr
|
||||
{
|
||||
TC_GAME_API void LoadDisables();
|
||||
TC_GAME_API bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0);
|
||||
TC_GAME_API bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const* ref, uint8 flags = 0);
|
||||
TC_GAME_API void CheckQuestDisables();
|
||||
TC_GAME_API bool IsVMAPDisabledFor(uint32 entry, uint8 flags);
|
||||
TC_GAME_API bool IsPathfindingEnabled(uint32 mapId);
|
||||
|
||||
@@ -41,6 +41,9 @@ class AreaTrigger : public WorldObject, public GridObject<AreaTrigger>
|
||||
void SetDuration(int32 newDuration) { _duration = newDuration; }
|
||||
void Delay(int32 delaytime) { SetDuration(GetDuration() - delaytime); }
|
||||
|
||||
ObjectGuid GetOwnerGUID() const override { return ObjectGuid::Empty; }
|
||||
uint32 GetFaction() const override { return 0; }
|
||||
|
||||
protected:
|
||||
int32 _duration;
|
||||
};
|
||||
|
||||
@@ -147,6 +147,15 @@ void Corpse::DeleteFromDB(ObjectGuid const& ownerGuid, CharacterDatabaseTransact
|
||||
CharacterDatabase.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
uint32 Corpse::GetFaction() const
|
||||
{
|
||||
// inherit faction from player race
|
||||
uint32 const race = GetByteValue(CORPSE_FIELD_BYTES_1, 1);
|
||||
|
||||
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
|
||||
return rEntry ? rEntry->FactionID : 0;
|
||||
}
|
||||
|
||||
void Corpse::ResetGhostTime()
|
||||
{
|
||||
m_time = GameTime::GetGameTime();
|
||||
|
||||
@@ -63,7 +63,8 @@ class TC_GAME_API Corpse : public WorldObject, public GridObject<Corpse>
|
||||
void DeleteFromDB(CharacterDatabaseTransaction& trans);
|
||||
static void DeleteFromDB(ObjectGuid const& ownerGuid, CharacterDatabaseTransaction& trans);
|
||||
|
||||
ObjectGuid GetOwnerGUID() const { return GetGuidValue(CORPSE_FIELD_OWNER); }
|
||||
ObjectGuid GetOwnerGUID() const override { return GetGuidValue(CORPSE_FIELD_OWNER); }
|
||||
uint32 GetFaction() const override;
|
||||
|
||||
time_t const& GetGhostTime() const { return m_time; }
|
||||
void ResetGhostTime();
|
||||
|
||||
@@ -2150,7 +2150,7 @@ void Creature::LoadTemplateImmunities()
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster, Optional<uint8> effectMask /*= {}*/) const
|
||||
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const
|
||||
{
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
@@ -2161,9 +2161,6 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster, Option
|
||||
if (!spellInfo->Effects[i].IsEffect())
|
||||
continue;
|
||||
|
||||
if (effectMask && !(*effectMask & (1 << i)))
|
||||
continue;
|
||||
|
||||
if (!IsImmunedToSpellEffect(spellInfo, i, caster))
|
||||
{
|
||||
immunedToAllEffects = false;
|
||||
@@ -2176,8 +2173,11 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster, Option
|
||||
return Unit::IsImmunedToSpell(spellInfo, caster);
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const
|
||||
{
|
||||
if (!spellInfo->Effects[index].IsEffect())
|
||||
return true;
|
||||
|
||||
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effects[index].Effect == SPELL_EFFECT_HEAL)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -129,8 +129,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
bool IsClassTrainerOf(Player const* player) const;
|
||||
bool CanCreatureAttack(Unit const* victim, bool force = true) const;
|
||||
void LoadTemplateImmunities();
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster, Optional<uint8> effectMask = {}) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const override;
|
||||
bool isElite() const;
|
||||
bool isWorldBoss() const;
|
||||
|
||||
|
||||
@@ -269,6 +269,12 @@ void DynamicObject::RemoveCasterViewpoint()
|
||||
}
|
||||
}
|
||||
|
||||
uint32 DynamicObject::GetFaction() const
|
||||
{
|
||||
ASSERT(_caster);
|
||||
return _caster->GetFaction();
|
||||
}
|
||||
|
||||
void DynamicObject::BindToCaster()
|
||||
{
|
||||
ASSERT(!_caster);
|
||||
|
||||
@@ -55,11 +55,13 @@ class TC_GAME_API DynamicObject : public WorldObject, public GridObject<DynamicO
|
||||
void SetCasterViewpoint();
|
||||
void RemoveCasterViewpoint();
|
||||
Unit* GetCaster() const { return _caster; }
|
||||
uint32 GetFaction() const override;
|
||||
void BindToCaster();
|
||||
void UnbindFromCaster();
|
||||
uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
|
||||
SpellInfo const* GetSpellInfo() const;
|
||||
ObjectGuid GetCasterGUID() const { return GetGuidValue(DYNAMICOBJECT_CASTER); }
|
||||
ObjectGuid GetOwnerGUID() const override { return GetCasterGUID(); }
|
||||
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -785,6 +785,8 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, P
|
||||
|
||||
void GameObject::Update(uint32 diff)
|
||||
{
|
||||
m_Events.Update(diff);
|
||||
|
||||
if (AI())
|
||||
AI()->UpdateAI(diff);
|
||||
else if (!AIM_Initialize())
|
||||
@@ -1068,8 +1070,10 @@ void GameObject::Update(uint32 diff)
|
||||
else if (Unit* target = ObjectAccessor::GetUnit(*this, m_lootStateUnitGUID))
|
||||
{
|
||||
// Some traps do not have a spell but should be triggered
|
||||
CastSpellExtraArgs args;
|
||||
args.SetOriginalCaster(GetOwnerGUID());
|
||||
if (goInfo->trap.spellId)
|
||||
CastSpell(target, goInfo->trap.spellId);
|
||||
CastSpell(target, goInfo->trap.spellId, args);
|
||||
|
||||
// Template value or 4 seconds
|
||||
m_cooldownTime = GameTime::GetGameTimeMS() + (goInfo->trap.cooldown ? goInfo->trap.cooldown : uint32(4)) * IN_MILLISECONDS;
|
||||
@@ -1521,11 +1525,6 @@ bool GameObject::IsDestructibleBuilding() const
|
||||
return gInfo->type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING;
|
||||
}
|
||||
|
||||
Unit* GameObject::GetOwner() const
|
||||
{
|
||||
return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
|
||||
}
|
||||
|
||||
void GameObject::SaveRespawnTime(uint32 forceDelay)
|
||||
{
|
||||
if (m_goData && (forceDelay || m_respawnTime > GameTime::GetGameTime()) && m_spawnedByDefault)
|
||||
@@ -2408,69 +2407,6 @@ void GameObject::Use(Unit* user)
|
||||
CastSpell(user, spellId);
|
||||
}
|
||||
|
||||
void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /* = true*/)
|
||||
{
|
||||
CastSpell(target, spellId, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
|
||||
}
|
||||
|
||||
void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags triggered)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
bool self = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CASTER)
|
||||
{
|
||||
self = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (target)
|
||||
target->CastSpell(target, spellInfo->Id, triggered);
|
||||
return;
|
||||
}
|
||||
|
||||
//summon world trigger
|
||||
Creature* trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, spellInfo->CalcCastTime() + 100);
|
||||
if (!trigger)
|
||||
return;
|
||||
|
||||
// remove immunity flags, to allow spell to target anything
|
||||
trigger->SetImmuneToAll(false);
|
||||
PhasingHandler::InheritPhaseShift(trigger, this);
|
||||
|
||||
CastSpellExtraArgs args;
|
||||
args.TriggerFlags = triggered;
|
||||
if (Unit* owner = GetOwner())
|
||||
{
|
||||
trigger->SetFaction(owner->GetFaction());
|
||||
if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
|
||||
// copy pvp state flags from owner
|
||||
trigger->SetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, owner->GetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG));
|
||||
// needed for GO casts for proper target validation checks
|
||||
trigger->SetOwnerGUID(owner->GetGUID());
|
||||
|
||||
args.OriginalCaster = owner->GetGUID();
|
||||
trigger->CastSpell(target ? target : trigger, spellInfo->Id, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger->SetFaction(spellInfo->IsPositive() ? FACTION_FRIENDLY : FACTION_MONSTER);
|
||||
// Set owner guid for target if no owner available - needed by trigger auras
|
||||
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
|
||||
|
||||
args.OriginalCaster = target ? target->GetGUID() : ObjectGuid::Empty;
|
||||
trigger->CastSpell(target ? target : trigger, spellInfo->Id, args);
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::SendCustomAnim(uint32 anim)
|
||||
{
|
||||
WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM, 8+4);
|
||||
@@ -2585,7 +2521,7 @@ QuaternionData GameObject::GetWorldRotation() const
|
||||
return localRotation;
|
||||
}
|
||||
|
||||
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
|
||||
void GameObject::ModifyHealth(int32 change, WorldObject* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
|
||||
{
|
||||
if (!m_goValue.Building.MaxHealth || !change)
|
||||
return;
|
||||
@@ -2604,10 +2540,8 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/
|
||||
// Set the health bar, value = 255 * healthPct;
|
||||
SetGoAnimProgress(m_goValue.Building.Health * 255 / m_goValue.Building.MaxHealth);
|
||||
|
||||
Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr;
|
||||
|
||||
// dealing damage, send packet
|
||||
if (player)
|
||||
if (Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr)
|
||||
{
|
||||
WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8 + 8 + 8 + 4 + 4);
|
||||
data << GetPackGUID();
|
||||
@@ -2635,11 +2569,10 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/
|
||||
if (newState == GetDestructibleState())
|
||||
return;
|
||||
|
||||
/// @todo: pass attackerOrHealer instead of player
|
||||
SetDestructibleState(newState, player, false);
|
||||
SetDestructibleState(newState, attackerOrHealer, false);
|
||||
}
|
||||
|
||||
void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker /*= nullptr*/, bool setHealth /*= false*/)
|
||||
void GameObject::SetDestructibleState(GameObjectDestructibleState state, WorldObject* attackerOrHealer /*= nullptr*/, bool setHealth /*= false*/)
|
||||
{
|
||||
// the user calling this must know he is already operating on destructible gameobject
|
||||
ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING);
|
||||
@@ -2659,8 +2592,8 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player*
|
||||
case GO_DESTRUCTIBLE_DAMAGED:
|
||||
{
|
||||
if (GetGOInfo()->building.damagedEvent)
|
||||
GameEvents::Trigger(GetGOInfo()->building.damagedEvent, eventInvoker, this);
|
||||
AI()->Damaged(eventInvoker, m_goInfo->building.damageEvent);
|
||||
GameEvents::Trigger(GetGOInfo()->building.damagedEvent, attackerOrHealer, this);
|
||||
AI()->Damaged(attackerOrHealer, m_goInfo->building.damageEvent);
|
||||
|
||||
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
|
||||
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
|
||||
@@ -2685,12 +2618,12 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player*
|
||||
case GO_DESTRUCTIBLE_DESTROYED:
|
||||
{
|
||||
if (GetGOInfo()->building.destroyedEvent)
|
||||
GameEvents::Trigger(GetGOInfo()->building.destroyedEvent, eventInvoker, this);
|
||||
AI()->Destroyed(eventInvoker, m_goInfo->building.destroyedEvent);
|
||||
GameEvents::Trigger(GetGOInfo()->building.destroyedEvent, attackerOrHealer, this);
|
||||
AI()->Destroyed(attackerOrHealer, m_goInfo->building.destroyedEvent);
|
||||
|
||||
if (eventInvoker)
|
||||
if (Battleground* bg = eventInvoker->GetBattleground())
|
||||
bg->DestroyGate(eventInvoker, this);
|
||||
if (attackerOrHealer && attackerOrHealer->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Battleground* bg = attackerOrHealer->ToPlayer()->GetBattleground())
|
||||
bg->DestroyGate(attackerOrHealer->ToPlayer(), this);
|
||||
|
||||
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
|
||||
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
|
||||
@@ -2712,7 +2645,7 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player*
|
||||
case GO_DESTRUCTIBLE_REBUILDING:
|
||||
{
|
||||
if (GetGOInfo()->building.rebuildingEvent)
|
||||
GameEvents::Trigger(GetGOInfo()->building.rebuildingEvent, eventInvoker, this);
|
||||
GameEvents::Trigger(GetGOInfo()->building.rebuildingEvent, attackerOrHealer, this);
|
||||
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_DESTROYED);
|
||||
|
||||
uint32 modelId = m_goInfo->displayId;
|
||||
|
||||
@@ -160,8 +160,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
m_spawnedByDefault = false; // all object with owner is despawned after delay
|
||||
SetGuidValue(OBJECT_FIELD_CREATED_BY, owner);
|
||||
}
|
||||
ObjectGuid GetOwnerGUID() const { return GetGuidValue(OBJECT_FIELD_CREATED_BY); }
|
||||
Unit* GetOwner() const;
|
||||
ObjectGuid GetOwnerGUID() const override { return GetGuidValue(OBJECT_FIELD_CREATED_BY); }
|
||||
|
||||
void SetSpellId(uint32 id)
|
||||
{
|
||||
@@ -273,14 +272,12 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
|
||||
GameObject* LookupFishingHoleAround(float range);
|
||||
|
||||
void CastSpell(Unit* target, uint32 spell, bool triggered = true);
|
||||
void CastSpell(Unit* target, uint32 spell, TriggerCastFlags triggered);
|
||||
void SendCustomAnim(uint32 anim);
|
||||
bool IsInRange(float x, float y, float z, float radius) const;
|
||||
|
||||
void ModifyHealth(int32 change, Unit* attackerOrHealer = nullptr, uint32 spellId = 0);
|
||||
void ModifyHealth(int32 change, WorldObject* attackerOrHealer = nullptr, uint32 spellId = 0);
|
||||
// sets GameObject type 33 destruction flags and optionally default health for that state
|
||||
void SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker = nullptr, bool setHealth = false);
|
||||
void SetDestructibleState(GameObjectDestructibleState state, WorldObject* attackerOrHealer = nullptr, bool setHealth = false);
|
||||
GameObjectDestructibleState GetDestructibleState() const
|
||||
{
|
||||
if (HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED))
|
||||
@@ -301,8 +298,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
void SetDisplayId(uint32 displayid);
|
||||
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
||||
|
||||
uint32 GetFaction() const { return GetUInt32Value(GAMEOBJECT_FACTION); }
|
||||
void SetFaction(uint32 faction) { SetUInt32Value(GAMEOBJECT_FACTION, faction); }
|
||||
uint32 GetFaction() const override { return GetUInt32Value(GAMEOBJECT_FACTION); }
|
||||
void SetFaction(uint32 faction) override { SetUInt32Value(GAMEOBJECT_FACTION, faction); }
|
||||
|
||||
GameObjectModel* m_model;
|
||||
void GetRespawnPosition(float &x, float &y, float &z, float* ori = nullptr) const;
|
||||
|
||||
@@ -42,8 +42,10 @@
|
||||
#include "PhasingHandler.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Player.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
#include "Transport.h"
|
||||
@@ -1143,8 +1145,8 @@ bool Object::PrintIndexError(uint32 index, bool set) const
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
|
||||
m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0),
|
||||
m_movementInfo(), m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(true), m_liquidStatus(LIQUID_MAP_NO_WATER),
|
||||
m_wmoGroupID(0), m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0),
|
||||
m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0)
|
||||
@@ -2324,6 +2326,922 @@ Player* WorldObject::SelectNearestPlayer(float distance) const
|
||||
return target;
|
||||
}
|
||||
|
||||
ObjectGuid WorldObject::GetCharmerOrOwnerOrOwnGUID() const
|
||||
{
|
||||
ObjectGuid guid = GetCharmerOrOwnerGUID();
|
||||
if (!guid.IsEmpty())
|
||||
return guid;
|
||||
return GetGUID();
|
||||
}
|
||||
|
||||
Unit* WorldObject::GetOwner() const
|
||||
{
|
||||
return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
|
||||
}
|
||||
|
||||
Unit* WorldObject::GetCharmerOrOwner() const
|
||||
{
|
||||
if (Unit const* unit = ToUnit())
|
||||
return unit->GetCharmerOrOwner();
|
||||
else if (GameObject const* go = ToGameObject())
|
||||
return go->GetOwner();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* WorldObject::GetCharmerOrOwnerOrSelf() const
|
||||
{
|
||||
if (Unit* u = GetCharmerOrOwner())
|
||||
return u;
|
||||
|
||||
return const_cast<WorldObject*>(this)->ToUnit();
|
||||
}
|
||||
|
||||
Player* WorldObject::GetCharmerOrOwnerPlayerOrPlayerItself() const
|
||||
{
|
||||
ObjectGuid guid = GetCharmerOrOwnerGUID();
|
||||
if (guid.IsPlayer())
|
||||
return ObjectAccessor::GetPlayer(*this, guid);
|
||||
|
||||
return const_cast<WorldObject*>(this)->ToPlayer();
|
||||
}
|
||||
|
||||
Player* WorldObject::GetAffectingPlayer() const
|
||||
{
|
||||
if (!GetCharmerOrOwnerGUID())
|
||||
return const_cast<WorldObject*>(this)->ToPlayer();
|
||||
|
||||
if (Unit* owner = GetCharmerOrOwner())
|
||||
return owner->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Player* WorldObject::GetSpellModOwner() const
|
||||
{
|
||||
if (Player* player = const_cast<WorldObject*>(this)->ToPlayer())
|
||||
return player;
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
Creature const* creature = ToCreature();
|
||||
if (creature->HasUnitTypeMask(UNIT_MASK_PET | UNIT_MASK_TOTEM | UNIT_MASK_GUARDIAN | UNIT_MASK_HUNTER_PET | UNIT_MASK_MINION))
|
||||
{
|
||||
if (Unit* owner = creature->GetOwner())
|
||||
return owner->ToPlayer();
|
||||
}
|
||||
}
|
||||
else if (GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
{
|
||||
GameObject const* go = ToGameObject();
|
||||
if (Unit* owner = go->GetOwner())
|
||||
return owner->ToPlayer();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// function uses real base points (typically value - 1)
|
||||
int32 WorldObject::CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effectIndex, int32 const* basePoints) const
|
||||
{
|
||||
return spellProto->Effects[effectIndex].CalcValue(this, basePoints, target);
|
||||
}
|
||||
|
||||
float WorldObject::GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (!spellInfo->RangeEntry)
|
||||
return 0;
|
||||
if (spellInfo->RangeEntry->RangeMax[1] == spellInfo->RangeEntry->RangeMax[0])
|
||||
return spellInfo->GetMaxRange();
|
||||
if (!target)
|
||||
return spellInfo->GetMaxRange(true);
|
||||
return spellInfo->GetMaxRange(!IsHostileTo(target));
|
||||
}
|
||||
|
||||
float WorldObject::GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (!spellInfo->RangeEntry)
|
||||
return 0;
|
||||
if (spellInfo->RangeEntry->RangeMin[1] == spellInfo->RangeEntry->RangeMin[0])
|
||||
return spellInfo->GetMinRange();
|
||||
if (!target)
|
||||
return spellInfo->GetMinRange(true);
|
||||
return spellInfo->GetMinRange(!IsHostileTo(target));
|
||||
}
|
||||
|
||||
float WorldObject::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const
|
||||
{
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
{
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value);
|
||||
switch (effect_index)
|
||||
{
|
||||
case EFFECT_0:
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value);
|
||||
break;
|
||||
case EFFECT_1:
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value);
|
||||
break;
|
||||
case EFFECT_2:
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int32 WorldObject::ModSpellDuration(SpellInfo const* spellInfo, WorldObject const* target, int32 duration, bool positive, uint32 effectMask)
|
||||
{
|
||||
// don't mod permanent auras duration
|
||||
if (duration < 0)
|
||||
return duration;
|
||||
|
||||
// some auras are not affected by duration modifiers
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR7_IGNORE_DURATION_MODS))
|
||||
return duration;
|
||||
|
||||
// cut duration only of negative effects
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (!unitTarget)
|
||||
return duration;
|
||||
|
||||
// cut duration only of negative effects
|
||||
if (!positive)
|
||||
{
|
||||
int32 mechanicMask = spellInfo->GetSpellMechanicMaskByEffectMask(effectMask);
|
||||
auto mechanicCheck = [mechanicMask](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (mechanicMask & (1 << aurEff->GetMiscValue()))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// Find total mod value (negative bonus)
|
||||
int32 durationMod_always = unitTarget->GetTotalAuraModifier(SPELL_AURA_MECHANIC_DURATION_MOD, mechanicCheck);
|
||||
// Find max mod (negative bonus)
|
||||
int32 durationMod_not_stack = unitTarget->GetMaxNegativeAuraModifier(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanicCheck);
|
||||
|
||||
// Select strongest negative mod
|
||||
int32 durationMod = std::min(durationMod_always, durationMod_not_stack);
|
||||
if (durationMod != 0)
|
||||
AddPct(duration, durationMod);
|
||||
|
||||
// there are only negative mods currently
|
||||
durationMod_always = unitTarget->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL, spellInfo->Dispel);
|
||||
durationMod_not_stack = unitTarget->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK, spellInfo->Dispel);
|
||||
|
||||
durationMod = std::min(durationMod_always, durationMod_not_stack);
|
||||
if (durationMod != 0)
|
||||
AddPct(duration, durationMod);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// else positive mods here, there are no currently
|
||||
// when there will be, change GetTotalAuraModifierByMiscValue to GetMaxPositiveAuraModifierByMiscValue
|
||||
|
||||
// Mixology - duration boost
|
||||
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_POTION && (
|
||||
sSpellMgr->IsSpellMemberOfSpellGroup(spellInfo->Id, SPELL_GROUP_ELIXIR_BATTLE) ||
|
||||
sSpellMgr->IsSpellMemberOfSpellGroup(spellInfo->Id, SPELL_GROUP_ELIXIR_GUARDIAN)))
|
||||
{
|
||||
if (unitTarget->HasAura(53042) && unitTarget->HasSpell(spellInfo->Effects[0].TriggerSpell))
|
||||
duration *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::max(duration, 0);
|
||||
}
|
||||
|
||||
void WorldObject::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime, Spell* spell)
|
||||
{
|
||||
if (!spellInfo || castTime < 0)
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
|
||||
|
||||
Unit const* unitCaster = ToUnit();
|
||||
if (!unitCaster)
|
||||
return;
|
||||
|
||||
if (!(spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_IS_TRADESKILL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
|
||||
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
|
||||
castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
|
||||
castTime = int32(float(castTime) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
|
||||
else if (spellInfo->SpellVisual[0] == 3881 && unitCaster->HasAura(67556)) // cooking with Chef Hat.
|
||||
castTime = 500;
|
||||
}
|
||||
|
||||
void WorldObject::ModSpellDurationTime(SpellInfo const* spellInfo, int32& duration, Spell* spell)
|
||||
{
|
||||
if (!spellInfo || duration < 0)
|
||||
return;
|
||||
|
||||
if (spellInfo->IsChanneled() && !spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, duration, spell);
|
||||
|
||||
Unit const* unitCaster = ToUnit();
|
||||
if (!unitCaster)
|
||||
return;
|
||||
|
||||
if (!(spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_IS_TRADESKILL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
|
||||
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
|
||||
duration = int32(float(duration) * GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
|
||||
duration = int32(float(duration) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
|
||||
}
|
||||
|
||||
float WorldObject::MeleeSpellMissChance(Unit const* /*victim*/, WeaponAttackType /*attType*/, SpellInfo const* /*spellInfo*/) const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
SpellMissInfo WorldObject::MeleeSpellHitResult(Unit* /*victim*/, SpellInfo const* /*spellInfo*/) const
|
||||
{
|
||||
return SPELL_MISS_NONE;
|
||||
}
|
||||
|
||||
SpellMissInfo WorldObject::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
|
||||
{
|
||||
// Can`t miss on dead target (on skinning for example)
|
||||
if (!victim->IsAlive() && !victim->IsPlayer())
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR7_CANT_MISS))
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
|
||||
|
||||
// PvP - PvE spell misschances per leveldif > 2
|
||||
int32 lchance = victim->IsPlayer() ? 7 : 11;
|
||||
int32 thisLevel = getLevelForTarget(victim);
|
||||
if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTrigger())
|
||||
thisLevel = std::max<int32>(thisLevel, spellInfo->SpellLevel);
|
||||
int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel;
|
||||
int32 levelBasedHitDiff = leveldif;
|
||||
|
||||
// Base hit chance from attacker and victim levels
|
||||
int32 modHitChance = 100;
|
||||
if (levelBasedHitDiff >= 0)
|
||||
{
|
||||
if (victim->IsPlayer())
|
||||
{
|
||||
modHitChance = 94 - 3 * std::min(levelBasedHitDiff, 3);
|
||||
levelBasedHitDiff -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
modHitChance = 96 - std::min(levelBasedHitDiff, 2);
|
||||
levelBasedHitDiff -= 2;
|
||||
}
|
||||
if (levelBasedHitDiff > 0)
|
||||
modHitChance -= lchance * std::min(levelBasedHitDiff, 7);
|
||||
}
|
||||
else
|
||||
modHitChance = 97 - levelBasedHitDiff;
|
||||
|
||||
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
|
||||
|
||||
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
|
||||
modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
|
||||
|
||||
// Decrease hit chance from victim rating bonus
|
||||
if (victim->IsPlayer())
|
||||
modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
|
||||
|
||||
int32 hitChance = modHitChance * 100;
|
||||
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
|
||||
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
|
||||
if (Unit const* unit = ToUnit())
|
||||
hitChance += int32(unit->m_modSpellHitChance * 100.0f);
|
||||
|
||||
RoundToInterval(hitChance, 0, 10000);
|
||||
|
||||
int32 tmp = 10000 - hitChance;
|
||||
|
||||
int32 rand = irand(0, 9999);
|
||||
if (tmp > 0 && rand < tmp)
|
||||
return SPELL_MISS_MISS;
|
||||
|
||||
// Chance resist mechanic (select max value from every mechanic spell effect)
|
||||
int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
|
||||
|
||||
// Chance resist debuff
|
||||
if (!spellInfo->IsPositive() && !spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
|
||||
{
|
||||
// resistance chance for binary spells, equals to average damage reduction of non-binary spell
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_MAGIC))
|
||||
resist_chance += int32(Unit::CalculateAverageResistReduction(this, spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.f); // 100 for spell calculations, and 100 for return value percentage
|
||||
}
|
||||
|
||||
// Roll chance
|
||||
if (resist_chance > 0 && rand < (tmp += resist_chance))
|
||||
return SPELL_MISS_RESIST;
|
||||
|
||||
// cast by caster in front of victim
|
||||
if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
|
||||
{
|
||||
int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
|
||||
if (deflect_chance > 0 && rand < (tmp += deflect_chance))
|
||||
return SPELL_MISS_DEFLECT;
|
||||
}
|
||||
|
||||
return SPELL_MISS_NONE;
|
||||
}
|
||||
|
||||
// Calculate spell hit result can be:
|
||||
// Every spell can: Evade/Immune/Reflect/Sucesful hit
|
||||
// For melee based spells:
|
||||
// Miss
|
||||
// Dodge
|
||||
// Parry
|
||||
// For spells
|
||||
// Resist
|
||||
SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect /*= false*/) const
|
||||
{
|
||||
// Check for immune
|
||||
if (victim->IsImmunedToSpell(spellInfo, this))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
|
||||
// returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
|
||||
if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
// All positive spells can`t miss
|
||||
/// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
|
||||
if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
if (this == victim)
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
// Return evade for units in evade mode
|
||||
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
|
||||
return SPELL_MISS_EVADE;
|
||||
|
||||
// Try victim reflect spell
|
||||
if (canReflect)
|
||||
{
|
||||
int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
|
||||
reflectchance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_REFLECT_SPELLS_SCHOOL, spellInfo->GetSchoolMask());
|
||||
|
||||
if (reflectchance > 0 && roll_chance_i(reflectchance))
|
||||
return SPELL_MISS_REFLECT;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
switch (spellInfo->DmgClass)
|
||||
{
|
||||
case SPELL_DAMAGE_CLASS_RANGED:
|
||||
case SPELL_DAMAGE_CLASS_MELEE:
|
||||
return MeleeSpellHitResult(victim, spellInfo);
|
||||
case SPELL_DAMAGE_CLASS_NONE:
|
||||
return SPELL_MISS_NONE;
|
||||
case SPELL_DAMAGE_CLASS_MAGIC:
|
||||
return MagicSpellHitResult(victim, spellInfo);
|
||||
}
|
||||
return SPELL_MISS_NONE;
|
||||
}
|
||||
|
||||
FactionTemplateEntry const* WorldObject::GetFactionTemplateEntry() const
|
||||
{
|
||||
FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(GetFaction());
|
||||
if (!entry)
|
||||
{
|
||||
if (Player const* player = ToPlayer())
|
||||
TC_LOG_ERROR("entities", "Player %s has invalid faction (faction template id) #%u", player->GetName().c_str(), GetFaction());
|
||||
else if (Creature const* creature = ToCreature())
|
||||
TC_LOG_ERROR("entities", "Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureTemplate()->Entry, GetFaction());
|
||||
else if (GameObject const* go = ToGameObject())
|
||||
TC_LOG_ERROR("entities", "GameObject (template id: %u) has invalid faction (faction template id) #%u", go->GetGOInfo()->entry, GetFaction());
|
||||
else
|
||||
TC_LOG_ERROR("entities", "WorldObject (name: %s, type: %u) has invalid faction (faction template id) #%u", GetName().c_str(), uint32(GetTypeId()), GetFaction());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// function based on function Unit::UnitReaction from 13850 client
|
||||
ReputationRank WorldObject::GetReactionTo(WorldObject const* target) const
|
||||
{
|
||||
// always friendly to self
|
||||
if (this == target)
|
||||
return REP_FRIENDLY;
|
||||
|
||||
// always friendly to charmer or owner
|
||||
if (GetCharmerOrOwnerOrSelf() == target->GetCharmerOrOwnerOrSelf())
|
||||
return REP_FRIENDLY;
|
||||
|
||||
Player const* selfPlayerOwner = GetAffectingPlayer();
|
||||
Player const* targetPlayerOwner = target->GetAffectingPlayer();
|
||||
|
||||
// check forced reputation to support SPELL_AURA_FORCE_REACTION
|
||||
if (selfPlayerOwner)
|
||||
{
|
||||
if (FactionTemplateEntry const* targetFactionTemplateEntry = target->GetFactionTemplateEntry())
|
||||
if (ReputationRank const* repRank = selfPlayerOwner->GetReputationMgr().GetForcedRankIfAny(targetFactionTemplateEntry))
|
||||
return *repRank;
|
||||
}
|
||||
else if (targetPlayerOwner)
|
||||
{
|
||||
if (FactionTemplateEntry const* selfFactionTemplateEntry = GetFactionTemplateEntry())
|
||||
if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(selfFactionTemplateEntry))
|
||||
return *repRank;
|
||||
}
|
||||
|
||||
Unit const* unit = ToUnit();
|
||||
Unit const* targetUnit = target->ToUnit();
|
||||
if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
if (selfPlayerOwner && targetPlayerOwner)
|
||||
{
|
||||
// always friendly to other unit controlled by player, or to the player himself
|
||||
if (selfPlayerOwner == targetPlayerOwner)
|
||||
return REP_FRIENDLY;
|
||||
|
||||
// duel - always hostile to opponent
|
||||
if (selfPlayerOwner->duel && selfPlayerOwner->duel->opponent == targetPlayerOwner && selfPlayerOwner->duel->startTime != 0)
|
||||
return REP_HOSTILE;
|
||||
|
||||
// same group - checks dependant only on our faction - skip FFA_PVP for example
|
||||
if (selfPlayerOwner->IsInRaidWith(targetPlayerOwner))
|
||||
return REP_FRIENDLY; // return true to allow config option AllowTwoSide.Interaction.Group to work
|
||||
// however client seems to allow mixed group parties, because in 13850 client it works like:
|
||||
// return GetFactionReactionTo(GetFactionTemplateEntry(), target);
|
||||
}
|
||||
|
||||
// check FFA_PVP
|
||||
if (unit->IsFFAPvP() && targetUnit->IsFFAPvP())
|
||||
return REP_HOSTILE;
|
||||
|
||||
if (selfPlayerOwner)
|
||||
{
|
||||
if (FactionTemplateEntry const* targetFactionTemplateEntry = targetUnit->GetFactionTemplateEntry())
|
||||
{
|
||||
if (ReputationRank const* repRank = selfPlayerOwner->GetReputationMgr().GetForcedRankIfAny(targetFactionTemplateEntry))
|
||||
return *repRank;
|
||||
if (!selfPlayerOwner->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_IGNORE_REPUTATION))
|
||||
{
|
||||
if (FactionEntry const* targetFactionEntry = sFactionStore.LookupEntry(targetFactionTemplateEntry->Faction))
|
||||
{
|
||||
if (targetFactionEntry->CanHaveReputation())
|
||||
{
|
||||
// check contested flags
|
||||
if (targetFactionTemplateEntry->IsHostileToPvpActivePlayers()
|
||||
&& selfPlayerOwner->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
|
||||
return REP_HOSTILE;
|
||||
|
||||
// if faction has reputation, hostile state depends only from AtWar state
|
||||
if (selfPlayerOwner->GetReputationMgr().IsAtWar(targetFactionEntry))
|
||||
return REP_HOSTILE;
|
||||
return REP_FRIENDLY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do checks dependant only on our faction
|
||||
return WorldObject::GetFactionReactionTo(GetFactionTemplateEntry(), target);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ ReputationRank WorldObject::GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, WorldObject const* target)
|
||||
{
|
||||
// always neutral when no template entry found
|
||||
if (!factionTemplateEntry)
|
||||
return REP_NEUTRAL;
|
||||
|
||||
FactionTemplateEntry const* targetFactionTemplateEntry = target->GetFactionTemplateEntry();
|
||||
|
||||
if (Player const* targetPlayerOwner = target->GetAffectingPlayer())
|
||||
{
|
||||
// check contested flags
|
||||
if (factionTemplateEntry->IsHostileToPvpActivePlayers()
|
||||
&& targetPlayerOwner->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
|
||||
return REP_HOSTILE;
|
||||
if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry))
|
||||
return *repRank;
|
||||
if (!target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_IGNORE_REPUTATION))
|
||||
{
|
||||
if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->Faction))
|
||||
{
|
||||
if (factionEntry->CanHaveReputation())
|
||||
{
|
||||
// CvP case - check reputation, don't allow state higher than neutral when at war
|
||||
ReputationRank repRank = targetPlayerOwner->GetReputationMgr().GetRank(factionEntry);
|
||||
if (targetPlayerOwner->GetReputationMgr().IsAtWar(factionEntry))
|
||||
repRank = std::min(REP_NEUTRAL, repRank);
|
||||
return repRank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// common faction based check
|
||||
if (factionTemplateEntry->IsHostileTo(targetFactionTemplateEntry))
|
||||
return REP_HOSTILE;
|
||||
if (factionTemplateEntry->IsFriendlyTo(targetFactionTemplateEntry))
|
||||
return REP_FRIENDLY;
|
||||
if (targetFactionTemplateEntry->IsFriendlyTo(factionTemplateEntry))
|
||||
return REP_FRIENDLY;
|
||||
// neutral by default
|
||||
return REP_NEUTRAL;
|
||||
}
|
||||
|
||||
bool WorldObject::IsHostileTo(WorldObject const* target) const
|
||||
{
|
||||
return GetReactionTo(target) <= REP_HOSTILE;
|
||||
}
|
||||
|
||||
bool WorldObject::IsFriendlyTo(WorldObject const* target) const
|
||||
{
|
||||
return GetReactionTo(target) >= REP_FRIENDLY;
|
||||
}
|
||||
|
||||
bool WorldObject::IsHostileToPlayers() const
|
||||
{
|
||||
FactionTemplateEntry const* my_faction = GetFactionTemplateEntry();
|
||||
if (!my_faction->Faction)
|
||||
return false;
|
||||
|
||||
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->Faction);
|
||||
if (raw_faction && raw_faction->ReputationIndex >= 0)
|
||||
return false;
|
||||
|
||||
return my_faction->IsHostileToPlayers();
|
||||
}
|
||||
|
||||
bool WorldObject::IsNeutralToAll() const
|
||||
{
|
||||
FactionTemplateEntry const* my_faction = GetFactionTemplateEntry();
|
||||
if (!my_faction->Faction)
|
||||
return true;
|
||||
|
||||
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->Faction);
|
||||
if (raw_faction && raw_faction->ReputationIndex >= 0)
|
||||
return false;
|
||||
|
||||
return my_faction->IsNeutralToAll();
|
||||
}
|
||||
|
||||
void WorldObject::CastSpell(SpellCastTargets const& targets, uint32 spellId, CastSpellExtraArgs const& args /*= { }*/)
|
||||
{
|
||||
SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!info)
|
||||
{
|
||||
TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell %u by caster %s", spellId, GetGUID().ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(this, info, args.TriggerFlags, args.OriginalCaster);
|
||||
for (auto const& pair : args.SpellValueOverrides)
|
||||
spell->SetSpellValue(pair.first, pair.second);
|
||||
|
||||
spell->m_CastItem = args.CastItem;
|
||||
spell->prepare(targets, args.TriggeringAura);
|
||||
}
|
||||
|
||||
void WorldObject::CastSpell(WorldObject* target, uint32 spellId, CastSpellExtraArgs const& args /*= { }*/)
|
||||
{
|
||||
SpellCastTargets targets;
|
||||
if (target)
|
||||
{
|
||||
if (Unit* unitTarget = target->ToUnit())
|
||||
targets.SetUnitTarget(unitTarget);
|
||||
else if (GameObject* goTarget = target->ToGameObject())
|
||||
targets.SetGOTarget(goTarget);
|
||||
else
|
||||
{
|
||||
TC_LOG_ERROR("entities.unit", "CastSpell: Invalid target %s passed to spell cast by %s", target->GetGUID().ToString().c_str(), GetGUID().ToString().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
CastSpell(targets, spellId, args);
|
||||
}
|
||||
|
||||
void WorldObject::CastSpell(Position const& dest, uint32 spellId, CastSpellExtraArgs const& args /*= { }*/)
|
||||
{
|
||||
SpellCastTargets targets;
|
||||
targets.SetDst(dest);
|
||||
CastSpell(targets, spellId, args);
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAttack from 13850 client
|
||||
bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
// can't attack self
|
||||
if (this == target)
|
||||
return false;
|
||||
|
||||
// can't attack GMs
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
|
||||
return false;
|
||||
|
||||
Unit const* unit = ToUnit();
|
||||
Unit const* targetUnit = target->ToUnit();
|
||||
|
||||
// CvC case - can attack each other only when one of them is hostile
|
||||
if (unit && !unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && targetUnit && !targetUnit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
return IsHostileTo(target) || target->IsHostileTo(this);
|
||||
|
||||
// PvP, PvC, CvP case
|
||||
// can't attack friendly targets
|
||||
if (IsFriendlyTo(target) || target->IsFriendlyTo(this))
|
||||
return false;
|
||||
|
||||
Player const* playerAffectingAttacker = unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : nullptr;
|
||||
Player const* playerAffectingTarget = targetUnit && targetUnit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? target->GetAffectingPlayer() : nullptr;
|
||||
|
||||
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
|
||||
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
|
||||
{
|
||||
Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
|
||||
|
||||
if (Unit const* creature = playerAffectingAttacker ? targetUnit : unit)
|
||||
{
|
||||
if (creature->IsContestedGuard() && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
|
||||
return true;
|
||||
|
||||
if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry())
|
||||
{
|
||||
if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate)))
|
||||
if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction))
|
||||
if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry))
|
||||
if (!(repState->Flags & FACTION_FLAG_AT_WAR))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Creature const* creatureAttacker = ToCreature();
|
||||
if (creatureAttacker && (creatureAttacker->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
|
||||
return false;
|
||||
|
||||
if (!bySpell)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldObject::IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const
|
||||
{
|
||||
ASSERT(target);
|
||||
ASSERT(bySpell);
|
||||
|
||||
// can't attack unattackable units
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
|
||||
return false;
|
||||
|
||||
Unit const* unit = ToUnit();
|
||||
// visibility checks (only units)
|
||||
if (unit)
|
||||
{
|
||||
// can't attack invisible
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
|
||||
{
|
||||
if (!unit->CanSeeOrDetect(target, bySpell->IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
else if (!obj)
|
||||
{
|
||||
// ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
|
||||
bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) ||
|
||||
(target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && IsInCombatWith(target));
|
||||
|
||||
if (!CanSeeOrDetect(target, ignoreStealthCheck))
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// can't attack dead
|
||||
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
// can't attack untargetable
|
||||
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
|
||||
&& unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (Player const* playerAttacker = ToPlayer())
|
||||
{
|
||||
if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check flags
|
||||
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_NOT_ATTACKABLE_2))
|
||||
return false;
|
||||
|
||||
if (unit && !unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && unitTarget->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG))
|
||||
{
|
||||
if (unitTarget && !unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && unit && unit->IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
|
||||
// check duel - before sanctuary checks
|
||||
Player const* playerAffectingAttacker = unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : nullptr;
|
||||
Player const* playerAffectingTarget = unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) ? target->GetAffectingPlayer() : nullptr;
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->opponent == playerAffectingTarget && playerAffectingAttacker->duel->startTime != 0)
|
||||
return true;
|
||||
|
||||
// PvP case - can't attack when attacker or target are in sanctuary
|
||||
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
|
||||
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && (unitTarget->IsInSanctuary() || unit->IsInSanctuary()))
|
||||
return false;
|
||||
|
||||
// additional checks - only PvP case
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
{
|
||||
if (unitTarget->IsPvP())
|
||||
return true;
|
||||
|
||||
if (unit->IsFFAPvP() && unitTarget->IsFFAPvP())
|
||||
return true;
|
||||
|
||||
return unit->HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_UNK1)
|
||||
|| unitTarget->HasByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_UNK1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAssist from 13850 client
|
||||
bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/, bool spellCheck /*= true*/) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
// can assist to self
|
||||
if (this == target)
|
||||
return true;
|
||||
|
||||
// can't assist GMs
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
|
||||
return false;
|
||||
|
||||
// can't assist non-friendly targets
|
||||
if (GetReactionTo(target) < REP_NEUTRAL && target->GetReactionTo(this) < REP_NEUTRAL && (!ToCreature() || !(ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)))
|
||||
return false;
|
||||
|
||||
if (!bySpell)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldObject::IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const
|
||||
{
|
||||
ASSERT(target);
|
||||
ASSERT(bySpell);
|
||||
|
||||
// can't assist unattackable units
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
|
||||
// can't assist unattackable units
|
||||
if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
|
||||
return false;
|
||||
|
||||
// can't assist own vehicle or passenger
|
||||
Unit const* unit = ToUnit();
|
||||
if (unit && unitTarget && unit->GetVehicle())
|
||||
{
|
||||
if (unit->IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
|
||||
if (unit->GetVehicleBase()->IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
}
|
||||
|
||||
// can't assist invisible
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !CanSeeOrDetect(target, bySpell->IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
// can't assist dead
|
||||
if (!bySpell->IsAllowingDeadTarget() && unitTarget && !unitTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
// can't assist untargetable
|
||||
if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
{
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
if (unitTarget && unitTarget->IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unitTarget && unitTarget->IsImmuneToNPC())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// PvP case
|
||||
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
Player const* targetPlayerOwner = target->GetAffectingPlayer();
|
||||
if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
Player const* selfPlayerOwner = GetAffectingPlayer();
|
||||
if (selfPlayerOwner && targetPlayerOwner)
|
||||
{
|
||||
// can't assist player which is dueling someone
|
||||
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner->duel)
|
||||
return false;
|
||||
}
|
||||
// can't assist player in ffa_pvp zone from outside
|
||||
if (unitTarget->IsFFAPvP() && unit && !unit->IsFFAPvP())
|
||||
return false;
|
||||
|
||||
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
||||
if (unitTarget->IsPvP())
|
||||
if (unit && unit->IsInSanctuary() && !unitTarget->IsInSanctuary())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// PvC case - player can assist creature only if has specific type flags
|
||||
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
|
||||
else if (unit && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
{
|
||||
if (!bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
|
||||
if (unitTarget && !unitTarget->IsPvP())
|
||||
if (Creature const* creatureTarget = target->ToCreature())
|
||||
return ((creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) || (creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* WorldObject::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
|
||||
{
|
||||
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REDIRECTED) || spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES))
|
||||
return victim;
|
||||
|
||||
Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET);
|
||||
for (AuraEffect const* aurEff : magnetAuras)
|
||||
{
|
||||
if (Unit* magnet = aurEff->GetBase()->GetCaster())
|
||||
{
|
||||
if (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK && IsValidAttackTarget(magnet, spellInfo))
|
||||
{
|
||||
/// @todo handle this charge drop by proc in cast phase on explicit target
|
||||
if (spellInfo->Speed > 0.0f)
|
||||
{
|
||||
// Set up missile speed based delay
|
||||
uint32 delay = uint32(std::floor(std::max<float>(victim->GetDistance(this), 5.0f) / spellInfo->Speed * 1000.0f));
|
||||
// Schedule charge drop
|
||||
aurEff->GetBase()->DropChargeDelayed(delay, AuraRemoveFlags::Expired);
|
||||
}
|
||||
else
|
||||
aurEff->GetBase()->DropCharge(AuraRemoveFlags::Expired);
|
||||
|
||||
return magnet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return victim;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Duration.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "GridReference.h"
|
||||
#include "GridRefManager.h"
|
||||
#include "ModelIgnoreFlags.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "PhaseShift.h"
|
||||
#include "Position.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "UpdateFields.h"
|
||||
#include "UpdateMask.h"
|
||||
#include <list>
|
||||
@@ -45,6 +47,9 @@ class GameObject;
|
||||
class InstanceScript;
|
||||
class Map;
|
||||
class Player;
|
||||
class Spell;
|
||||
class SpellCastTargets;
|
||||
class SpellInfo;
|
||||
class TempSummon;
|
||||
class TransportBase;
|
||||
class Unit;
|
||||
@@ -52,6 +57,7 @@ class UpdateData;
|
||||
class WorldObject;
|
||||
class WorldPacket;
|
||||
class ZoneScript;
|
||||
struct FactionTemplateEntry;
|
||||
struct PositionFullTerrainStatus;
|
||||
struct QuaternionData;
|
||||
enum ZLiquidStatus : uint32;
|
||||
@@ -418,6 +424,58 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
GameObject* FindNearestGameObjectOfType(GameobjectTypes type, float range) const;
|
||||
Player* SelectNearestPlayer(float distance) const;
|
||||
|
||||
virtual ObjectGuid GetOwnerGUID() const = 0;
|
||||
virtual ObjectGuid GetCharmerOrOwnerGUID() const { return GetOwnerGUID(); }
|
||||
ObjectGuid GetCharmerOrOwnerOrOwnGUID() const;
|
||||
|
||||
Unit* GetOwner() const;
|
||||
Unit* GetCharmerOrOwner() const;
|
||||
Unit* GetCharmerOrOwnerOrSelf() const;
|
||||
Player* GetCharmerOrOwnerPlayerOrPlayerItself() const;
|
||||
Player* GetAffectingPlayer() const;
|
||||
|
||||
Player* GetSpellModOwner() const;
|
||||
int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effIndex, int32 const* basePoints = nullptr) const;
|
||||
|
||||
// target dependent range checks
|
||||
float GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
|
||||
float GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
|
||||
|
||||
float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const;
|
||||
int32 ModSpellDuration(SpellInfo const* spellProto, WorldObject const* target, int32 duration, bool positive, uint32 effectMask);
|
||||
void ModSpellCastTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr);
|
||||
void ModSpellDurationTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr);
|
||||
|
||||
virtual float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo = nullptr) const;
|
||||
virtual SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
|
||||
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
|
||||
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false) const;
|
||||
|
||||
virtual uint32 GetFaction() const = 0;
|
||||
virtual void SetFaction(uint32 /*faction*/) { }
|
||||
FactionTemplateEntry const* GetFactionTemplateEntry() const;
|
||||
|
||||
ReputationRank GetReactionTo(WorldObject const* target) const;
|
||||
static ReputationRank GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, WorldObject const* target);
|
||||
|
||||
bool IsHostileTo(WorldObject const* target) const;
|
||||
bool IsHostileToPlayers() const;
|
||||
bool IsFriendlyTo(WorldObject const* target) const;
|
||||
bool IsNeutralToAll() const;
|
||||
|
||||
// CastSpell's third arg can be a variety of things - check out CastSpellExtraArgs' constructors!
|
||||
void CastSpell(SpellCastTargets const& targets, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
void CastSpell(WorldObject* target, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
void CastSpell(Position const& dest, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
|
||||
bool IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
|
||||
bool IsValidSpellAttackTarget(WorldObject const* target, SpellInfo const* bySpell) const;
|
||||
|
||||
bool IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
|
||||
bool IsValidSpellAssistTarget(WorldObject const* target, SpellInfo const* bySpell) const;
|
||||
|
||||
Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo);
|
||||
|
||||
template <typename Container>
|
||||
void GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange = 250.0f) const;
|
||||
|
||||
@@ -481,6 +539,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
float GetMapWaterOrGroundLevel(float x, float y, float z, float* ground = nullptr) const;
|
||||
float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f) const; // DEFAULT_HEIGHT_SEARCH in map.h
|
||||
|
||||
// Event handler
|
||||
EventProcessor m_Events;
|
||||
|
||||
uint16 GetAIAnimKitId() const { return m_aiAnimKitId; }
|
||||
void SetAIAnimKitId(uint16 animKitId);
|
||||
uint16 GetMovementAnimKitId() const { return m_movementAnimKitId; }
|
||||
@@ -499,7 +560,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
bool m_isActive;
|
||||
bool m_isFarVisible;
|
||||
Optional<float> m_visibilityDistanceOverride;
|
||||
const bool m_isWorldObject;
|
||||
bool const m_isWorldObject;
|
||||
ZoneScript* m_zoneScript;
|
||||
|
||||
// transports (gameobjects only)
|
||||
@@ -527,7 +588,6 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
private:
|
||||
Map* m_currMap; // current object's Map location
|
||||
|
||||
//uint32 m_mapId; // object at map with map_id
|
||||
uint32 m_InstanceId; // in map copy with instance id
|
||||
PhaseShift _phaseShift;
|
||||
PhaseShift _suppressedPhaseShift; // contains phases for current area but not applied due to conditions
|
||||
|
||||
@@ -1798,7 +1798,7 @@ void Player::SetObjectScale(float scale)
|
||||
SendMovementSetCollisionHeight(GetCollisionHeight(), UPDATE_COLLISION_HEIGHT_SCALE);
|
||||
}
|
||||
|
||||
bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const
|
||||
bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const
|
||||
{
|
||||
// players are immune to taunt (the aura and the spell effect)
|
||||
if (spellInfo->Effects[index].IsAura(SPELL_AURA_MOD_TAUNT))
|
||||
@@ -22632,7 +22632,7 @@ void Player::UpdatePotionCooldown(Spell* spell)
|
||||
m_lastPotionId = 0;
|
||||
}
|
||||
|
||||
void Player::SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura)
|
||||
void Player::SetResurrectRequestData(WorldObject const* caster, uint32 health, uint32 mana, uint32 appliedAura)
|
||||
{
|
||||
ASSERT(!IsResurrectRequested());
|
||||
_resurrectionData = new ResurrectionData();
|
||||
@@ -23285,94 +23285,6 @@ Player* Player::GetSelectedPlayer() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Player::SendComboPoints()
|
||||
{
|
||||
|
||||
Unit* combotarget = ObjectAccessor::GetUnit(*this, m_comboTarget);
|
||||
if (combotarget)
|
||||
{
|
||||
WorldPacket data;
|
||||
Player* movingMe = GetCharmerOrSelfPlayer();
|
||||
if (movingMe != this)
|
||||
{
|
||||
data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, movingMe->GetPackGUID().size()+combotarget->GetPackGUID().size()+1);
|
||||
data << movingMe->GetPackGUID();
|
||||
}
|
||||
else
|
||||
data.Initialize(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1);
|
||||
data << combotarget->GetPackGUID();
|
||||
data << uint8(m_comboPoints);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::AddComboPoints(Unit* target, int8 count, Spell* spell)
|
||||
{
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints;
|
||||
|
||||
// without combo points lost (duration checked in aura)
|
||||
RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
|
||||
|
||||
if (target->GetGUID() == m_comboTarget)
|
||||
*comboPoints += count;
|
||||
else
|
||||
{
|
||||
if (m_comboTarget)
|
||||
if (Unit* target2 = ObjectAccessor::GetUnit(*this, m_comboTarget))
|
||||
target2->RemoveComboPointHolder(GetGUID());
|
||||
|
||||
// Spells will always add value to m_comboPoints eventualy, so it must be cleared first
|
||||
if (spell)
|
||||
m_comboPoints = 0;
|
||||
|
||||
m_comboTarget = target->GetGUID();
|
||||
*comboPoints = count;
|
||||
|
||||
target->AddComboPointHolder(GetGUID());
|
||||
}
|
||||
|
||||
if (*comboPoints > 5)
|
||||
*comboPoints = 5;
|
||||
else if (*comboPoints < 0)
|
||||
*comboPoints = 0;
|
||||
|
||||
if (!spell)
|
||||
SendComboPoints();
|
||||
}
|
||||
|
||||
void Player::GainSpellComboPoints(int8 count)
|
||||
{
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
m_comboPoints += count;
|
||||
if (m_comboPoints > 5) m_comboPoints = 5;
|
||||
else if (m_comboPoints < 0) m_comboPoints = 0;
|
||||
|
||||
SendComboPoints();
|
||||
}
|
||||
|
||||
void Player::ClearComboPoints()
|
||||
{
|
||||
if (!m_comboTarget)
|
||||
return;
|
||||
|
||||
// without combopoints lost (duration checked in aura)
|
||||
RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
|
||||
|
||||
m_comboPoints = 0;
|
||||
|
||||
SendComboPoints();
|
||||
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*this, m_comboTarget))
|
||||
target->RemoveComboPointHolder(GetGUID());
|
||||
|
||||
m_comboTarget.Clear();
|
||||
}
|
||||
|
||||
bool Player::IsInGroup(ObjectGuid groupGuid) const
|
||||
{
|
||||
if (Group const* group = GetGroup())
|
||||
@@ -26046,9 +25958,9 @@ void Player::ResetAchievementCriteria(AchievementCriteriaCondition condition, ui
|
||||
m_achievementMgr->ResetAchievementCriteria(condition, value, evenIfCriteriaComplete);
|
||||
}
|
||||
|
||||
void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= nullptr*/, GameObject* go /*= nullptr*/)
|
||||
void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, WorldObject* ref /*= nullptr*/, GameObject* go /*= nullptr*/)
|
||||
{
|
||||
m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, ref, this);
|
||||
Guild* guild = sGuildMgr->GetGuildById(GetGuildId());
|
||||
if (!guild)
|
||||
return;
|
||||
@@ -26058,7 +25970,7 @@ void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 mis
|
||||
if (sAchievementMgr->IsGroupCriteriaType(type))
|
||||
return;
|
||||
|
||||
guild->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this, go);
|
||||
guild->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, ref, this, go);
|
||||
}
|
||||
|
||||
void Player::CompletedAchievement(AchievementEntry const* entry)
|
||||
|
||||
@@ -1031,7 +1031,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
|
||||
void Update(uint32 time) override;
|
||||
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const override;
|
||||
|
||||
bool IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const;
|
||||
|
||||
@@ -1521,14 +1521,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SetTarget(ObjectGuid /*guid*/) override { } /// Used for serverside target changes, does not apply to players
|
||||
void SetSelection(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_TARGET, guid); }
|
||||
|
||||
uint8 GetComboPoints() const { return m_comboPoints; }
|
||||
ObjectGuid GetComboTarget() const { return m_comboTarget; }
|
||||
|
||||
void AddComboPoints(Unit* target, int8 count, Spell* spell = nullptr);
|
||||
void GainSpellComboPoints(int8 count);
|
||||
void ClearComboPoints();
|
||||
void SendComboPoints();
|
||||
|
||||
void SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError = 0, ObjectGuid::LowType item_guid = 0, uint32 item_count = 0) const;
|
||||
void SendNewMail() const;
|
||||
void UpdateNextMailTimeAndUnreads();
|
||||
@@ -1663,7 +1655,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
|
||||
void UpdatePotionCooldown(Spell* spell = nullptr);
|
||||
|
||||
void SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura);
|
||||
void SetResurrectRequestData(WorldObject const* caster, uint32 health, uint32 mana, uint32 appliedAura);
|
||||
void ClearResurrectRequestData()
|
||||
{
|
||||
delete _resurrectionData;
|
||||
@@ -2329,7 +2321,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
bool HasAchieved(uint32 achievementId) const;
|
||||
void ResetAchievements();
|
||||
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete = false);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit* unit = nullptr, GameObject* go = nullptr);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject* ref = nullptr, GameObject* go = nullptr);
|
||||
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0);
|
||||
void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry);
|
||||
void CompletedAchievement(AchievementEntry const* entry);
|
||||
@@ -2565,9 +2557,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
|
||||
uint32 m_ExtraFlags;
|
||||
|
||||
ObjectGuid m_comboTarget;
|
||||
int8 m_comboPoints;
|
||||
|
||||
QuestStatusMap m_QuestStatus;
|
||||
QuestStatusSaveMap m_QuestStatusSave;
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ void Totem::UnSummon(uint32 msTime)
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const
|
||||
bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const
|
||||
{
|
||||
/// @todo possibly all negative auras immune?
|
||||
if (GetEntry() == 5925)
|
||||
|
||||
@@ -57,7 +57,7 @@ class TC_GAME_API Totem : public Minion
|
||||
void UpdateAttackPowerAndDamage(bool /*ranged*/) override { }
|
||||
void UpdateDamagePhysical(WeaponAttackType /*attType*/) override { }
|
||||
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const override;
|
||||
|
||||
protected:
|
||||
TotemType m_type;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -19,7 +19,6 @@
|
||||
#define __UNIT_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "CombatManager.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
@@ -403,15 +402,15 @@ enum MeleeHitOutcome : uint8
|
||||
class DispelInfo
|
||||
{
|
||||
public:
|
||||
explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
|
||||
_dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
|
||||
explicit DispelInfo(WorldObject* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
|
||||
_dispeller(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
|
||||
|
||||
Unit* GetDispeller() const { return _dispellerUnit; }
|
||||
WorldObject* GetDispeller() const { return _dispeller; }
|
||||
uint32 GetDispellerSpellId() const { return _dispellerSpell; }
|
||||
uint8 GetRemovedCharges() const { return _chargesRemoved; }
|
||||
void SetRemovedCharges(uint8 amount) { _chargesRemoved = amount; }
|
||||
private:
|
||||
Unit* _dispellerUnit;
|
||||
WorldObject* _dispeller;
|
||||
uint32 _dispellerSpell;
|
||||
uint8 _chargesRemoved;
|
||||
};
|
||||
@@ -855,14 +854,10 @@ class TC_GAME_API Unit : public WorldObject
|
||||
virtual bool IsAffectedByDiminishingReturns() const { return (GetCharmerOrOwnerPlayerOrPlayerItself() != nullptr); }
|
||||
DiminishingLevels GetDiminishing(DiminishingGroup group) const;
|
||||
void IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered);
|
||||
bool ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, Unit* caster, DiminishingLevels previousLevel) const;
|
||||
bool ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const;
|
||||
void ApplyDiminishingAura(DiminishingGroup group, bool apply);
|
||||
void ClearDiminishings();
|
||||
|
||||
// target dependent range checks
|
||||
float GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
|
||||
float GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
|
||||
|
||||
virtual void Update(uint32 time) override;
|
||||
|
||||
void setAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; }
|
||||
@@ -943,7 +938,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); }
|
||||
uint32 GetResistance(SpellSchoolMask mask) const;
|
||||
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); }
|
||||
static float CalculateAverageResistReduction(Unit const* attacker, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
|
||||
static float CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
|
||||
|
||||
uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
|
||||
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
|
||||
@@ -994,17 +989,9 @@ class TC_GAME_API Unit : public WorldObject
|
||||
virtual void SetSheath(SheathState sheathed);
|
||||
|
||||
// faction template id
|
||||
uint32 GetFaction() const { return GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE); }
|
||||
void SetFaction(uint32 faction) { SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction); }
|
||||
FactionTemplateEntry const* GetFactionTemplateEntry() const;
|
||||
uint32 GetFaction() const override { return GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE); }
|
||||
void SetFaction(uint32 faction) override { SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction); }
|
||||
|
||||
ReputationRank GetReactionTo(Unit const* target) const;
|
||||
ReputationRank static GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, Unit const* target);
|
||||
|
||||
bool IsHostileTo(Unit const* unit) const;
|
||||
bool IsHostileToPlayers() const;
|
||||
bool IsFriendlyTo(Unit const* unit) const;
|
||||
bool IsNeutralToAll() const;
|
||||
bool IsInPartyWith(Unit const* unit) const;
|
||||
bool IsInRaidWith(Unit const* unit) const;
|
||||
void GetPartyMembers(std::list<Unit*> &units);
|
||||
@@ -1073,10 +1060,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const& casterGuid) const;
|
||||
|
||||
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo = nullptr) const;
|
||||
SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo);
|
||||
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo);
|
||||
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false, Optional<uint8> effectMask = {});
|
||||
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo = nullptr) const override;
|
||||
SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const override;
|
||||
|
||||
float GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const;
|
||||
float GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const;
|
||||
@@ -1169,12 +1154,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
bool isTargetableForAttack(bool checkFakeDeath = true) const;
|
||||
|
||||
bool IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell = nullptr, WorldObject const* obj = nullptr, bool spellCheck = true) const;
|
||||
bool IsValidSpellAttackTarget(Unit const* target, SpellInfo const* bySpell, WorldObject const* obj = nullptr) const;
|
||||
|
||||
bool IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell = nullptr, bool spellCheck = true) const;
|
||||
bool IsValidSpellAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
|
||||
|
||||
bool IsInWater() const;
|
||||
bool IsUnderWater() const;
|
||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||
@@ -1185,11 +1164,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers powerType);
|
||||
void EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType);
|
||||
|
||||
// CastSpell's third arg can be a variety of things - check out CastSpellExtraArgs' constructors!
|
||||
void CastSpell(SpellCastTargets const& targets, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
void CastSpell(WorldObject* target, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
void CastSpell(Position const& dest, uint32 spellId, CastSpellExtraArgs const& args = { });
|
||||
|
||||
Aura* AddAura(uint32 spellId, Unit* target);
|
||||
Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target);
|
||||
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
|
||||
@@ -1254,7 +1228,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
DeathState getDeathState() const { return m_deathState; }
|
||||
virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet
|
||||
|
||||
ObjectGuid GetOwnerGUID() const { return GetGuidValue(UNIT_FIELD_SUMMONEDBY); }
|
||||
ObjectGuid GetOwnerGUID() const override { return GetGuidValue(UNIT_FIELD_SUMMONEDBY); }
|
||||
void SetOwnerGUID(ObjectGuid owner);
|
||||
ObjectGuid GetCreatorGUID() const { return GetGuidValue(UNIT_FIELD_CREATEDBY); }
|
||||
void SetCreatorGUID(ObjectGuid creator) { SetGuidValue(UNIT_FIELD_CREATEDBY, creator); }
|
||||
@@ -1274,20 +1248,12 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
bool IsControlledByPlayer() const { return m_ControlledByPlayer; }
|
||||
Player* GetControllingPlayer() const;
|
||||
ObjectGuid GetCharmerOrOwnerGUID() const { return IsCharmed() ? GetCharmerGUID() : GetOwnerGUID(); }
|
||||
ObjectGuid GetCharmerOrOwnerGUID() const override { return IsCharmed() ? GetCharmerGUID() : GetOwnerGUID(); }
|
||||
bool IsCharmedOwnedByPlayerOrPlayer() const { return GetCharmerOrOwnerOrOwnGUID().IsPlayer(); }
|
||||
|
||||
ObjectGuid GetCharmerOrOwnerOrOwnGUID() const;
|
||||
|
||||
Unit* GetOwner() const;
|
||||
Guardian* GetGuardianPet() const;
|
||||
Minion* GetFirstMinion() const;
|
||||
Unit* GetCharmerOrOwner() const { return IsCharmed() ? GetCharmer() : GetOwner(); }
|
||||
Unit* GetCharmerOrOwnerOrSelf() const;
|
||||
Player* GetCharmerOrOwnerPlayerOrPlayerItself() const;
|
||||
Player* GetAffectingPlayer() const;
|
||||
|
||||
Player* GetSpellModOwner() const;
|
||||
|
||||
void SetMinion(Minion *minion, bool apply);
|
||||
void GetAllMinionsByEntry(std::list<Creature*>& Minions, uint32 entry);
|
||||
@@ -1378,8 +1344,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault);
|
||||
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault);
|
||||
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, Unit* dispeller, uint8 chargesRemoved = 1);
|
||||
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, Unit* stealer);
|
||||
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved = 1);
|
||||
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer);
|
||||
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid);
|
||||
void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = nullptr, bool negative = true, bool positive = true);
|
||||
void RemoveNotOwnLimitedTargetAuras(bool onPhaseChange = false);
|
||||
@@ -1422,7 +1388,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraApplication * except = nullptr) const;
|
||||
Aura* GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0) const;
|
||||
|
||||
void GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect = false) const;
|
||||
void GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect = false) const;
|
||||
|
||||
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster = ObjectGuid::Empty) const;
|
||||
uint32 GetAuraCount(uint32 spellId) const;
|
||||
@@ -1524,10 +1490,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
float m_modAttackSpeedPct[3];
|
||||
|
||||
// Event handler
|
||||
EventProcessor m_Events;
|
||||
|
||||
// stat system
|
||||
// stat system
|
||||
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply);
|
||||
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount);
|
||||
@@ -1631,7 +1593,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
bool HasAuraState(AuraStateType flag, SpellInfo const* spellProto = nullptr, Unit const* Caster = nullptr) const;
|
||||
void UnsummonAllTotems();
|
||||
bool IsMagnet() const;
|
||||
Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo);
|
||||
Unit* GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo = nullptr);
|
||||
|
||||
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask, bool withSpellPowerPctMod = false) const;
|
||||
@@ -1659,14 +1620,14 @@ class TC_GAME_API Unit : public WorldObject
|
||||
uint32 GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraType auraType, uint8 effectIndex = 0) const;
|
||||
|
||||
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
|
||||
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster, Optional<uint8> effectMask = {}) const; // redefined in Creature
|
||||
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const; // redefined in Creature
|
||||
uint32 GetSchoolImmunityMask() const;
|
||||
uint32 GetDamageImmunityMask() const;
|
||||
uint32 GetMechanicImmunityMask() const;
|
||||
|
||||
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const; // redefined in Creature
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster) const; // redefined in Creature
|
||||
|
||||
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr, int8 effIndex = -1);
|
||||
static uint32 CalcArmorReducedDamage(Unit const* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK, uint8 attackerLevel = 0);
|
||||
@@ -1683,12 +1644,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void SetSpeedRateReal(UnitMoveType mtype, float rate);
|
||||
|
||||
public:
|
||||
float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const;
|
||||
int32 CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints = nullptr) const;
|
||||
int32 ModSpellDuration(SpellInfo const* spellProto, Unit const* target, int32 duration, bool positive, uint32 effectMask);
|
||||
void ModSpellCastTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr);
|
||||
void ModSpellDurationTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr);
|
||||
|
||||
// Makes the unit follow the given target. Use this function above using the MotionMaster::MoveFollow for default follow behaivior.
|
||||
void FollowTarget(Unit* target);
|
||||
|
||||
@@ -1727,9 +1682,19 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void SetControlled(bool apply, UnitState state);
|
||||
void ApplyControlStatesIfNeeded();
|
||||
|
||||
///-----------Combo point system-------------------
|
||||
void AddComboPoints(Unit* target, int8 count, Spell* spell = nullptr);
|
||||
void GainSpellComboPoints(int8 count);
|
||||
void ClearComboPoints();
|
||||
void SendComboPoints();
|
||||
void AddComboPointHolder(ObjectGuid lowguid) { m_ComboPointHolders.insert(lowguid); }
|
||||
void RemoveComboPointHolder(ObjectGuid lowguid) { m_ComboPointHolders.erase(lowguid); }
|
||||
void ClearComboPointHolders();
|
||||
uint8 GetComboPoints() const { return m_comboPoints; }
|
||||
ObjectGuid GetComboTarget() const { return m_comboTarget; }
|
||||
|
||||
ObjectGuid m_comboTarget;
|
||||
int8 m_comboPoints;
|
||||
|
||||
///----------Pet responses methods-----------------
|
||||
void SendPetActionFeedback (uint8 msg);
|
||||
|
||||
@@ -425,17 +425,17 @@ bool AnyDeadUnitObjectInRangeCheck::operator()(Creature* u)
|
||||
|
||||
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Player* u)
|
||||
{
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && WorldObjectSpellTargetCheck::operator()(u);
|
||||
}
|
||||
|
||||
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Corpse* u)
|
||||
{
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && WorldObjectSpellTargetCheck::operator()(u);
|
||||
}
|
||||
|
||||
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u)
|
||||
{
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
|
||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && WorldObjectSpellTargetCheck::operator()(u);
|
||||
}
|
||||
|
||||
template void ObjectUpdater::Visit<Creature>(CreatureMapType&);
|
||||
|
||||
@@ -636,29 +636,26 @@ namespace Trinity
|
||||
class TC_GAME_API AnyDeadUnitObjectInRangeCheck
|
||||
{
|
||||
public:
|
||||
AnyDeadUnitObjectInRangeCheck(Unit* searchObj, float range) : i_searchObj(searchObj), i_range(range) { }
|
||||
AnyDeadUnitObjectInRangeCheck(WorldObject* searchObj, float range) : i_searchObj(searchObj), i_range(range) { }
|
||||
bool operator()(Player* u);
|
||||
bool operator()(Corpse* u);
|
||||
bool operator()(Creature* u);
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
|
||||
protected:
|
||||
Unit const* const i_searchObj;
|
||||
WorldObject const* const i_searchObj;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class TC_GAME_API AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck
|
||||
class TC_GAME_API AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck, public WorldObjectSpellTargetCheck
|
||||
{
|
||||
public:
|
||||
AnyDeadUnitSpellTargetInRangeCheck(Unit* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check)
|
||||
: AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(searchObj, searchObj, spellInfo, check, nullptr)
|
||||
AnyDeadUnitSpellTargetInRangeCheck(WorldObject* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check)
|
||||
: AnyDeadUnitObjectInRangeCheck(searchObj, range), WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, nullptr)
|
||||
{ }
|
||||
bool operator()(Player* u);
|
||||
bool operator()(Corpse* u);
|
||||
bool operator()(Creature* u);
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
|
||||
protected:
|
||||
SpellInfo const* i_spellInfo;
|
||||
WorldObjectSpellTargetCheck i_check;
|
||||
};
|
||||
|
||||
// WorldObject do classes
|
||||
@@ -678,25 +675,24 @@ namespace Trinity
|
||||
class GameObjectFocusCheck
|
||||
{
|
||||
public:
|
||||
GameObjectFocusCheck(Unit const* unit, uint32 focusId) : i_unit(unit), i_focusId(focusId) { }
|
||||
GameObjectFocusCheck(WorldObject const* caster, uint32 focusId) : _caster(caster), _focusId(focusId) { }
|
||||
bool operator()(GameObject* go) const
|
||||
{
|
||||
if (go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS)
|
||||
return false;
|
||||
|
||||
if (go->GetGOInfo()->spellFocus.focusId != i_focusId)
|
||||
if (go->GetGOInfo()->spellFocus.focusId != _focusId)
|
||||
return false;
|
||||
|
||||
if (!go->isSpawned())
|
||||
return false;
|
||||
|
||||
float dist = go->GetGOInfo()->spellFocus.dist / 2.f;
|
||||
|
||||
return go->IsWithinDistInMap(i_unit, dist);
|
||||
float const dist = go->GetGOInfo()->spellFocus.dist / 2.f;
|
||||
return go->IsWithinDistInMap(_caster, dist);
|
||||
}
|
||||
private:
|
||||
Unit const* i_unit;
|
||||
uint32 i_focusId;
|
||||
WorldObject const* _caster;
|
||||
uint32 _focusId;
|
||||
};
|
||||
|
||||
// Find the nearest Fishing hole and return true only if source object is in range of hole
|
||||
|
||||
@@ -3981,7 +3981,7 @@ bool Guild::HasAchieved(uint32 achievementId) const
|
||||
return m_achievementMgr->HasAchieved(achievementId);
|
||||
}
|
||||
|
||||
void Guild::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player, GameObject* go)
|
||||
void Guild::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject* unit, Player* player, GameObject* go)
|
||||
{
|
||||
m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, player, go);
|
||||
}
|
||||
|
||||
@@ -891,7 +891,7 @@ public:
|
||||
void ResetTimes(bool weekly);
|
||||
|
||||
bool HasAchieved(uint32 achievementId) const;
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player, GameObject* go = nullptr);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject* ref, Player* player, GameObject* go = nullptr);
|
||||
|
||||
inline void SetAchievementPointsFor(ObjectGuid guid, uint32 achievementPoint)
|
||||
{
|
||||
|
||||
@@ -348,8 +348,6 @@ Aura* Aura::TryRefreshStackOrCreate(AuraCreateInfo& createInfo)
|
||||
|
||||
Aura* Aura::TryCreate(AuraCreateInfo& createInfo)
|
||||
{
|
||||
ASSERT(createInfo.Caster || createInfo.CasterGUID);
|
||||
|
||||
uint8 effMask = createInfo._auraEffectMask;
|
||||
if (createInfo._targetEffectMask)
|
||||
effMask = createInfo._targetEffectMask;
|
||||
@@ -363,17 +361,25 @@ Aura* Aura::TryCreate(AuraCreateInfo& createInfo)
|
||||
|
||||
Aura* Aura::Create(AuraCreateInfo& createInfo)
|
||||
{
|
||||
ASSERT(createInfo.Caster || createInfo.CasterGUID);
|
||||
|
||||
// try to get caster of aura
|
||||
if (createInfo.CasterGUID)
|
||||
if (!createInfo.CasterGUID.IsEmpty())
|
||||
{
|
||||
if (createInfo._owner->GetGUID() == createInfo.CasterGUID)
|
||||
createInfo.Caster = createInfo._owner->ToUnit();
|
||||
// world gameobjects can't own auras and they send empty casterguid
|
||||
// checked on sniffs with spell 22247
|
||||
if (createInfo.CasterGUID.IsGameObject())
|
||||
{
|
||||
createInfo.Caster = nullptr;
|
||||
createInfo.CasterGUID.Clear();
|
||||
}
|
||||
else
|
||||
createInfo.Caster = ObjectAccessor::GetUnit(*createInfo._owner, createInfo.CasterGUID);
|
||||
{
|
||||
if (createInfo._owner->GetGUID() == createInfo.CasterGUID)
|
||||
createInfo.Caster = createInfo._owner->ToUnit();
|
||||
else
|
||||
createInfo.Caster = ObjectAccessor::GetUnit(*createInfo._owner, createInfo.CasterGUID);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (createInfo.Caster)
|
||||
createInfo.CasterGUID = createInfo.Caster->GetGUID();
|
||||
|
||||
// check if aura can be owned by owner
|
||||
@@ -425,7 +431,7 @@ Aura* Aura::Create(AuraCreateInfo& createInfo)
|
||||
}
|
||||
|
||||
Aura::Aura(AuraCreateInfo const& createInfo) :
|
||||
m_spellInfo(createInfo._spellInfo), m_casterGuid(createInfo.CasterGUID.IsEmpty() ? createInfo.Caster->GetGUID() : createInfo.CasterGUID),
|
||||
m_spellInfo(createInfo._spellInfo), m_casterGuid(createInfo.CasterGUID),
|
||||
m_castItemGuid(createInfo.CastItem ? createInfo.CastItem->GetGUID() : ObjectGuid::Empty), m_applyTime(GameTime::GetGameTime()),
|
||||
m_owner(createInfo._owner), m_timeCla(0), m_updateTargetMapInterval(0),
|
||||
_casterInfo(), m_procCharges(0), m_stackAmount(1),
|
||||
|
||||
+663
-496
File diff suppressed because it is too large.
Load diff
@@ -211,8 +211,7 @@ class TC_GAME_API SpellCastTargets
|
||||
float GetSpeedXY() const { return m_speed * std::cos(m_elevation); }
|
||||
float GetSpeedZ() const { return m_speed * std::sin(m_elevation); }
|
||||
|
||||
void Update(Unit* caster);
|
||||
void OutDebug() const;
|
||||
void Update(WorldObject* caster);
|
||||
|
||||
private:
|
||||
uint32 m_targetMask;
|
||||
@@ -411,7 +410,7 @@ class TC_GAME_API Spell
|
||||
|
||||
typedef std::unordered_set<Aura*> UsedSpellMods;
|
||||
|
||||
Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty);
|
||||
Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty);
|
||||
~Spell();
|
||||
|
||||
void InitExplicitTargets(SpellCastTargets const& targets);
|
||||
@@ -434,10 +433,10 @@ class TC_GAME_API Spell
|
||||
void SelectEffectTypeImplicitTargets(uint8 effIndex);
|
||||
|
||||
uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionContainer* condList);
|
||||
template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius);
|
||||
template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
|
||||
|
||||
WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList = nullptr);
|
||||
void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal);
|
||||
|
||||
GameObject* SearchSpellFocus();
|
||||
@@ -479,7 +478,7 @@ class TC_GAME_API Spell
|
||||
bool CheckSpellCancelsFear(uint32* param1) const;
|
||||
bool CheckSpellCancelsConfuse(uint32* param1) const;
|
||||
|
||||
int32 CalculateDamage(uint8 i, Unit const* target) const;
|
||||
int32 CalculateDamage(uint8 effIndex, Unit const* target) const;
|
||||
|
||||
void Delayed();
|
||||
void DelayedChannel();
|
||||
@@ -564,7 +563,7 @@ class TC_GAME_API Spell
|
||||
|
||||
CurrentSpellTypes GetCurrentContainer() const;
|
||||
|
||||
Unit* GetCaster() const { return m_caster; }
|
||||
WorldObject* GetCaster() const { return m_caster; }
|
||||
Unit* GetOriginalCaster() const { return m_originalCaster; }
|
||||
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
|
||||
int32 GetPowerCost() const { return m_powerCost; }
|
||||
@@ -586,7 +585,7 @@ class TC_GAME_API Spell
|
||||
void SendLoot(ObjectGuid guid, LootType loottype);
|
||||
std::pair<float, float> GetMinMaxRange(bool strict) const;
|
||||
|
||||
Unit* const m_caster;
|
||||
WorldObject* const m_caster;
|
||||
|
||||
SpellValue* const m_spellValue;
|
||||
|
||||
@@ -605,12 +604,12 @@ class TC_GAME_API Spell
|
||||
uint8 m_runesState;
|
||||
|
||||
uint8 m_delayAtDamageCount;
|
||||
bool isDelayableNoMore()
|
||||
bool IsDelayableNoMore()
|
||||
{
|
||||
if (m_delayAtDamageCount >= 2)
|
||||
return true;
|
||||
|
||||
m_delayAtDamageCount++;
|
||||
++m_delayAtDamageCount;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -636,6 +635,7 @@ class TC_GAME_API Spell
|
||||
SpellMissInfo targetMissInfo;
|
||||
SpellEffectHandleMode effectHandleMode;
|
||||
// used in effects handlers
|
||||
Unit* unitCaster;
|
||||
UnitAura* _spellAura;
|
||||
DynObjAura* _dynObjAura;
|
||||
|
||||
@@ -792,7 +792,6 @@ class TC_GAME_API Spell
|
||||
|
||||
// effect helpers
|
||||
void CalculateJumpSpeeds(uint8 i, float dist, float & speedxy, float & speedz);
|
||||
|
||||
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellHitInfo& data);
|
||||
void UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& data);
|
||||
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& predict);
|
||||
@@ -824,25 +823,28 @@ namespace Trinity
|
||||
{
|
||||
struct TC_GAME_API WorldObjectSpellTargetCheck
|
||||
{
|
||||
Unit* _caster;
|
||||
Unit* _referer;
|
||||
protected:
|
||||
WorldObject* _caster;
|
||||
WorldObject* _referer;
|
||||
SpellInfo const* _spellInfo;
|
||||
SpellTargetCheckTypes _targetSelectionType;
|
||||
ConditionSourceInfo* _condSrcInfo;
|
||||
ConditionContainer* _condList;
|
||||
std::unique_ptr<ConditionSourceInfo> _condSrcInfo;
|
||||
ConditionContainer const* _condList;
|
||||
|
||||
WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
|
||||
SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo,
|
||||
SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
|
||||
~WorldObjectSpellTargetCheck();
|
||||
bool operator()(WorldObject* target);
|
||||
|
||||
bool operator()(WorldObject* target) const;
|
||||
};
|
||||
|
||||
struct TC_GAME_API WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck
|
||||
{
|
||||
float _range;
|
||||
Position const* _position;
|
||||
WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
|
||||
SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
WorldObjectSpellNearbyTargetCheck(float range, WorldObject* caster, SpellInfo const* spellInfo,
|
||||
SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
|
||||
|
||||
bool operator()(WorldObject* target);
|
||||
};
|
||||
|
||||
@@ -850,8 +852,9 @@ namespace Trinity
|
||||
{
|
||||
float _range;
|
||||
Position const* _position;
|
||||
WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
|
||||
Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
WorldObjectSpellAreaTargetCheck(float range, Position const* position, WorldObject* caster,
|
||||
WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
|
||||
|
||||
bool operator()(WorldObject* target);
|
||||
};
|
||||
|
||||
@@ -859,8 +862,9 @@ namespace Trinity
|
||||
{
|
||||
Position _coneSrc;
|
||||
float _coneAngle;
|
||||
WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float range, Unit* caster,
|
||||
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float range, WorldObject* caster,
|
||||
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
|
||||
|
||||
bool operator()(WorldObject* target);
|
||||
};
|
||||
|
||||
@@ -868,12 +872,13 @@ namespace Trinity
|
||||
{
|
||||
float _range;
|
||||
Position const* _position;
|
||||
WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster,
|
||||
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList);
|
||||
WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster,
|
||||
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList);
|
||||
|
||||
bool operator()(WorldObject* target);
|
||||
};
|
||||
}
|
||||
|
||||
typedef void(Spell::*pEffect)(SpellEffIndex effIndex);
|
||||
typedef void(Spell::*SpellEffectHandlerFn)(SpellEffIndex effIndex);
|
||||
|
||||
#endif
|
||||
@@ -210,7 +210,7 @@ struct TC_GAME_API CastSpellExtraArgs
|
||||
struct
|
||||
{
|
||||
friend struct CastSpellExtraArgs;
|
||||
friend class Unit;
|
||||
friend class WorldObject;
|
||||
|
||||
private:
|
||||
void AddMod(SpellValueMod mod, int32 val) { data.push_back({ mod, val }); }
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -423,7 +423,7 @@ bool SpellEffectInfo::IsUnitOwnedAuraEffect() const
|
||||
return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA || Effect == SPELL_EFFECT_APPLY_AURA_2;
|
||||
}
|
||||
|
||||
uint32 SpellEffectInfo::CalcPeriod(Unit* caster, Spell* spell /* = nullptr */) const
|
||||
uint32 SpellEffectInfo::CalcPeriod(WorldObject const* caster, Spell* spell /* = nullptr */) const
|
||||
{
|
||||
// Default value found in client.
|
||||
uint32 period = AuraPeriod;
|
||||
@@ -435,27 +435,31 @@ uint32 SpellEffectInfo::CalcPeriod(Unit* caster, Spell* spell /* = nullptr */) c
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_ACTIVATION_TIME, period, spell);
|
||||
|
||||
if (_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !_spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
|
||||
period = int32(period * caster->GetFloatValue(UNIT_MOD_CAST_HASTE));
|
||||
if (caster->IsUnit() && _spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !_spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
|
||||
period = int32(period * caster->ToUnit()->GetFloatValue(UNIT_MOD_CAST_HASTE));
|
||||
}
|
||||
|
||||
return period;
|
||||
}
|
||||
|
||||
int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* target) const
|
||||
int32 SpellEffectInfo::CalcValue(WorldObject const* caster, int32 const* bp, Unit const* target) const
|
||||
{
|
||||
float basePointsPerLevel = RealPointsPerLevel;
|
||||
int32 basePoints = bp ? *bp : BasePoints;
|
||||
float comboDamage = PointsPerComboPoint;
|
||||
|
||||
Unit const* casterUnit = nullptr;
|
||||
if (caster)
|
||||
casterUnit = caster->ToUnit();
|
||||
|
||||
// base amount modification based on spell lvl vs caster lvl
|
||||
if (Scaling.Coefficient != 0.0f)
|
||||
{
|
||||
uint32 level = _spellInfo->SpellLevel;
|
||||
if (target && _spellInfo->IsPositiveEffect(_effIndex) && (Effect == SPELL_EFFECT_APPLY_AURA || Effect == SPELL_EFFECT_APPLY_AURA_2))
|
||||
level = target->getLevel();
|
||||
else if (caster)
|
||||
level = caster->getLevel();
|
||||
else if (casterUnit)
|
||||
level = casterUnit->getLevel();
|
||||
|
||||
if (_spellInfo->HasAttribute(SPELL_ATTR10_USE_SPELL_BASE_LEVEL_FOR_SCALING))
|
||||
level = _spellInfo->BaseLevel;
|
||||
@@ -494,9 +498,9 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (caster)
|
||||
if (casterUnit && basePointsPerLevel != 0.0f)
|
||||
{
|
||||
int32 level = int32(caster->getLevel());
|
||||
int32 level = int32(casterUnit->getLevel());
|
||||
if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
|
||||
level = int32(_spellInfo->MaxLevel);
|
||||
else if (level < int32(_spellInfo->BaseLevel))
|
||||
@@ -528,17 +532,17 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
|
||||
float value = float(basePoints);
|
||||
|
||||
// random damage
|
||||
if (caster)
|
||||
if (casterUnit)
|
||||
{
|
||||
// bonus amount from combo points
|
||||
if (_spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DAMAGE) && caster->IsMovedByClient() && comboDamage)
|
||||
if (uint8 comboPoints = caster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints())
|
||||
if (_spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DAMAGE) && casterUnit->IsMovedByClient() && comboDamage)
|
||||
if (uint8 comboPoints = casterUnit->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints())
|
||||
value += comboDamage * comboPoints;
|
||||
|
||||
value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
|
||||
value = casterUnit->ApplyEffectModifiers(_spellInfo, _effIndex, value);
|
||||
|
||||
if (!caster->IsControlledByPlayer() &&
|
||||
_spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() &&
|
||||
if (!casterUnit->IsControlledByPlayer() &&
|
||||
_spellInfo->SpellLevel && _spellInfo->SpellLevel != casterUnit->getLevel() &&
|
||||
!basePointsPerLevel && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
|
||||
{
|
||||
bool canEffectScale = false;
|
||||
@@ -582,12 +586,12 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
|
||||
if (canEffectScale)
|
||||
{
|
||||
GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(_spellInfo->SpellLevel - 1);
|
||||
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1);
|
||||
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(casterUnit->getLevel() - 1);
|
||||
if (spellScaler && casterScaler)
|
||||
{
|
||||
value *= casterScaler->ratio / spellScaler->ratio;
|
||||
if (caster->getLevel() > 80)
|
||||
value *= (caster->getLevel() - 80) * 4.4f; // Cataclysm creatures have a way higher jump in stats than previous expansions so we use this estimated value based on combat log packet research
|
||||
if (casterUnit->getLevel() > 80)
|
||||
value *= (casterUnit->getLevel() - 80) * 4.4f; // Cataclysm creatures have a way higher jump in stats than previous expansions so we use this estimated value based on combat log packet research
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,7 +608,7 @@ int32 SpellEffectInfo::CalcBaseValue(int32 value) const
|
||||
return value - 1;
|
||||
}
|
||||
|
||||
float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
|
||||
float SpellEffectInfo::CalcValueMultiplier(WorldObject* caster, Spell* spell) const
|
||||
{
|
||||
float multiplier = Amplitude;
|
||||
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
|
||||
@@ -612,7 +616,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
|
||||
float SpellEffectInfo::CalcDamageMultiplier(WorldObject* caster, Spell* spell) const
|
||||
{
|
||||
float multiplierPercent = DamageMultiplier * 100.0f;
|
||||
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr))
|
||||
@@ -630,7 +634,7 @@ bool SpellEffectInfo::HasMaxRadius() const
|
||||
return MaxRadiusEntry != nullptr;
|
||||
}
|
||||
|
||||
float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
|
||||
float SpellEffectInfo::CalcRadius(WorldObject* caster, Spell* spell) const
|
||||
{
|
||||
const SpellRadiusEntry* entry = RadiusEntry;
|
||||
if (!HasRadius() && HasMaxRadius())
|
||||
@@ -642,8 +646,11 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
|
||||
float radius = entry->RadiusMin;
|
||||
if (caster)
|
||||
{
|
||||
radius += entry->RadiusPerLevel * caster->getLevel();
|
||||
if (Unit* casterUnit = caster->ToUnit())
|
||||
radius += entry->RadiusPerLevel * casterUnit->getLevel();
|
||||
|
||||
radius = std::min(radius, entry->RadiusMax);
|
||||
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
|
||||
}
|
||||
@@ -1116,7 +1123,7 @@ bool SpellInfo::HasOnlyDamageEffects() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpellInfo::CanBeInterrupted(Unit* interruptTarget, bool ignoreImmunity /*= false*/) const
|
||||
bool SpellInfo::CanBeInterrupted(Unit const* interruptTarget, bool ignoreImmunity /*= false*/) const
|
||||
{
|
||||
return HasAttribute(SPELL_ATTR7_CAN_ALWAYS_BE_INTERRUPTED)
|
||||
|| HasChannelInterruptFlag(SpellAuraInterruptFlags::Damage | SpellAuraInterruptFlags::EnteringCombat)
|
||||
@@ -1867,7 +1874,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* target, bool implicit) const
|
||||
SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject const* target, bool implicit /*= true*/) const
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && caster == target)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
@@ -1955,7 +1962,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
// Do not allow pet or guardian targets if the spell is a raid buff or may not target pets at all
|
||||
if ((HasAttribute(SPELL_ATTR7_CONSOLIDATED_RAID_BUFF) || HasAttribute(SPELL_ATTR5_DONT_ALLOW_PET_TARGET)) && (!caster->IsPet() && !caster->IsGuardian()))
|
||||
if ((HasAttribute(SPELL_ATTR7_CONSOLIDATED_RAID_BUFF) || HasAttribute(SPELL_ATTR5_DONT_ALLOW_PET_TARGET)) && (caster->IsCreature() && !caster->ToCreature()->IsPet() && !caster->ToCreature()->IsGuardian()))
|
||||
if ((unitTarget->IsPet() || unitTarget->IsGuardian()))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
@@ -1974,7 +1981,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
}
|
||||
|
||||
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells
|
||||
if (unitTarget != caster && (caster->IsControlledByPlayer() || !IsPositive()) && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
||||
if (unitTarget != caster && (caster->GetAffectingPlayer() || !IsPositive()) && unitTarget->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!unitTarget->ToPlayer()->IsVisible())
|
||||
return SPELL_FAILED_BM_OR_INVISGOD;
|
||||
@@ -1994,13 +2001,16 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
him, because it would be it's passenger, there's no such case where this gets to fail legitimacy, this problem
|
||||
cannot be solved from within the check in other way since target type cannot be called for the spell currently
|
||||
Spell examples: [ID - 52864 Devour Water, ID - 52862 Devour Wind, ID - 49370 Wyrmrest Defender: Destabilize Azure Dragonshrine Effect] */
|
||||
if (!caster->IsVehicle() && !(caster->GetCharmerOrOwner() == target))
|
||||
if (Unit const* unitCaster = caster->ToUnit())
|
||||
{
|
||||
if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
if (!unitCaster->IsVehicle() && !(unitCaster->GetCharmerOrOwner() == target))
|
||||
{
|
||||
if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, unitCaster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, unitCaster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (TargetAuraSpell && !unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster)))
|
||||
@@ -2019,7 +2029,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget) const
|
||||
SpellCastResult SpellInfo::CheckExplicitTarget(WorldObject const* caster, WorldObject const* target, Item const* itemTarget) const
|
||||
{
|
||||
uint32 neededTargets = GetExplicitTargetMask();
|
||||
if (!target)
|
||||
@@ -2034,19 +2044,20 @@ SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject c
|
||||
{
|
||||
if (neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER))
|
||||
{
|
||||
Unit const* unitCaster = caster->ToUnit();
|
||||
if (neededTargets & TARGET_FLAG_UNIT_ENEMY)
|
||||
if (caster->IsValidAttackTarget(unitTarget, this))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_ALLY
|
||||
|| (neededTargets & TARGET_FLAG_UNIT_PARTY && caster->IsInPartyWith(unitTarget))
|
||||
|| (neededTargets & TARGET_FLAG_UNIT_RAID && caster->IsInRaidWith(unitTarget)))
|
||||
if (caster->IsValidAssistTarget(unitTarget, this))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_MINIPET)
|
||||
if (unitTarget->GetGUID() == caster->GetCritterGUID())
|
||||
if ((neededTargets & TARGET_FLAG_UNIT_ALLY)
|
||||
|| ((neededTargets & TARGET_FLAG_UNIT_PARTY) && unitCaster && unitCaster->IsInPartyWith(unitTarget))
|
||||
|| ((neededTargets & TARGET_FLAG_UNIT_RAID) && unitCaster && unitCaster->IsInRaidWith(unitTarget)))
|
||||
if (caster->IsValidAssistTarget(unitTarget, this))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_PASSENGER)
|
||||
if (unitTarget->IsOnVehicle(caster))
|
||||
if ((neededTargets & TARGET_FLAG_UNIT_MINIPET) && unitCaster)
|
||||
if (unitTarget->GetGUID() == unitCaster->GetCritterGUID())
|
||||
return SPELL_CAST_OK;
|
||||
if ((neededTargets & TARGET_FLAG_UNIT_PASSENGER) && unitCaster)
|
||||
if (unitTarget->IsOnVehicle(unitCaster))
|
||||
return SPELL_CAST_OK;
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
@@ -3335,7 +3346,7 @@ float SpellInfo::GetMinRange(bool positive) const
|
||||
return RangeEntry->RangeMin[0];
|
||||
}
|
||||
|
||||
float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
|
||||
float SpellInfo::GetMaxRange(bool positive, WorldObject* caster, Spell* spell) const
|
||||
{
|
||||
if (!RangeEntry)
|
||||
return 0.0f;
|
||||
@@ -3364,7 +3375,7 @@ int32 SpellInfo::GetMaxDuration() const
|
||||
return (DurationEntry->MaxDuration == -1) ? -1 : abs(DurationEntry->MaxDuration);
|
||||
}
|
||||
|
||||
int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
|
||||
int32 SpellInfo::CalcDuration(WorldObject const* caster, Spell* spell) const
|
||||
{
|
||||
if (IsPassive() && !DurationEntry)
|
||||
return -1;
|
||||
@@ -3376,17 +3387,18 @@ int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
|
||||
if (duration == -1)
|
||||
return -1;
|
||||
|
||||
if (caster != nullptr)
|
||||
{
|
||||
uint32 level = caster->getLevel();
|
||||
if (MaxLevel > 0 && level > MaxLevel)
|
||||
level = MaxLevel;
|
||||
if (BaseLevel > 0)
|
||||
level -= BaseLevel;
|
||||
Unit const* unitCaster = caster ? caster->ToUnit() : nullptr;
|
||||
if (!unitCaster)
|
||||
return std::min(GetMaxDuration(), DurationEntry->Duration);
|
||||
|
||||
duration = DurationEntry->Duration + DurationEntry->DurationPerLevel * level;
|
||||
duration = std::min(GetMaxDuration(), duration);
|
||||
}
|
||||
uint32 level = unitCaster->getLevel();
|
||||
if (MaxLevel > 0 && level > MaxLevel)
|
||||
level = MaxLevel;
|
||||
if (BaseLevel > 0)
|
||||
level -= BaseLevel;
|
||||
|
||||
duration = DurationEntry->Duration + DurationEntry->DurationPerLevel * level;
|
||||
duration = std::min(GetMaxDuration(), duration);
|
||||
|
||||
if (duration == -1)
|
||||
return -1;
|
||||
@@ -3394,21 +3406,20 @@ int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
|
||||
// Increase duration based on combo points
|
||||
if (HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DURATION))
|
||||
{
|
||||
if (uint8 comboPoints = (caster && caster->IsMovedByClient()) ? caster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints() : 0)
|
||||
if (uint8 comboPoints = unitCaster->IsMovedByClient() ? unitCaster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints() : 0)
|
||||
{
|
||||
if (GetDuration() != GetMaxDuration() && GetDuration() != -1)
|
||||
duration += int32((GetMaxDuration() - GetDuration()) * comboPoints / 5);
|
||||
}
|
||||
}
|
||||
|
||||
if (caster != nullptr)
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SPELLMOD_DURATION, duration, spell);
|
||||
if (Player* modOwner = unitCaster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SPELLMOD_DURATION, duration, spell);
|
||||
|
||||
bool hasteAffectsDuration = HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION);
|
||||
bool spellHasteAffectsPeriodic = HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC);
|
||||
// That aura is not used as of 4.3.4, but just include it, as it still is technically supported by the client, and so should we.
|
||||
bool hasPeriodicHasteAuras = caster != nullptr && caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, this);
|
||||
bool hasPeriodicHasteAuras = unitCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, this);
|
||||
|
||||
if (spellHasteAffectsPeriodic || hasteAffectsDuration)
|
||||
{
|
||||
@@ -3423,13 +3434,13 @@ int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
|
||||
|
||||
if ((spellHasteAffectsPeriodic || hasPeriodicHasteAuras) && !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
|
||||
{
|
||||
float hasteValue = caster ? caster->GetFloatValue(UNIT_MOD_CAST_HASTE) : 0.0f;
|
||||
float hasteValue = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE);
|
||||
if (hasteValue > 0.0f)
|
||||
{
|
||||
if (hasteAffectsDuration)
|
||||
return int32(duration * hasteValue);
|
||||
|
||||
int32 effectPeriod = Effects[periodicEffectIndex].CalcPeriod(caster, spell);
|
||||
int32 effectPeriod = Effects[periodicEffectIndex].CalcPeriod(unitCaster, spell);
|
||||
|
||||
if (effectPeriod > 0)
|
||||
{
|
||||
@@ -3450,10 +3461,10 @@ int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
|
||||
uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= nullptr*/) const
|
||||
{
|
||||
int32 castTime = 0;
|
||||
if (!level && spell)
|
||||
level = spell->GetCaster()->getLevel();
|
||||
if (!level && spell && spell->GetCaster()->IsUnit())
|
||||
level = spell->GetCaster()->ToUnit()->getLevel();
|
||||
|
||||
// not all spells have cast time index and this is all is pasiive abilities
|
||||
// not all spells have cast time index and this is all is passive abilities
|
||||
if (level && Scaling.CastTimeMax > 0)
|
||||
{
|
||||
castTime = Scaling.CastTimeMax;
|
||||
@@ -3515,17 +3526,22 @@ uint32 SpellInfo::GetRecoveryTime() const
|
||||
return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime;
|
||||
}
|
||||
|
||||
int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, Spell* spell) const
|
||||
int32 SpellInfo::CalcPowerCost(WorldObject const* caster, SpellSchoolMask schoolMask, Spell* spell) const
|
||||
{
|
||||
// gameobject casts don't use power
|
||||
Unit const* unitCaster = caster->ToUnit();
|
||||
if (!unitCaster)
|
||||
return 0;
|
||||
|
||||
// Spell drain all exist power on cast (Only paladin lay of Hands)
|
||||
if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER))
|
||||
{
|
||||
// If power type - health drain all
|
||||
if (PowerType == POWER_HEALTH)
|
||||
return caster->GetHealth();
|
||||
return unitCaster->GetHealth();
|
||||
// Else drain all power
|
||||
if (PowerType < MAX_POWERS)
|
||||
return caster->GetPower(Powers(PowerType));
|
||||
return unitCaster->GetPower(Powers(PowerType));
|
||||
|
||||
TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", PowerType, Id);
|
||||
return 0;
|
||||
@@ -3556,15 +3572,15 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
{
|
||||
// health as power used
|
||||
case POWER_HEALTH:
|
||||
ressource = caster->GetCreateHealth();
|
||||
ressource = unitCaster->GetCreateHealth();
|
||||
break;
|
||||
case POWER_MANA:
|
||||
ressource = caster->GetCreateMana();
|
||||
ressource = unitCaster->GetCreateMana();
|
||||
break;
|
||||
case POWER_RAGE:
|
||||
case POWER_FOCUS:
|
||||
case POWER_ENERGY:
|
||||
ressource = caster->GetMaxPower(Powers(PowerType));
|
||||
ressource = unitCaster->GetMaxPower(Powers(PowerType));
|
||||
break;
|
||||
case POWER_RUNE:
|
||||
case POWER_RUNIC_POWER:
|
||||
@@ -3581,7 +3597,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
|
||||
// Scaling
|
||||
if (SpellScalingId)
|
||||
powerCost = int32(ceilf(GetSpellScalingMultiplier(caster, GetSpellScaling(), true) * (double)powerCost));
|
||||
powerCost = int32(ceilf(GetSpellScalingMultiplier(unitCaster, GetSpellScaling(), true) * (double)powerCost));
|
||||
else
|
||||
{
|
||||
uint32 manaCostPerLevel = invertSign ? -int32(ManaCostPerlevel) : ManaCostPerlevel;
|
||||
@@ -3590,7 +3606,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
}
|
||||
|
||||
// Flat mod from caster auras by spell school and power type
|
||||
Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL);
|
||||
Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL);
|
||||
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
|
||||
{
|
||||
if (!((*i)->GetMiscValue() & schoolMask))
|
||||
@@ -3604,7 +3620,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST))
|
||||
{
|
||||
uint32 speed = 0;
|
||||
if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm()))
|
||||
if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(unitCaster->GetShapeshiftForm()))
|
||||
speed = ss->CombatRoundTime;
|
||||
else
|
||||
{
|
||||
@@ -3612,7 +3628,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
|
||||
slot = OFF_ATTACK;
|
||||
|
||||
speed = caster->GetAttackTime(slot);
|
||||
speed = unitCaster->GetAttackTime(slot);
|
||||
}
|
||||
|
||||
powerCost += speed / 100;
|
||||
@@ -3622,12 +3638,12 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell);
|
||||
|
||||
if (!caster->IsControlledByPlayer())
|
||||
if (!unitCaster->IsControlledByPlayer())
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
|
||||
{
|
||||
GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(SpellLevel - 1);
|
||||
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1);
|
||||
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(unitCaster->getLevel() - 1);
|
||||
if (spellScaler && spellScaler->ratio > 0.f && casterScaler && casterScaler->ratio > 0.f)
|
||||
powerCost *= casterScaler->ratio / spellScaler->ratio;
|
||||
}
|
||||
@@ -3637,7 +3653,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
powerCost = -powerCost;
|
||||
|
||||
// PCT mod from user auras by spell school and power type
|
||||
Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT);
|
||||
Unit::AuraEffectList const& aurasPct = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT);
|
||||
for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i)
|
||||
{
|
||||
if (!((*i)->GetMiscValue() & schoolMask))
|
||||
@@ -3651,16 +3667,16 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S
|
||||
return powerCost;
|
||||
}
|
||||
|
||||
float SpellInfo::GetSpellScalingMultiplier(Unit const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated /*= false*/) const
|
||||
float SpellInfo::GetSpellScalingMultiplier(WorldObject const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated /*= false*/) const
|
||||
{
|
||||
if (!caster || !scalingEntry)
|
||||
if (!caster || !caster->IsUnit() || !scalingEntry)
|
||||
return 1.f;
|
||||
|
||||
float multiplier = 1.f;
|
||||
float scalingMultiplier = 1.f;
|
||||
|
||||
int32 castTimeMaxLevel = scalingEntry->CastTimeMaxLevel;
|
||||
uint8 casterLevel = caster->getLevel();
|
||||
uint8 casterLevel = caster->ToUnit()->getLevel();
|
||||
|
||||
if (casterLevel < castTimeMaxLevel && scalingEntry->CastTimeMax)
|
||||
{
|
||||
|
||||
@@ -291,14 +291,14 @@ public:
|
||||
bool IsAreaAuraEffect() const;
|
||||
bool IsUnitOwnedAuraEffect() const;
|
||||
|
||||
int32 CalcValue(Unit const* caster = nullptr, int32 const* basePoints = nullptr, Unit const* target = nullptr) const;
|
||||
int32 CalcValue(WorldObject const* caster = nullptr, int32 const* basePoints = nullptr, Unit const* target = nullptr) const;
|
||||
int32 CalcBaseValue(int32 value) const;
|
||||
float CalcValueMultiplier(Unit* caster, Spell* spell = nullptr) const;
|
||||
float CalcDamageMultiplier(Unit* caster, Spell* spell = nullptr) const;
|
||||
float CalcValueMultiplier(WorldObject* caster, Spell* spell = nullptr) const;
|
||||
float CalcDamageMultiplier(WorldObject* caster, Spell* spell = nullptr) const;
|
||||
|
||||
bool HasRadius() const;
|
||||
bool HasMaxRadius() const;
|
||||
float CalcRadius(Unit* caster = nullptr, Spell* = nullptr) const;
|
||||
float CalcRadius(WorldObject* caster = nullptr, Spell* = nullptr) const;
|
||||
|
||||
uint32 GetProvidedTargetMask() const;
|
||||
uint32 GetMissingTargetMask(bool srcSet = false, bool destSet = false, uint32 mask = 0) const;
|
||||
@@ -306,7 +306,7 @@ public:
|
||||
SpellEffectImplicitTargetTypes GetImplicitTargetType() const;
|
||||
SpellTargetObjectTypes GetUsedTargetObjectType() const;
|
||||
|
||||
uint32 CalcPeriod(Unit* caster, Spell* spell = nullptr) const;
|
||||
uint32 CalcPeriod(WorldObject const* caster, Spell* spell = nullptr) const;
|
||||
|
||||
private:
|
||||
struct StaticData
|
||||
@@ -493,7 +493,7 @@ class TC_GAME_API SpellInfo
|
||||
inline bool HasAttribute(SpellAttr10 attribute) const { return !!(AttributesEx10 & attribute); }
|
||||
inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
|
||||
|
||||
bool CanBeInterrupted(Unit* interruptTarget, bool ignoreImmunity = false) const;
|
||||
bool CanBeInterrupted(Unit const* interruptTarget, bool ignoreImmunity = false) const;
|
||||
|
||||
bool HasAnyAuraInterruptFlag() const;
|
||||
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const { return AuraInterruptFlags.HasFlag(flag); }
|
||||
@@ -559,8 +559,8 @@ class TC_GAME_API SpellInfo
|
||||
|
||||
SpellCastResult CheckShapeshift(uint32 form) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = nullptr) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
SpellCastResult CheckTarget(WorldObject const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(WorldObject const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
SpellCastResult CheckVehicle(Unit const* caster) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
@@ -578,20 +578,20 @@ class TC_GAME_API SpellInfo
|
||||
SpellSpecificType GetSpellSpecific() const;
|
||||
|
||||
float GetMinRange(bool positive = false) const;
|
||||
float GetMaxRange(bool positive = false, Unit* caster = nullptr, Spell* spell = nullptr) const;
|
||||
float GetMaxRange(bool positive = false, WorldObject* caster = nullptr, Spell* spell = nullptr) const;
|
||||
|
||||
int32 GetDuration() const;
|
||||
int32 GetMaxDuration() const;
|
||||
|
||||
int32 CalcDuration(Unit* caster, Spell* spell = nullptr) const;
|
||||
int32 CalcDuration(WorldObject const* caster, Spell* spell = nullptr) const;
|
||||
|
||||
uint32 GetMaxTicks() const;
|
||||
|
||||
uint32 CalcCastTime(uint8 level = 0, Spell* spell = nullptr) const;
|
||||
uint32 GetRecoveryTime() const;
|
||||
|
||||
int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, Spell* spell = nullptr) const;
|
||||
float GetSpellScalingMultiplier(Unit const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated = false) const;
|
||||
int32 CalcPowerCost(WorldObject const* caster, SpellSchoolMask schoolMask, Spell* spell = nullptr) const;
|
||||
float GetSpellScalingMultiplier(WorldObject const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated = false) const;
|
||||
|
||||
bool IsRanked() const;
|
||||
uint8 GetRank() const;
|
||||
|
||||
@@ -174,7 +174,7 @@ void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id)
|
||||
mSpellDifficultySearcherMap[spellId] = id;
|
||||
}
|
||||
|
||||
uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const
|
||||
uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, WorldObject const* caster) const
|
||||
{
|
||||
if (!GetSpellInfo(spellId))
|
||||
return spellId;
|
||||
@@ -216,7 +216,7 @@ uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) con
|
||||
return uint32(difficultyEntry->DifficultySpellID[mode]);
|
||||
}
|
||||
|
||||
SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const
|
||||
SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, WorldObject const* caster) const
|
||||
{
|
||||
if (!spell)
|
||||
return nullptr;
|
||||
|
||||
@@ -617,8 +617,8 @@ class TC_GAME_API SpellMgr
|
||||
// Spell difficulty
|
||||
uint32 GetSpellDifficultyId(uint32 spellId) const;
|
||||
void SetSpellDifficultyId(uint32 spellId, uint32 id);
|
||||
uint32 GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const;
|
||||
SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const;
|
||||
uint32 GetSpellIdForDifficulty(uint32 spellId, WorldObject const* caster) const;
|
||||
SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, WorldObject const* caster) const;
|
||||
|
||||
// Spell Ranks table
|
||||
SpellChainNode const* GetSpellChainNode(uint32 spell_id) const;
|
||||
|
||||
@@ -186,12 +186,17 @@ bool SpellScript::IsInEffectHook() const
|
||||
|
||||
Unit* SpellScript::GetCaster() const
|
||||
{
|
||||
return m_spell->GetCaster();
|
||||
return m_spell->GetCaster()->ToUnit();
|
||||
}
|
||||
|
||||
GameObject* SpellScript::GetGObjCaster() const
|
||||
{
|
||||
return m_spell->GetCaster()->ToGameObject();
|
||||
}
|
||||
|
||||
Unit* SpellScript::GetOriginalCaster() const
|
||||
{
|
||||
return m_spell->GetOriginalCaster();
|
||||
return m_spell->GetOriginalCaster();
|
||||
}
|
||||
|
||||
SpellInfo const* SpellScript::GetSpellInfo() const
|
||||
@@ -642,7 +647,16 @@ ObjectGuid AuraScript::GetCasterGUID() const
|
||||
|
||||
Unit* AuraScript::GetCaster() const
|
||||
{
|
||||
return m_aura->GetCaster();
|
||||
if (WorldObject* caster = m_aura->GetCaster())
|
||||
return caster->ToUnit();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GameObject* AuraScript::GetGObjCaster() const
|
||||
{
|
||||
if (WorldObject* caster = m_aura->GetCaster())
|
||||
return caster->ToGameObject();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WorldObject* AuraScript::GetOwner() const
|
||||
|
||||
@@ -613,6 +613,7 @@ class TC_GAME_API SpellScript : public _SpellScript
|
||||
//
|
||||
// methods useable during all spell handling phases
|
||||
Unit* GetCaster() const;
|
||||
GameObject* GetGObjCaster() const;
|
||||
Unit* GetOriginalCaster() const;
|
||||
SpellInfo const* GetSpellInfo() const;
|
||||
SpellValue const* GetSpellValue() const;
|
||||
@@ -1036,6 +1037,8 @@ class TC_GAME_API AuraScript : public _SpellScript
|
||||
ObjectGuid GetCasterGUID() const;
|
||||
// returns unit which cast the aura or nullptr if not avalible (caster logged out for example)
|
||||
Unit* GetCaster() const;
|
||||
// returns gameobject which cast the aura or NULL if not available
|
||||
GameObject* GetGObjCaster() const;
|
||||
// returns object on which aura was cast, target for non-area auras, area aura source for area auras
|
||||
WorldObject* GetOwner() const;
|
||||
// returns owner if it's unit or unit derived object, nullptr otherwise (only for persistent area auras nullptr is returned)
|
||||
|
||||
@@ -1736,12 +1736,12 @@ class spell_icc_sprit_alarm : public SpellScriptLoader
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameObject* trap = GetCaster()->FindNearestGameObject(trapId, 5.0f))
|
||||
if (GameObject* trap = GetGObjCaster()->FindNearestGameObject(trapId, 5.0f))
|
||||
trap->SetRespawnTime(trap->GetGOInfo()->GetAutoCloseTime() / IN_MILLISECONDS);
|
||||
|
||||
std::list<Creature*> wards;
|
||||
GetCaster()->GetCreatureListWithEntryInGrid(wards, NPC_DEATHBOUND_WARD, 150.0f);
|
||||
wards.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
|
||||
GetGObjCaster()->GetCreatureListWithEntryInGrid(wards, NPC_DEATHBOUND_WARD, 150.0f);
|
||||
wards.sort(Trinity::ObjectDistanceOrderPred(GetGObjCaster()));
|
||||
for (std::list<Creature*>::iterator itr = wards.begin(); itr != wards.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->IsAlive() && (*itr)->HasAura(SPELL_STONEFORM))
|
||||
|
||||
@@ -1313,7 +1313,7 @@ class go_ulduar_tower : public GameObjectScript
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Destroyed(Player* /*player*/, uint32 /*eventId*/) override
|
||||
void Destroyed(WorldObject* /*attacker*/, uint32 /*eventId*/) override
|
||||
{
|
||||
switch (me->GetEntry())
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user