46 :
UnitAI(creature), me(creature), _boundary(nullptr),
47 _negateBoundary(false), _scriptId(scriptId ? scriptId : creature->GetScriptId()), _isEngaged(false), _moveInLOSLocked(false)
49 ASSERT(
_scriptId,
"A CreatureAI was initialized with an invalid scriptId!");
95 if (
Player* player = ref.GetSource())
201 if (!summon->GetVehicle() &&
ShouldFollowOnSpawn(summon->m_Properties) && summon->CanFollowOwner())
205 summon->GetMotionMaster()->Clear();
206 summon->GetMotionMaster()->MoveFollow(owner,
PET_FOLLOW_DIST, summon->GetFollowAngle());
279 TC_LOG_ERROR(
"scripts.ai",
"CreatureAI::EngagementStart called even though creature is already engaged. Creature debug info:\n{}",
me->
GetDebugInfo());
291 TC_LOG_DEBUG(
"scripts.ai",
"CreatureAI::EngagementOver called even though creature is not currently engaged. Creature debug info:\n{}",
me->
GetDebugInfo());
330 if (victim &&
me->
Attack(victim,
true))
355 typedef std::pair<int32, int32> coordinate;
363 std::queue<coordinate> Q;
364 std::unordered_set<coordinate> alreadyChecked;
365 std::unordered_set<coordinate> outOfBounds;
380 bool boundsWarning =
false;
384 coordinate front = Q.front();
385 bool hasOutOfBoundsNeighbor =
false;
386 for (coordinate
const& off : std::list<coordinate>{ {1, 0}, {0, 1}, {-1, 0}, {0, -1} })
388 coordinate next(front.first + off.first, front.second + off.second);
391 boundsWarning =
true;
394 if (alreadyChecked.find(next) == alreadyChecked.end())
401 outOfBounds.insert(next);
402 hasOutOfBoundsNeighbor =
true;
404 alreadyChecked.insert(next);
406 else if (outOfBounds.find(next) != outOfBounds.end())
407 hasOutOfBoundsNeighbor =
true;
409 if (fill || hasOutOfBoundsNeighbor)
415 point->SetImmuneToAll(
true);
416 if (!hasOutOfBoundsNeighbor)
417 point->SetUninteractible(
true);
440 if (!areaBoundary->IsWithinBoundary(pos))
const float BOUNDARY_VISUALIZE_SPAWN_HEIGHT
const uint32 BOUNDARY_VISUALIZE_CREATURE
AISpellInfoType * GetAISpellInfo(uint32 spellId, Difficulty difficulty)
const int32 BOUNDARY_VISUALIZE_FAILSAFE_LIMIT
const int8 BOUNDARY_VISUALIZE_STEP_SIZE
const float BOUNDARY_VISUALIZE_CREATURE_SCALE
static bool ShouldFollowOnSpawn(SummonPropertiesEntry const *properties)
std::vector< AreaBoundary const * > CreatureBoundary
std::chrono::seconds Seconds
Seconds shorthand typedef.
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
@ LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED
@ LANG_CREATURE_MOVEMENT_NOT_BOUNDED
@ LANG_CREATURE_NO_INTERIOR_POINT_FOUND
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
@ TEMPSUMMON_TIMED_DESPAWN
std::optional< T > Optional
Optional helper class to wrap optional values within.
static bool CanBeginCombat(Unit const *a, Unit const *b)
int32 VisualizeBoundary(Seconds duration, Unit *owner=nullptr, bool fill=false) const
virtual void MoveInLineOfSight(Unit *)
static bool IsInBounds(CreatureBoundary const &boundary, Position const *who)
void TriggerAlert(Unit const *who) const
CreatureBoundary const * _boundary
void OnOwnerCombatInteraction(Unit *target)
Creature * DoSummonFlyer(uint32 entry, WorldObject *obj, float flightZ, float radius=5.0f, Milliseconds despawnTime=30s, TempSummonType summonType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
void JustEnteredCombat(Unit *) override
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
bool _EnterEvadeMode(EvadeReason why=EvadeReason::Other)
void OnCharmed(bool isNew) override
CreatureAI(Creature *creature, uint32 scriptId={})
virtual void JustAppeared()
virtual bool CheckInRoom()
virtual Optional< QuestGiverStatus > GetDialogStatus(Player const *player)
== Gossip system ================================
bool IsInBoundary(Position const *who=nullptr) const
void SetBoundary(CreatureBoundary const *boundary, bool negativeBoundaries=false)
void AttackStart(Unit *victim) override
== Triggered Actions Requested ==================
void EngagementStart(Unit *who)
Creature * DoSummon(uint32 entry, Position const &pos, Milliseconds despawnTime=30s, TempSummonType summonType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
void MoveInLineOfSight_Safe(Unit *who)
== Reactions At =================================
bool IsTapListNotClearedOnEvade() const
void DoImmediateBoundaryCheck()
void StartDefaultCombatMovement(Unit *victim, Optional< float > range={}, Optional< float > angle={})
bool _IsTargetAcceptable(Unit const *target) const
void GetHomePosition(float &x, float &y, float &z, float &ori) const
void SetLastDamagedTime(time_t val)
bool HasReactState(ReactStates state) const
void DoNotReacquireSpellFocusTarget()
bool IsEngaged() const override
void ResetPlayerDamageReq()
void SetCannotReachTarget(bool cannotReach)
void SetTappedBy(Unit const *unit, bool withGroup=true)
void AtEngage(Unit *target) override
void AtDisengage() override
void SetTarget(ObjectGuid const &guid) override
bool IsStateRestoredOnEvade() const
void SendAIReaction(AiReaction reactionType)
bool IsInEvadeMode() const
std::string GetDebugInfo() const override
bool CanStartAttack(Unit const *u, bool force) const
static char const * ToConstant(Enum value)
PlayerList const & GetPlayers() const
void MoveFollow(Unit *target, float dist, Optional< ChaseAngle > angle={}, Optional< Milliseconds > duration={}, bool ignoreTargetWalk=false, MovementSlot slot=MOTION_SLOT_ACTIVE, Optional< Scripting::v2::ActionResultSetter< MovementStopReason > > &&scriptResult={})
void MoveDistract(uint32 time, float orientation)
static ObjectGuid const Empty
std::string ToString() const
static ObjectGuid GetGUID(Object const *o)
static std::unordered_map< std::pair< uint32, Difficulty >, AISpellInfoType > AISpellInfo
virtual void OnCharmed(bool isNew)
void ClearUnitState(uint32 f)
Vehicle * GetVehicle() const
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Unit * GetVehicleBase() const
MotionMaster * GetMotionMaster()
TempSummon * ToTempSummon()
void AddUnitState(uint32 f)
Unit * GetCharmerOrOwner() const
bool Attack(Unit *victim, bool meleeAttack)
void EngageWithTarget(Unit *who)
virtual float GetFollowAngle() const
bool HasUnitState(const uint32 f) const
SpellHistory * GetSpellHistory()
ObjectGuid LastCharmerGUID
void RemoveAurasOnEvade()
bool IsHostileTo(WorldObject const *target) const
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Position GetRandomNearPosition(float radius)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
constexpr float GetPositionX() const
constexpr float GetPositionY() const
float GetAbsoluteAngle(float x, float y) const
constexpr void GetPosition(float &x, float &y) const
constexpr float GetPositionZ() const
EnumFlag< SummonPropertiesFlags > GetFlags() const