Core/Spells: rework part 5: GameObject casting

This commit is contained in:
ariel- authored and Ovahlord committed 2022-09-12 09:15:14 +02:00
1 parent c901772640
commit b6fac86b71
43 files changed
+2638 -2337

No files matched your search

+13 -4
View File
@@ -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
+4 -2
View File
@@ -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)
{
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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);
+56 -36
View File
@@ -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;
+8 -7
View File
@@ -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())
+8 -7
View File
@@ -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();
+2 -1
View File
@@ -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;
+2 -2
View File
@@ -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;
+921 -3
View File
@@ -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
{
+62 -2
View File
@@ -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
+5 -93
View File
@@ -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)
+3 -14
View File
@@ -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;
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+27 -62
View File
@@ -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&);
+11 -15
View File
@@ -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
+1 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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)
{
+16 -10
View File
@@ -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),
File diff suppressed because it is too large. Load diff
+32 -27
View File
@@ -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
+1 -1
View File
@@ -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
+94 -78
View File
@@ -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)
{
+12 -12
View File
@@ -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;
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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;
+17 -3
View File
@@ -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
+3
View File
@@ -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())
{