/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef TRINITY_GRIDNOTIFIERS_H
#define TRINITY_GRIDNOTIFIERS_H
#include "AreaTrigger.h"
#include "Creature.h"
#include "Corpse.h"
#include "Conversation.h"
#include "DynamicObject.h"
#include "GameObject.h"
#include "Player.h"
#include "SceneObject.h"
#include "Spell.h"
#include "SpellInfo.h"
#include "UnitAI.h"
#include "UpdateData.h"
namespace Trinity
{
template
struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
template<> struct GridMapTypeMaskForType : std::integral_constant { };
struct TC_GAME_API VisibleNotifier
{
Player &i_player;
UpdateData i_data;
std::set i_visibleNow;
GuidUnorderedSet vis_guids;
VisibleNotifier(Player &player);
~VisibleNotifier();
template void Visit(GridRefManager &m);
void SendToSelf(void);
VisibleNotifier(VisibleNotifier const&) = delete;
VisibleNotifier(VisibleNotifier&&) = delete;
VisibleNotifier& operator=(VisibleNotifier const&) = delete;
VisibleNotifier& operator=(VisibleNotifier&&) = delete;
};
struct VisibleChangesNotifier
{
IteratorPair i_objects;
explicit VisibleChangesNotifier(IteratorPair objects) : i_objects(objects) { }
template void Visit(GridRefManager &) { }
void Visit(PlayerMapType &);
void Visit(CreatureMapType &);
void Visit(DynamicObjectMapType &);
};
struct TC_GAME_API PlayerRelocationNotifier : public VisibleNotifier
{
PlayerRelocationNotifier(Player &player) : VisibleNotifier(player) { }
template void Visit(GridRefManager &m) { VisibleNotifier::Visit(m); }
void Visit(CreatureMapType &);
void Visit(PlayerMapType &);
};
struct TC_GAME_API CreatureRelocationNotifier
{
Creature &i_creature;
CreatureRelocationNotifier(Creature &c) : i_creature(c) { }
template void Visit(GridRefManager &) { }
void Visit(CreatureMapType &);
void Visit(PlayerMapType &);
};
struct TC_GAME_API DelayedUnitRelocation
{
Map &i_map;
Cell &cell;
CellCoord &p;
const float i_radius;
DelayedUnitRelocation(Cell &c, CellCoord &pair, Map &map, float radius) :
i_map(map), cell(c), p(pair), i_radius(radius) { }
template void Visit(GridRefManager &) { }
void Visit(CreatureMapType &);
void Visit(PlayerMapType &);
};
struct TC_GAME_API AIRelocationNotifier
{
Unit &i_unit;
bool isCreature;
explicit AIRelocationNotifier(Unit &unit) : i_unit(unit), isCreature(unit.GetTypeId() == TYPEID_UNIT) { }
template void Visit(GridRefManager &) { }
void Visit(CreatureMapType &);
};
struct TC_GAME_API CreatureAggroGracePeriodExpiredNotifier
{
Creature& i_creature;
CreatureAggroGracePeriodExpiredNotifier(Creature& c) : i_creature(c) { }
template void Visit(GridRefManager&) { }
void Visit(CreatureMapType&);
void Visit(PlayerMapType&);
};
struct GridUpdater
{
GridType &i_grid;
uint32 i_timeDiff;
GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) { }
template void updateObjects(GridRefManager &m)
{
for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter)
iter->GetSource()->Update(i_timeDiff);
}
void Visit(PlayerMapType &m) { updateObjects(m); }
void Visit(CreatureMapType &m){ updateObjects(m); }
void Visit(GameObjectMapType &m) { updateObjects(m); }
void Visit(DynamicObjectMapType &m) { updateObjects(m); }
void Visit(CorpseMapType &m) { updateObjects(m); }
void Visit(AreaTriggerMapType &m) { updateObjects(m); }
void Visit(SceneObjectMapType &m) { updateObjects(m); }
void Visit(ConversationMapType &m) { updateObjects(m); }
};
struct PacketSenderRef
{
WorldPacket const* Data;
PacketSenderRef(WorldPacket const* message) : Data(message) { }
void operator()(Player const* player) const
{
player->SendDirectMessage(Data);
}
};
template
struct PacketSenderOwning
{
Packet Data;
void operator()(Player const* player) const
{
player->SendDirectMessage(Data.GetRawPacket());
}
};
template
struct MessageDistDeliverer
{
WorldObject const* i_source;
PacketSender& i_packetSender;
PhaseShift const* i_phaseShift;
float i_distSq;
Team team;
Player const* skipped_receiver;
bool required3dDist;
MessageDistDeliverer(WorldObject const* src, PacketSender& packetSender, float dist, bool own_team_only = false, Player const* skipped = nullptr, bool req3dDist = false)
: i_source(src), i_packetSender(packetSender), i_phaseShift(&src->GetPhaseShift()), i_distSq(dist * dist)
, team(TEAM_OTHER)
, skipped_receiver(skipped)
, required3dDist(req3dDist)
{
if (own_team_only)
if (Player const* player = src->ToPlayer())
team = player->GetEffectiveTeam();
}
void Visit(PlayerMapType &m) const;
void Visit(CreatureMapType &m) const;
void Visit(DynamicObjectMapType &m) const;
template void Visit(GridRefManager &) const { }
void SendPacket(Player const* player) const
{
// never send packet to self
if (player == i_source || (team && player->GetEffectiveTeam() != team) || skipped_receiver == player)
return;
if (!player->HaveAtClient(i_source))
return;
i_packetSender(player);
}
};
template
struct MessageDistDelivererToHostile
{
Unit* i_source;
PacketSender& i_packetSender;
PhaseShift const* i_phaseShift;
float i_distSq;
MessageDistDelivererToHostile(Unit* src, PacketSender& packetSender, float dist)
: i_source(src), i_packetSender(packetSender), i_phaseShift(&src->GetPhaseShift()), i_distSq(dist * dist)
{
}
void Visit(PlayerMapType &m) const;
void Visit(CreatureMapType &m) const;
void Visit(DynamicObjectMapType &m) const;
template void Visit(GridRefManager &) const { }
void SendPacket(Player const* player) const
{
// never send packet to self
if (player == i_source || !player->HaveAtClient(i_source) || player->IsFriendlyTo(i_source))
return;
i_packetSender(player);
}
};
struct ObjectUpdater
{
uint32 i_timeDiff;
explicit ObjectUpdater(const uint32 diff) : i_timeDiff(diff) { }
template void Visit(GridRefManager &m);
void Visit(PlayerMapType &) { }
void Visit(CorpseMapType &) { }
};
// SEARCHERS & LIST SEARCHERS & WORKERS
// WorldObject searchers & workers
enum class WorldObjectSearcherContinuation
{
Continue,
Return
};
template
class SearcherFirstObjectResult
{
Type& result;
protected:
explicit SearcherFirstObjectResult(Type& ref_) : result(ref_) { }
WorldObjectSearcherContinuation ShouldContinue() const
{
return result ? WorldObjectSearcherContinuation::Return : WorldObjectSearcherContinuation::Continue;
}
void Insert(Type object)
{
result = object;
}
};
template
class SearcherLastObjectResult
{
Type& result;
protected:
explicit SearcherLastObjectResult(Type& ref_) : result(ref_) { }
WorldObjectSearcherContinuation ShouldContinue() const
{
return WorldObjectSearcherContinuation::Continue;
}
void Insert(Type object)
{
result = object;
}
};
// Generic base class to insert elements into arbitrary containers using push_back
template
class SearcherContainerResult
{
using InserterType = void(*)(void*, Type&&);
void* ref;
InserterType inserter;
protected:
template
explicit SearcherContainerResult(T& ref_) : ref(&ref_)
{
inserter = [](void* containerRaw, Type&& object)
{
T* container = reinterpret_cast(containerRaw);
container->insert(container->end(), std::move(object));
};
}
WorldObjectSearcherContinuation ShouldContinue() const
{
return WorldObjectSearcherContinuation::Continue;
}
void Insert(Type object)
{
inserter(ref, std::move(object));
}
};
struct DynamicGridMapTypeMaskCheck
{
DynamicGridMapTypeMaskCheck(uint32 mask) : MaskValue(mask) { }
static constexpr bool IsStatic = false;
uint32 MaskValue;
constexpr bool Includes(uint32 mapTypeMask) const
{
return (MaskValue & mapTypeMask) != 0;
}
};
template
struct StaticGridMapTypeMaskCheck
{
StaticGridMapTypeMaskCheck(uint32) { }
static constexpr bool IsStatic = true;
static constexpr bool Includes(uint32 mapTypeMask)
{
return (MapTypeMask & mapTypeMask) != 0;
}
};
template
struct WorldObjectSearcherBase : Result
{
MapTypeMaskCheck i_mapTypeMask;
PhaseShift const* i_phaseShift;
Check& i_check;
template
void Visit(GridRefManager& m)
{
if constexpr (MapTypeMaskCheck::IsStatic)
{
if constexpr (MapTypeMaskCheck::Includes(GridMapTypeMaskForType::value))
VisitImpl(m);
}
else
{
if (i_mapTypeMask.Includes(GridMapTypeMaskForType::value))
VisitImpl(m);
}
}
protected:
template
WorldObjectSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: Result(result), i_mapTypeMask(mapTypeMask), i_phaseShift(&phaseShift), i_check(check) { }
private:
template
void VisitImpl(GridRefManager&);
};
template
struct WorldObjectWorkerBase
{
MapTypeMaskCheck i_mapTypeMask;
PhaseShift const* i_phaseShift;
Work& i_work;
template
void Visit(GridRefManager const& m)
{
if constexpr (MapTypeMaskCheck::IsStatic)
{
if constexpr (MapTypeMaskCheck::Includes(GridMapTypeMaskForType::value))
VisitImpl(m);
}
else
{
if (i_mapTypeMask.Includes(GridMapTypeMaskForType::value))
VisitImpl(m);
}
}
protected:
WorldObjectWorkerBase(PhaseShift const& phaseShift, Work& work, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: i_mapTypeMask(mapTypeMask), i_phaseShift(&phaseShift), i_work(work) { }
private:
template
inline void VisitImpl(GridRefManager const& m)
{
for (GridReference const& ref : m)
if (ref.GetSource()->InSamePhase(*i_phaseShift))
this->i_work(ref.GetSource());
}
};
template
struct WorldObjectSearcher : WorldObjectSearcherBase>
{
WorldObjectSearcher(PhaseShift const& phaseShift, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectSearcherBase>(phaseShift, result, check, mapTypeMask) { }
WorldObjectSearcher(WorldObject const* searcher, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectSearcher(searcher->GetPhaseShift(), result, check, mapTypeMask) { }
};
template
struct WorldObjectLastSearcher : WorldObjectSearcherBase>
{
WorldObjectLastSearcher(PhaseShift const& phaseShift, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectSearcherBase>(phaseShift, result, check, mapTypeMask) { }
WorldObjectLastSearcher(WorldObject const* searcher, WorldObject*& result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectLastSearcher(searcher->GetPhaseShift(), result, check, mapTypeMask) { }
};
template
struct WorldObjectListSearcher : WorldObjectSearcherBase>
{
template
WorldObjectListSearcher(PhaseShift const& phaseShift, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectSearcherBase>(phaseShift, container, check, mapTypeMask) { }
template
WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectListSearcher(searcher->GetPhaseShift(), container, check, mapTypeMask) { }
};
template
WorldObjectListSearcher(PhaseShift const&, Container&, Check const&) -> WorldObjectListSearcher;
template
WorldObjectListSearcher(WorldObject const*, Container&, Check const&) -> WorldObjectListSearcher;
template
struct WorldObjectWorker : WorldObjectWorkerBase
{
WorldObjectWorker(PhaseShift const& phaseShift, Work& work, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectWorkerBase(phaseShift, work, mapTypeMask) { }
WorldObjectWorker(WorldObject const* searcher, Work& work, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
: WorldObjectWorker(searcher->GetPhaseShift(), work, mapTypeMask) { }
};
// Gameobject searchers
template
struct GameObjectSearcherBase : WorldObjectSearcherBase>
{
template
GameObjectSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct GameObjectSearcher : GameObjectSearcherBase>
{
GameObjectSearcher(PhaseShift const& phaseShift, GameObject*& result, Check& check)
: GameObjectSearcherBase>(phaseShift, result, check) { }
GameObjectSearcher(WorldObject const* searcher, GameObject*& result, Check& check)
: GameObjectSearcher(searcher->GetPhaseShift(), result, check) { }
};
// Last accepted by Check GO if any (Check can change requirements at each call)
template
struct GameObjectLastSearcher : GameObjectSearcherBase>
{
GameObjectLastSearcher(PhaseShift const& phaseShift, GameObject*& result, Check& check)
: GameObjectSearcherBase>(phaseShift, result, check) { }
GameObjectLastSearcher(WorldObject const* searcher, GameObject*& result, Check& check)
: GameObjectLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct GameObjectListSearcher : GameObjectSearcherBase>
{
template
GameObjectListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: GameObjectSearcherBase>(phaseShift, container, check) { }
template
GameObjectListSearcher(WorldObject const* searcher, Container& container, Check& check)
: GameObjectListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
GameObjectListSearcher(PhaseShift const&, Container&, Check const&) -> GameObjectListSearcher;
template
GameObjectListSearcher(WorldObject const*, Container&, Check const&) -> GameObjectListSearcher;
template
struct GameObjectWorker : WorldObjectWorkerBase>
{
GameObjectWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
GameObjectWorker(WorldObject const* searcher, Work& work)
: GameObjectWorker(searcher->GetPhaseShift(), work) { }
};
// Unit searchers
template
struct UnitSearcherBase : WorldObjectSearcherBase>
{
template
UnitSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
// First accepted by Check Unit if any
template
struct UnitSearcher : UnitSearcherBase>
{
UnitSearcher(PhaseShift const& phaseShift, Unit*& result, Check& check)
: UnitSearcherBase>(phaseShift, result, check) { }
UnitSearcher(WorldObject const* searcher, Unit*& result, Check& check)
: UnitSearcher(searcher->GetPhaseShift(), result, check) { }
};
// Last accepted by Check Unit if any (Check can change requirements at each call)
template
struct UnitLastSearcher : UnitSearcherBase>
{
UnitLastSearcher(PhaseShift const& phaseShift, Unit*& result, Check& check)
: UnitSearcherBase>(phaseShift, result, check) { }
UnitLastSearcher(WorldObject const* searcher, Unit*& result, Check& check)
: UnitLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
// All accepted by Check units if any
template
struct UnitListSearcher : UnitSearcherBase>
{
template
UnitListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: UnitSearcherBase>(phaseShift, container, check) { }
template
UnitListSearcher(WorldObject const* searcher, Container& container, Check& check)
: UnitListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct UnitWorker : WorldObjectWorkerBase>
{
UnitWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
UnitWorker(WorldObject const* searcher, Work& work)
: UnitWorker(searcher->GetPhaseShift(), work) { }
};
// Creature searchers
template
struct CreatureSearcherBase : WorldObjectSearcherBase>
{
template
CreatureSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct CreatureSearcher : CreatureSearcherBase>
{
CreatureSearcher(PhaseShift const& phaseShift, Creature*& result, Check& check)
: CreatureSearcherBase>(phaseShift, result, check) { }
CreatureSearcher(WorldObject const* searcher, Creature*& result, Check& check)
: CreatureSearcher(searcher->GetPhaseShift(), result, check) { }
};
// Last accepted by Check Creature if any (Check can change requirements at each call)
template
struct CreatureLastSearcher : CreatureSearcherBase>
{
CreatureLastSearcher(PhaseShift const& phaseShift, Creature*& result, Check& check)
: CreatureSearcherBase>(phaseShift, result, check) { }
CreatureLastSearcher(WorldObject const* searcher, Creature*& result, Check& check)
: CreatureLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct CreatureListSearcher : CreatureSearcherBase>
{
template
CreatureListSearcher(PhaseShift const& phaseShift, Container& container, Check & check)
: CreatureSearcherBase>(phaseShift, container, check) { }
template
CreatureListSearcher(WorldObject const* searcher, Container& container, Check & check)
: CreatureListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct CreatureWorker : WorldObjectWorkerBase>
{
CreatureWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
CreatureWorker(WorldObject const* searcher, Work& work)
: CreatureWorker(searcher->GetPhaseShift(), work) { }
};
// Player searchers
template
struct PlayerSearcherBase : WorldObjectSearcherBase>
{
template
PlayerSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct PlayerSearcher : PlayerSearcherBase>
{
PlayerSearcher(PhaseShift const& phaseShift, Player*& result, Check& check)
: PlayerSearcherBase>(phaseShift, result, check) { }
PlayerSearcher(WorldObject const* searcher, Player*& result, Check& check)
: PlayerSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct PlayerLastSearcher : PlayerSearcherBase>
{
PlayerLastSearcher(PhaseShift const& phaseShift, Player*& result, Check& check)
: PlayerSearcherBase>(phaseShift, result, check) { }
PlayerLastSearcher(WorldObject const* searcher, Player*& result, Check& check)
: PlayerLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct PlayerListSearcher : PlayerSearcherBase>
{
template
PlayerListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: PlayerSearcherBase>(phaseShift, container, check) { }
template
PlayerListSearcher(WorldObject const* searcher, Container& container, Check& check)
: PlayerListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct PlayerWorker : WorldObjectWorkerBase>
{
PlayerWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
PlayerWorker(WorldObject const* searcher, Work& work)
: PlayerWorker(searcher->GetPhaseShift(), work) { }
};
template
struct PlayerDistWorker
{
WorldObject const* i_searcher;
float i_dist;
Work& i_work;
PlayerDistWorker(WorldObject const* searcher, float _dist, Work& _do)
: i_searcher(searcher), i_dist(_dist), i_work(_do) { }
void Visit(PlayerMapType const& m) const
{
for (GridReference const& ref : m)
if (ref.GetSource()->InSamePhase(i_searcher) && ref.GetSource()->IsWithinDist(i_searcher, i_dist))
i_work(ref.GetSource());
}
template void Visit(GridRefManager const&) const { }
};
// AreaTrigger searchers
template
struct AreaTriggerSearcherBase : WorldObjectSearcherBase>
{
template
AreaTriggerSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct AreaTriggerSearcher : AreaTriggerSearcherBase>
{
AreaTriggerSearcher(PhaseShift const& phaseShift, AreaTrigger*& result, Check& check)
: AreaTriggerSearcherBase>(phaseShift, result, check) { }
AreaTriggerSearcher(WorldObject const* searcher, AreaTrigger*& result, Check& check)
: AreaTriggerSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct AreaTriggerLastSearcher : AreaTriggerSearcherBase>
{
AreaTriggerLastSearcher(PhaseShift const& phaseShift, AreaTrigger*& result, Check& check)
: AreaTriggerSearcherBase>(phaseShift, result, check) { }
AreaTriggerLastSearcher(WorldObject const* searcher, AreaTrigger*& result, Check& check)
: AreaTriggerLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct AreaTriggerListSearcher : AreaTriggerSearcherBase>
{
template
AreaTriggerListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: AreaTriggerSearcherBase>(phaseShift, container, check) { }
template
AreaTriggerListSearcher(WorldObject const* searcher, Container& container, Check& check)
: AreaTriggerListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct AreaTriggerWorker : WorldObjectWorkerBase>
{
AreaTriggerWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
AreaTriggerWorker(WorldObject const* searcher, Work& work)
: AreaTriggerWorker(searcher->GetPhaseShift(), work) { }
};
// SceneObject searchers
template
struct SceneObjectSearcherBase : WorldObjectSearcherBase>
{
template
SceneObjectSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct SceneObjectSearcher : SceneObjectSearcherBase>
{
SceneObjectSearcher(PhaseShift const& phaseShift, SceneObject*& result, Check& check)
: SceneObjectSearcherBase>(phaseShift, result, check) { }
SceneObjectSearcher(WorldObject const* searcher, SceneObject*& result, Check& check)
: SceneObjectSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct SceneObjectLastSearcher : SceneObjectSearcherBase>
{
SceneObjectLastSearcher(PhaseShift const& phaseShift, SceneObject*& result, Check& check)
: SceneObjectSearcherBase>(phaseShift, result, check) { }
SceneObjectLastSearcher(WorldObject const* searcher, SceneObject*& result, Check& check)
: SceneObjectLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct SceneObjectListSearcher : SceneObjectSearcherBase>
{
template
SceneObjectListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: SceneObjectSearcherBase>(phaseShift, container, check) { }
template
SceneObjectListSearcher(WorldObject const* searcher, Container& container, Check& check)
: SceneObjectListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct SceneObjectWorker : WorldObjectWorkerBase>
{
SceneObjectWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
SceneObjectWorker(WorldObject const* searcher, Work& work)
: SceneObjectWorker(searcher->GetPhaseShift(), work) { }
};
// Conversation searchers
template
struct ConversationSearcherBase : WorldObjectSearcherBase>
{
template
ConversationSearcherBase(PhaseShift const& phaseShift, Container& result, Check& check)
: WorldObjectSearcherBase>(phaseShift, result, check) { }
};
template
struct ConversationSearcher : ConversationSearcherBase>
{
ConversationSearcher(PhaseShift const& phaseShift, Conversation*& result, Check& check)
: ConversationSearcherBase>(phaseShift, result, check) { }
ConversationSearcher(WorldObject const* searcher, Conversation*& result, Check& check)
: ConversationSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct ConversationLastSearcher : ConversationSearcherBase>
{
ConversationLastSearcher(PhaseShift const& phaseShift, Conversation*& result, Check& check)
: ConversationSearcherBase>(phaseShift, result, check) { }
ConversationLastSearcher(WorldObject const* searcher, Conversation*& result, Check& check)
: ConversationLastSearcher(searcher->GetPhaseShift(), result, check) { }
};
template
struct ConversationListSearcher : ConversationSearcherBase>
{
template
ConversationListSearcher(PhaseShift const& phaseShift, Container& container, Check& check)
: ConversationSearcherBase>(phaseShift, container, check) { }
template
ConversationListSearcher(WorldObject const* searcher, Container& container, Check& check)
: ConversationListSearcher(searcher->GetPhaseShift(), container, check) { }
};
template
struct ConversationWorker : WorldObjectWorkerBase>
{
ConversationWorker(PhaseShift const& phaseShift, Work& work)
: WorldObjectWorkerBase>(phaseShift, work) { }
ConversationWorker(WorldObject const* searcher, Work& work)
: ConversationWorker(searcher->GetPhaseShift(), work) { }
};
// CHECKS && DO classes
// CHECK modifiers
class InRangeCheckCustomizer
{
public:
explicit InRangeCheckCustomizer(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { }
bool Test(WorldObject const* o) const
{
return i_obj.IsWithinDist(o, i_range);
}
void Update(WorldObject const* /*o*/) { }
private:
WorldObject const& i_obj;
float i_range;
};
class NearestCheckCustomizer
{
public:
explicit NearestCheckCustomizer(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { }
bool Test(WorldObject const* o) const
{
return i_obj.IsWithinDist(o, i_range);
}
void Update(WorldObject const* o)
{
i_range = i_obj.GetDistance(o);
}
private:
WorldObject const& i_obj;
float i_range;
};
// WorldObject check classes
class TC_GAME_API AnyDeadUnitObjectInRangeCheck
{
public:
AnyDeadUnitObjectInRangeCheck(WorldObject* searchObj, float range) : i_searchObj(searchObj), i_range(range) { }
bool operator()(Player* u);
bool operator()(Corpse* u);
bool operator()(Creature* u);
template bool operator()(NOT_INTERESTED*) { return false; }
protected:
WorldObject const* const i_searchObj;
float i_range;
};
class TC_GAME_API AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck, public WorldObjectSpellTargetCheck
{
public:
AnyDeadUnitSpellTargetInRangeCheck(WorldObject* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check, SpellTargetObjectTypes objectType)
: AnyDeadUnitObjectInRangeCheck(searchObj, range), WorldObjectSpellTargetCheck(searchObj, searchObj, spellInfo, check, nullptr, objectType)
{ }
bool operator()(Player* u);
bool operator()(Corpse* u);
bool operator()(Creature* u);
template bool operator()(NOT_INTERESTED*) { return false; }
};
// WorldObject do classes
class RespawnDo
{
public:
RespawnDo() { }
void operator()(Creature* u) const { u->Respawn(); }
void operator()(GameObject* u) const { u->Respawn(); }
void operator()(WorldObject const*) const { }
};
// GameObject checks
class GameObjectFocusCheck
{
public:
GameObjectFocusCheck(WorldObject const* caster, uint32 focusId) : _caster(caster), _focusId(focusId) { }
bool operator()(GameObject* go) const
{
if (go->GetGOInfo()->GetSpellFocusType() != _focusId)
return false;
if (!go->isSpawned())
return false;
float const dist = go->GetGOInfo()->GetSpellFocusRadius();
return go->IsWithinDist(_caster, dist);
}
private:
WorldObject const* _caster;
uint32 _focusId;
};
// Find the nearest Fishing hole and return true only if source object is in range of hole
class NearestGameObjectFishingHole
{
public:
NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { }
bool operator()(GameObject* go)
{
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDist(go, i_range) && i_obj.IsWithinDist(go, (float)go->GetGOInfo()->fishingHole.radius))
{
i_range = i_obj.GetDistance(go);
return true;
}
return false;
}
private:
WorldObject const& i_obj;
float i_range;
// prevent clone
NearestGameObjectFishingHole(NearestGameObjectFishingHole const&) = delete;
};
class NearestGameObjectCheck
{
public:
NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999.f) { }
bool operator()(GameObject* go)
{
if (i_obj.IsWithinDist(go, i_range))
{
i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const& i_obj;
float i_range;
// prevent clone this object
NearestGameObjectCheck(NearestGameObjectCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO)
class NearestGameObjectEntryInObjectRangeCheck
{
public:
NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj, uint32 entry, float range, bool spawnedOnly = true) : i_obj(obj), i_entry(entry), i_range(range), i_spawnedOnly(spawnedOnly) { }
bool operator()(GameObject* go)
{
if ((!i_spawnedOnly || go->isSpawned()) && go->GetEntry() == i_entry && go->GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDist(go, i_range))
{
i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const& i_obj;
uint32 i_entry;
float i_range;
bool i_spawnedOnly;
// prevent clone this object
NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest unspawned GO)
class NearestUnspawnedGameObjectEntryInObjectRangeCheck
{
public:
NearestUnspawnedGameObjectEntryInObjectRangeCheck(WorldObject const& obj, uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) { }
bool operator()(GameObject* go)
{
if (!go->isSpawned() && go->GetEntry() == i_entry && go->GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDist(go, i_range))
{
i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const& i_obj;
uint32 i_entry;
float i_range;
// prevent clone this object
NearestUnspawnedGameObjectEntryInObjectRangeCheck(NearestUnspawnedGameObjectEntryInObjectRangeCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO with a certain type)
class NearestGameObjectTypeInObjectRangeCheck
{
public:
NearestGameObjectTypeInObjectRangeCheck(WorldObject const& obj, GameobjectTypes type, float range) : i_obj(obj), i_type(type), i_range(range) { }
bool operator()(GameObject* go)
{
if (go->GetGoType() == i_type && i_obj.IsWithinDist(go, i_range))
{
i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const& i_obj;
GameobjectTypes i_type;
float i_range;
// prevent clone this object
NearestGameObjectTypeInObjectRangeCheck(NearestGameObjectTypeInObjectRangeCheck const&) = delete;
};
// Unit checks
class MostHPMissingInRange
{
public:
MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) { }
bool operator()(Unit* u)
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDist(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
{
i_hp = u->GetMaxHealth() - u->GetHealth();
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint64 i_hp;
};
class MostHPPercentMissingInRange
{
public:
MostHPPercentMissingInRange(Unit const* obj, float range, uint32 minHpPct, uint32 maxHpPct) : i_obj(obj), i_range(range), i_minHpPct(minHpPct), i_maxHpPct(maxHpPct), i_hpPct(101.f) { }
bool operator()(Unit* u)
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDist(u, i_range) && i_minHpPct <= u->GetHealthPct() && u->GetHealthPct() <= i_maxHpPct && u->GetHealthPct() < i_hpPct)
{
i_hpPct = u->GetHealthPct();
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
float i_minHpPct, i_maxHpPct, i_hpPct;
};
class FriendlyBelowHpPctEntryInRange
{
public:
FriendlyBelowHpPctEntryInRange(Unit const* obj, uint32 entry, float range, uint8 pct, bool excludeSelf) : i_obj(obj), i_entry(entry), i_range(range), i_pct(pct), i_excludeSelf(excludeSelf) { }
bool operator()(Unit* u)
{
if (i_excludeSelf && i_obj->GetGUID() == u->GetGUID())
return false;
if (u->GetEntry() == i_entry && u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDist(u, i_range) && u->HealthBelowPct(i_pct))
return true;
return false;
}
private:
Unit const* i_obj;
uint32 i_entry;
float i_range;
uint8 i_pct;
bool i_excludeSelf;
};
class FriendlyCCedInRange
{
public:
FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) { }
bool operator()(Unit* u) const
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDist(u, i_range) &&
(u->IsFeared() || u->IsCharmed() || u->HasRootAura() || u->HasUnitState(UNIT_STATE_STUNNED) || u->HasUnitState(UNIT_STATE_CONFUSED)))
{
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
};
class FriendlyMissingBuffInRange
{
public:
FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) { }
bool operator()(Unit* u) const
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDist(u, i_range) && !u->HasAura(i_spell))
return true;
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_spell;
};
class AnyUnfriendlyUnitInObjectRangeCheck
{
public:
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
bool operator()(Unit* u) const
{
if (u->IsAlive() && i_obj->IsWithinDist(u, i_range) && !i_funit->IsFriendlyTo(u))
return true;
return false;
}
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
};
class NearestAttackableNoTotemUnitInObjectRangeCheck
{
public:
NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) { }
bool operator()(Unit* u)
{
if (!u->IsAlive())
return false;
if (u->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
return false;
if (u->GetTypeId() == TYPEID_UNIT && u->ToCreature()->IsTotem())
return false;
if (!u->isTargetableForAttack(false))
return false;
if (!i_obj->IsWithinDist(u, i_range) || !i_obj->IsValidAttackTarget(u))
return false;
i_range = i_obj->GetDistance(*u);
return true;
}
private:
WorldObject const* i_obj;
float i_range;
};
class AnyFriendlyUnitInObjectRangeCheck
{
public:
AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true)
: i_obj(obj), i_funit(funit), i_range(range), i_playerOnly(playerOnly), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius) { }
bool operator()(Unit* u) const
{
if (!u->IsAlive())
return false;
float searchRadius = i_range;
if (i_incOwnRadius)
searchRadius += i_obj->GetCombatReach();
if (i_incTargetRadius)
searchRadius += u->GetCombatReach();
if (!u->IsInMap(i_obj) || !u->InSamePhase(i_obj) || !u->IsWithinVerticalCylinder(*i_obj, searchRadius, searchRadius, true))
return false;
if (!i_funit->IsFriendlyTo(u))
return false;
return !i_playerOnly || u->GetTypeId() == TYPEID_PLAYER;
}
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
bool i_playerOnly;
bool i_incOwnRadius;
bool i_incTargetRadius;
};
class AnyGroupedUnitInObjectRangeCheck
{
public:
AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false, bool incOwnRadius = true, bool incTargetRadius = true)
: _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius) { }
bool operator()(Unit* u) const
{
if (_playerOnly && u->GetTypeId() != TYPEID_PLAYER)
return false;
if (_raid)
{
if (!_refUnit->IsInRaidWith(u))
return false;
}
else if (!_refUnit->IsInPartyWith(u))
return false;
if (_refUnit->IsHostileTo(u))
return false;
if (!u->IsAlive())
return false;
float searchRadius = _range;
if (i_incOwnRadius)
searchRadius += _source->GetCombatReach();
if (i_incTargetRadius)
searchRadius += u->GetCombatReach();
return u->IsInMap(_source) && u->InSamePhase(_source) && u->IsWithinVerticalCylinder(*_source, searchRadius, searchRadius, true);
}
private:
WorldObject const* _source;
Unit const* _refUnit;
float _range;
bool _raid;
bool _playerOnly;
bool i_incOwnRadius;
bool i_incTargetRadius;
};
class AnyUnitInObjectRangeCheck
{
public:
AnyUnitInObjectRangeCheck(WorldObject const* obj, float range, bool check3D = true, bool reqAlive = true) : i_obj(obj), i_range(range), i_check3D(check3D), i_reqAlive(reqAlive) { }
bool operator()(Unit* u) const
{
if (i_reqAlive && !u->IsAlive())
return false;
if (!i_obj->IsWithinDist(u, i_range, i_check3D))
return false;
return true;
}
private:
WorldObject const* i_obj;
float i_range;
bool i_check3D;
bool i_reqAlive;
};
// Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit)
class NearestAttackableUnitInObjectRangeCheck
{
public:
NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
bool operator()(Unit* u)
{
if (u->isTargetableForAttack() && i_obj->IsWithinDist(u, i_range) &&
(i_funit->IsInCombatWith(u) || i_funit->IsHostileTo(u)) && i_obj->CanSeeOrDetect(u))
{
i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
// prevent clone this object
NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&) = delete;
};
class AnyAoETargetUnitInObjectRangeCheck
{
public:
AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr, bool incOwnRadius = true, bool incTargetRadius = true)
: i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range), i_incOwnRadius(incOwnRadius), i_incTargetRadius(incTargetRadius)
{
}
bool operator()(Unit* u) const
{
// Check contains checks for: live, uninteractible, non-attackable flags, flight check and GM check, ignore totems
if (u->GetTypeId() == TYPEID_UNIT && u->IsTotem())
return false;
if (_spellInfo)
{
if (!u->IsPlayer())
{
if (_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
return false;
if (_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && u->IsControlledByPlayer())
return false;
}
else if (_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
return false;
}
if (!i_funit->IsValidAttackTarget(u, _spellInfo))
return false;
float searchRadius = i_range;
if (i_incOwnRadius)
searchRadius += i_obj->GetCombatReach();
if (i_incTargetRadius)
searchRadius += u->GetCombatReach();
return u->IsInMap(i_obj) && u->InSamePhase(i_obj) && u->IsWithinVerticalCylinder(*i_obj, searchRadius, searchRadius, true);
}
private:
WorldObject const* i_obj;
Unit const* i_funit;
SpellInfo const* _spellInfo;
float i_range;
bool i_incOwnRadius;
bool i_incTargetRadius;
};
// do attack at call of help to friendly crearture
class CallOfHelpCreatureInRangeDo
{
public:
CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range)
: i_funit(funit), i_enemy(enemy), i_range(range) { }
void operator()(Creature* u) const
{
if (u == i_funit)
return;
if (!u->CanAssistTo(i_funit, i_enemy, false))
return;
// too far
// Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big
if (!u->IsWithinDist(i_funit, i_range, true, false, false))
return;
// only if see assisted creature's enemy
if (!u->IsWithinLOSInMap(i_enemy))
return;
u->EngageWithTarget(i_enemy);
}
private:
Unit* const i_funit;
Unit* const i_enemy;
float i_range;
};
struct AnyDeadUnitCheck
{
bool operator()(Unit* u) const
{
return !u->IsAlive();
}
};
// Creature checks
class NearestHostileUnitCheck
{
public:
explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0.f, bool playerOnly = false) : me(creature), i_playerOnly(playerOnly)
{
m_range = (dist == 0.f ? 9999.f : dist);
}
bool operator()(Unit* u)
{
if (!me->IsWithinDist(u, m_range))
return false;
if (!me->IsValidAttackTarget(u))
return false;
if (i_playerOnly && u->GetTypeId() != TYPEID_PLAYER)
return false;
m_range = me->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
private:
Creature const* me;
float m_range;
bool i_playerOnly;
NearestHostileUnitCheck(NearestHostileUnitCheck const&) = delete;
};
class NearestHostileUnitInAttackDistanceCheck
{
public:
explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0.f) : me(creature)
{
m_range = (dist == 0.f ? 9999.f : dist);
m_force = (dist == 0.f ? false : true);
}
bool operator()(Unit* u)
{
if (!me->IsWithinDist(u, m_range))
return false;
if (!me->CanSeeOrDetect(u))
return false;
if (m_force)
{
if (!me->IsValidAttackTarget(u))
return false;
}
else if (!me->CanStartAttack(u, false))
return false;
m_range = me->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
private:
Creature const* me;
float m_range;
bool m_force;
NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&) = delete;
};
class NearestHostileUnitInAggroRangeCheck
{
public:
explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false, bool ignoreCivilians = false) : _me(creature), _useLOS(useLOS), _ignoreCivilians(ignoreCivilians) { }
bool operator()(Unit* u) const
{
if (!u->IsHostileTo(_me))
return false;
if (!u->IsWithinDist(_me, _me->GetAggroRange(u)))
return false;
if (!_me->IsValidAttackTarget(u))
return false;
if (_useLOS && !u->IsWithinLOSInMap(_me))
return false;
// pets in aggressive do not attack civilians
if (_ignoreCivilians)
if (Creature* c = u->ToCreature())
if (c->IsCivilian())
return false;
return true;
}
private:
Creature const* _me;
bool _useLOS;
bool _ignoreCivilians;
NearestHostileUnitInAggroRangeCheck(NearestHostileUnitInAggroRangeCheck const&) = delete;
};
class AnyAssistCreatureInRangeCheck
{
public:
AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range)
: i_funit(funit), i_enemy(enemy), i_range(range) { }
bool operator()(Creature* u) const
{
if (u == i_funit)
return false;
if (!u->CanAssistTo(i_funit, i_enemy))
return false;
// too far
// Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big
if (!i_funit->IsWithinDist(u, i_range, true, false, false))
return false;
// only if see assisted creature
if (!i_funit->IsWithinLOSInMap(u))
return false;
return true;
}
private:
Unit* const i_funit;
Unit* const i_enemy;
float i_range;
};
class NearestAssistCreatureInCreatureRangeCheck
{
public:
NearestAssistCreatureInCreatureRangeCheck(Creature* obj, Unit* enemy, float range)
: i_obj(obj), i_enemy(enemy), i_range(range) { }
bool operator()(Creature* u)
{
if (u == i_obj)
return false;
if (!u->CanAssistTo(i_obj, i_enemy))
return false;
// Don't use combat reach distance, range must be an absolute value, otherwise the chain aggro range will be too big
if (!i_obj->IsWithinDist(u, i_range, true, false, false))
return false;
if (!i_obj->IsWithinLOSInMap(u))
return false;
i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
private:
Creature* const i_obj;
Unit* const i_enemy;
float i_range;
// prevent clone this object
NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature)
class NearestCreatureEntryWithLiveStateInObjectRangeCheck
{
public:
NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj, uint32 entry, bool alive, float range)
: i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) { }
bool operator()(Creature* u)
{
if (u->getDeathState() != DEAD
&& u->GetEntry() == i_entry
&& u->IsAlive() == i_alive
&& u->GetGUID() != i_obj.GetGUID()
&& i_obj.IsWithinDist(u, i_range)
&& u->CheckPrivateObjectOwnerVisibility(&i_obj))
{
i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check
return true;
}
return false;
}
private:
WorldObject const& i_obj;
uint32 i_entry;
bool i_alive;
float i_range;
// prevent clone this object
NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&) = delete;
};
template
class CreatureWithOptionsInObjectRangeCheck
{
public:
CreatureWithOptionsInObjectRangeCheck(WorldObject const& obj, Customizer& customizer, FindCreatureOptions const& args)
: i_obj(obj), i_args(args), i_customizer(customizer) { }
bool operator()(Creature const* u) const
{
if (u->getDeathState() == DEAD) // Despawned
return false;
if (u->GetGUID() == i_obj.GetGUID())
return false;
if (!i_customizer.Test(u))
return false;
if (i_args.CreatureId && u->GetEntry() != i_args.CreatureId)
return false;
if (i_args.StringId && !u->HasStringId(*i_args.StringId))
return false;
if (i_args.IsAlive.has_value())
{
switch (*i_args.IsAlive)
{
case FindCreatureAliveState::Alive:
{
if (!u->IsAlive())
return false;
break;
}
case FindCreatureAliveState::Dead:
{
if (u->IsAlive())
return false;
break;
}
case FindCreatureAliveState::EffectivelyAlive:
{
if (!u->IsAlive() || u->HasUnitFlag2(UNIT_FLAG2_FEIGN_DEATH))
return false;
break;
}
case FindCreatureAliveState::EffectivelyDead:
{
if (u->IsAlive() && !u->HasUnitFlag2(UNIT_FLAG2_FEIGN_DEATH))
return false;
break;
}
default:
break;
}
}
if (i_args.IsSummon.has_value() && u->IsSummon() != i_args.IsSummon)
return false;
if (i_args.IsInCombat.has_value() && u->IsInCombat() != i_args.IsInCombat)
return false;
if ((i_args.OwnerGuid && u->GetOwnerGUID() != i_args.OwnerGuid)
|| (i_args.CharmerGuid && u->GetCharmerGUID() != i_args.CharmerGuid)
|| (i_args.CreatorGuid && u->GetCreatorGUID() != i_args.CreatorGuid)
|| (i_args.DemonCreatorGuid && u->GetDemonCreatorGUID() != i_args.DemonCreatorGuid)
|| (i_args.PrivateObjectOwnerGuid && u->GetPrivateObjectOwner() != i_args.PrivateObjectOwnerGuid))
return false;
if (i_args.IgnorePrivateObjects && u->IsPrivateObject())
return false;
if (i_args.IgnoreNotOwnedPrivateObjects && !u->CheckPrivateObjectOwnerVisibility(&i_obj))
return false;
if (i_args.AuraSpellId && !u->HasAura(*i_args.AuraSpellId))
return false;
i_customizer.Update(u);
return true;
}
private:
WorldObject const& i_obj;
FindCreatureOptions const& i_args;
Customizer& i_customizer;
};
template
class GameObjectWithOptionsInObjectRangeCheck
{
public:
GameObjectWithOptionsInObjectRangeCheck(WorldObject const& obj, Customizer& customizer, FindGameObjectOptions const& args)
: i_obj(obj), i_args(args), i_customizer(customizer) { }
bool operator()(GameObject const* go) const
{
if (i_args.IsSpawned.has_value() && i_args.IsSpawned != go->isSpawned()) // Despawned
return false;
if (go->GetGUID() == i_obj.GetGUID())
return false;
if (!i_customizer.Test(go))
return false;
if (i_args.GameObjectId && go->GetEntry() != i_args.GameObjectId)
return false;
if (i_args.StringId && !go->HasStringId(*i_args.StringId))
return false;
if (i_args.IsSummon.has_value() && (go->GetSpawnId() == 0) != i_args.IsSummon)
return false;
if ((i_args.OwnerGuid && go->GetOwnerGUID() != i_args.OwnerGuid)
|| (i_args.PrivateObjectOwnerGuid && go->GetPrivateObjectOwner() != i_args.PrivateObjectOwnerGuid))
return false;
if (i_args.IgnorePrivateObjects && go->IsPrivateObject())
return false;
if (i_args.IgnoreNotOwnedPrivateObjects && !go->CheckPrivateObjectOwnerVisibility(&i_obj))
return false;
if (i_args.GameObjectType && go->GetGoType() != i_args.GameObjectType)
return false;
i_customizer.Update(go);
return true;
}
private:
WorldObject const& i_obj;
FindGameObjectOptions const& i_args;
Customizer& i_customizer;
};
class AnyPlayerInPositionRangeCheck
{
public:
AnyPlayerInPositionRangeCheck(Position const* pos, float range, bool reqAlive = true) : _pos(pos), _range(range), _reqAlive(reqAlive) { }
bool operator()(Player* u)
{
if (_reqAlive && !u->IsAlive())
return false;
if (!u->IsWithinDist3d(_pos, _range))
return false;
return true;
}
private:
Position const* _pos;
float _range;
bool _reqAlive;
};
class NearestPlayerInObjectRangeCheck
{
public:
NearestPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) { }
bool operator()(Player* u)
{
if (u->IsAlive() && i_obj->IsWithinDist(u, i_range))
{
i_range = i_obj->GetDistance(u);
return true;
}
return false;
}
private:
WorldObject const* i_obj;
float i_range;
NearestPlayerInObjectRangeCheck(NearestPlayerInObjectRangeCheck const&) = delete;
};
class AllFriendlyCreaturesInGrid
{
public:
AllFriendlyCreaturesInGrid(Unit const* obj) : unit(obj) { }
bool operator()(Unit* u) const
{
if (u->IsAlive() && u->IsVisible() && u->IsFriendlyTo(unit))
return true;
return false;
}
private:
Unit const* unit;
};
class AllGameObjectsWithEntryInRange
{
public:
AllGameObjectsWithEntryInRange(WorldObject const* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }
bool operator()(GameObject* go) const
{
if ((!m_uiEntry || go->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(go, m_fRange, false))
return true;
return false;
}
private:
WorldObject const* m_pObject;
uint32 m_uiEntry;
float m_fRange;
};
class AllCreaturesOfEntryInRange
{
public:
AllCreaturesOfEntryInRange(WorldObject const* object, uint32 entry, float maxRange = 0.0f) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }
bool operator()(Unit* unit) const
{
if (m_uiEntry)
{
if (unit->GetEntry() != m_uiEntry)
return false;
}
if (m_fRange)
{
if (m_fRange > 0.0f && !m_pObject->IsWithinDist(unit, m_fRange, false))
return false;
if (m_fRange < 0.0f && m_pObject->IsWithinDist(unit, m_fRange, false))
return false;
}
return true;
}
private:
WorldObject const* m_pObject;
uint32 m_uiEntry;
float m_fRange;
};
class PlayerAtMinimumRangeAway
{
public:
PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : unit(unit), fRange(fMinRange) { }
bool operator()(Player* player) const
{
//No threat list check, must be done explicit if expected to be in combat with creature
if (!player->IsGameMaster() && player->IsAlive() && !unit->IsWithinDist(player, fRange, false))
return true;
return false;
}
private:
Unit const* unit;
float fRange;
};
class GameObjectInRangeCheck
{
public:
GameObjectInRangeCheck(float _x, float _y, float _z, float _range, uint32 _entry = 0) :
x(_x), y(_y), z(_z), range(_range), entry(_entry) { }
bool operator()(GameObject* go) const
{
if (!entry || (go->GetGOInfo() && go->GetGOInfo()->entry == entry))
return go->IsInRange(x, y, z, range);
else return false;
}
private:
float x, y, z, range;
uint32 entry;
};
class AllWorldObjectsInRange
{
public:
AllWorldObjectsInRange(WorldObject const* object, float maxRange) : m_pObject(object), m_fRange(maxRange) { }
bool operator()(WorldObject* go) const
{
return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->InSamePhase(go);
}
private:
WorldObject const* m_pObject;
float m_fRange;
};
class ObjectTypeIdCheck
{
public:
ObjectTypeIdCheck(TypeID typeId, bool equals) : _typeId(typeId), _equals(equals) { }
bool operator()(WorldObject* object) const
{
return (object->GetTypeId() == _typeId) == _equals;
}
private:
TypeID _typeId;
bool _equals;
};
class ObjectGUIDCheck
{
public:
ObjectGUIDCheck(ObjectGuid GUID) : _GUID(GUID) { }
bool operator()(WorldObject* object) const
{
return object->GetGUID() == _GUID;
}
private:
ObjectGuid _GUID;
};
class HeightDifferenceCheck
{
public:
HeightDifferenceCheck(WorldObject* go, float diff, bool reverse)
: _baseObject(go), _difference(diff), _reverse(reverse)
{
}
bool operator()(WorldObject* unit) const
{
return (unit->GetPositionZ() - _baseObject->GetPositionZ() > _difference) != _reverse;
}
private:
WorldObject* _baseObject;
float _difference;
bool _reverse;
};
class UnitAuraCheck
{
public:
UnitAuraCheck(bool present, uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty) : _present(present), _spellId(spellId), _casterGUID(casterGUID) { }
bool operator()(Unit* unit) const
{
return unit->HasAura(_spellId, _casterGUID) == _present;
}
bool operator()(WorldObject* object) const
{
return object->ToUnit() && object->ToUnit()->HasAura(_spellId, _casterGUID) == _present;
}
private:
bool _present;
uint32 _spellId;
ObjectGuid _casterGUID;
};
class ObjectEntryAndPrivateOwnerIfExistsCheck
{
public:
ObjectEntryAndPrivateOwnerIfExistsCheck(ObjectGuid ownerGUID, uint32 entry) : _ownerGUID(ownerGUID), _entry(entry) { }
bool operator()(WorldObject* object) const
{
return object->GetEntry() == _entry && (!object->IsPrivateObject() || object->GetPrivateObjectOwner() == _ownerGUID);
}
private:
ObjectGuid _ownerGUID;
uint32 _entry;
};
class NearestAreaTriggerEntryInObjectRangeCheck
{
public:
NearestAreaTriggerEntryInObjectRangeCheck(WorldObject const& obj, uint32 entry, float range, bool spawnedOnly = false) : i_obj(obj), i_entry(entry), i_range(range), i_spawnedOnly(spawnedOnly) { }
bool operator()(AreaTrigger const* at)
{
if ((!i_spawnedOnly || at->IsStaticSpawn()) && at->GetEntry() == i_entry && at->GetGUID() != i_obj.GetGUID() && i_obj.IsWithinDist(at, i_range))
{
i_range = i_obj.GetDistance(at);
return true;
}
return false;
}
private:
WorldObject const& i_obj;
uint32 i_entry;
float i_range;
bool i_spawnedOnly;
// prevent clone this object
NearestAreaTriggerEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&) = delete;
};
// Player checks and do
// Prepare using Builder localized packets with caching and send to player
template
class LocalizedDo
{
using LocalizedAction = std::remove_pointer_t()(LocaleConstant{}))>;
public:
explicit LocalizedDo(Localizer& localizer) : _localizer(localizer) { }
void operator()(Player const* p);
private:
Localizer& _localizer;
std::vector> _localizedCache; // 0 = default, i => i-1 locale index
};
}
#endif