mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 01:37:00 +00:00
[12676] AI-Event throwing and receiving implementation
Add new AI hooks to * SendAIEvent (either around the npc, or to a specified npc) * ReceiveAIEvent (hook to receive sent events)
This commit is contained in:
parent
60a7bec73f
commit
c7a07a7dc6
5 changed files with 141 additions and 63 deletions
|
|
@ -97,34 +97,6 @@ VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint8 type, u
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
if (Unit* victim = m_owner.GetMap()->GetUnit(m_victimGuid))
|
||||
{
|
||||
while (!m_assistantGuids.empty())
|
||||
{
|
||||
Creature* assistant = m_owner.GetMap()->GetAnyTypeCreature(*m_assistantGuids.rbegin());
|
||||
m_assistantGuids.pop_back();
|
||||
|
||||
if (assistant && assistant->CanAssistTo(&m_owner, victim))
|
||||
{
|
||||
assistant->SetNoCallAssistance(true);
|
||||
if (assistant->AI())
|
||||
assistant->AI()->AttackStart(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AssistDelayEvent::AssistDelayEvent(ObjectGuid victim, Unit& owner, std::list<Creature*> const& assistants) : BasicEvent(), m_victimGuid(victim), m_owner(owner)
|
||||
{
|
||||
// Pushing guids because in delay can happen some creature gets despawned => invalid pointer
|
||||
m_assistantGuids.reserve(assistants.size());
|
||||
for (std::list<Creature*>::const_iterator itr = assistants.begin(); itr != assistants.end(); ++itr)
|
||||
m_assistantGuids.push_back((*itr)->GetObjectGuid());
|
||||
}
|
||||
|
||||
bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
m_owner.ForcedDespawn();
|
||||
|
|
@ -1800,24 +1772,7 @@ void Creature::CallAssistance()
|
|||
if (!m_AlreadyCallAssistance && getVictim() && !isCharmed())
|
||||
{
|
||||
SetNoCallAssistance(true);
|
||||
|
||||
float radius = sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS);
|
||||
if (radius > 0)
|
||||
{
|
||||
std::list<Creature*> assistList;
|
||||
|
||||
{
|
||||
MaNGOS::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius);
|
||||
MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(assistList, u_check);
|
||||
Cell::VisitGridObjects(this, searcher, radius);
|
||||
}
|
||||
|
||||
if (!assistList.empty())
|
||||
{
|
||||
AssistDelayEvent* e = new AssistDelayEvent(getVictim()->GetObjectGuid(), *this, assistList);
|
||||
m_Events.AddEvent(e, m_Events.CalculateTime(sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY)));
|
||||
}
|
||||
}
|
||||
AI()->SendAIEvent(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1846,7 +1801,7 @@ bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /
|
|||
return false;
|
||||
|
||||
// skip fighting creature
|
||||
if (isInCombat())
|
||||
if (enemy && isInCombat())
|
||||
return false;
|
||||
|
||||
// only free creature
|
||||
|
|
@ -1866,7 +1821,7 @@ bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /
|
|||
}
|
||||
|
||||
// skip non hostile to caster enemy creatures
|
||||
if (!IsHostileTo(enemy))
|
||||
if (enemy && !IsHostileTo(enemy))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -780,20 +780,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
|
|||
CreatureInfo const* m_creatureInfo; // in difficulty mode > 0 can different from ObjMgr::GetCreatureTemplate(GetEntry())
|
||||
};
|
||||
|
||||
class AssistDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
AssistDelayEvent(ObjectGuid victim, Unit& owner, std::list<Creature*> const& assistants);
|
||||
|
||||
bool Execute(uint64 e_time, uint32 p_time) override;
|
||||
private:
|
||||
AssistDelayEvent();
|
||||
|
||||
ObjectGuid m_victimGuid;
|
||||
GuidVector m_assistantGuids;
|
||||
Unit& m_owner;
|
||||
};
|
||||
|
||||
class ForcedDespawnDelayEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
#include "Creature.h"
|
||||
#include "DBCStores.h"
|
||||
#include "Spell.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
CreatureAI::~CreatureAI()
|
||||
{
|
||||
|
|
@ -152,3 +155,79 @@ void CreatureAI::HandleMovementOnAttackStart(Unit* victim)
|
|||
m_creature->StopMoving();
|
||||
}
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Event system
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AiDelayEventAround : public BasicEvent
|
||||
{
|
||||
public:
|
||||
AiDelayEventAround(AIEventType eventType, ObjectGuid invokerGuid, Creature& owner, std::list<Creature*> const& receivers) :
|
||||
BasicEvent(),
|
||||
m_eventType(eventType),
|
||||
m_invokerGuid(invokerGuid),
|
||||
m_owner(owner)
|
||||
{
|
||||
// Pushing guids because in delay can happen some creature gets despawned => invalid pointer
|
||||
m_receiverGuids.reserve(receivers.size());
|
||||
for (std::list<Creature*>::const_iterator itr = receivers.begin(); itr != receivers.end(); ++itr)
|
||||
m_receiverGuids.push_back((*itr)->GetObjectGuid());
|
||||
}
|
||||
|
||||
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
|
||||
{
|
||||
Unit* pInvoker = m_owner.GetMap()->GetUnit(m_invokerGuid);
|
||||
|
||||
for (GuidVector::const_reverse_iterator itr = m_receiverGuids.rbegin(); itr != m_receiverGuids.rend(); ++itr)
|
||||
{
|
||||
if (Creature* pReceiver = m_owner.GetMap()->GetAnyTypeCreature(*itr))
|
||||
{
|
||||
pReceiver->AI()->ReceiveAIEvent(m_eventType, &m_owner, pInvoker);
|
||||
// Special case for type 0 (call-assistance)
|
||||
if (m_eventType == AI_EVENT_CALL_ASSISTANCE && pInvoker && pReceiver->CanAssistTo(&m_owner, pInvoker))
|
||||
{
|
||||
pReceiver->SetNoCallAssistance(true);
|
||||
pReceiver->AI()->AttackStart(pInvoker);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_receiverGuids.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
AiDelayEventAround();
|
||||
|
||||
ObjectGuid m_invokerGuid;
|
||||
GuidVector m_receiverGuids;
|
||||
Creature& m_owner;
|
||||
|
||||
AIEventType m_eventType;
|
||||
};
|
||||
|
||||
void CreatureAI::SendAIEvent(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius) const
|
||||
{
|
||||
if (fRadius > 0)
|
||||
{
|
||||
std::list<Creature*> receiverList;
|
||||
|
||||
// Use this check here to collect only assitable creatures in case of CALL_ASSISTANCE, else be less strict
|
||||
MaNGOS::AnyAssistCreatureInRangeCheck u_check(m_creature, eventType == AI_EVENT_CALL_ASSISTANCE ? pInvoker : NULL, fRadius);
|
||||
MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(receiverList, u_check);
|
||||
Cell::VisitGridObjects(m_creature, searcher, fRadius);
|
||||
|
||||
if (!receiverList.empty())
|
||||
{
|
||||
AiDelayEventAround* e = new AiDelayEventAround(eventType, pInvoker ? pInvoker->GetObjectGuid() : ObjectGuid(), *m_creature, receiverList);
|
||||
m_creature->m_Events.AddEvent(e, m_creature->m_Events.CalculateTime(uiDelay));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAI::SendAIEvent(AIEventType eventType, Unit* pInvoker, Creature* pReceiver) const
|
||||
{
|
||||
MANGOS_ASSERT(pReceiver);
|
||||
pReceiver->AI()->ReceiveAIEvent(eventType, m_creature, pInvoker);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,37 @@ enum CastFlags
|
|||
CAST_AURA_NOT_PRESENT = 0x20, // Only casts the spell if the target does not have an aura from the spell
|
||||
};
|
||||
|
||||
enum AIEventType
|
||||
{
|
||||
// Usable with Event AI
|
||||
AI_EVENT_JUST_DIED = 0, // Sender = Killed Npc, Invoker = Killer
|
||||
AI_EVENT_CRITICAL_HEALTH = 1, // Sender = Hurt Npc, Invoker = DamageDealer
|
||||
AI_EVENT_LOST_HEALTH = 2, // Sender = Hurt Npc, Invoker = DamageDealer
|
||||
AI_EVENT_GOT_CCED = 3, // Sender = CCed Npc, Invoker = Caster that CCed
|
||||
AI_EVENT_GOT_FULL_HEALTH = 4, // Sender = Healed Npc, Invoker = Healer
|
||||
AI_EVENT_CUSTOM_EVENTAI_A = 5, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists)
|
||||
AI_EVENT_CUSTOM_EVENTAI_B = 6, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists)
|
||||
MAXIMAL_AI_EVENT_EVENTAI = 7,
|
||||
|
||||
// Internal Use
|
||||
AI_EVENT_CALL_ASSISTANCE = 10, // Sender = Attacked Npc, Invoker = Enemy
|
||||
|
||||
// Predefined for SD2
|
||||
AI_EVENT_START_ESCORT = 100, // Invoker = Escorting Player
|
||||
AI_EVENT_START_ESCORT_B = 101, // Invoker = Escorting Player
|
||||
AI_EVENT_START_EVENT = 102, // Invoker = EventStarter
|
||||
AI_EVENT_START_EVENT_A = 103, // Invoker = EventStarter
|
||||
AI_EVENT_START_EVENT_B = 104, // Invoker = EventStarter
|
||||
|
||||
// Some IDs for special cases in SD2
|
||||
AI_EVENT_CUSTOM_A = 1000,
|
||||
AI_EVENT_CUSTOM_B = 1001,
|
||||
AI_EVENT_CUSTOM_C = 1002,
|
||||
AI_EVENT_CUSTOM_D = 1003,
|
||||
AI_EVENT_CUSTOM_E = 1004,
|
||||
AI_EVENT_CUSTOM_F = 1005,
|
||||
};
|
||||
|
||||
class MANGOS_DLL_SPEC CreatureAI
|
||||
{
|
||||
public:
|
||||
|
|
@ -277,6 +308,33 @@ class MANGOS_DLL_SPEC CreatureAI
|
|||
void SetCombatMovement(bool enable, bool stopOrStartMovement = false);
|
||||
bool IsCombatMovement() const { return m_isCombatMovement; }
|
||||
|
||||
///== Event Handling ===============================
|
||||
|
||||
/**
|
||||
* Send an AI Event to nearby Creatures around
|
||||
* @param uiType number to specify the event, default cases listed in enum AIEventType
|
||||
* @param pInvoker Unit that triggered this event (like an attacker)
|
||||
* @param uiDelay delay time until the Event will be triggered
|
||||
* @param fRadius range in which for receiver is searched
|
||||
*/
|
||||
void SendAIEvent(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius) const;
|
||||
|
||||
/**
|
||||
* Send an AI Event to a Creature
|
||||
* @param eventType to specify the event, default cases listed in enum AIEventType
|
||||
* @param pInvoker Unit that triggered this event (like an attacker)
|
||||
* @param pReceiver Creature to receive this event
|
||||
*/
|
||||
void SendAIEvent(AIEventType eventType, Unit* pInvoker, Creature* pReceiver) const;
|
||||
|
||||
/**
|
||||
* Called when an AI Event is received
|
||||
* @param eventType to specify the event, default cases listed in enum AIEventType
|
||||
* @param pSender Creature that sent this event
|
||||
* @param pInvoker Unit that triggered this event (like an attacker)
|
||||
*/
|
||||
virtual void ReceiveAIEvent(AIEventType /*eventType*/, Creature* /*pSender*/, Unit* /*pInvoker*/) {}
|
||||
|
||||
protected:
|
||||
void HandleMovementOnAttackStart(Unit* victim);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "12675"
|
||||
#define REVISION_NR "12676"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue