/*
* 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_UNITAI_H
#define TRINITY_UNITAI_H
#include "Errors.h"
#include "Hash.h"
#include "ObjectGuid.h"
#include "SharedDefines.h"
#include "SpellDefines.h"
#include "UnitAICommon.h"
#include
#define CAST_AI(a, b) (dynamic_cast(b))
#define ENSURE_AI(a,b) (EnsureAI(b))
template
T* EnsureAI(U* ai)
{
T* cast_ai = dynamic_cast(ai);
ASSERT(cast_ai);
return cast_ai;
}
class Player;
class Quest;
class SpellInfo;
class Unit;
struct AISpellInfoType;
enum DamageEffectType : uint8;
enum Difficulty : uint8;
enum MovementGeneratorType : uint8;
enum SpellEffIndex : uint8;
class TC_GAME_API UnitAI
{
protected:
Unit* const me;
public:
explicit UnitAI(Unit* unit) : me(unit) { }
virtual ~UnitAI() { }
virtual bool CanAIAttack(Unit const* /*target*/) const { return true; }
virtual void AttackStart(Unit* victim);
virtual void UpdateAI(uint32 diff) = 0;
virtual void InitializeAI();
virtual void Reset() { }
// Called when unit's charm state changes with isNew = false
// Implementation should call me->ScheduleAIChange() if AI replacement is desired
// If this call is made, AI will be replaced on the next tick
// When replacement is made, OnCharmed is called with isNew = true
virtual void OnCharmed(bool isNew);
// Pass parameters between AI
virtual void DoAction([[maybe_unused]] int32 param) { }
virtual uint32 GetData([[maybe_unused]] uint32 id) const { return 0; }
virtual void SetData([[maybe_unused]] uint32 id, [[maybe_unused]] uint32 value) { }
virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id) { }
virtual ObjectGuid GetGUID([[maybe_unused]] int32 id) const { return ObjectGuid::Empty; }
// Select the best target (in order) from the threat list that fulfill the following:
// - Not among the first entries in order (or SelectTargetMethod::MaxThreat order,
// if is SelectTargetMethod::Random).
// - Within at most yards (if dist > 0.0f)
// - At least - yards away (if dist < 0.0f)
// - Is a player (if playerOnly = true)
// - Not the current tank (if withTank = false)
// - Has aura with ID (if aura > 0)
// - Does not have aura with ID - (if aura < 0)
Unit* SelectTarget(SelectTargetMethod targetType, uint32 offset = 0, float dist = 0.0f, bool playerOnly = false, bool withTank = true, int32 aura = 0);
// Select the best target (in order) satisfying from the threat list.
// If is nonzero, the first entries in order (or SelectTargetMethod::MaxThreat
// order, if is SelectTargetMethod::Random) are skipped.
template
Unit* SelectTarget(SelectTargetMethod targetType, uint32 offset, PREDICATE const& predicate)
{
std::list targetList;
SelectTargetList(targetList, std::numeric_limits::max(), targetType, offset, predicate);
return FinalizeTargetSelection(targetList, targetType);
}
// Select the best (up to) targets (in order) from the threat list that fulfill the following:
// - Not among the first entries in order (or SelectTargetMethod::MaxThreat order,
// if is SelectTargetMethod::Random).
// - Within at most yards (if dist > 0.0f)
// - At least - yards away (if dist < 0.0f)
// - Is a player (if playerOnly = true)
// - Not the current tank (if withTank = false)
// - Has aura with ID (if aura > 0)
// - Does not have aura with ID - (if aura < 0)
// The resulting targets are stored in (which is cleared first).
void SelectTargetList(std::list& targetList, uint32 num, SelectTargetMethod targetType, uint32 offset = 0, float dist = 0.0f, bool playerOnly = false, bool withTank = true, int32 aura = 0);
// Select the best (up to) targets (in order) satisfying from the threat list and stores them in (which is cleared first).
// If is nonzero, the first entries in order (or SelectTargetMethod::MaxThreat
// order, if is SelectTargetMethod::Random) are skipped.
template
void SelectTargetList(std::list& targetList, uint32 num, SelectTargetMethod targetType, uint32 offset, PREDICATE const& predicate)
{
if (!PrepareTargetListSelection(targetList, targetType, offset))
return;
// then finally filter by predicate
targetList.remove_if([&predicate](Unit* target) { return !predicate(target); });
FinalizeTargetListSelection(targetList, num, targetType);
}
// Called when the unit enters combat
// (NOTE: Creature engage logic should NOT be here, but in JustEngagedWith, which happens once threat is established!)
virtual void JustEnteredCombat(Unit* /*who*/) { }
// Called when the unit leaves combat
virtual void JustExitedCombat() { }
// Called when the unit is about to be removed from the world (despawn, grid unload, corpse disappearing, player logging out etc.)
virtual void OnDespawn() { }
// Called at any Damage to any victim (before damage apply)
virtual void DamageDealt(Unit* /*victim*/, uint32& /*damage*/, DamageEffectType /*damageType*/) { }
// Called at any Damage from any attacker (before damage apply)
// Note: it for recalculation damage or special reaction at damage
virtual void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) { }
// Called when the creature receives heal
virtual void HealReceived(Unit* /*done_by*/, uint32& /*addhealth*/) { }
// Called when the unit heals
virtual void HealDone(Unit* /*done_to*/, uint32& /*addhealth*/) { }
/// Called when a spell is interrupted by Spell::EffectInterruptCast
/// Use to reschedule next planned cast of spell.
virtual void SpellInterrupted(uint32 /*spellId*/, uint32 /*unTimeMs*/) { }
void AttackStartCaster(Unit* victim, float dist);
SpellCastResult DoCast(uint32 spellId);
SpellCastResult DoCast(Unit* victim, uint32 spellId, CastSpellExtraArgs const& args = {});
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const& args = {}) { return DoCast(me, spellId, args); }
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const& args = {});
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const& args = {}) { return DoCast(nullptr, spellId, args); }
bool DoSpellAttackIfReady(uint32 spellId);
static std::unordered_map, AISpellInfoType> AISpellInfo;
static void FillAISpellInfo();
// Called when a game event starts or ends
virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) { }
virtual std::string GetDebugInfo() const;
private:
UnitAI(UnitAI const& right) = delete;
UnitAI& operator=(UnitAI const& right) = delete;
Unit* FinalizeTargetSelection(std::list& targetList, SelectTargetMethod targetType);
bool PrepareTargetListSelection(std::list& targetList, SelectTargetMethod targetType, uint32 offset);
void FinalizeTargetListSelection(std::list& targetList, uint32 num, SelectTargetMethod targetType);
};
#endif