fix(Core/Spells): Forward core changes (#8841)

This commit is contained in:
acidmanifesto
2021-12-09 22:24:16 +01:00
committed by GitHub
parent 0300cef119
commit 85d2c39a48
14 changed files with 233 additions and 140 deletions

View File

@@ -74,17 +74,17 @@ void VisitorHelper(VISITOR& v, ContainerUnorderedMap<TypeList<H, T>, KEY_TYPE>&
VisitorHelper(v, c._TailElements);
}
template<class VISITOR, class OBJECT_TYPES, class KEY_TYPE>
template <class VISITOR, class OBJECT_TYPES, class KEY_TYPE>
void VisitorHelper(VISITOR& v, TypeUnorderedMapContainer<OBJECT_TYPES, KEY_TYPE>& c)
{
VisitorHelper(v, c.GetElements());
}
template<class VISITOR, class TYPE_CONTAINER>
template <class VISITOR, class TYPE_CONTAINER>
class TypeContainerVisitor
{
public:
TypeContainerVisitor(VISITOR& v) : i_visitor(v) { }
TypeContainerVisitor(VISITOR& v) : i_visitor(v) {}
void Visit(TYPE_CONTAINER& c)
{

View File

@@ -640,6 +640,11 @@ ConditionMgr::~ConditionMgr()
Clean();
}
bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const
{
return SpellsUsedInSpellClickConditions.find(spellId) != SpellsUsedInSpellClickConditions.end();
}
ConditionMgr* ConditionMgr::instance()
{
static ConditionMgr instance;
@@ -694,7 +699,7 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& co
return mask;
}
bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions)
bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const
{
// groupId, groupCheckPassed
std::map<uint32, bool> ElseGroupStore;
@@ -738,19 +743,19 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo,
return false;
}
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions)
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const
{
ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
return IsObjectMeetToConditions(srcInfo, conditions);
}
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions)
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) const
{
ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2);
return IsObjectMeetToConditions(srcInfo, conditions);
}
bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions)
bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const
{
if (conditions.empty())
return true;
@@ -1055,6 +1060,10 @@ void ConditionMgr::LoadConditions(bool isReload)
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
{
SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
if (cond->ConditionType == CONDITION_AURA)
{
SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1);
}
valid = true;
++count;
continue; // do not add to m_AllocatedMemory to avoid double deleting
@@ -1123,6 +1132,10 @@ void ConditionMgr::LoadConditions(bool isReload)
}
// add new Condition to storage based on Type/Entry
if (cond->SourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT && cond->ConditionType == CONDITION_AURA)
{
SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1);
}
ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond);
++count;
} while (result->NextRow());
@@ -2314,7 +2327,7 @@ void ConditionMgr::Clean()
itr->second.clear();
}
SpellClickEventConditionStore.clear();
SpellsUsedInSpellClickConditions.clear();
for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr)
{

View File

@@ -22,7 +22,10 @@
#include "Errors.h"
#include <list>
#include <map>
#include <unordered_set>
#include <vector>
class Creature;
class Player;
class Unit;
class WorldObject;
@@ -254,9 +257,9 @@ public:
ConditionList GetConditionReferences(uint32 refId);
uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions);
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions);
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions);
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const;
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) const;
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const;
[[nodiscard]] bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const;
[[nodiscard]] bool CanHaveSourceIdSet(ConditionSourceType sourceType) const;
ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
@@ -264,6 +267,7 @@ public:
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId);
bool IsSpellUsedInSpellClickConditions(uint32 spellId) const;
private:
bool isSourceTypeValid(Condition* cond);
@@ -271,7 +275,7 @@ private:
bool addToGossipMenus(Condition* cond);
bool addToGossipMenuItems(Condition* cond);
bool addToSpellImplicitTargetConditions(Condition* cond);
bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const;
void Clean(); // free up resources
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
@@ -282,6 +286,8 @@ private:
CreatureSpellConditionContainer SpellClickEventConditionStore;
NpcVendorConditionContainer NpcVendorConditionContainerStore;
SmartEventConditionContainer SmartEventConditionStore;
std::unordered_set<uint32> SpellsUsedInSpellClickConditions;
};
#define sConditionMgr ConditionMgr::instance()

View File

@@ -1473,7 +1473,7 @@ public:
[[nodiscard]] bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false, bool* showInLoot = nullptr) const;
[[nodiscard]] bool HasQuestForGO(int32 GOId) const;
[[nodiscard]] bool HasQuest(uint32 questId) const;
void UpdateForQuestWorldObjects();
void UpdateVisibleGameobjectsOrSpellClicks();
[[nodiscard]] bool CanShareQuest(uint32 quest_id) const;
void SendQuestComplete(uint32 quest_id);

View File

@@ -1548,7 +1548,7 @@ void Player::SendQuestUpdate(uint32 questId)
RemoveAurasDueToSpell(oldSpellId);
}
UpdateForQuestWorldObjects();
UpdateVisibleGameobjectsOrSpellClicks();
}
QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
@@ -1809,7 +1809,7 @@ void Player::ItemAddedQuestCheck(uint32 entry, uint32 count)
}
}
}
UpdateForQuestWorldObjects();
UpdateVisibleGameobjectsOrSpellClicks();
}
void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count)
@@ -1850,7 +1850,7 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count)
}
}
}
UpdateForQuestWorldObjects();
UpdateVisibleGameobjectsOrSpellClicks();
}
void Player::KilledMonster(CreatureTemplate const* cInfo, ObjectGuid guid)

View File

@@ -2848,7 +2848,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
sScriptMgr->OnEquip(this, pItem, bag, slot, update);
UpdateForQuestWorldObjects();
UpdateVisibleGameobjectsOrSpellClicks();
return pItem;
}

View File

@@ -1820,7 +1820,7 @@ void Player::UpdateTriggerVisibility()
GetSession()->SendPacket(&packet);
}
void Player::UpdateForQuestWorldObjects()
void Player::UpdateVisibleGameobjectsOrSpellClicks()
{
if (m_clientGUIDs.empty())
return;
@@ -1847,19 +1847,9 @@ void Player::UpdateForQuestWorldObjects()
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
for (SpellClickInfoContainer::const_iterator _itr = clickPair.first; _itr != clickPair.second; ++_itr)
{
//! This code doesn't look right, but it was logically converted to condition system to do the exact
//! same thing it did before. It definitely needs to be overlooked for intended functionality.
ConditionList conds = sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), _itr->second.spellId);
bool buildUpdateBlock = false;
for (ConditionList::const_iterator jtr = conds.begin(); jtr != conds.end() && !buildUpdateBlock; ++jtr)
if ((*jtr)->ConditionType == CONDITION_QUESTREWARDED || (*jtr)->ConditionType == CONDITION_QUESTTAKEN)
buildUpdateBlock = true;
if (buildUpdateBlock)
{
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
break;
}
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
break;
}
}
}

View File

@@ -4072,6 +4072,14 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
aurApp->_HandleEffect(i, true);
}
if (Player* player = ToPlayer())
{
if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
{
player->UpdateVisibleGameobjectsOrSpellClicks();
}
}
}
// removes aura application from lists and unapplies effects
@@ -4150,6 +4158,14 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo
aura->HandleAuraSpecificMods(aurApp, caster, false, false);
if (Player* player = ToPlayer())
{
if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
{
player->UpdateVisibleGameobjectsOrSpellClicks();
}
}
// only way correctly remove all auras from list
//if (removedAuras != m_removedAurasCount) new aura may be added
i = m_appliedAuras.begin();

View File

@@ -165,6 +165,29 @@ namespace Acore
// WorldObject searchers & workers
// Generic base class to insert elements into arbitrary containers using push_back
template <typename Type> class ContainerInserter
{
using InserterType = void (*)(void*, Type&&);
void* ref;
InserterType inserter;
// MSVC workaround
template <typename T> static void InserterOf(void* ref, Type&& type)
{
static_cast<T*>(ref)->push_back(std::move(type));
}
protected:
template <typename T> ContainerInserter(T& ref_) : ref(&ref_), inserter(&InserterOf<T>) {}
void Insert(Type type)
{
inserter(ref, std::move(type));
}
};
template<class Check>
struct WorldObjectSearcher
{
@@ -206,15 +229,15 @@ namespace Acore
};
template<class Check>
struct WorldObjectListSearcher
struct WorldObjectListSearcher : ContainerInserter<WorldObject*>
{
uint32 i_mapTypeMask;
uint32 i_phaseMask;
std::list<WorldObject*>& i_objects;
Check& i_check;
WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*>& objects, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
template <typename Container> WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: ContainerInserter<WorldObject*>(container),
i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
void Visit(PlayerMapType& m);
void Visit(CreatureMapType& m);
@@ -316,14 +339,14 @@ namespace Acore
};
template<class Check>
struct GameObjectListSearcher
struct GameObjectListSearcher : ContainerInserter<GameObject*>
{
uint32 i_phaseMask;
std::list<GameObject*>& i_objects;
Check& i_check;
GameObjectListSearcher(WorldObject const* searcher, std::list<GameObject*>& objects, Check& check)
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
template <typename Container> GameObjectListSearcher(WorldObject const* searcher, Container& container, Check& check)
: ContainerInserter<GameObject*>(container),
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
void Visit(GameObjectMapType& m);
@@ -388,14 +411,14 @@ namespace Acore
// All accepted by Check units if any
template<class Check>
struct UnitListSearcher
struct UnitListSearcher : ContainerInserter<Unit*>
{
uint32 i_phaseMask;
std::list<Unit*>& i_objects;
Check& i_check;
UnitListSearcher(WorldObject const* searcher, std::list<Unit*>& objects, Check& check)
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
template <typename Container> UnitListSearcher(WorldObject const* searcher, Container& container, Check& check)
: ContainerInserter<Unit*>(container),
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
void Visit(PlayerMapType& m);
void Visit(CreatureMapType& m);
@@ -437,14 +460,14 @@ namespace Acore
};
template<class Check>
struct CreatureListSearcher
struct CreatureListSearcher : ContainerInserter<Creature*>
{
uint32 i_phaseMask;
std::list<Creature*>& i_objects;
Check& i_check;
CreatureListSearcher(WorldObject const* searcher, std::list<Creature*>& objects, Check& check)
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
template <typename Container> CreatureListSearcher(WorldObject const* searcher, Container& container, Check& check)
: ContainerInserter<Creature*>(container),
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
void Visit(CreatureMapType& m);
@@ -488,14 +511,14 @@ namespace Acore
};
template<class Check>
struct PlayerListSearcher
struct PlayerListSearcher : ContainerInserter<Player*>
{
uint32 i_phaseMask;
std::list<Player*>& i_objects;
Check& i_check;
PlayerListSearcher(WorldObject const* searcher, std::list<Player*>& objects, Check& check)
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
template <typename Container> PlayerListSearcher(WorldObject const* searcher, Container& container, Check& check)
: ContainerInserter<Player*>(container),
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
void Visit(PlayerMapType& m);
@@ -803,20 +826,23 @@ namespace Acore
{
public:
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
bool operator()(Unit* u)
bool operator()(Unit* u) const
{
if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) &&
(i_funit->GetTypeId() != TYPEID_UNIT || !i_funit->ToCreature()->IsAvoidingAOE())) // pussywizard
(i_funit->GetTypeId() != TYPEID_UNIT || !i_funit->ToCreature()->IsAvoidingAOE())) // pussywizard)
{
return true;
else
return false;
}
return false;
}
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
};
class AnyUnfriendlyNoTotemUnitInObjectRangeCheck
{
public:
@@ -903,9 +929,19 @@ namespace Acore
class AnyGroupedUnitInObjectRangeCheck
{
public:
AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid) : _source(obj), _refUnit(funit), _range(range), _raid(raid) {}
AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false) : _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly) {}
bool operator()(Unit* u)
{
if (G3D::fuzzyEq(_range, 0.0f))
{
return false;
}
if (_playerOnly && u->GetTypeId() != TYPEID_PLAYER)
{
return false;
}
if (_raid)
{
if (!_refUnit->IsInRaidWith(u))
@@ -922,6 +958,7 @@ namespace Acore
Unit const* _refUnit;
float _range;
bool _raid;
bool _playerOnly;
};
class AnyUnitInObjectRangeCheck
@@ -968,27 +1005,35 @@ namespace Acore
class AnyAoETargetUnitInObjectRangeCheck
{
public:
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range)
: i_obj(obj), i_funit(funit), _spellInfo(nullptr), i_range(range)
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr)
: i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range)
{
Unit const* check = i_funit;
Unit const* owner = i_funit->GetOwner();
if (owner)
check = owner;
i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER);
if (i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT)
_spellInfo = sSpellMgr->GetSpellInfo(((DynamicObject*)i_obj)->GetSpellId());
if (!_spellInfo)
{
if (DynamicObject const* dynObj = i_obj->ToDynObject())
{
_spellInfo = sSpellMgr->GetSpellInfo(dynObj->GetSpellId());
}
}
}
bool operator()(Unit* u)
{
// Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems
if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem())
if (u->GetTypeId() == TYPEID_UNIT && ((Creature*) u)->IsTotem())
{
return false;
if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range))
return true;
return false;
}
if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) && u->GetTypeId() != TYPEID_PLAYER)
{
return false;
}
return i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range);
}
private:
bool i_targetForPlayer;

View File

@@ -253,7 +253,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(PlayerMapType& m)
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -264,7 +264,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(CreatureMapType& m)
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -275,7 +275,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(CorpseMapType& m)
for (CorpseMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -286,7 +286,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(GameObjectMapType& m)
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -297,7 +297,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType& m)
for (DynamicObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
// Gameobject searchers
@@ -341,7 +341,7 @@ void Acore::GameObjectListSearcher<Check>::Visit(GameObjectMapType& m)
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
// Unit searchers
@@ -418,7 +418,7 @@ void Acore::UnitListSearcher<Check>::Visit(PlayerMapType& m)
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -427,7 +427,7 @@ void Acore::UnitListSearcher<Check>::Visit(CreatureMapType& m)
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
// Creature searchers
@@ -471,7 +471,7 @@ void Acore::CreatureListSearcher<Check>::Visit(CreatureMapType& m)
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>
@@ -480,7 +480,7 @@ void Acore::PlayerListSearcher<Check>::Visit(PlayerMapType& m)
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
i_objects.push_back(itr->GetSource());
Insert(itr->GetSource());
}
template<class Check>

View File

@@ -298,7 +298,7 @@ void Group::ConvertToRaid()
// update quest related GO states (quest activity dependent from raid membership)
for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
if (Player* player = ObjectAccessor::FindPlayer(citr->guid))
player->UpdateForQuestWorldObjects();
player->UpdateVisibleGameobjectsOrSpellClicks();
// pussywizard: client automatically clears df "eye" near minimap, so remove from raid browser
if (sLFGMgr->GetState(GetLeaderGUID()) == lfg::LFG_STATE_RAIDBROWSER)
@@ -475,7 +475,7 @@ bool Group::AddMember(Player* player)
// quest related GO state dependent from raid membership
if (isRaidGroup())
player->UpdateForQuestWorldObjects();
player->UpdateVisibleGameobjectsOrSpellClicks();
{
// Broadcast new player group member fields to rest of the group
@@ -560,7 +560,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R
player->SetGroup(nullptr);
// quest related GO state dependent from raid membership
player->UpdateForQuestWorldObjects();
player->UpdateVisibleGameobjectsOrSpellClicks();
}
WorldPacket data;
@@ -774,7 +774,7 @@ void Group::Disband(bool hideDestroy /* = false */)
// quest related GO state dependent from raid membership
if (isRaidGroup())
player->UpdateForQuestWorldObjects();
player->UpdateVisibleGameobjectsOrSpellClicks();
WorldPacket data;
if (!hideDestroy)

View File

@@ -18,6 +18,7 @@
#include "ArenaSpectator.h"
#include "CellImpl.h"
#include "Common.h"
#include "ConditionMgr.h"
#include "DynamicObject.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
@@ -560,19 +561,18 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;
// fill up to date target list
// target, effMask
std::map<Unit*, uint8> targets;
// target, effMask
std::unordered_map<Unit*, uint8> targets;
FillTargetMap(targets, caster);
UnitList targetsToRemove;
std::deque<Unit*> targetsToRemove;
// mark all auras as ready to remove
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
std::map<Unit*, uint8>::iterator existing = targets.find(appIter->second->GetTarget());
auto itr = targets.find(appIter->second->GetTarget());
// not found in current area - remove the aura
if (existing == targets.end())
if (itr == targets.end())
targetsToRemove.push_back(appIter->second->GetTarget());
else
{
@@ -580,22 +580,22 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (IsArea())
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
if ((existing->second & (1 << effIndex)) && existing->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex))
existing->second &= ~(1 << effIndex);
if ((itr->second & (1 << effIndex)) && itr->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex))
itr->second &= ~(1 << effIndex);
}
// needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
if (appIter->second->GetEffectMask() != existing->second || !CanBeAppliedOn(existing->first))
if (appIter->second->GetEffectMask() != itr->second || !CanBeAppliedOn(itr->first))
targetsToRemove.push_back(appIter->second->GetTarget());
// nothing todo - aura already applied
// remove from auras to register list
targets.erase(existing);
targets.erase(itr);
}
}
// register auras for units
for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr != targets.end();)
for (auto itr = targets.begin(); itr != targets.end();)
{
// aura mustn't be already applied on target
if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
@@ -608,7 +608,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (aurApp->GetTarget() != itr->first)
{
// remove from auras to register list
targets.erase(itr++);
itr = targets.erase(itr);
continue;
}
else
@@ -675,7 +675,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
}
}
if (!addUnit)
targets.erase(itr++);
itr = targets.erase(itr);
else
{
// owner has to be in world, or effect has to be applied to self
@@ -693,15 +693,15 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
}
// remove auras from units no longer needing them
for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end(); ++itr)
if (AuraApplication* aurApp = GetApplicationOfTarget((*itr)->GetGUID()))
(*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
for (Unit* unit : targetsToRemove)
if (AuraApplication* aurApp = GetApplicationOfTarget(unit->GetGUID()))
unit->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
if (!apply)
return;
// apply aura effects for units
for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
for (auto itr = targets.begin(); itr != targets.end(); ++itr)
{
if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
{
@@ -2660,72 +2660,85 @@ void UnitAura::Remove(AuraRemoveMode removeMode)
GetUnitOwner()->RemoveOwnedAura(this, removeMode);
}
void UnitAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* caster)
void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster)
{
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
if (!HasEffect(effIndex))
continue;
UnitList targetList;
std::deque<Unit*> units;
// non-area aura
if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA)
{
targetList.push_back(GetUnitOwner());
}
units.push_back(GetUnitOwner());
else
{
float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster);
if (!GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED))
{
Unit* ref = caster;
ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
SpellTargetCheckTypes selectionType = TARGET_CHECK_DEFAULT;
switch (GetSpellInfo()->Effects[effIndex].Effect)
{
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
{
targetList.push_back(GetUnitOwner());
Acore::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID);
Acore::UnitListSearcher<Acore::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
units.push_back(GetUnitOwner());
Acore::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER));
Acore::UnitListSearcher<Acore::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
{
targetList.push_back(GetUnitOwner());
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
units.push_back(GetUnitOwner());
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER));
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
{
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); // No GetCharmer in searcher
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
targetList.push_back(GetUnitOwner());
if (!condList || sConditionMgr->IsObjectMeetToConditions(GetUnitOwner(), ref, *condList))
units.push_back(GetUnitOwner());
[[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked.
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
{
if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner())
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
targetList.push_back(owner);
if (!condList || sConditionMgr->IsObjectMeetToConditions(owner, ref, *condList))
units.push_back(owner);
break;
}
default:
break;
}
if (selectionType != TARGET_CHECK_DEFAULT)
{
Acore::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList);
Acore::UnitListSearcher<Acore::WorldObjectSpellAreaTargetCheck> searcher(GetUnitOwner(), units, check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
}
for (Unit* unit : units)
{
auto itr = targets.find(unit);
if (itr != targets.end())
itr->second |= 1 << effIndex;
else
targets[unit] = 1 << effIndex;
}
}
}
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
{
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
if (existing != targets.end())
existing->second |= 1 << effIndex;
else
targets[*itr] = 1 << effIndex;
}
}
}
@@ -2747,7 +2760,7 @@ void DynObjAura::Remove(AuraRemoveMode removeMode)
_Remove(removeMode);
}
void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/)
void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* /*caster*/)
{
Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
float radius = GetDynobjOwner()->GetRadius();
@@ -2756,12 +2769,13 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
{
if (!HasEffect(effIndex))
continue;
UnitList targetList;
std::deque<Unit*> units;
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
{
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER));
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
}
// pussywizard: TARGET_DEST_DYNOBJ_NONE is supposed to search for both friendly and unfriendly targets, so for any unit
@@ -2769,30 +2783,35 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
else if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
{
Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Acore::UnitListSearcher<Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
Acore::UnitListSearcher<Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
}
else
{
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
}
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
for (Unit* unit : units)
{
// xinef: check z level and los dependence
Unit* target = *itr;
float zLevel = GetDynobjOwner()->GetPositionZ();
if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel)
if (!target->IsWithinLOSInMap(GetDynobjOwner()))
if (unit->GetPositionZ() + 3.0f < zLevel || unit->GetPositionZ() - 5.0f > zLevel)
{
if (!unit->IsWithinLOSInMap(GetDynobjOwner()))
{
continue;
}
}
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
if (existing != targets.end())
existing->second |= 1 << effIndex;
auto itr = targets.find(unit);
if (itr != targets.end())
{
itr->second |= 1 << effIndex;
}
else
targets[*itr] = 1 << effIndex;
targets[unit] = 1 << effIndex;
}
}
}

View File

@@ -105,7 +105,11 @@ public:
ObjectGuid GetCasterGUID() const { return m_casterGuid; }
Unit* GetCaster() const;
WorldObject* GetOwner() const { return m_owner; }
Unit* GetUnitOwner() const { ASSERT(GetType() == UNIT_AURA_TYPE); return (Unit*)m_owner; }
Unit* GetUnitOwner() const
{
ASSERT(GetType() == UNIT_AURA_TYPE);
return (Unit*) m_owner->ToUnit();
}
DynamicObject* GetDynobjOwner() const { ASSERT(GetType() == DYNOBJ_AURA_TYPE); return (DynamicObject*)m_owner; }
AuraObjectType GetType() const;
@@ -115,7 +119,7 @@ public:
void _Remove(AuraRemoveMode removeMode);
virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0;
virtual void FillTargetMap(std::map<Unit*, uint8>& targets, Unit* caster) = 0;
virtual void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) = 0;
void UpdateTargetMap(Unit* caster, bool apply = true);
void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);}
@@ -284,7 +288,7 @@ public:
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
void FillTargetMap(std::map<Unit*, uint8>& targets, Unit* caster) override;
void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) override;
// Allow Apply Aura Handler to modify and access m_AuraDRGroup
void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
@@ -304,6 +308,6 @@ protected:
public:
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
void FillTargetMap(std::map<Unit*, uint8>& targets, Unit* caster) override;
void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) override;
};
#endif

View File

@@ -169,7 +169,7 @@ public:
_initialSelection = false;
// Find victim of Summon Gargoyle spell
std::list<Unit*> targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50);
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
Cell::VisitAllObjects(me, searcher, 50.0f);
for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)