fix(Core/Spells): Forward core changes (#8841)
This commit is contained in:
@@ -74,17 +74,17 @@ void VisitorHelper(VISITOR& v, ContainerUnorderedMap<TypeList<H, T>, KEY_TYPE>&
|
|||||||
VisitorHelper(v, c._TailElements);
|
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)
|
void VisitorHelper(VISITOR& v, TypeUnorderedMapContainer<OBJECT_TYPES, KEY_TYPE>& c)
|
||||||
{
|
{
|
||||||
VisitorHelper(v, c.GetElements());
|
VisitorHelper(v, c.GetElements());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class VISITOR, class TYPE_CONTAINER>
|
template <class VISITOR, class TYPE_CONTAINER>
|
||||||
class TypeContainerVisitor
|
class TypeContainerVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TypeContainerVisitor(VISITOR& v) : i_visitor(v) { }
|
TypeContainerVisitor(VISITOR& v) : i_visitor(v) {}
|
||||||
|
|
||||||
void Visit(TYPE_CONTAINER& c)
|
void Visit(TYPE_CONTAINER& c)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -640,6 +640,11 @@ ConditionMgr::~ConditionMgr()
|
|||||||
Clean();
|
Clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const
|
||||||
|
{
|
||||||
|
return SpellsUsedInSpellClickConditions.find(spellId) != SpellsUsedInSpellClickConditions.end();
|
||||||
|
}
|
||||||
|
|
||||||
ConditionMgr* ConditionMgr::instance()
|
ConditionMgr* ConditionMgr::instance()
|
||||||
{
|
{
|
||||||
static ConditionMgr instance;
|
static ConditionMgr instance;
|
||||||
@@ -694,7 +699,7 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& co
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions)
|
bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const
|
||||||
{
|
{
|
||||||
// groupId, groupCheckPassed
|
// groupId, groupCheckPassed
|
||||||
std::map<uint32, bool> ElseGroupStore;
|
std::map<uint32, bool> ElseGroupStore;
|
||||||
@@ -738,19 +743,19 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions)
|
bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const
|
||||||
{
|
{
|
||||||
ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
|
ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
|
||||||
return IsObjectMeetToConditions(srcInfo, conditions);
|
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);
|
ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2);
|
||||||
return IsObjectMeetToConditions(srcInfo, conditions);
|
return IsObjectMeetToConditions(srcInfo, conditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions)
|
bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const
|
||||||
{
|
{
|
||||||
if (conditions.empty())
|
if (conditions.empty())
|
||||||
return true;
|
return true;
|
||||||
@@ -1055,6 +1060,10 @@ void ConditionMgr::LoadConditions(bool isReload)
|
|||||||
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
|
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
|
||||||
{
|
{
|
||||||
SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
|
SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
|
||||||
|
if (cond->ConditionType == CONDITION_AURA)
|
||||||
|
{
|
||||||
|
SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1);
|
||||||
|
}
|
||||||
valid = true;
|
valid = true;
|
||||||
++count;
|
++count;
|
||||||
continue; // do not add to m_AllocatedMemory to avoid double deleting
|
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
|
// 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);
|
ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond);
|
||||||
++count;
|
++count;
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
@@ -2314,7 +2327,7 @@ void ConditionMgr::Clean()
|
|||||||
itr->second.clear();
|
itr->second.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellClickEventConditionStore.clear();
|
SpellsUsedInSpellClickConditions.clear();
|
||||||
|
|
||||||
for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr)
|
for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,10 @@
|
|||||||
#include "Errors.h"
|
#include "Errors.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Creature;
|
||||||
class Player;
|
class Player;
|
||||||
class Unit;
|
class Unit;
|
||||||
class WorldObject;
|
class WorldObject;
|
||||||
@@ -254,9 +257,9 @@ public:
|
|||||||
ConditionList GetConditionReferences(uint32 refId);
|
ConditionList GetConditionReferences(uint32 refId);
|
||||||
|
|
||||||
uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions);
|
uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions);
|
||||||
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions);
|
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const;
|
||||||
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions);
|
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) const;
|
||||||
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
|
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const;
|
||||||
[[nodiscard]] bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const;
|
[[nodiscard]] bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const;
|
||||||
[[nodiscard]] bool CanHaveSourceIdSet(ConditionSourceType sourceType) const;
|
[[nodiscard]] bool CanHaveSourceIdSet(ConditionSourceType sourceType) const;
|
||||||
ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
|
ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
|
||||||
@@ -264,6 +267,7 @@ public:
|
|||||||
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
|
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
|
||||||
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
|
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
|
||||||
ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId);
|
ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId);
|
||||||
|
bool IsSpellUsedInSpellClickConditions(uint32 spellId) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isSourceTypeValid(Condition* cond);
|
bool isSourceTypeValid(Condition* cond);
|
||||||
@@ -271,7 +275,7 @@ private:
|
|||||||
bool addToGossipMenus(Condition* cond);
|
bool addToGossipMenus(Condition* cond);
|
||||||
bool addToGossipMenuItems(Condition* cond);
|
bool addToGossipMenuItems(Condition* cond);
|
||||||
bool addToSpellImplicitTargetConditions(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
|
void Clean(); // free up resources
|
||||||
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
|
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
|
||||||
@@ -282,6 +286,8 @@ private:
|
|||||||
CreatureSpellConditionContainer SpellClickEventConditionStore;
|
CreatureSpellConditionContainer SpellClickEventConditionStore;
|
||||||
NpcVendorConditionContainer NpcVendorConditionContainerStore;
|
NpcVendorConditionContainer NpcVendorConditionContainerStore;
|
||||||
SmartEventConditionContainer SmartEventConditionStore;
|
SmartEventConditionContainer SmartEventConditionStore;
|
||||||
|
|
||||||
|
std::unordered_set<uint32> SpellsUsedInSpellClickConditions;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sConditionMgr ConditionMgr::instance()
|
#define sConditionMgr ConditionMgr::instance()
|
||||||
|
|||||||
@@ -1473,7 +1473,7 @@ public:
|
|||||||
[[nodiscard]] bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false, bool* showInLoot = nullptr) const;
|
[[nodiscard]] bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false, bool* showInLoot = nullptr) const;
|
||||||
[[nodiscard]] bool HasQuestForGO(int32 GOId) const;
|
[[nodiscard]] bool HasQuestForGO(int32 GOId) const;
|
||||||
[[nodiscard]] bool HasQuest(uint32 questId) const;
|
[[nodiscard]] bool HasQuest(uint32 questId) const;
|
||||||
void UpdateForQuestWorldObjects();
|
void UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
[[nodiscard]] bool CanShareQuest(uint32 quest_id) const;
|
[[nodiscard]] bool CanShareQuest(uint32 quest_id) const;
|
||||||
|
|
||||||
void SendQuestComplete(uint32 quest_id);
|
void SendQuestComplete(uint32 quest_id);
|
||||||
|
|||||||
@@ -1548,7 +1548,7 @@ void Player::SendQuestUpdate(uint32 questId)
|
|||||||
RemoveAurasDueToSpell(oldSpellId);
|
RemoveAurasDueToSpell(oldSpellId);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateForQuestWorldObjects();
|
UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
|
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)
|
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)
|
void Player::KilledMonster(CreatureTemplate const* cInfo, ObjectGuid guid)
|
||||||
|
|||||||
@@ -2848,7 +2848,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
|
|||||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
|
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
|
||||||
|
|
||||||
sScriptMgr->OnEquip(this, pItem, bag, slot, update);
|
sScriptMgr->OnEquip(this, pItem, bag, slot, update);
|
||||||
UpdateForQuestWorldObjects();
|
UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
return pItem;
|
return pItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1820,7 +1820,7 @@ void Player::UpdateTriggerVisibility()
|
|||||||
GetSession()->SendPacket(&packet);
|
GetSession()->SendPacket(&packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::UpdateForQuestWorldObjects()
|
void Player::UpdateVisibleGameobjectsOrSpellClicks()
|
||||||
{
|
{
|
||||||
if (m_clientGUIDs.empty())
|
if (m_clientGUIDs.empty())
|
||||||
return;
|
return;
|
||||||
@@ -1847,19 +1847,9 @@ void Player::UpdateForQuestWorldObjects()
|
|||||||
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
|
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
|
||||||
for (SpellClickInfoContainer::const_iterator _itr = clickPair.first; _itr != clickPair.second; ++_itr)
|
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);
|
ConditionList conds = sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), _itr->second.spellId);
|
||||||
bool buildUpdateBlock = false;
|
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||||
for (ConditionList::const_iterator jtr = conds.begin(); jtr != conds.end() && !buildUpdateBlock; ++jtr)
|
break;
|
||||||
if ((*jtr)->ConditionType == CONDITION_QUESTREWARDED || (*jtr)->ConditionType == CONDITION_QUESTTAKEN)
|
|
||||||
buildUpdateBlock = true;
|
|
||||||
|
|
||||||
if (buildUpdateBlock)
|
|
||||||
{
|
|
||||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4072,6 +4072,14 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
|
|||||||
if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
|
if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
|
||||||
aurApp->_HandleEffect(i, true);
|
aurApp->_HandleEffect(i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Player* player = ToPlayer())
|
||||||
|
{
|
||||||
|
if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
|
||||||
|
{
|
||||||
|
player->UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// removes aura application from lists and unapplies effects
|
// 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);
|
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
|
// only way correctly remove all auras from list
|
||||||
//if (removedAuras != m_removedAurasCount) new aura may be added
|
//if (removedAuras != m_removedAurasCount) new aura may be added
|
||||||
i = m_appliedAuras.begin();
|
i = m_appliedAuras.begin();
|
||||||
|
|||||||
@@ -165,6 +165,29 @@ namespace Acore
|
|||||||
|
|
||||||
// WorldObject searchers & workers
|
// 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>
|
template<class Check>
|
||||||
struct WorldObjectSearcher
|
struct WorldObjectSearcher
|
||||||
{
|
{
|
||||||
@@ -206,15 +229,15 @@ namespace Acore
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
struct WorldObjectListSearcher
|
struct WorldObjectListSearcher : ContainerInserter<WorldObject*>
|
||||||
{
|
{
|
||||||
uint32 i_mapTypeMask;
|
uint32 i_mapTypeMask;
|
||||||
uint32 i_phaseMask;
|
uint32 i_phaseMask;
|
||||||
std::list<WorldObject*>& i_objects;
|
|
||||||
Check& i_check;
|
Check& i_check;
|
||||||
|
|
||||||
WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*>& objects, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
|
template <typename Container> WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
|
||||||
: i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
|
: ContainerInserter<WorldObject*>(container),
|
||||||
|
i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
|
||||||
|
|
||||||
void Visit(PlayerMapType& m);
|
void Visit(PlayerMapType& m);
|
||||||
void Visit(CreatureMapType& m);
|
void Visit(CreatureMapType& m);
|
||||||
@@ -316,14 +339,14 @@ namespace Acore
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
struct GameObjectListSearcher
|
struct GameObjectListSearcher : ContainerInserter<GameObject*>
|
||||||
{
|
{
|
||||||
uint32 i_phaseMask;
|
uint32 i_phaseMask;
|
||||||
std::list<GameObject*>& i_objects;
|
|
||||||
Check& i_check;
|
Check& i_check;
|
||||||
|
|
||||||
GameObjectListSearcher(WorldObject const* searcher, std::list<GameObject*>& objects, Check& check)
|
template <typename Container> GameObjectListSearcher(WorldObject const* searcher, Container& container, Check& check)
|
||||||
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
|
: ContainerInserter<GameObject*>(container),
|
||||||
|
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
|
||||||
|
|
||||||
void Visit(GameObjectMapType& m);
|
void Visit(GameObjectMapType& m);
|
||||||
|
|
||||||
@@ -388,14 +411,14 @@ namespace Acore
|
|||||||
|
|
||||||
// All accepted by Check units if any
|
// All accepted by Check units if any
|
||||||
template<class Check>
|
template<class Check>
|
||||||
struct UnitListSearcher
|
struct UnitListSearcher : ContainerInserter<Unit*>
|
||||||
{
|
{
|
||||||
uint32 i_phaseMask;
|
uint32 i_phaseMask;
|
||||||
std::list<Unit*>& i_objects;
|
|
||||||
Check& i_check;
|
Check& i_check;
|
||||||
|
|
||||||
UnitListSearcher(WorldObject const* searcher, std::list<Unit*>& objects, Check& check)
|
template <typename Container> UnitListSearcher(WorldObject const* searcher, Container& container, Check& check)
|
||||||
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
|
: ContainerInserter<Unit*>(container),
|
||||||
|
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
|
||||||
|
|
||||||
void Visit(PlayerMapType& m);
|
void Visit(PlayerMapType& m);
|
||||||
void Visit(CreatureMapType& m);
|
void Visit(CreatureMapType& m);
|
||||||
@@ -437,14 +460,14 @@ namespace Acore
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
struct CreatureListSearcher
|
struct CreatureListSearcher : ContainerInserter<Creature*>
|
||||||
{
|
{
|
||||||
uint32 i_phaseMask;
|
uint32 i_phaseMask;
|
||||||
std::list<Creature*>& i_objects;
|
|
||||||
Check& i_check;
|
Check& i_check;
|
||||||
|
|
||||||
CreatureListSearcher(WorldObject const* searcher, std::list<Creature*>& objects, Check& check)
|
template <typename Container> CreatureListSearcher(WorldObject const* searcher, Container& container, Check& check)
|
||||||
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
|
: ContainerInserter<Creature*>(container),
|
||||||
|
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
|
||||||
|
|
||||||
void Visit(CreatureMapType& m);
|
void Visit(CreatureMapType& m);
|
||||||
|
|
||||||
@@ -488,14 +511,14 @@ namespace Acore
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
struct PlayerListSearcher
|
struct PlayerListSearcher : ContainerInserter<Player*>
|
||||||
{
|
{
|
||||||
uint32 i_phaseMask;
|
uint32 i_phaseMask;
|
||||||
std::list<Player*>& i_objects;
|
|
||||||
Check& i_check;
|
Check& i_check;
|
||||||
|
|
||||||
PlayerListSearcher(WorldObject const* searcher, std::list<Player*>& objects, Check& check)
|
template <typename Container> PlayerListSearcher(WorldObject const* searcher, Container& container, Check& check)
|
||||||
: i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
|
: ContainerInserter<Player*>(container),
|
||||||
|
i_phaseMask(searcher->GetPhaseMask()), i_check(check) {}
|
||||||
|
|
||||||
void Visit(PlayerMapType& m);
|
void Visit(PlayerMapType& m);
|
||||||
|
|
||||||
@@ -803,20 +826,23 @@ namespace Acore
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
|
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) &&
|
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;
|
return true;
|
||||||
else
|
}
|
||||||
return false;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WorldObject const* i_obj;
|
WorldObject const* i_obj;
|
||||||
Unit const* i_funit;
|
Unit const* i_funit;
|
||||||
float i_range;
|
float i_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AnyUnfriendlyNoTotemUnitInObjectRangeCheck
|
class AnyUnfriendlyNoTotemUnitInObjectRangeCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -903,9 +929,19 @@ namespace Acore
|
|||||||
class AnyGroupedUnitInObjectRangeCheck
|
class AnyGroupedUnitInObjectRangeCheck
|
||||||
{
|
{
|
||||||
public:
|
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)
|
bool operator()(Unit* u)
|
||||||
{
|
{
|
||||||
|
if (G3D::fuzzyEq(_range, 0.0f))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_playerOnly && u->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_raid)
|
if (_raid)
|
||||||
{
|
{
|
||||||
if (!_refUnit->IsInRaidWith(u))
|
if (!_refUnit->IsInRaidWith(u))
|
||||||
@@ -922,6 +958,7 @@ namespace Acore
|
|||||||
Unit const* _refUnit;
|
Unit const* _refUnit;
|
||||||
float _range;
|
float _range;
|
||||||
bool _raid;
|
bool _raid;
|
||||||
|
bool _playerOnly;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AnyUnitInObjectRangeCheck
|
class AnyUnitInObjectRangeCheck
|
||||||
@@ -968,27 +1005,35 @@ namespace Acore
|
|||||||
class AnyAoETargetUnitInObjectRangeCheck
|
class AnyAoETargetUnitInObjectRangeCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range)
|
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr)
|
||||||
: i_obj(obj), i_funit(funit), _spellInfo(nullptr), i_range(range)
|
: i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range)
|
||||||
{
|
{
|
||||||
Unit const* check = i_funit;
|
Unit const* check = i_funit;
|
||||||
Unit const* owner = i_funit->GetOwner();
|
Unit const* owner = i_funit->GetOwner();
|
||||||
if (owner)
|
if (owner)
|
||||||
check = owner;
|
check = owner;
|
||||||
i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER);
|
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)
|
bool operator()(Unit* u)
|
||||||
{
|
{
|
||||||
// Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems
|
// 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;
|
return false;
|
||||||
|
}
|
||||||
if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range))
|
if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) && u->GetTypeId() != TYPEID_PLAYER)
|
||||||
return true;
|
{
|
||||||
|
return false;
|
||||||
return false;
|
}
|
||||||
|
return i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
bool i_targetForPlayer;
|
bool i_targetForPlayer;
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(PlayerMapType& m)
|
|||||||
|
|
||||||
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -264,7 +264,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(CreatureMapType& m)
|
|||||||
|
|
||||||
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -275,7 +275,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(CorpseMapType& m)
|
|||||||
|
|
||||||
for (CorpseMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (CorpseMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -286,7 +286,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(GameObjectMapType& m)
|
|||||||
|
|
||||||
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -297,7 +297,7 @@ void Acore::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType& m)
|
|||||||
|
|
||||||
for (DynamicObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (DynamicObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gameobject searchers
|
// Gameobject searchers
|
||||||
@@ -341,7 +341,7 @@ void Acore::GameObjectListSearcher<Check>::Visit(GameObjectMapType& m)
|
|||||||
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unit searchers
|
// Unit searchers
|
||||||
@@ -418,7 +418,7 @@ void Acore::UnitListSearcher<Check>::Visit(PlayerMapType& m)
|
|||||||
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -427,7 +427,7 @@ void Acore::UnitListSearcher<Check>::Visit(CreatureMapType& m)
|
|||||||
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creature searchers
|
// Creature searchers
|
||||||
@@ -471,7 +471,7 @@ void Acore::CreatureListSearcher<Check>::Visit(CreatureMapType& m)
|
|||||||
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
@@ -480,7 +480,7 @@ void Acore::PlayerListSearcher<Check>::Visit(PlayerMapType& m)
|
|||||||
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||||
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
if (itr->GetSource()->InSamePhase(i_phaseMask))
|
||||||
if (i_check(itr->GetSource()))
|
if (i_check(itr->GetSource()))
|
||||||
i_objects.push_back(itr->GetSource());
|
Insert(itr->GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Check>
|
template<class Check>
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ void Group::ConvertToRaid()
|
|||||||
// update quest related GO states (quest activity dependent from raid membership)
|
// update quest related GO states (quest activity dependent from raid membership)
|
||||||
for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
|
for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
|
||||||
if (Player* player = ObjectAccessor::FindPlayer(citr->guid))
|
if (Player* player = ObjectAccessor::FindPlayer(citr->guid))
|
||||||
player->UpdateForQuestWorldObjects();
|
player->UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
|
|
||||||
// pussywizard: client automatically clears df "eye" near minimap, so remove from raid browser
|
// pussywizard: client automatically clears df "eye" near minimap, so remove from raid browser
|
||||||
if (sLFGMgr->GetState(GetLeaderGUID()) == lfg::LFG_STATE_RAIDBROWSER)
|
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
|
// quest related GO state dependent from raid membership
|
||||||
if (isRaidGroup())
|
if (isRaidGroup())
|
||||||
player->UpdateForQuestWorldObjects();
|
player->UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
|
|
||||||
{
|
{
|
||||||
// Broadcast new player group member fields to rest of the group
|
// 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);
|
player->SetGroup(nullptr);
|
||||||
|
|
||||||
// quest related GO state dependent from raid membership
|
// quest related GO state dependent from raid membership
|
||||||
player->UpdateForQuestWorldObjects();
|
player->UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldPacket data;
|
WorldPacket data;
|
||||||
@@ -774,7 +774,7 @@ void Group::Disband(bool hideDestroy /* = false */)
|
|||||||
|
|
||||||
// quest related GO state dependent from raid membership
|
// quest related GO state dependent from raid membership
|
||||||
if (isRaidGroup())
|
if (isRaidGroup())
|
||||||
player->UpdateForQuestWorldObjects();
|
player->UpdateVisibleGameobjectsOrSpellClicks();
|
||||||
|
|
||||||
WorldPacket data;
|
WorldPacket data;
|
||||||
if (!hideDestroy)
|
if (!hideDestroy)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "ArenaSpectator.h"
|
#include "ArenaSpectator.h"
|
||||||
#include "CellImpl.h"
|
#include "CellImpl.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "ConditionMgr.h"
|
||||||
#include "DynamicObject.h"
|
#include "DynamicObject.h"
|
||||||
#include "GridNotifiers.h"
|
#include "GridNotifiers.h"
|
||||||
#include "GridNotifiersImpl.h"
|
#include "GridNotifiersImpl.h"
|
||||||
@@ -560,19 +561,18 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
|||||||
m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;
|
m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;
|
||||||
|
|
||||||
// fill up to date target list
|
// fill up to date target list
|
||||||
// target, effMask
|
// target, effMask
|
||||||
std::map<Unit*, uint8> targets;
|
std::unordered_map<Unit*, uint8> targets;
|
||||||
|
|
||||||
FillTargetMap(targets, caster);
|
FillTargetMap(targets, caster);
|
||||||
|
|
||||||
UnitList targetsToRemove;
|
std::deque<Unit*> targetsToRemove;
|
||||||
|
|
||||||
// mark all auras as ready to remove
|
// mark all auras as ready to remove
|
||||||
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
|
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
|
// not found in current area - remove the aura
|
||||||
if (existing == targets.end())
|
if (itr == targets.end())
|
||||||
targetsToRemove.push_back(appIter->second->GetTarget());
|
targetsToRemove.push_back(appIter->second->GetTarget());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -580,22 +580,22 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
|||||||
if (IsArea())
|
if (IsArea())
|
||||||
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||||
{
|
{
|
||||||
if ((existing->second & (1 << effIndex)) && existing->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex))
|
if ((itr->second & (1 << effIndex)) && itr->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex))
|
||||||
existing->second &= ~(1 << effIndex);
|
itr->second &= ~(1 << effIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// needs readding - remove now, will be applied in next update cycle
|
// 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)
|
// (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());
|
targetsToRemove.push_back(appIter->second->GetTarget());
|
||||||
// nothing todo - aura already applied
|
// nothing todo - aura already applied
|
||||||
// remove from auras to register list
|
// remove from auras to register list
|
||||||
targets.erase(existing);
|
targets.erase(itr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// register auras for units
|
// 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
|
// aura mustn't be already applied on target
|
||||||
if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
|
if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
|
||||||
@@ -608,7 +608,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
|||||||
if (aurApp->GetTarget() != itr->first)
|
if (aurApp->GetTarget() != itr->first)
|
||||||
{
|
{
|
||||||
// remove from auras to register list
|
// remove from auras to register list
|
||||||
targets.erase(itr++);
|
itr = targets.erase(itr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -675,7 +675,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!addUnit)
|
if (!addUnit)
|
||||||
targets.erase(itr++);
|
itr = targets.erase(itr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// owner has to be in world, or effect has to be applied to self
|
// 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
|
// remove auras from units no longer needing them
|
||||||
for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end(); ++itr)
|
for (Unit* unit : targetsToRemove)
|
||||||
if (AuraApplication* aurApp = GetApplicationOfTarget((*itr)->GetGUID()))
|
if (AuraApplication* aurApp = GetApplicationOfTarget(unit->GetGUID()))
|
||||||
(*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
|
unit->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
|
||||||
|
|
||||||
if (!apply)
|
if (!apply)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// apply aura effects for units
|
// 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()))
|
if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
|
||||||
{
|
{
|
||||||
@@ -2660,72 +2660,85 @@ void UnitAura::Remove(AuraRemoveMode removeMode)
|
|||||||
GetUnitOwner()->RemoveOwnedAura(this, 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)
|
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||||
{
|
{
|
||||||
if (!HasEffect(effIndex))
|
if (!HasEffect(effIndex))
|
||||||
continue;
|
continue;
|
||||||
UnitList targetList;
|
|
||||||
|
std::deque<Unit*> units;
|
||||||
|
|
||||||
// non-area aura
|
// non-area aura
|
||||||
if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA)
|
if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA)
|
||||||
{
|
units.push_back(GetUnitOwner());
|
||||||
targetList.push_back(GetUnitOwner());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster);
|
float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster);
|
||||||
|
|
||||||
if (!GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED))
|
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)
|
switch (GetSpellInfo()->Effects[effIndex].Effect)
|
||||||
{
|
{
|
||||||
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
|
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
|
||||||
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
|
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
|
||||||
{
|
{
|
||||||
targetList.push_back(GetUnitOwner());
|
units.push_back(GetUnitOwner());
|
||||||
Acore::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID);
|
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(), targetList, u_check);
|
Acore::UnitListSearcher<Acore::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
|
||||||
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
|
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
|
||||||
{
|
{
|
||||||
targetList.push_back(GetUnitOwner());
|
units.push_back(GetUnitOwner());
|
||||||
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
|
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER));
|
||||||
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
|
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
|
||||||
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
|
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
|
||||||
{
|
{
|
||||||
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); // No GetCharmer in searcher
|
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher
|
||||||
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
|
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
|
||||||
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
|
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.
|
[[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:
|
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
|
||||||
{
|
{
|
||||||
if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner())
|
if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner())
|
||||||
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
|
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
|
||||||
targetList.push_back(owner);
|
if (!condList || sConditionMgr->IsObjectMeetToConditions(owner, ref, *condList))
|
||||||
|
units.push_back(owner);
|
||||||
break;
|
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);
|
_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();
|
Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
|
||||||
float radius = GetDynobjOwner()->GetRadius();
|
float radius = GetDynobjOwner()->GetRadius();
|
||||||
@@ -2756,12 +2769,13 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
|||||||
{
|
{
|
||||||
if (!HasEffect(effIndex))
|
if (!HasEffect(effIndex))
|
||||||
continue;
|
continue;
|
||||||
UnitList targetList;
|
|
||||||
|
std::deque<Unit*> units;
|
||||||
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|
||||||
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
||||||
{
|
{
|
||||||
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER));
|
||||||
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
|
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
|
||||||
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
|
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
|
||||||
}
|
}
|
||||||
// pussywizard: TARGET_DEST_DYNOBJ_NONE is supposed to search for both friendly and unfriendly targets, so for any unit
|
// 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)
|
else if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
|
||||||
{
|
{
|
||||||
Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
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);
|
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
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);
|
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
|
// xinef: check z level and los dependence
|
||||||
Unit* target = *itr;
|
|
||||||
float zLevel = GetDynobjOwner()->GetPositionZ();
|
float zLevel = GetDynobjOwner()->GetPositionZ();
|
||||||
if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel)
|
if (unit->GetPositionZ() + 3.0f < zLevel || unit->GetPositionZ() - 5.0f > zLevel)
|
||||||
if (!target->IsWithinLOSInMap(GetDynobjOwner()))
|
{
|
||||||
|
if (!unit->IsWithinLOSInMap(GetDynobjOwner()))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
|
auto itr = targets.find(unit);
|
||||||
if (existing != targets.end())
|
if (itr != targets.end())
|
||||||
existing->second |= 1 << effIndex;
|
{
|
||||||
|
itr->second |= 1 << effIndex;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
targets[*itr] = 1 << effIndex;
|
targets[unit] = 1 << effIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,11 @@ public:
|
|||||||
ObjectGuid GetCasterGUID() const { return m_casterGuid; }
|
ObjectGuid GetCasterGUID() const { return m_casterGuid; }
|
||||||
Unit* GetCaster() const;
|
Unit* GetCaster() const;
|
||||||
WorldObject* GetOwner() const { return m_owner; }
|
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; }
|
DynamicObject* GetDynobjOwner() const { ASSERT(GetType() == DYNOBJ_AURA_TYPE); return (DynamicObject*)m_owner; }
|
||||||
|
|
||||||
AuraObjectType GetType() const;
|
AuraObjectType GetType() const;
|
||||||
@@ -115,7 +119,7 @@ public:
|
|||||||
void _Remove(AuraRemoveMode removeMode);
|
void _Remove(AuraRemoveMode removeMode);
|
||||||
virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0;
|
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 UpdateTargetMap(Unit* caster, bool apply = true);
|
||||||
|
|
||||||
void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);}
|
void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);}
|
||||||
@@ -284,7 +288,7 @@ public:
|
|||||||
|
|
||||||
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
|
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
|
// Allow Apply Aura Handler to modify and access m_AuraDRGroup
|
||||||
void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
|
void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
|
||||||
@@ -304,6 +308,6 @@ protected:
|
|||||||
public:
|
public:
|
||||||
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
|
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
|
#endif
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public:
|
|||||||
_initialSelection = false;
|
_initialSelection = false;
|
||||||
// Find victim of Summon Gargoyle spell
|
// Find victim of Summon Gargoyle spell
|
||||||
std::list<Unit*> targets;
|
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);
|
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
|
||||||
Cell::VisitAllObjects(me, searcher, 50.0f);
|
Cell::VisitAllObjects(me, searcher, 50.0f);
|
||||||
for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
||||||
|
|||||||
Reference in New Issue
Block a user